@buildautomaton/cli 0.1.19 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +945 -543
- package/dist/cli.js.map +4 -4
- package/dist/index.js +912 -514
- package/dist/index.js.map +4 -4
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -2240,7 +2240,7 @@ var require_websocket = __commonJS({
|
|
|
2240
2240
|
var http = __require("http");
|
|
2241
2241
|
var net = __require("net");
|
|
2242
2242
|
var tls = __require("tls");
|
|
2243
|
-
var { randomBytes: randomBytes2, createHash
|
|
2243
|
+
var { randomBytes: randomBytes2, createHash } = __require("crypto");
|
|
2244
2244
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
2245
2245
|
var { URL: URL2 } = __require("url");
|
|
2246
2246
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -2900,7 +2900,7 @@ var require_websocket = __commonJS({
|
|
|
2900
2900
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
2901
2901
|
return;
|
|
2902
2902
|
}
|
|
2903
|
-
const digest =
|
|
2903
|
+
const digest = createHash("sha1").update(key + GUID).digest("base64");
|
|
2904
2904
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
2905
2905
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
2906
2906
|
return;
|
|
@@ -3267,7 +3267,7 @@ var require_websocket_server = __commonJS({
|
|
|
3267
3267
|
var EventEmitter2 = __require("events");
|
|
3268
3268
|
var http = __require("http");
|
|
3269
3269
|
var { Duplex } = __require("stream");
|
|
3270
|
-
var { createHash
|
|
3270
|
+
var { createHash } = __require("crypto");
|
|
3271
3271
|
var extension = require_extension();
|
|
3272
3272
|
var PerMessageDeflate = require_permessage_deflate();
|
|
3273
3273
|
var subprotocol = require_subprotocol();
|
|
@@ -3568,7 +3568,7 @@ var require_websocket_server = __commonJS({
|
|
|
3568
3568
|
);
|
|
3569
3569
|
}
|
|
3570
3570
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3571
|
-
const digest =
|
|
3571
|
+
const digest = createHash("sha1").update(key + GUID).digest("base64");
|
|
3572
3572
|
const headers = [
|
|
3573
3573
|
"HTTP/1.1 101 Switching Protocols",
|
|
3574
3574
|
"Upgrade: websocket",
|
|
@@ -20943,8 +20943,8 @@ var init_acp = __esm({
|
|
|
20943
20943
|
this.#requestHandler = requestHandler;
|
|
20944
20944
|
this.#notificationHandler = notificationHandler;
|
|
20945
20945
|
this.#stream = stream;
|
|
20946
|
-
this.#closedPromise = new Promise((
|
|
20947
|
-
this.#abortController.signal.addEventListener("abort", () =>
|
|
20946
|
+
this.#closedPromise = new Promise((resolve16) => {
|
|
20947
|
+
this.#abortController.signal.addEventListener("abort", () => resolve16());
|
|
20948
20948
|
});
|
|
20949
20949
|
this.#receive();
|
|
20950
20950
|
}
|
|
@@ -21093,8 +21093,8 @@ var init_acp = __esm({
|
|
|
21093
21093
|
}
|
|
21094
21094
|
async sendRequest(method, params) {
|
|
21095
21095
|
const id = this.#nextRequestId++;
|
|
21096
|
-
const responsePromise = new Promise((
|
|
21097
|
-
this.#pendingResponses.set(id, { resolve:
|
|
21096
|
+
const responsePromise = new Promise((resolve16, reject) => {
|
|
21097
|
+
this.#pendingResponses.set(id, { resolve: resolve16, reject });
|
|
21098
21098
|
});
|
|
21099
21099
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
21100
21100
|
return responsePromise;
|
|
@@ -21669,7 +21669,7 @@ var require_has_flag = __commonJS({
|
|
|
21669
21669
|
var require_supports_color = __commonJS({
|
|
21670
21670
|
"../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
|
|
21671
21671
|
"use strict";
|
|
21672
|
-
var
|
|
21672
|
+
var os7 = __require("os");
|
|
21673
21673
|
var tty = __require("tty");
|
|
21674
21674
|
var hasFlag = require_has_flag();
|
|
21675
21675
|
var { env } = process;
|
|
@@ -21717,7 +21717,7 @@ var require_supports_color = __commonJS({
|
|
|
21717
21717
|
return min;
|
|
21718
21718
|
}
|
|
21719
21719
|
if (process.platform === "win32") {
|
|
21720
|
-
const osRelease =
|
|
21720
|
+
const osRelease = os7.release().split(".");
|
|
21721
21721
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
21722
21722
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
21723
21723
|
}
|
|
@@ -22268,14 +22268,14 @@ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
|
|
|
22268
22268
|
return out.join("\n");
|
|
22269
22269
|
}
|
|
22270
22270
|
|
|
22271
|
-
// src/files/cwd/bridge-
|
|
22271
|
+
// src/files/cwd/bridge-root.ts
|
|
22272
22272
|
import * as path from "node:path";
|
|
22273
|
-
var
|
|
22274
|
-
function
|
|
22275
|
-
if (
|
|
22276
|
-
|
|
22273
|
+
var bridgeRootPath = null;
|
|
22274
|
+
function getBridgeRoot() {
|
|
22275
|
+
if (bridgeRootPath == null) {
|
|
22276
|
+
bridgeRootPath = path.resolve(process.cwd());
|
|
22277
22277
|
}
|
|
22278
|
-
return
|
|
22278
|
+
return bridgeRootPath;
|
|
22279
22279
|
}
|
|
22280
22280
|
|
|
22281
22281
|
// src/agents/acp/safe-fs-path.ts
|
|
@@ -22373,6 +22373,52 @@ function createSdkStdioExtNotificationHandler(options) {
|
|
|
22373
22373
|
}
|
|
22374
22374
|
}
|
|
22375
22375
|
|
|
22376
|
+
// src/agents/acp/enrich-acp-permission-rpc-result.ts
|
|
22377
|
+
var META_KEY = "permissionOptionKind";
|
|
22378
|
+
function optionRecordId(rec) {
|
|
22379
|
+
const raw = rec.optionId ?? rec.id;
|
|
22380
|
+
if (typeof raw === "string" && raw.trim() !== "") return raw.trim();
|
|
22381
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return String(raw);
|
|
22382
|
+
return "";
|
|
22383
|
+
}
|
|
22384
|
+
function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
|
|
22385
|
+
if (params == null || result == null || typeof result !== "object" || Array.isArray(result)) {
|
|
22386
|
+
return result;
|
|
22387
|
+
}
|
|
22388
|
+
const root = result;
|
|
22389
|
+
const outcome = root.outcome;
|
|
22390
|
+
if (outcome == null || typeof outcome !== "object" || Array.isArray(outcome)) return result;
|
|
22391
|
+
const o = outcome;
|
|
22392
|
+
if (o.outcome !== "selected" || typeof o.optionId !== "string" || o.optionId.trim() === "") {
|
|
22393
|
+
return result;
|
|
22394
|
+
}
|
|
22395
|
+
const selectedId = o.optionId.trim();
|
|
22396
|
+
const prevMeta = o._meta != null && typeof o._meta === "object" && !Array.isArray(o._meta) ? o._meta : {};
|
|
22397
|
+
if (typeof prevMeta[META_KEY] === "string" && prevMeta[META_KEY].trim() !== "") {
|
|
22398
|
+
return result;
|
|
22399
|
+
}
|
|
22400
|
+
const rawOpts = Array.isArray(params.options) ? params.options : [];
|
|
22401
|
+
let matchedKind;
|
|
22402
|
+
for (const item of rawOpts) {
|
|
22403
|
+
if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
|
|
22404
|
+
const rec = item;
|
|
22405
|
+
const id = optionRecordId(rec);
|
|
22406
|
+
if (!id || id !== selectedId) continue;
|
|
22407
|
+
if (typeof rec.kind === "string" && rec.kind.trim() !== "") {
|
|
22408
|
+
matchedKind = rec.kind.trim();
|
|
22409
|
+
break;
|
|
22410
|
+
}
|
|
22411
|
+
}
|
|
22412
|
+
if (!matchedKind) return result;
|
|
22413
|
+
return {
|
|
22414
|
+
...root,
|
|
22415
|
+
outcome: {
|
|
22416
|
+
...o,
|
|
22417
|
+
_meta: { ...prevMeta, [META_KEY]: matchedKind }
|
|
22418
|
+
}
|
|
22419
|
+
};
|
|
22420
|
+
}
|
|
22421
|
+
|
|
22376
22422
|
// src/agents/acp/clients/sdk-stdio-acp-client.ts
|
|
22377
22423
|
function formatSpawnError(err, command) {
|
|
22378
22424
|
if (err.code === "ENOENT") {
|
|
@@ -22394,7 +22440,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22394
22440
|
const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
|
|
22395
22441
|
const {
|
|
22396
22442
|
command,
|
|
22397
|
-
cwd =
|
|
22443
|
+
cwd = getBridgeRoot(),
|
|
22398
22444
|
backendAgentType,
|
|
22399
22445
|
onSessionUpdate,
|
|
22400
22446
|
onRequest,
|
|
@@ -22413,7 +22459,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22413
22459
|
child.once("close", (code, signal) => {
|
|
22414
22460
|
onAgentSubprocessExit?.({ code, signal });
|
|
22415
22461
|
});
|
|
22416
|
-
return new Promise((
|
|
22462
|
+
return new Promise((resolve16, reject) => {
|
|
22417
22463
|
let initSettled = false;
|
|
22418
22464
|
const settleReject = (err) => {
|
|
22419
22465
|
if (initSettled) return;
|
|
@@ -22427,7 +22473,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22427
22473
|
const settleResolve = (handle) => {
|
|
22428
22474
|
if (initSettled) return;
|
|
22429
22475
|
initSettled = true;
|
|
22430
|
-
|
|
22476
|
+
resolve16(handle);
|
|
22431
22477
|
};
|
|
22432
22478
|
child.on("error", (err) => {
|
|
22433
22479
|
settleReject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -22450,7 +22496,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22450
22496
|
onSessionUpdate
|
|
22451
22497
|
});
|
|
22452
22498
|
let permissionSeq = 0;
|
|
22453
|
-
const
|
|
22499
|
+
const pendingPermissionReplies = /* @__PURE__ */ new Map();
|
|
22454
22500
|
const client = (_agent) => ({
|
|
22455
22501
|
async requestPermission(params) {
|
|
22456
22502
|
const requestId = `perm-${++permissionSeq}`;
|
|
@@ -22463,15 +22509,15 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22463
22509
|
});
|
|
22464
22510
|
} catch {
|
|
22465
22511
|
}
|
|
22466
|
-
return await new Promise((
|
|
22467
|
-
|
|
22512
|
+
return await new Promise((resolve17) => {
|
|
22513
|
+
pendingPermissionReplies.set(requestId, { resolve: resolve17, params: paramsRecord });
|
|
22468
22514
|
});
|
|
22469
22515
|
},
|
|
22470
22516
|
async readTextFile(params) {
|
|
22471
|
-
const
|
|
22472
|
-
if (!
|
|
22517
|
+
const resolvedPath = resolveSafePathUnderCwd(cwd, params.path);
|
|
22518
|
+
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
22473
22519
|
try {
|
|
22474
|
-
let content = readFileSync(
|
|
22520
|
+
let content = readFileSync(resolvedPath, "utf8");
|
|
22475
22521
|
content = sliceFileContentRange(content, params.line, params.limit);
|
|
22476
22522
|
return { content };
|
|
22477
22523
|
} catch (e) {
|
|
@@ -22480,17 +22526,17 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22480
22526
|
}
|
|
22481
22527
|
},
|
|
22482
22528
|
async writeTextFile(params) {
|
|
22483
|
-
const
|
|
22484
|
-
if (!
|
|
22529
|
+
const resolvedPath = resolveSafePathUnderCwd(cwd, params.path);
|
|
22530
|
+
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
22485
22531
|
let oldText = "";
|
|
22486
22532
|
try {
|
|
22487
|
-
oldText = readFileSync(
|
|
22533
|
+
oldText = readFileSync(resolvedPath, "utf8");
|
|
22488
22534
|
} catch (e) {
|
|
22489
22535
|
if (e.code !== "ENOENT") throw e;
|
|
22490
22536
|
}
|
|
22491
|
-
mkdirSync(dirname(
|
|
22492
|
-
writeFileSync(
|
|
22493
|
-
const displayPath = toDisplayPathRelativeToCwd(cwd,
|
|
22537
|
+
mkdirSync(dirname(resolvedPath), { recursive: true });
|
|
22538
|
+
writeFileSync(resolvedPath, params.content, "utf8");
|
|
22539
|
+
const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
|
|
22494
22540
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, params.content);
|
|
22495
22541
|
onFileChange?.({ path: displayPath, oldText, newText: params.content, patchContent });
|
|
22496
22542
|
return {};
|
|
@@ -22572,9 +22618,9 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22572
22618
|
}
|
|
22573
22619
|
},
|
|
22574
22620
|
async cancel() {
|
|
22575
|
-
for (const [id,
|
|
22576
|
-
|
|
22577
|
-
|
|
22621
|
+
for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
|
|
22622
|
+
pendingPermissionReplies.delete(id);
|
|
22623
|
+
entry.resolve({ outcome: { outcome: "cancelled" } });
|
|
22578
22624
|
}
|
|
22579
22625
|
try {
|
|
22580
22626
|
await connection.cancel({ sessionId });
|
|
@@ -22590,10 +22636,11 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22590
22636
|
}
|
|
22591
22637
|
},
|
|
22592
22638
|
resolveRequest(requestId, result) {
|
|
22593
|
-
const
|
|
22594
|
-
if (!
|
|
22595
|
-
|
|
22596
|
-
|
|
22639
|
+
const entry = pendingPermissionReplies.get(requestId);
|
|
22640
|
+
if (!entry) return;
|
|
22641
|
+
pendingPermissionReplies.delete(requestId);
|
|
22642
|
+
const enriched = enrichAcpPermissionRpcResultFromRequestParams(result, entry.params);
|
|
22643
|
+
entry.resolve(enriched);
|
|
22597
22644
|
},
|
|
22598
22645
|
disconnect() {
|
|
22599
22646
|
child.kill();
|
|
@@ -22700,7 +22747,7 @@ async function proxyToLocal(request) {
|
|
|
22700
22747
|
};
|
|
22701
22748
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
22702
22749
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
22703
|
-
const once = await new Promise((
|
|
22750
|
+
const once = await new Promise((resolve16) => {
|
|
22704
22751
|
const req = mod.request(opts, (res) => {
|
|
22705
22752
|
const chunks = [];
|
|
22706
22753
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -22711,7 +22758,7 @@ async function proxyToLocal(request) {
|
|
|
22711
22758
|
if (typeof v === "string") headers[k] = v;
|
|
22712
22759
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
22713
22760
|
}
|
|
22714
|
-
|
|
22761
|
+
resolve16({
|
|
22715
22762
|
id: request.id,
|
|
22716
22763
|
statusCode: res.statusCode ?? 0,
|
|
22717
22764
|
headers,
|
|
@@ -22720,7 +22767,7 @@ async function proxyToLocal(request) {
|
|
|
22720
22767
|
});
|
|
22721
22768
|
});
|
|
22722
22769
|
req.on("error", (err) => {
|
|
22723
|
-
|
|
22770
|
+
resolve16({
|
|
22724
22771
|
id: request.id,
|
|
22725
22772
|
statusCode: 0,
|
|
22726
22773
|
headers: {},
|
|
@@ -22862,7 +22909,7 @@ var previewSkill = {
|
|
|
22862
22909
|
const exe = parts[0];
|
|
22863
22910
|
const args = parts.slice(1);
|
|
22864
22911
|
previewProcess = spawn2(isWindows && exe === "npm" ? "npm.cmd" : exe, args, {
|
|
22865
|
-
cwd:
|
|
22912
|
+
cwd: getBridgeRoot(),
|
|
22866
22913
|
stdio: ["ignore", "pipe", "pipe"],
|
|
22867
22914
|
env: {
|
|
22868
22915
|
...process.env,
|
|
@@ -23041,7 +23088,7 @@ function installBridgeProcessResilience() {
|
|
|
23041
23088
|
}
|
|
23042
23089
|
|
|
23043
23090
|
// src/cli-version.ts
|
|
23044
|
-
var CLI_VERSION = "0.1.
|
|
23091
|
+
var CLI_VERSION = "0.1.21".length > 0 ? "0.1.21" : "0.0.0-dev";
|
|
23045
23092
|
|
|
23046
23093
|
// ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
|
|
23047
23094
|
import process7 from "node:process";
|
|
@@ -23476,14 +23523,14 @@ var baseOpen = async (options) => {
|
|
|
23476
23523
|
}
|
|
23477
23524
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
23478
23525
|
if (options.wait) {
|
|
23479
|
-
return new Promise((
|
|
23526
|
+
return new Promise((resolve16, reject) => {
|
|
23480
23527
|
subprocess.once("error", reject);
|
|
23481
23528
|
subprocess.once("close", (exitCode) => {
|
|
23482
23529
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
23483
23530
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
23484
23531
|
return;
|
|
23485
23532
|
}
|
|
23486
|
-
|
|
23533
|
+
resolve16(subprocess);
|
|
23487
23534
|
});
|
|
23488
23535
|
});
|
|
23489
23536
|
}
|
|
@@ -23779,8 +23826,8 @@ function runPendingAuth(options) {
|
|
|
23779
23826
|
let hasOpenedBrowser = false;
|
|
23780
23827
|
let resolved = false;
|
|
23781
23828
|
let resolveAuth;
|
|
23782
|
-
const authPromise = new Promise((
|
|
23783
|
-
resolveAuth =
|
|
23829
|
+
const authPromise = new Promise((resolve16) => {
|
|
23830
|
+
resolveAuth = resolve16;
|
|
23784
23831
|
});
|
|
23785
23832
|
let reconnectAttempt = 0;
|
|
23786
23833
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -23902,7 +23949,7 @@ function runPendingAuth(options) {
|
|
|
23902
23949
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
23903
23950
|
const say = log2 ?? logImmediate;
|
|
23904
23951
|
say("Cleaning up connections\u2026");
|
|
23905
|
-
await new Promise((
|
|
23952
|
+
await new Promise((resolve16) => setImmediate(resolve16));
|
|
23906
23953
|
state.closedByUser = true;
|
|
23907
23954
|
clearReconnectQuietTimer(state.mainQuiet);
|
|
23908
23955
|
clearReconnectQuietTimer(state.firehoseQuiet);
|
|
@@ -23944,21 +23991,36 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
|
|
|
23944
23991
|
say("Shutdown complete.");
|
|
23945
23992
|
}
|
|
23946
23993
|
|
|
23994
|
+
// src/paths/session-layout-paths.ts
|
|
23995
|
+
import * as path5 from "node:path";
|
|
23996
|
+
function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
|
|
23997
|
+
const resolved = worktreePaths.map((p) => path5.resolve(p)).filter(Boolean);
|
|
23998
|
+
if (resolved.length === 0) return null;
|
|
23999
|
+
resolved.sort();
|
|
24000
|
+
return resolved[0];
|
|
24001
|
+
}
|
|
24002
|
+
function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
|
|
24003
|
+
if (resolvedSessionParentPath != null && String(resolvedSessionParentPath).trim() !== "") {
|
|
24004
|
+
return path5.resolve(String(resolvedSessionParentPath).trim());
|
|
24005
|
+
}
|
|
24006
|
+
return getBridgeRoot();
|
|
24007
|
+
}
|
|
24008
|
+
|
|
23947
24009
|
// src/git/session-git-queue.ts
|
|
23948
24010
|
import { execFile as execFile7 } from "node:child_process";
|
|
23949
24011
|
import { readFile, stat } from "node:fs/promises";
|
|
23950
24012
|
import { promisify as promisify7 } from "node:util";
|
|
23951
|
-
import * as
|
|
24013
|
+
import * as path8 from "node:path";
|
|
23952
24014
|
|
|
23953
24015
|
// src/git/pre-turn-snapshot.ts
|
|
23954
24016
|
import * as fs8 from "node:fs";
|
|
23955
|
-
import * as
|
|
24017
|
+
import * as path7 from "node:path";
|
|
23956
24018
|
import { execFile as execFile6 } from "node:child_process";
|
|
23957
24019
|
import { promisify as promisify6 } from "node:util";
|
|
23958
24020
|
|
|
23959
24021
|
// src/git/discover-repos.ts
|
|
23960
24022
|
import * as fs7 from "node:fs";
|
|
23961
|
-
import * as
|
|
24023
|
+
import * as path6 from "node:path";
|
|
23962
24024
|
|
|
23963
24025
|
// ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
|
|
23964
24026
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -28543,9 +28605,9 @@ async function isGitRepoDirectory(dirPath) {
|
|
|
28543
28605
|
}
|
|
28544
28606
|
|
|
28545
28607
|
// src/git/discover-repos.ts
|
|
28546
|
-
async function discoverGitRepos(cwd =
|
|
28608
|
+
async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
28547
28609
|
const result = [];
|
|
28548
|
-
const cwdResolved =
|
|
28610
|
+
const cwdResolved = path6.resolve(cwd);
|
|
28549
28611
|
if (await isGitRepoDirectory(cwdResolved)) {
|
|
28550
28612
|
const remoteUrl = await getRemoteOriginUrl(cwdResolved);
|
|
28551
28613
|
result.push({ absolutePath: cwdResolved, remoteUrl });
|
|
@@ -28558,7 +28620,7 @@ async function discoverGitRepos(cwd = getBridgeWorkspaceDirectory()) {
|
|
|
28558
28620
|
}
|
|
28559
28621
|
for (const ent of entries) {
|
|
28560
28622
|
if (!ent.isDirectory()) continue;
|
|
28561
|
-
const childPath =
|
|
28623
|
+
const childPath = path6.join(cwdResolved, ent.name);
|
|
28562
28624
|
if (await isGitRepoDirectory(childPath)) {
|
|
28563
28625
|
const remoteUrl = await getRemoteOriginUrl(childPath);
|
|
28564
28626
|
result.push({ absolutePath: childPath, remoteUrl });
|
|
@@ -28566,12 +28628,12 @@ async function discoverGitRepos(cwd = getBridgeWorkspaceDirectory()) {
|
|
|
28566
28628
|
}
|
|
28567
28629
|
return result;
|
|
28568
28630
|
}
|
|
28569
|
-
async function discoverGitReposUnderRoot(
|
|
28570
|
-
const root =
|
|
28631
|
+
async function discoverGitReposUnderRoot(rootPath) {
|
|
28632
|
+
const root = path6.resolve(rootPath);
|
|
28571
28633
|
const roots = [];
|
|
28572
28634
|
async function walk(dir) {
|
|
28573
28635
|
if (await isGitRepoDirectory(dir)) {
|
|
28574
|
-
roots.push(
|
|
28636
|
+
roots.push(path6.resolve(dir));
|
|
28575
28637
|
return;
|
|
28576
28638
|
}
|
|
28577
28639
|
let entries;
|
|
@@ -28582,7 +28644,7 @@ async function discoverGitReposUnderRoot(rootAbs) {
|
|
|
28582
28644
|
}
|
|
28583
28645
|
for (const ent of entries) {
|
|
28584
28646
|
if (!ent.isDirectory() || ent.name === ".git") continue;
|
|
28585
|
-
await walk(
|
|
28647
|
+
await walk(path6.join(dir, ent.name));
|
|
28586
28648
|
}
|
|
28587
28649
|
}
|
|
28588
28650
|
await walk(root);
|
|
@@ -28598,7 +28660,7 @@ async function discoverGitReposUnderRoot(rootAbs) {
|
|
|
28598
28660
|
// src/git/pre-turn-snapshot.ts
|
|
28599
28661
|
var execFileAsync5 = promisify6(execFile6);
|
|
28600
28662
|
function snapshotsDirForCwd(agentCwd) {
|
|
28601
|
-
return
|
|
28663
|
+
return path7.join(agentCwd, ".buildautomaton", "snapshots");
|
|
28602
28664
|
}
|
|
28603
28665
|
async function gitStashCreate(repoRoot, log2) {
|
|
28604
28666
|
try {
|
|
@@ -28625,14 +28687,20 @@ async function gitRun(repoRoot, args, log2, label) {
|
|
|
28625
28687
|
}
|
|
28626
28688
|
}
|
|
28627
28689
|
async function resolveSnapshotRepoRoots(options) {
|
|
28628
|
-
const { worktreePaths, fallbackCwd, log: log2 } = options;
|
|
28690
|
+
const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
|
|
28629
28691
|
if (worktreePaths?.length) {
|
|
28630
|
-
const uniq = [...new Set(worktreePaths.map((p) =>
|
|
28692
|
+
const uniq = [...new Set(worktreePaths.map((p) => path7.resolve(p)))];
|
|
28631
28693
|
return uniq;
|
|
28632
28694
|
}
|
|
28633
28695
|
try {
|
|
28634
28696
|
const repos = await discoverGitReposUnderRoot(fallbackCwd);
|
|
28635
|
-
|
|
28697
|
+
const mapped = repos.map((r) => r.absolutePath);
|
|
28698
|
+
const sid = sessionId?.trim();
|
|
28699
|
+
if (sid) {
|
|
28700
|
+
const filtered = mapped.filter((root) => path7.basename(root) === sid);
|
|
28701
|
+
if (filtered.length > 0) return filtered;
|
|
28702
|
+
}
|
|
28703
|
+
return mapped;
|
|
28636
28704
|
} catch (e) {
|
|
28637
28705
|
log2(`[snapshot] Discover repositories failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
28638
28706
|
return [];
|
|
@@ -28659,7 +28727,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
28659
28727
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
28660
28728
|
repos
|
|
28661
28729
|
};
|
|
28662
|
-
const filePath =
|
|
28730
|
+
const filePath = path7.join(dir, `${runId}.json`);
|
|
28663
28731
|
try {
|
|
28664
28732
|
fs8.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
28665
28733
|
} catch (e) {
|
|
@@ -28697,7 +28765,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
|
|
|
28697
28765
|
return { ok: true };
|
|
28698
28766
|
}
|
|
28699
28767
|
function snapshotFilePath(agentCwd, runId) {
|
|
28700
|
-
return
|
|
28768
|
+
return path7.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
|
|
28701
28769
|
}
|
|
28702
28770
|
|
|
28703
28771
|
// src/git/session-git-queue.ts
|
|
@@ -28746,7 +28814,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
28746
28814
|
continue;
|
|
28747
28815
|
}
|
|
28748
28816
|
const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
28749
|
-
const slug =
|
|
28817
|
+
const slug = path8.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
|
|
28750
28818
|
for (const rel of lines) {
|
|
28751
28819
|
if (rel.includes("..")) continue;
|
|
28752
28820
|
try {
|
|
@@ -28760,8 +28828,8 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
28760
28828
|
);
|
|
28761
28829
|
if (!patchContent.trim()) continue;
|
|
28762
28830
|
const displayPath = multiRepo ? `${slug}/${rel}` : rel;
|
|
28763
|
-
const
|
|
28764
|
-
const newText = await readWorkspaceFileAsUtf8(
|
|
28831
|
+
const workspaceFilePath = path8.join(repo.path, rel);
|
|
28832
|
+
const newText = await readWorkspaceFileAsUtf8(workspaceFilePath);
|
|
28765
28833
|
sendSessionUpdate({
|
|
28766
28834
|
type: "session_file_change",
|
|
28767
28835
|
sessionId,
|
|
@@ -28779,18 +28847,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
28779
28847
|
}
|
|
28780
28848
|
}
|
|
28781
28849
|
|
|
28782
|
-
// ../types/
|
|
28783
|
-
init_zod();
|
|
28784
|
-
init_zod();
|
|
28785
|
-
init_zod();
|
|
28786
|
-
init_zod();
|
|
28787
|
-
init_zod();
|
|
28788
|
-
init_zod();
|
|
28789
|
-
init_zod();
|
|
28790
|
-
init_zod();
|
|
28791
|
-
init_zod();
|
|
28792
|
-
init_zod();
|
|
28793
|
-
init_zod();
|
|
28850
|
+
// ../types/src/work-items.ts
|
|
28794
28851
|
init_zod();
|
|
28795
28852
|
var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
|
|
28796
28853
|
var WorkItemProgressSchema = external_exports.object({
|
|
@@ -28831,6 +28888,9 @@ var WorkItemSchema = external_exports.object({
|
|
|
28831
28888
|
dependencies: external_exports.array(WorkItemDependencySchema).default([]),
|
|
28832
28889
|
assignedToUserId: external_exports.string().optional()
|
|
28833
28890
|
});
|
|
28891
|
+
|
|
28892
|
+
// ../types/src/user-profiles.ts
|
|
28893
|
+
init_zod();
|
|
28834
28894
|
var UserWorkspaceProfileSchema = external_exports.object({
|
|
28835
28895
|
id: external_exports.string(),
|
|
28836
28896
|
workspaceId: external_exports.string(),
|
|
@@ -28840,6 +28900,9 @@ var UserWorkspaceProfileSchema = external_exports.object({
|
|
|
28840
28900
|
preferences: external_exports.record(external_exports.unknown()).optional(),
|
|
28841
28901
|
learnings: external_exports.array(external_exports.string())
|
|
28842
28902
|
});
|
|
28903
|
+
|
|
28904
|
+
// ../types/src/runtime.ts
|
|
28905
|
+
init_zod();
|
|
28843
28906
|
var WorkspaceOwnerInfoSchema = external_exports.object({
|
|
28844
28907
|
ownerId: external_exports.string(),
|
|
28845
28908
|
ownerName: external_exports.string().optional(),
|
|
@@ -28853,6 +28916,9 @@ var WorkspaceRuntimeEntrySchema = external_exports.object({
|
|
|
28853
28916
|
owner: WorkspaceOwnerInfoSchema.optional(),
|
|
28854
28917
|
isOwner: external_exports.boolean().optional()
|
|
28855
28918
|
});
|
|
28919
|
+
|
|
28920
|
+
// ../types/src/agent.ts
|
|
28921
|
+
init_zod();
|
|
28856
28922
|
var ProjectContextSchema = external_exports.object({
|
|
28857
28923
|
projectId: external_exports.string(),
|
|
28858
28924
|
context: external_exports.record(external_exports.unknown()).default({}),
|
|
@@ -28877,6 +28943,9 @@ var WebSocketMessageSchema = external_exports.object({
|
|
|
28877
28943
|
data: external_exports.any().optional(),
|
|
28878
28944
|
error: external_exports.string().optional()
|
|
28879
28945
|
});
|
|
28946
|
+
|
|
28947
|
+
// ../types/src/checkpoints.ts
|
|
28948
|
+
init_zod();
|
|
28880
28949
|
var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
|
|
28881
28950
|
var CheckpointSummarySchema = external_exports.object({
|
|
28882
28951
|
id: external_exports.string(),
|
|
@@ -28887,6 +28956,9 @@ var CheckpointSummarySchema = external_exports.object({
|
|
|
28887
28956
|
createdAt: external_exports.string(),
|
|
28888
28957
|
updatedAt: external_exports.string()
|
|
28889
28958
|
});
|
|
28959
|
+
|
|
28960
|
+
// ../types/src/threads.ts
|
|
28961
|
+
init_zod();
|
|
28890
28962
|
var ThreadMetaSchema = external_exports.object({
|
|
28891
28963
|
threadId: external_exports.string(),
|
|
28892
28964
|
workspaceId: external_exports.string(),
|
|
@@ -28914,6 +28986,9 @@ var ThreadMessageSchema = external_exports.object({
|
|
|
28914
28986
|
var ThreadCheckpointSummarySchema = CheckpointSummarySchema.extend({
|
|
28915
28987
|
threadId: external_exports.string()
|
|
28916
28988
|
});
|
|
28989
|
+
|
|
28990
|
+
// ../types/src/content-items.ts
|
|
28991
|
+
init_zod();
|
|
28917
28992
|
var ContentSourceSchema = external_exports.enum(["notion", "doc", "slack_thread", "other"]);
|
|
28918
28993
|
var ContentItemMetaSchema = external_exports.object({
|
|
28919
28994
|
contentId: external_exports.string(),
|
|
@@ -28935,6 +29010,9 @@ var ContentStorageRefSchema = external_exports.object({
|
|
|
28935
29010
|
var ContentCheckpointSummarySchema = CheckpointSummarySchema.extend({
|
|
28936
29011
|
contentId: external_exports.string()
|
|
28937
29012
|
});
|
|
29013
|
+
|
|
29014
|
+
// ../types/src/stories.ts
|
|
29015
|
+
init_zod();
|
|
28938
29016
|
var StoryMetaSchema = external_exports.object({
|
|
28939
29017
|
storyId: external_exports.string(),
|
|
28940
29018
|
workspaceId: external_exports.string(),
|
|
@@ -28957,6 +29035,9 @@ var StoryContentItemRefSchema = external_exports.object({
|
|
|
28957
29035
|
var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
|
|
28958
29036
|
storyId: external_exports.string()
|
|
28959
29037
|
});
|
|
29038
|
+
|
|
29039
|
+
// ../types/src/sessions.ts
|
|
29040
|
+
init_zod();
|
|
28960
29041
|
var BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID = "__builtin_change_summary__";
|
|
28961
29042
|
var SessionMetaSchema = external_exports.object({
|
|
28962
29043
|
sessionId: external_exports.string(),
|
|
@@ -28999,6 +29080,8 @@ var SessionThreadRefSchema = external_exports.object({
|
|
|
28999
29080
|
threadId: external_exports.string(),
|
|
29000
29081
|
addedAt: external_exports.string()
|
|
29001
29082
|
});
|
|
29083
|
+
|
|
29084
|
+
// ../types/src/change-summary-path.ts
|
|
29002
29085
|
function normalizeRepoRelativePath(p) {
|
|
29003
29086
|
let t = p.trim().replace(/\\/g, "/");
|
|
29004
29087
|
while (t.startsWith("./")) t = t.slice(2);
|
|
@@ -29015,6 +29098,8 @@ function resolveChangeSummaryPathAgainstAllowed(rawPath, allowed) {
|
|
|
29015
29098
|
}
|
|
29016
29099
|
return null;
|
|
29017
29100
|
}
|
|
29101
|
+
|
|
29102
|
+
// ../types/src/parse-change-summary-json.ts
|
|
29018
29103
|
function clampSummaryToAtMostTwoLines(summary) {
|
|
29019
29104
|
const lines = summary.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
|
|
29020
29105
|
return lines.slice(0, 2).join("\n");
|
|
@@ -29057,6 +29142,8 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
29057
29142
|
}
|
|
29058
29143
|
return rows;
|
|
29059
29144
|
}
|
|
29145
|
+
|
|
29146
|
+
// ../types/src/build-change-summary-prompt.ts
|
|
29060
29147
|
var PATCH_PREVIEW_MAX = 12e3;
|
|
29061
29148
|
function clip(s, max) {
|
|
29062
29149
|
if (s.length <= max) return s;
|
|
@@ -29114,6 +29201,8 @@ function buildSessionChangeSummaryPrompt(files) {
|
|
|
29114
29201
|
}
|
|
29115
29202
|
return lines.join("\n");
|
|
29116
29203
|
}
|
|
29204
|
+
|
|
29205
|
+
// ../types/src/dedupe-session-file-changes-by-path.ts
|
|
29117
29206
|
function defaultRichness(c) {
|
|
29118
29207
|
const patch = typeof c.patchContent === "string" ? c.patchContent.length : 0;
|
|
29119
29208
|
const nt = typeof c.newText === "string" ? c.newText.length : 0;
|
|
@@ -29131,6 +29220,9 @@ function dedupeSessionFileChangesByPath(items, richness = (item) => defaultRichn
|
|
|
29131
29220
|
}
|
|
29132
29221
|
return Array.from(byPath.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);
|
|
29133
29222
|
}
|
|
29223
|
+
|
|
29224
|
+
// ../types/src/artifacts.ts
|
|
29225
|
+
init_zod();
|
|
29134
29226
|
var ArtifactMetaSchema = external_exports.object({
|
|
29135
29227
|
artifactId: external_exports.string(),
|
|
29136
29228
|
workspaceId: external_exports.string(),
|
|
@@ -29144,6 +29236,9 @@ var ArtifactMetaSchema = external_exports.object({
|
|
|
29144
29236
|
createdAt: external_exports.string(),
|
|
29145
29237
|
updatedAt: external_exports.string()
|
|
29146
29238
|
});
|
|
29239
|
+
|
|
29240
|
+
// ../types/src/templates.ts
|
|
29241
|
+
init_zod();
|
|
29147
29242
|
var TemplateMetaSchema = external_exports.object({
|
|
29148
29243
|
templateId: external_exports.string(),
|
|
29149
29244
|
workspaceId: external_exports.string(),
|
|
@@ -29153,6 +29248,9 @@ var TemplateMetaSchema = external_exports.object({
|
|
|
29153
29248
|
createdAt: external_exports.string(),
|
|
29154
29249
|
updatedAt: external_exports.string()
|
|
29155
29250
|
});
|
|
29251
|
+
|
|
29252
|
+
// ../types/src/git-repos.ts
|
|
29253
|
+
init_zod();
|
|
29156
29254
|
var GitRepoMetaSchema = external_exports.object({
|
|
29157
29255
|
/** Stable id for the repo (e.g. hash of normalized canonical URL). Used for DO idFromName. */
|
|
29158
29256
|
repoId: external_exports.string(),
|
|
@@ -29346,7 +29444,7 @@ async function sendPromptToAgent(options) {
|
|
|
29346
29444
|
|
|
29347
29445
|
// src/agents/acp/ensure-acp-client.ts
|
|
29348
29446
|
import * as fs9 from "node:fs";
|
|
29349
|
-
import * as
|
|
29447
|
+
import * as path11 from "node:path";
|
|
29350
29448
|
|
|
29351
29449
|
// src/error-message.ts
|
|
29352
29450
|
function errorMessage(err) {
|
|
@@ -29447,7 +29545,7 @@ __export(cursor_acp_client_exports, {
|
|
|
29447
29545
|
detectLocalAgentPresence: () => detectLocalAgentPresence3
|
|
29448
29546
|
});
|
|
29449
29547
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
|
|
29450
|
-
import { dirname as
|
|
29548
|
+
import { dirname as dirname3 } from "node:path";
|
|
29451
29549
|
import { spawn as spawn4 } from "node:child_process";
|
|
29452
29550
|
import * as readline from "node:readline";
|
|
29453
29551
|
|
|
@@ -29497,7 +29595,7 @@ function buildCursorAcpSpawnCommand(base, sessionMode) {
|
|
|
29497
29595
|
async function createCursorAcpClient(options) {
|
|
29498
29596
|
const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
|
|
29499
29597
|
const {
|
|
29500
|
-
cwd =
|
|
29598
|
+
cwd = getBridgeRoot(),
|
|
29501
29599
|
backendAgentType,
|
|
29502
29600
|
onSessionUpdate,
|
|
29503
29601
|
onRequest,
|
|
@@ -29513,7 +29611,7 @@ async function createCursorAcpClient(options) {
|
|
|
29513
29611
|
});
|
|
29514
29612
|
const stderrCapture = createStderrCapture(child);
|
|
29515
29613
|
child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
|
|
29516
|
-
return new Promise((
|
|
29614
|
+
return new Promise((resolve16, reject) => {
|
|
29517
29615
|
child.on("error", (err) => {
|
|
29518
29616
|
child.kill();
|
|
29519
29617
|
reject(new Error(formatSpawnError2(err, command[0])));
|
|
@@ -29539,7 +29637,9 @@ async function createCursorAcpClient(options) {
|
|
|
29539
29637
|
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }) + "\n");
|
|
29540
29638
|
}
|
|
29541
29639
|
function resolveRequest(requestId, result) {
|
|
29542
|
-
|
|
29640
|
+
const pending2 = pendingRequests.get(requestId);
|
|
29641
|
+
const payload = pending2?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending2.params) : result;
|
|
29642
|
+
respond(requestId, payload);
|
|
29543
29643
|
pendingRequests.delete(requestId);
|
|
29544
29644
|
}
|
|
29545
29645
|
let promptOutputBuffer = "";
|
|
@@ -29595,14 +29695,14 @@ async function createCursorAcpClient(options) {
|
|
|
29595
29695
|
if (dbgFs) {
|
|
29596
29696
|
console.error(`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""}`);
|
|
29597
29697
|
}
|
|
29598
|
-
const
|
|
29599
|
-
if (!
|
|
29698
|
+
const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
|
|
29699
|
+
if (!resolvedPath) {
|
|
29600
29700
|
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty)`);
|
|
29601
29701
|
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
29602
29702
|
return;
|
|
29603
29703
|
}
|
|
29604
29704
|
try {
|
|
29605
|
-
let content = readFileSync3(
|
|
29705
|
+
let content = readFileSync3(resolvedPath, "utf8");
|
|
29606
29706
|
const line2 = typeof params.line === "number" ? params.line : void 0;
|
|
29607
29707
|
const limit = typeof params.limit === "number" ? params.limit : void 0;
|
|
29608
29708
|
content = sliceLinesByRange(content, line2, limit);
|
|
@@ -29626,15 +29726,15 @@ async function createCursorAcpClient(options) {
|
|
|
29626
29726
|
`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""} newBytes=${newText.length}`
|
|
29627
29727
|
);
|
|
29628
29728
|
}
|
|
29629
|
-
const
|
|
29630
|
-
if (!
|
|
29729
|
+
const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
|
|
29730
|
+
if (!resolvedPath) {
|
|
29631
29731
|
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
|
|
29632
29732
|
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
29633
29733
|
return;
|
|
29634
29734
|
}
|
|
29635
29735
|
let oldText = "";
|
|
29636
29736
|
try {
|
|
29637
|
-
oldText = readFileSync3(
|
|
29737
|
+
oldText = readFileSync3(resolvedPath, "utf8");
|
|
29638
29738
|
} catch (e) {
|
|
29639
29739
|
if (e.code !== "ENOENT") {
|
|
29640
29740
|
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
@@ -29642,13 +29742,13 @@ async function createCursorAcpClient(options) {
|
|
|
29642
29742
|
}
|
|
29643
29743
|
}
|
|
29644
29744
|
try {
|
|
29645
|
-
mkdirSync3(
|
|
29646
|
-
writeFileSync3(
|
|
29745
|
+
mkdirSync3(dirname3(resolvedPath), { recursive: true });
|
|
29746
|
+
writeFileSync3(resolvedPath, newText, "utf8");
|
|
29647
29747
|
} catch (e) {
|
|
29648
29748
|
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
29649
29749
|
return;
|
|
29650
29750
|
}
|
|
29651
|
-
const displayPath = toDisplayPathRelativeToCwd(cwd,
|
|
29751
|
+
const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
|
|
29652
29752
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
29653
29753
|
onFileChange?.({ path: displayPath, oldText, newText, patchContent });
|
|
29654
29754
|
respond(id, null);
|
|
@@ -29700,7 +29800,7 @@ async function createCursorAcpClient(options) {
|
|
|
29700
29800
|
const newResult = await send("session/new", { cwd, mcpServers: [] });
|
|
29701
29801
|
const sessionId = newResult?.sessionId ?? "";
|
|
29702
29802
|
if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
|
|
29703
|
-
|
|
29803
|
+
resolve16({
|
|
29704
29804
|
sessionId,
|
|
29705
29805
|
async sendPrompt(prompt, _options) {
|
|
29706
29806
|
promptOutputBuffer = "";
|
|
@@ -29764,8 +29864,7 @@ async function createCursorAcpClient(options) {
|
|
|
29764
29864
|
resolveRequest(requestId, result) {
|
|
29765
29865
|
const numericId = Number(requestId);
|
|
29766
29866
|
if (!Number.isFinite(numericId)) return;
|
|
29767
|
-
|
|
29768
|
-
if (!pendingRequest) return;
|
|
29867
|
+
if (!pendingRequests.get(numericId)) return;
|
|
29769
29868
|
resolveRequest(numericId, result);
|
|
29770
29869
|
},
|
|
29771
29870
|
disconnect() {
|
|
@@ -29891,16 +29990,16 @@ import { existsSync, statSync } from "node:fs";
|
|
|
29891
29990
|
|
|
29892
29991
|
// src/git/get-git-repo-root-sync.ts
|
|
29893
29992
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
29894
|
-
import * as
|
|
29993
|
+
import * as path9 from "node:path";
|
|
29895
29994
|
function getGitRepoRootSync(startDir) {
|
|
29896
29995
|
try {
|
|
29897
29996
|
const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
29898
|
-
cwd:
|
|
29997
|
+
cwd: path9.resolve(startDir),
|
|
29899
29998
|
encoding: "utf8",
|
|
29900
29999
|
stdio: ["ignore", "pipe", "ignore"],
|
|
29901
30000
|
maxBuffer: 1024 * 1024
|
|
29902
30001
|
}).trim();
|
|
29903
|
-
return out ?
|
|
30002
|
+
return out ? path9.resolve(out) : null;
|
|
29904
30003
|
} catch {
|
|
29905
30004
|
return null;
|
|
29906
30005
|
}
|
|
@@ -29909,64 +30008,64 @@ function getGitRepoRootSync(startDir) {
|
|
|
29909
30008
|
// src/agents/acp/workspace-files.ts
|
|
29910
30009
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
29911
30010
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
29912
|
-
import * as
|
|
29913
|
-
function resolveWorkspaceFilePath(
|
|
30011
|
+
import * as path10 from "node:path";
|
|
30012
|
+
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
29914
30013
|
const trimmed2 = rawPath.trim();
|
|
29915
30014
|
if (!trimmed2) return null;
|
|
29916
|
-
const
|
|
29917
|
-
let
|
|
29918
|
-
if (!
|
|
29919
|
-
const candidate =
|
|
29920
|
-
const gitRoot2 = getGitRepoRootSync(
|
|
30015
|
+
const normalizedSessionParent = path10.resolve(sessionParentPath);
|
|
30016
|
+
let resolvedPath = resolveSafePathUnderCwd(sessionParentPath, trimmed2);
|
|
30017
|
+
if (!resolvedPath) {
|
|
30018
|
+
const candidate = path10.isAbsolute(trimmed2) ? path10.normalize(trimmed2) : path10.normalize(path10.resolve(normalizedSessionParent, trimmed2));
|
|
30019
|
+
const gitRoot2 = getGitRepoRootSync(sessionParentPath);
|
|
29921
30020
|
if (!gitRoot2) return null;
|
|
29922
|
-
const rel =
|
|
29923
|
-
if (rel.startsWith("..") ||
|
|
29924
|
-
|
|
30021
|
+
const rel = path10.relative(gitRoot2, candidate);
|
|
30022
|
+
if (rel.startsWith("..") || path10.isAbsolute(rel)) return null;
|
|
30023
|
+
resolvedPath = candidate;
|
|
29925
30024
|
}
|
|
29926
|
-
const gitRoot = getGitRepoRootSync(
|
|
30025
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
29927
30026
|
if (gitRoot) {
|
|
29928
|
-
const relFromRoot =
|
|
29929
|
-
if (!relFromRoot.startsWith("..") && !
|
|
29930
|
-
return {
|
|
30027
|
+
const relFromRoot = path10.relative(gitRoot, resolvedPath);
|
|
30028
|
+
if (!relFromRoot.startsWith("..") && !path10.isAbsolute(relFromRoot)) {
|
|
30029
|
+
return { resolvedPath, display: relFromRoot.split(path10.sep).join("/") };
|
|
29931
30030
|
}
|
|
29932
30031
|
}
|
|
29933
|
-
return {
|
|
30032
|
+
return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
|
|
29934
30033
|
}
|
|
29935
|
-
function readUtf8WorkspaceFile(
|
|
30034
|
+
function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
29936
30035
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
29937
|
-
const gitRoot = getGitRepoRootSync(
|
|
30036
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
29938
30037
|
if (gitRoot) {
|
|
29939
|
-
const
|
|
29940
|
-
const rel =
|
|
29941
|
-
if (!rel.startsWith("..") && !
|
|
30038
|
+
const resolvedPath2 = path10.resolve(gitRoot, displayPath);
|
|
30039
|
+
const rel = path10.relative(gitRoot, resolvedPath2);
|
|
30040
|
+
if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
|
|
29942
30041
|
try {
|
|
29943
|
-
return readFileSync4(
|
|
30042
|
+
return readFileSync4(resolvedPath2, "utf8");
|
|
29944
30043
|
} catch {
|
|
29945
30044
|
}
|
|
29946
30045
|
}
|
|
29947
30046
|
}
|
|
29948
|
-
const
|
|
29949
|
-
if (!
|
|
30047
|
+
const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
30048
|
+
if (!resolvedPath) return "";
|
|
29950
30049
|
try {
|
|
29951
|
-
return readFileSync4(
|
|
30050
|
+
return readFileSync4(resolvedPath, "utf8");
|
|
29952
30051
|
} catch {
|
|
29953
30052
|
return "";
|
|
29954
30053
|
}
|
|
29955
30054
|
}
|
|
29956
|
-
function
|
|
30055
|
+
function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
|
|
29957
30056
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
29958
|
-
const gitRoot = getGitRepoRootSync(
|
|
30057
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
29959
30058
|
if (gitRoot) {
|
|
29960
|
-
const
|
|
29961
|
-
const rel =
|
|
29962
|
-
if (!rel.startsWith("..") && !
|
|
30059
|
+
const resolvedPath = path10.resolve(gitRoot, displayPath);
|
|
30060
|
+
const rel = path10.relative(gitRoot, resolvedPath);
|
|
30061
|
+
if (!rel.startsWith("..") && !path10.isAbsolute(rel)) return resolvedPath;
|
|
29963
30062
|
}
|
|
29964
|
-
return resolveSafePathUnderCwd(
|
|
30063
|
+
return resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
29965
30064
|
}
|
|
29966
|
-
function readGitHeadBlob(
|
|
30065
|
+
function readGitHeadBlob(sessionParentPath, displayPath) {
|
|
29967
30066
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
29968
|
-
const gitRoot = getGitRepoRootSync(
|
|
29969
|
-
const execCwd = gitRoot ??
|
|
30067
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30068
|
+
const execCwd = gitRoot ?? sessionParentPath;
|
|
29970
30069
|
try {
|
|
29971
30070
|
return execFileSync3("git", ["show", `HEAD:${displayPath}`], {
|
|
29972
30071
|
cwd: execCwd,
|
|
@@ -29979,9 +30078,9 @@ function readGitHeadBlob(cwd, displayPath) {
|
|
|
29979
30078
|
}
|
|
29980
30079
|
|
|
29981
30080
|
// src/agents/acp/session-file-change-path-kind.ts
|
|
29982
|
-
function gitHeadPathObjectType(
|
|
30081
|
+
function gitHeadPathObjectType(sessionParentPath, displayPath) {
|
|
29983
30082
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
29984
|
-
const gitRoot = getGitRepoRootSync(
|
|
30083
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
29985
30084
|
if (!gitRoot) return null;
|
|
29986
30085
|
try {
|
|
29987
30086
|
return execFileSync4("git", ["cat-file", "-t", `HEAD:${displayPath}`], {
|
|
@@ -29992,11 +30091,11 @@ function gitHeadPathObjectType(cwd, displayPath) {
|
|
|
29992
30091
|
return null;
|
|
29993
30092
|
}
|
|
29994
30093
|
}
|
|
29995
|
-
function getSessionFileChangeDirectoryFlags(
|
|
29996
|
-
const
|
|
29997
|
-
if (
|
|
30094
|
+
function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
|
|
30095
|
+
const resolvedPath = tryWorkspaceDisplayToPath(sessionParentPath, displayPath);
|
|
30096
|
+
if (resolvedPath && existsSync(resolvedPath)) {
|
|
29998
30097
|
try {
|
|
29999
|
-
if (statSync(
|
|
30098
|
+
if (statSync(resolvedPath).isDirectory()) {
|
|
30000
30099
|
return { isDirectory: true, directoryRemoved: false };
|
|
30001
30100
|
}
|
|
30002
30101
|
return { isDirectory: false, directoryRemoved: false };
|
|
@@ -30004,7 +30103,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
|
|
|
30004
30103
|
return { isDirectory: false, directoryRemoved: false };
|
|
30005
30104
|
}
|
|
30006
30105
|
}
|
|
30007
|
-
if (gitHeadPathObjectType(
|
|
30106
|
+
if (gitHeadPathObjectType(sessionParentPath, displayPath) === "tree") {
|
|
30008
30107
|
return { isDirectory: true, directoryRemoved: true };
|
|
30009
30108
|
}
|
|
30010
30109
|
return { isDirectory: false, directoryRemoved: false };
|
|
@@ -30012,7 +30111,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
|
|
|
30012
30111
|
|
|
30013
30112
|
// src/agents/acp/hooks/bridge-on-file-change.ts
|
|
30014
30113
|
function createBridgeOnFileChange(opts) {
|
|
30015
|
-
const { routing, getSendSessionUpdate, log: log2 } = opts;
|
|
30114
|
+
const { routing, getSendSessionUpdate, log: log2, sessionParentPath } = opts;
|
|
30016
30115
|
return (evt) => {
|
|
30017
30116
|
const runId = routing.runId;
|
|
30018
30117
|
const sessionId = routing.sessionId;
|
|
@@ -30023,8 +30122,7 @@ function createBridgeOnFileChange(opts) {
|
|
|
30023
30122
|
);
|
|
30024
30123
|
return;
|
|
30025
30124
|
}
|
|
30026
|
-
const
|
|
30027
|
-
const dirFlags = getSessionFileChangeDirectoryFlags(cwd, evt.path);
|
|
30125
|
+
const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, evt.path);
|
|
30028
30126
|
try {
|
|
30029
30127
|
send({
|
|
30030
30128
|
type: "session_file_change",
|
|
@@ -30101,12 +30199,12 @@ function extractDiffPath(o) {
|
|
|
30101
30199
|
}
|
|
30102
30200
|
|
|
30103
30201
|
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/push-diff.ts
|
|
30104
|
-
function pushDiffIfComplete(o,
|
|
30202
|
+
function pushDiffIfComplete(o, sessionParentPath, out) {
|
|
30105
30203
|
const t = o.type;
|
|
30106
30204
|
if (typeof t !== "string" || t.toLowerCase() !== "diff") return;
|
|
30107
30205
|
const rawPath = extractDiffPath(o);
|
|
30108
30206
|
if (!rawPath) return;
|
|
30109
|
-
const resolved = resolveWorkspaceFilePath(
|
|
30207
|
+
const resolved = resolveWorkspaceFilePath(sessionParentPath, rawPath);
|
|
30110
30208
|
if (!resolved) return;
|
|
30111
30209
|
const oldText = readOptionalTextField(o.oldText ?? o.old_text ?? o.before ?? o.oldContent);
|
|
30112
30210
|
const newText = readOptionalTextField(o.newText ?? o.new_text ?? o.after ?? o.newContent);
|
|
@@ -30125,17 +30223,17 @@ var NEST_KEYS = [
|
|
|
30125
30223
|
"data",
|
|
30126
30224
|
"arguments"
|
|
30127
30225
|
];
|
|
30128
|
-
function walkValue(value,
|
|
30226
|
+
function walkValue(value, sessionParentPath, depth, out) {
|
|
30129
30227
|
if (depth > 12 || value == null) return;
|
|
30130
30228
|
if (Array.isArray(value)) {
|
|
30131
|
-
for (const x of value) walkValue(x,
|
|
30229
|
+
for (const x of value) walkValue(x, sessionParentPath, depth + 1, out);
|
|
30132
30230
|
return;
|
|
30133
30231
|
}
|
|
30134
30232
|
if (typeof value !== "object") return;
|
|
30135
30233
|
const o = value;
|
|
30136
|
-
pushDiffIfComplete(o,
|
|
30234
|
+
pushDiffIfComplete(o, sessionParentPath, out);
|
|
30137
30235
|
if (o.type === "content" && o.content != null && typeof o.content === "object") {
|
|
30138
|
-
walkValue(o.content,
|
|
30236
|
+
walkValue(o.content, sessionParentPath, depth + 1, out);
|
|
30139
30237
|
}
|
|
30140
30238
|
for (const k of NEST_KEYS) {
|
|
30141
30239
|
if (o.type === "content" && k === "content") continue;
|
|
@@ -30143,23 +30241,23 @@ function walkValue(value, cwd, depth, out) {
|
|
|
30143
30241
|
if (v == null) continue;
|
|
30144
30242
|
if (k === "arguments" && typeof v === "string") {
|
|
30145
30243
|
try {
|
|
30146
|
-
walkValue(JSON.parse(v),
|
|
30244
|
+
walkValue(JSON.parse(v), sessionParentPath, depth + 1, out);
|
|
30147
30245
|
} catch {
|
|
30148
30246
|
}
|
|
30149
30247
|
continue;
|
|
30150
30248
|
}
|
|
30151
|
-
walkValue(v,
|
|
30249
|
+
walkValue(v, sessionParentPath, depth + 1, out);
|
|
30152
30250
|
}
|
|
30153
30251
|
}
|
|
30154
30252
|
|
|
30155
30253
|
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/extract.ts
|
|
30156
|
-
function extractAcpFileDiffsFromUpdate(update,
|
|
30254
|
+
function extractAcpFileDiffsFromUpdate(update, sessionParentPath) {
|
|
30157
30255
|
if (!update || typeof update !== "object") return [];
|
|
30158
30256
|
const u = update;
|
|
30159
30257
|
const out = [];
|
|
30160
30258
|
const content = u.content;
|
|
30161
30259
|
if (Array.isArray(content)) {
|
|
30162
|
-
for (const x of content) walkValue(x,
|
|
30260
|
+
for (const x of content) walkValue(x, sessionParentPath, 0, out);
|
|
30163
30261
|
}
|
|
30164
30262
|
const byPath = /* @__PURE__ */ new Map();
|
|
30165
30263
|
for (const d of out) byPath.set(d.path, d);
|
|
@@ -30167,18 +30265,18 @@ function extractAcpFileDiffsFromUpdate(update, cwd) {
|
|
|
30167
30265
|
}
|
|
30168
30266
|
|
|
30169
30267
|
// src/agents/acp/hooks/extract-tool-target-paths.ts
|
|
30170
|
-
function addPath(
|
|
30268
|
+
function addPath(sessionParentPath, raw, out) {
|
|
30171
30269
|
if (typeof raw !== "string") return;
|
|
30172
30270
|
const trimmed2 = raw.trim();
|
|
30173
30271
|
if (!trimmed2) return;
|
|
30174
|
-
const resolved = resolveWorkspaceFilePath(
|
|
30272
|
+
const resolved = resolveWorkspaceFilePath(sessionParentPath, trimmed2);
|
|
30175
30273
|
if (!resolved) return;
|
|
30176
30274
|
out.add(resolved.display);
|
|
30177
30275
|
}
|
|
30178
|
-
function walkLocations(
|
|
30276
|
+
function walkLocations(sessionParentPath, loc, out) {
|
|
30179
30277
|
if (!Array.isArray(loc)) return;
|
|
30180
30278
|
for (const item of loc) {
|
|
30181
|
-
if (item && typeof item === "object") addPath(
|
|
30279
|
+
if (item && typeof item === "object") addPath(sessionParentPath, item.path, out);
|
|
30182
30280
|
}
|
|
30183
30281
|
}
|
|
30184
30282
|
var PATH_KEYS = [
|
|
@@ -30191,56 +30289,56 @@ var PATH_KEYS = [
|
|
|
30191
30289
|
"file_path",
|
|
30192
30290
|
"target_file"
|
|
30193
30291
|
];
|
|
30194
|
-
function collectFromObject(
|
|
30292
|
+
function collectFromObject(sessionParentPath, obj, out, depth) {
|
|
30195
30293
|
if (depth > 10) return;
|
|
30196
30294
|
for (const k of PATH_KEYS) {
|
|
30197
|
-
if (k in obj) addPath(
|
|
30295
|
+
if (k in obj) addPath(sessionParentPath, obj[k], out);
|
|
30198
30296
|
}
|
|
30199
30297
|
for (const v of Object.values(obj)) {
|
|
30200
|
-
if (v != null && typeof v === "object") collectUnknown(
|
|
30298
|
+
if (v != null && typeof v === "object") collectUnknown(sessionParentPath, v, out, depth + 1);
|
|
30201
30299
|
}
|
|
30202
30300
|
}
|
|
30203
|
-
function collectUnknown(
|
|
30301
|
+
function collectUnknown(sessionParentPath, v, out, depth) {
|
|
30204
30302
|
if (depth > 10 || v == null) return;
|
|
30205
30303
|
if (Array.isArray(v)) {
|
|
30206
|
-
for (const x of v) collectUnknown(
|
|
30304
|
+
for (const x of v) collectUnknown(sessionParentPath, x, out, depth + 1);
|
|
30207
30305
|
return;
|
|
30208
30306
|
}
|
|
30209
|
-
if (typeof v === "object") collectFromObject(
|
|
30307
|
+
if (typeof v === "object") collectFromObject(sessionParentPath, v, out, depth);
|
|
30210
30308
|
}
|
|
30211
|
-
function walkContentArray(
|
|
30309
|
+
function walkContentArray(sessionParentPath, content, out) {
|
|
30212
30310
|
if (!Array.isArray(content)) return;
|
|
30213
30311
|
for (const item of content) {
|
|
30214
30312
|
if (!item || typeof item !== "object") continue;
|
|
30215
30313
|
const o = item;
|
|
30216
30314
|
if (typeof o.type === "string" && o.type.toLowerCase() === "diff") {
|
|
30217
|
-
for (const k of PATH_KEYS) if (k in o) addPath(
|
|
30315
|
+
for (const k of PATH_KEYS) if (k in o) addPath(sessionParentPath, o[k], out);
|
|
30218
30316
|
}
|
|
30219
30317
|
if (o.type === "content" && o.content != null && typeof o.content === "object") {
|
|
30220
30318
|
const inner = o.content;
|
|
30221
30319
|
if (typeof inner.type === "string" && inner.type.toLowerCase() === "diff") {
|
|
30222
|
-
for (const k of PATH_KEYS) if (k in inner) addPath(
|
|
30320
|
+
for (const k of PATH_KEYS) if (k in inner) addPath(sessionParentPath, inner[k], out);
|
|
30223
30321
|
}
|
|
30224
30322
|
}
|
|
30225
30323
|
}
|
|
30226
30324
|
}
|
|
30227
|
-
function extractToolTargetDisplayPaths(update,
|
|
30325
|
+
function extractToolTargetDisplayPaths(update, sessionParentPath) {
|
|
30228
30326
|
const out = /* @__PURE__ */ new Set();
|
|
30229
30327
|
if (!update || typeof update !== "object") return [];
|
|
30230
30328
|
const u = update;
|
|
30231
|
-
walkLocations(
|
|
30232
|
-
walkLocations(
|
|
30233
|
-
walkLocations(
|
|
30329
|
+
walkLocations(sessionParentPath, u.locations, out);
|
|
30330
|
+
walkLocations(sessionParentPath, u.fileLocations, out);
|
|
30331
|
+
walkLocations(sessionParentPath, u.file_locations, out);
|
|
30234
30332
|
const tc = u.toolCall ?? u.tool_call;
|
|
30235
30333
|
if (tc && typeof tc.arguments === "string") {
|
|
30236
30334
|
try {
|
|
30237
30335
|
const parsed = JSON.parse(tc.arguments);
|
|
30238
|
-
collectUnknown(
|
|
30336
|
+
collectUnknown(sessionParentPath, parsed, out, 0);
|
|
30239
30337
|
} catch {
|
|
30240
30338
|
}
|
|
30241
30339
|
}
|
|
30242
|
-
walkContentArray(
|
|
30243
|
-
collectFromObject(
|
|
30340
|
+
walkContentArray(sessionParentPath, u.content, out);
|
|
30341
|
+
collectFromObject(sessionParentPath, u, out, 0);
|
|
30244
30342
|
return [...out];
|
|
30245
30343
|
}
|
|
30246
30344
|
|
|
@@ -30306,7 +30404,7 @@ var PathSnapshotTracker = class {
|
|
|
30306
30404
|
this.beforeByToolKey.delete(toolKey);
|
|
30307
30405
|
this.accumulatedPathsByToolKey.delete(toolKey);
|
|
30308
30406
|
}
|
|
30309
|
-
captureBeforeFromDisk(toolKey, paths,
|
|
30407
|
+
captureBeforeFromDisk(toolKey, paths, sessionParentPath) {
|
|
30310
30408
|
if (paths.length === 0) return;
|
|
30311
30409
|
let m = this.beforeByToolKey.get(toolKey);
|
|
30312
30410
|
if (!m) {
|
|
@@ -30315,10 +30413,10 @@ var PathSnapshotTracker = class {
|
|
|
30315
30413
|
}
|
|
30316
30414
|
for (const p of paths) {
|
|
30317
30415
|
if (m.has(p)) continue;
|
|
30318
|
-
m.set(p, readUtf8WorkspaceFile(
|
|
30416
|
+
m.set(p, readUtf8WorkspaceFile(sessionParentPath, p));
|
|
30319
30417
|
}
|
|
30320
30418
|
}
|
|
30321
|
-
ensureBeforeFromHeadForMissing(toolKey, paths,
|
|
30419
|
+
ensureBeforeFromHeadForMissing(toolKey, paths, sessionParentPath) {
|
|
30322
30420
|
let m = this.beforeByToolKey.get(toolKey);
|
|
30323
30421
|
if (!m) {
|
|
30324
30422
|
m = /* @__PURE__ */ new Map();
|
|
@@ -30326,10 +30424,10 @@ var PathSnapshotTracker = class {
|
|
|
30326
30424
|
}
|
|
30327
30425
|
for (const p of paths) {
|
|
30328
30426
|
if (m.has(p)) continue;
|
|
30329
|
-
m.set(p, readGitHeadBlob(
|
|
30427
|
+
m.set(p, readGitHeadBlob(sessionParentPath, p));
|
|
30330
30428
|
}
|
|
30331
30429
|
}
|
|
30332
|
-
flushPathSnapshots(toolKey,
|
|
30430
|
+
flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
|
|
30333
30431
|
const t = this.debouncers.get(toolKey);
|
|
30334
30432
|
if (t) clearTimeout(t);
|
|
30335
30433
|
this.debouncers.delete(toolKey);
|
|
@@ -30338,10 +30436,10 @@ var PathSnapshotTracker = class {
|
|
|
30338
30436
|
this.beforeByToolKey.delete(toolKey);
|
|
30339
30437
|
if (!send || !runId || !sessionId) return;
|
|
30340
30438
|
for (const [displayPath, oldText] of beforeMap) {
|
|
30341
|
-
const newText = readUtf8WorkspaceFile(
|
|
30439
|
+
const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
|
|
30342
30440
|
if (oldText === newText) continue;
|
|
30343
30441
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
30344
|
-
const dirFlags = getSessionFileChangeDirectoryFlags(
|
|
30442
|
+
const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
|
|
30345
30443
|
try {
|
|
30346
30444
|
send({
|
|
30347
30445
|
type: "session_file_change",
|
|
@@ -30360,31 +30458,31 @@ var PathSnapshotTracker = class {
|
|
|
30360
30458
|
}
|
|
30361
30459
|
}
|
|
30362
30460
|
}
|
|
30363
|
-
scheduleDebouncedFlush(toolKey,
|
|
30461
|
+
scheduleDebouncedFlush(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
|
|
30364
30462
|
const prev = this.debouncers.get(toolKey);
|
|
30365
30463
|
if (prev) clearTimeout(prev);
|
|
30366
30464
|
this.debouncers.set(
|
|
30367
30465
|
toolKey,
|
|
30368
30466
|
setTimeout(() => {
|
|
30369
30467
|
this.debouncers.delete(toolKey);
|
|
30370
|
-
this.flushPathSnapshots(toolKey,
|
|
30468
|
+
this.flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
|
|
30371
30469
|
}, PATH_SNAPSHOT_DEBOUNCE_MS)
|
|
30372
30470
|
);
|
|
30373
30471
|
}
|
|
30374
|
-
handleToolCallLifecycle(updateKind, toolKey, toolPaths, status,
|
|
30472
|
+
handleToolCallLifecycle(updateKind, toolKey, toolPaths, status, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
|
|
30375
30473
|
if (updateKind === "tool_call") {
|
|
30376
30474
|
this.resetToolSnapshots(toolKey);
|
|
30377
30475
|
}
|
|
30378
30476
|
if (updateKind === "tool_call") {
|
|
30379
|
-
this.captureBeforeFromDisk(toolKey, toolPaths,
|
|
30477
|
+
this.captureBeforeFromDisk(toolKey, toolPaths, sessionParentPath);
|
|
30380
30478
|
} else if (updateKind === "tool_call_update") {
|
|
30381
30479
|
if (isCompletedToolStatus(status)) {
|
|
30382
|
-
this.ensureBeforeFromHeadForMissing(toolKey, toolPaths,
|
|
30383
|
-
this.flushPathSnapshots(toolKey,
|
|
30480
|
+
this.ensureBeforeFromHeadForMissing(toolKey, toolPaths, sessionParentPath);
|
|
30481
|
+
this.flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
|
|
30384
30482
|
} else {
|
|
30385
|
-
this.captureBeforeFromDisk(toolKey, toolPaths,
|
|
30483
|
+
this.captureBeforeFromDisk(toolKey, toolPaths, sessionParentPath);
|
|
30386
30484
|
if (this.beforeByToolKey.has(toolKey)) {
|
|
30387
|
-
this.scheduleDebouncedFlush(toolKey,
|
|
30485
|
+
this.scheduleDebouncedFlush(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
|
|
30388
30486
|
}
|
|
30389
30487
|
}
|
|
30390
30488
|
}
|
|
@@ -30392,11 +30490,11 @@ var PathSnapshotTracker = class {
|
|
|
30392
30490
|
};
|
|
30393
30491
|
|
|
30394
30492
|
// src/agents/acp/hooks/bridge-on-session-update/send-structured-file-changes.ts
|
|
30395
|
-
function sendExtractedDiffsAsSessionFileChanges(diffs, send,
|
|
30493
|
+
function sendExtractedDiffsAsSessionFileChanges(diffs, send, sessionParentPath, sessionId, runId, sentPaths, log2) {
|
|
30396
30494
|
for (const d of diffs) {
|
|
30397
30495
|
try {
|
|
30398
30496
|
const patchContent = editSnippetToUnifiedDiff(d.path, d.oldText, d.newText);
|
|
30399
|
-
const dirFlags = getSessionFileChangeDirectoryFlags(
|
|
30497
|
+
const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, d.path);
|
|
30400
30498
|
send({
|
|
30401
30499
|
type: "session_file_change",
|
|
30402
30500
|
sessionId,
|
|
@@ -30414,15 +30512,15 @@ function sendExtractedDiffsAsSessionFileChanges(diffs, send, cwd, sessionId, run
|
|
|
30414
30512
|
}
|
|
30415
30513
|
}
|
|
30416
30514
|
}
|
|
30417
|
-
function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send,
|
|
30515
|
+
function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, sessionParentPath, sessionId, runId, log2) {
|
|
30418
30516
|
for (const displayPath of mergedPaths) {
|
|
30419
30517
|
if (sentPaths.has(displayPath)) continue;
|
|
30420
|
-
const oldText = readGitHeadBlob(
|
|
30421
|
-
const newText = readUtf8WorkspaceFile(
|
|
30518
|
+
const oldText = readGitHeadBlob(sessionParentPath, displayPath);
|
|
30519
|
+
const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
|
|
30422
30520
|
if (oldText === newText) continue;
|
|
30423
30521
|
try {
|
|
30424
30522
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
30425
|
-
const dirFlags = getSessionFileChangeDirectoryFlags(
|
|
30523
|
+
const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
|
|
30426
30524
|
send({
|
|
30427
30525
|
type: "session_file_change",
|
|
30428
30526
|
sessionId,
|
|
@@ -30443,13 +30541,12 @@ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, cwd, s
|
|
|
30443
30541
|
|
|
30444
30542
|
// src/agents/acp/hooks/bridge-on-session-update/create-bridge-on-session-update.ts
|
|
30445
30543
|
function createBridgeOnSessionUpdate(opts) {
|
|
30446
|
-
const { routing, getSendSessionUpdate, log: log2 } = opts;
|
|
30544
|
+
const { routing, getSendSessionUpdate, log: log2, sessionParentPath } = opts;
|
|
30447
30545
|
const pathTracker = new PathSnapshotTracker();
|
|
30448
30546
|
return (params) => {
|
|
30449
30547
|
const runId = routing.runId;
|
|
30450
30548
|
const sessionId = routing.sessionId;
|
|
30451
30549
|
pathTracker.onRunIdChanged(runId);
|
|
30452
|
-
const cwd = getBridgeWorkspaceDirectory();
|
|
30453
30550
|
const send = getSendSessionUpdate();
|
|
30454
30551
|
const sentFileChangePaths = /* @__PURE__ */ new Set();
|
|
30455
30552
|
const p = params;
|
|
@@ -30457,7 +30554,7 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
30457
30554
|
const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
|
|
30458
30555
|
const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
|
|
30459
30556
|
const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
|
|
30460
|
-
const toolPaths = isToolUpdate ? extractToolTargetDisplayPaths(params,
|
|
30557
|
+
const toolPaths = isToolUpdate ? extractToolTargetDisplayPaths(params, sessionParentPath) : [];
|
|
30461
30558
|
const toolKey = isToolUpdate ? pathTracker.resolveToolKey(params, updateKind) : "";
|
|
30462
30559
|
if (updateKind === "tool_call") {
|
|
30463
30560
|
pathTracker.resetToolSnapshots(toolKey);
|
|
@@ -30472,7 +30569,7 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
30472
30569
|
toolKey,
|
|
30473
30570
|
toolPaths,
|
|
30474
30571
|
p.status,
|
|
30475
|
-
|
|
30572
|
+
sessionParentPath,
|
|
30476
30573
|
sentFileChangePaths,
|
|
30477
30574
|
deliver,
|
|
30478
30575
|
runId ?? "",
|
|
@@ -30480,9 +30577,17 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
30480
30577
|
log2
|
|
30481
30578
|
);
|
|
30482
30579
|
}
|
|
30483
|
-
const diffs = extractAcpFileDiffsFromUpdate(params,
|
|
30580
|
+
const diffs = extractAcpFileDiffsFromUpdate(params, sessionParentPath);
|
|
30484
30581
|
if (diffs.length > 0 && send && runId && sessionId) {
|
|
30485
|
-
sendExtractedDiffsAsSessionFileChanges(
|
|
30582
|
+
sendExtractedDiffsAsSessionFileChanges(
|
|
30583
|
+
diffs,
|
|
30584
|
+
send,
|
|
30585
|
+
sessionParentPath,
|
|
30586
|
+
sessionId,
|
|
30587
|
+
runId,
|
|
30588
|
+
sentFileChangePaths,
|
|
30589
|
+
log2
|
|
30590
|
+
);
|
|
30486
30591
|
} else if (diffs.length > 0) {
|
|
30487
30592
|
log2(
|
|
30488
30593
|
`[Bridge service] Agent file diff(s) not forwarded (${diffs.length}): session or run not wired to the bridge.`
|
|
@@ -30491,7 +30596,15 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
30491
30596
|
if (isCompletedToolCallUpdate && send && runId && sessionId) {
|
|
30492
30597
|
const acc = pathTracker.accumulatedPathsByToolKey.get(toolKey);
|
|
30493
30598
|
const merged = [.../* @__PURE__ */ new Set([...acc ? [...acc] : [], ...toolPaths])];
|
|
30494
|
-
sendGitHeadVsWorkspaceForToolPaths(
|
|
30599
|
+
sendGitHeadVsWorkspaceForToolPaths(
|
|
30600
|
+
merged,
|
|
30601
|
+
sentFileChangePaths,
|
|
30602
|
+
send,
|
|
30603
|
+
sessionParentPath,
|
|
30604
|
+
sessionId,
|
|
30605
|
+
runId,
|
|
30606
|
+
log2
|
|
30607
|
+
);
|
|
30495
30608
|
pathTracker.accumulatedPathsByToolKey.delete(toolKey);
|
|
30496
30609
|
}
|
|
30497
30610
|
if (runId && send) {
|
|
@@ -30526,11 +30639,12 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
30526
30639
|
|
|
30527
30640
|
// src/agents/acp/ensure-acp-client.ts
|
|
30528
30641
|
async function ensureAcpClient(options) {
|
|
30529
|
-
const { state, preferredAgentType, mode,
|
|
30530
|
-
const
|
|
30531
|
-
|
|
30532
|
-
|
|
30533
|
-
|
|
30642
|
+
const { state, preferredAgentType, mode, sessionParentPath, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
|
|
30643
|
+
const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
|
|
30644
|
+
if (state.acpStartPromise && !state.acpHandle) {
|
|
30645
|
+
await state.acpStartPromise;
|
|
30646
|
+
}
|
|
30647
|
+
if (state.acpHandle && state.lastAcpCwd != null && path11.resolve(state.lastAcpCwd) !== path11.resolve(targetSessionParentPath)) {
|
|
30534
30648
|
try {
|
|
30535
30649
|
state.acpHandle.disconnect();
|
|
30536
30650
|
} catch {
|
|
@@ -30562,14 +30676,14 @@ async function ensureAcpClient(options) {
|
|
|
30562
30676
|
if (!state.acpStartPromise) {
|
|
30563
30677
|
let statOk = false;
|
|
30564
30678
|
try {
|
|
30565
|
-
const st = fs9.statSync(
|
|
30679
|
+
const st = fs9.statSync(targetSessionParentPath);
|
|
30566
30680
|
statOk = st.isDirectory();
|
|
30567
30681
|
if (!statOk) {
|
|
30568
|
-
state.lastAcpStartError = `Agent cwd is not a directory: ${
|
|
30682
|
+
state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
|
|
30569
30683
|
log2(`[Agent] ${state.lastAcpStartError}`);
|
|
30570
30684
|
}
|
|
30571
30685
|
} catch {
|
|
30572
|
-
state.lastAcpStartError = `Agent cwd missing or inaccessible: ${
|
|
30686
|
+
state.lastAcpStartError = `Agent cwd missing or inaccessible: ${targetSessionParentPath}`;
|
|
30573
30687
|
log2(`[Agent] ${state.lastAcpStartError}`);
|
|
30574
30688
|
}
|
|
30575
30689
|
if (!statOk) {
|
|
@@ -30577,6 +30691,7 @@ async function ensureAcpClient(options) {
|
|
|
30577
30691
|
}
|
|
30578
30692
|
const hooks = buildAcpSessionBridgeHooks({
|
|
30579
30693
|
routing,
|
|
30694
|
+
sessionParentPath: targetSessionParentPath,
|
|
30580
30695
|
getSendSessionUpdate: () => sendSessionUpdate,
|
|
30581
30696
|
getSendRequest: () => sendRequest,
|
|
30582
30697
|
log: log2
|
|
@@ -30584,7 +30699,6 @@ async function ensureAcpClient(options) {
|
|
|
30584
30699
|
state.acpStartPromise = resolved.createClient({
|
|
30585
30700
|
command: resolved.command,
|
|
30586
30701
|
sessionMode: mode,
|
|
30587
|
-
cwd: targetCwd,
|
|
30588
30702
|
backendAgentType: preferredAgentType,
|
|
30589
30703
|
onAgentSubprocessExit: () => {
|
|
30590
30704
|
state.acpHandle = null;
|
|
@@ -30592,11 +30706,12 @@ async function ensureAcpClient(options) {
|
|
|
30592
30706
|
state.acpAgentKey = null;
|
|
30593
30707
|
state.lastAcpStartError = "Agent subprocess exited";
|
|
30594
30708
|
},
|
|
30595
|
-
...hooks
|
|
30709
|
+
...hooks,
|
|
30710
|
+
cwd: targetSessionParentPath
|
|
30596
30711
|
}).then((h) => {
|
|
30597
30712
|
state.lastAcpStartError = null;
|
|
30598
30713
|
state.acpHandle = h;
|
|
30599
|
-
state.lastAcpCwd =
|
|
30714
|
+
state.lastAcpCwd = targetSessionParentPath;
|
|
30600
30715
|
state.acpAgentKey = agentKey;
|
|
30601
30716
|
return h;
|
|
30602
30717
|
}).catch((err) => {
|
|
@@ -30645,7 +30760,7 @@ async function createAcpManager(options) {
|
|
|
30645
30760
|
runId,
|
|
30646
30761
|
mode,
|
|
30647
30762
|
agentType,
|
|
30648
|
-
|
|
30763
|
+
sessionParentPath,
|
|
30649
30764
|
sendResult: sendResult2,
|
|
30650
30765
|
sendSessionUpdate,
|
|
30651
30766
|
followUpCatalogPromptId,
|
|
@@ -30664,7 +30779,7 @@ async function createAcpManager(options) {
|
|
|
30664
30779
|
state,
|
|
30665
30780
|
preferredAgentType: preferredForPrompt,
|
|
30666
30781
|
mode,
|
|
30667
|
-
|
|
30782
|
+
sessionParentPath,
|
|
30668
30783
|
routing: promptRouting,
|
|
30669
30784
|
sendSessionUpdate,
|
|
30670
30785
|
sendRequest: sendSessionUpdate,
|
|
@@ -30713,7 +30828,7 @@ async function createAcpManager(options) {
|
|
|
30713
30828
|
sessionId,
|
|
30714
30829
|
runId,
|
|
30715
30830
|
agentType: preferredForPrompt,
|
|
30716
|
-
agentCwd:
|
|
30831
|
+
agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
|
|
30717
30832
|
sendResult: sendResult2,
|
|
30718
30833
|
sendSessionUpdate,
|
|
30719
30834
|
log: log2,
|
|
@@ -30768,12 +30883,12 @@ async function createAcpManager(options) {
|
|
|
30768
30883
|
}
|
|
30769
30884
|
|
|
30770
30885
|
// src/worktrees/session-worktree-manager.ts
|
|
30771
|
-
import * as
|
|
30886
|
+
import * as path18 from "node:path";
|
|
30772
30887
|
import os4 from "node:os";
|
|
30773
30888
|
|
|
30774
30889
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
30775
30890
|
import * as fs11 from "node:fs";
|
|
30776
|
-
import * as
|
|
30891
|
+
import * as path13 from "node:path";
|
|
30777
30892
|
|
|
30778
30893
|
// src/git/worktree-add.ts
|
|
30779
30894
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -30783,11 +30898,11 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
30783
30898
|
|
|
30784
30899
|
// src/worktrees/worktree-layout-file.ts
|
|
30785
30900
|
import * as fs10 from "node:fs";
|
|
30786
|
-
import * as
|
|
30901
|
+
import * as path12 from "node:path";
|
|
30787
30902
|
import os3 from "node:os";
|
|
30788
30903
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
30789
30904
|
function defaultWorktreeLayoutPath() {
|
|
30790
|
-
return
|
|
30905
|
+
return path12.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
30791
30906
|
}
|
|
30792
30907
|
function normalizeLoadedLayout(raw) {
|
|
30793
30908
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -30808,24 +30923,24 @@ function loadWorktreeLayout() {
|
|
|
30808
30923
|
}
|
|
30809
30924
|
function saveWorktreeLayout(layout) {
|
|
30810
30925
|
try {
|
|
30811
|
-
const dir =
|
|
30926
|
+
const dir = path12.dirname(defaultWorktreeLayoutPath());
|
|
30812
30927
|
fs10.mkdirSync(dir, { recursive: true });
|
|
30813
30928
|
fs10.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
30814
30929
|
} catch {
|
|
30815
30930
|
}
|
|
30816
30931
|
}
|
|
30817
|
-
function baseNameSafe(
|
|
30818
|
-
return
|
|
30932
|
+
function baseNameSafe(pathString) {
|
|
30933
|
+
return path12.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
30819
30934
|
}
|
|
30820
|
-
function getLauncherDirNameIfPresent(layout,
|
|
30821
|
-
const norm =
|
|
30822
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
30935
|
+
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
30936
|
+
const norm = path12.resolve(bridgeRootPath2);
|
|
30937
|
+
const existing = layout.launcherCwds.find((e) => path12.resolve(e.absolutePath) === norm);
|
|
30823
30938
|
return existing?.dirName;
|
|
30824
30939
|
}
|
|
30825
|
-
function allocateDirNameForLauncherCwd(layout,
|
|
30826
|
-
const existing = getLauncherDirNameIfPresent(layout,
|
|
30940
|
+
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
30941
|
+
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
30827
30942
|
if (existing) return existing;
|
|
30828
|
-
const norm =
|
|
30943
|
+
const norm = path12.resolve(bridgeRootPath2);
|
|
30829
30944
|
const base = baseNameSafe(norm);
|
|
30830
30945
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
30831
30946
|
let name = base;
|
|
@@ -30841,24 +30956,27 @@ function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
|
|
|
30841
30956
|
|
|
30842
30957
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
30843
30958
|
async function prepareNewSessionWorktrees(options) {
|
|
30844
|
-
const {
|
|
30845
|
-
const
|
|
30846
|
-
const cwdKey = allocateDirNameForLauncherCwd(layout,
|
|
30847
|
-
const
|
|
30848
|
-
const
|
|
30959
|
+
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
|
|
30960
|
+
const bridgeResolved = path13.resolve(bridgeRoot);
|
|
30961
|
+
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
30962
|
+
const bridgeKeyDir = path13.join(worktreesRootPath, cwdKey);
|
|
30963
|
+
const sessionDir = path13.join(bridgeKeyDir, sessionId);
|
|
30964
|
+
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
30849
30965
|
if (repos.length === 0) {
|
|
30850
|
-
log2("[worktrees] No Git repositories under
|
|
30966
|
+
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
30851
30967
|
return null;
|
|
30852
30968
|
}
|
|
30853
30969
|
const branch = `session-${sessionId}`;
|
|
30854
30970
|
const worktreePaths = [];
|
|
30855
|
-
fs11.mkdirSync(
|
|
30971
|
+
fs11.mkdirSync(sessionDir, { recursive: true });
|
|
30856
30972
|
for (const repo of repos) {
|
|
30857
|
-
let rel =
|
|
30858
|
-
if (rel.startsWith("..") ||
|
|
30973
|
+
let rel = path13.relative(bridgeResolved, repo.absolutePath);
|
|
30974
|
+
if (rel.startsWith("..") || path13.isAbsolute(rel)) continue;
|
|
30859
30975
|
const relNorm = rel === "" ? "." : rel;
|
|
30860
|
-
const wtPath =
|
|
30861
|
-
|
|
30976
|
+
const wtPath = relNorm === "." ? sessionDir : path13.join(sessionDir, relNorm);
|
|
30977
|
+
if (relNorm !== ".") {
|
|
30978
|
+
fs11.mkdirSync(path13.dirname(wtPath), { recursive: true });
|
|
30979
|
+
}
|
|
30862
30980
|
try {
|
|
30863
30981
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
30864
30982
|
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
|
|
@@ -30870,7 +30988,11 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
30870
30988
|
}
|
|
30871
30989
|
}
|
|
30872
30990
|
if (worktreePaths.length === 0) return null;
|
|
30873
|
-
return {
|
|
30991
|
+
return {
|
|
30992
|
+
worktreePaths,
|
|
30993
|
+
sessionParentPath: sessionDir,
|
|
30994
|
+
workingTreeRelRoot: sessionDir
|
|
30995
|
+
};
|
|
30874
30996
|
}
|
|
30875
30997
|
|
|
30876
30998
|
// src/git/rename-branch.ts
|
|
@@ -30902,16 +31024,16 @@ import * as fs13 from "node:fs";
|
|
|
30902
31024
|
|
|
30903
31025
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
30904
31026
|
import * as fs12 from "node:fs";
|
|
30905
|
-
import * as
|
|
31027
|
+
import * as path14 from "node:path";
|
|
30906
31028
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
30907
|
-
const gitDirFile =
|
|
31029
|
+
const gitDirFile = path14.join(wt, ".git");
|
|
30908
31030
|
if (!fs12.existsSync(gitDirFile) || !fs12.statSync(gitDirFile).isFile()) return "";
|
|
30909
31031
|
const first2 = fs12.readFileSync(gitDirFile, "utf8").trim();
|
|
30910
31032
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
30911
31033
|
if (!m) return "";
|
|
30912
|
-
const gitWorktreePath =
|
|
30913
|
-
const gitDir =
|
|
30914
|
-
return
|
|
31034
|
+
const gitWorktreePath = path14.resolve(wt, m[1].trim());
|
|
31035
|
+
const gitDir = path14.dirname(path14.dirname(gitWorktreePath));
|
|
31036
|
+
return path14.dirname(gitDir);
|
|
30915
31037
|
}
|
|
30916
31038
|
|
|
30917
31039
|
// src/git/worktree-remove.ts
|
|
@@ -31153,7 +31275,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
31153
31275
|
}
|
|
31154
31276
|
|
|
31155
31277
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
31156
|
-
import * as
|
|
31278
|
+
import * as path16 from "node:path";
|
|
31157
31279
|
|
|
31158
31280
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
31159
31281
|
function parseNameStatusLines(lines) {
|
|
@@ -31274,16 +31396,16 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
31274
31396
|
|
|
31275
31397
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
31276
31398
|
import * as fs16 from "node:fs";
|
|
31277
|
-
import * as
|
|
31399
|
+
import * as path15 from "node:path";
|
|
31278
31400
|
|
|
31279
31401
|
// src/git/working-directory/changes/count-lines.ts
|
|
31280
31402
|
import { createReadStream } from "node:fs";
|
|
31281
31403
|
import * as readline2 from "node:readline";
|
|
31282
|
-
async function countTextFileLines(
|
|
31404
|
+
async function countTextFileLines(filePath) {
|
|
31283
31405
|
let bytes = 0;
|
|
31284
31406
|
const maxBytes = 512e3;
|
|
31285
31407
|
let lines = 0;
|
|
31286
|
-
const stream = createReadStream(
|
|
31408
|
+
const stream = createReadStream(filePath, { encoding: "utf8" });
|
|
31287
31409
|
const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
|
|
31288
31410
|
for await (const _line of rl) {
|
|
31289
31411
|
lines += 1;
|
|
@@ -31311,15 +31433,15 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
31311
31433
|
return null;
|
|
31312
31434
|
}
|
|
31313
31435
|
}
|
|
31314
|
-
async function readWorktreeFileLines(
|
|
31436
|
+
async function readWorktreeFileLines(filePath) {
|
|
31315
31437
|
try {
|
|
31316
|
-
const raw = await fs15.promises.readFile(
|
|
31438
|
+
const raw = await fs15.promises.readFile(filePath, "utf8");
|
|
31317
31439
|
return raw.split(/\r?\n/);
|
|
31318
31440
|
} catch {
|
|
31319
31441
|
return null;
|
|
31320
31442
|
}
|
|
31321
31443
|
}
|
|
31322
|
-
async function hydrateUnifiedPatchWithFileContext(patch,
|
|
31444
|
+
async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, change) {
|
|
31323
31445
|
if (!patch.trim() || patch.includes("Binary files")) return patch;
|
|
31324
31446
|
const all = patch.split("\n");
|
|
31325
31447
|
const out = [];
|
|
@@ -31336,7 +31458,7 @@ async function hydrateUnifiedPatchWithFileContext(patch, absFile, repoGitCwd, pa
|
|
|
31336
31458
|
};
|
|
31337
31459
|
const diskLines = async () => {
|
|
31338
31460
|
if (diskCache !== void 0) return diskCache;
|
|
31339
|
-
diskCache = await readWorktreeFileLines(
|
|
31461
|
+
diskCache = await readWorktreeFileLines(filePath);
|
|
31340
31462
|
return diskCache;
|
|
31341
31463
|
};
|
|
31342
31464
|
while (i < all.length) {
|
|
@@ -31448,7 +31570,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
31448
31570
|
const rows = [];
|
|
31449
31571
|
for (const pathInRepo of paths) {
|
|
31450
31572
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
31451
|
-
const
|
|
31573
|
+
const repoFilePath = path15.join(repoGitCwd, pathInRepo);
|
|
31452
31574
|
const nums = numByPath.get(pathInRepo);
|
|
31453
31575
|
let additions = nums?.additions ?? 0;
|
|
31454
31576
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -31461,8 +31583,8 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
31461
31583
|
deletions = fromGit.deletions;
|
|
31462
31584
|
} else {
|
|
31463
31585
|
try {
|
|
31464
|
-
const st = await fs16.promises.stat(
|
|
31465
|
-
if (st.isFile()) additions = await countTextFileLines(
|
|
31586
|
+
const st = await fs16.promises.stat(repoFilePath);
|
|
31587
|
+
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
31466
31588
|
else additions = 0;
|
|
31467
31589
|
} catch {
|
|
31468
31590
|
additions = 0;
|
|
@@ -31487,10 +31609,10 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
31487
31609
|
} else {
|
|
31488
31610
|
pathInRepo = row.pathRelLauncher;
|
|
31489
31611
|
}
|
|
31490
|
-
const
|
|
31612
|
+
const filePath = path15.join(repoGitCwd, pathInRepo);
|
|
31491
31613
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
31492
31614
|
if (patch) {
|
|
31493
|
-
patch = await hydrateUnifiedPatchWithFileContext(patch,
|
|
31615
|
+
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
31494
31616
|
}
|
|
31495
31617
|
row.patchContent = patch;
|
|
31496
31618
|
}
|
|
@@ -31503,8 +31625,9 @@ function normRepoRel(p) {
|
|
|
31503
31625
|
return x === "" ? "." : x;
|
|
31504
31626
|
}
|
|
31505
31627
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
31506
|
-
const
|
|
31507
|
-
const
|
|
31628
|
+
const bridgeRoot = path16.resolve(getBridgeRoot());
|
|
31629
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path16.resolve(options.sessionWorktreeRootPath) : null;
|
|
31630
|
+
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
31508
31631
|
const out = [];
|
|
31509
31632
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
31510
31633
|
const basisInput = options.basis ?? { kind: "working" };
|
|
@@ -31515,8 +31638,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
31515
31638
|
throw new Error("commit sha is required for commit changes");
|
|
31516
31639
|
}
|
|
31517
31640
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
31518
|
-
for (const target of options.
|
|
31519
|
-
const t =
|
|
31641
|
+
for (const target of options.commitTargetPaths) {
|
|
31642
|
+
const t = path16.resolve(target);
|
|
31520
31643
|
if (!await isGitRepoDirectory(t)) continue;
|
|
31521
31644
|
const g = simpleGit(t);
|
|
31522
31645
|
let branch = "HEAD";
|
|
@@ -31528,8 +31651,9 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
31528
31651
|
const remoteUrl = await getRemoteOriginUrl(t);
|
|
31529
31652
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
31530
31653
|
let repoRelPath;
|
|
31531
|
-
if (
|
|
31532
|
-
const
|
|
31654
|
+
if (sessionWtRoot) {
|
|
31655
|
+
const anchor = legacyNested ? path16.dirname(t) : t;
|
|
31656
|
+
const relNorm = path16.relative(sessionWtRoot, anchor);
|
|
31533
31657
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
31534
31658
|
} else {
|
|
31535
31659
|
let top = t;
|
|
@@ -31538,8 +31662,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
31538
31662
|
} catch {
|
|
31539
31663
|
top = t;
|
|
31540
31664
|
}
|
|
31541
|
-
const rel =
|
|
31542
|
-
repoRelPath = rel.startsWith("..") ?
|
|
31665
|
+
const rel = path16.relative(bridgeRoot, path16.resolve(top)).replace(/\\/g, "/") || ".";
|
|
31666
|
+
repoRelPath = rel.startsWith("..") ? path16.basename(path16.resolve(top)) : rel;
|
|
31543
31667
|
}
|
|
31544
31668
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
31545
31669
|
if (filter && norm !== filter) continue;
|
|
@@ -31605,14 +31729,37 @@ async function commitSessionWorktrees(options) {
|
|
|
31605
31729
|
|
|
31606
31730
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
31607
31731
|
import * as fs17 from "node:fs";
|
|
31608
|
-
import * as
|
|
31609
|
-
function isGitDir(
|
|
31732
|
+
import * as path17 from "node:path";
|
|
31733
|
+
function isGitDir(dirPath) {
|
|
31610
31734
|
try {
|
|
31611
|
-
return fs17.existsSync(
|
|
31735
|
+
return fs17.existsSync(path17.join(dirPath, ".git"));
|
|
31612
31736
|
} catch {
|
|
31613
31737
|
return false;
|
|
31614
31738
|
}
|
|
31615
31739
|
}
|
|
31740
|
+
function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
31741
|
+
const out = [];
|
|
31742
|
+
const walk = (dir) => {
|
|
31743
|
+
if (isGitDir(dir)) {
|
|
31744
|
+
out.push(path17.resolve(dir));
|
|
31745
|
+
return;
|
|
31746
|
+
}
|
|
31747
|
+
let entries;
|
|
31748
|
+
try {
|
|
31749
|
+
entries = fs17.readdirSync(dir, { withFileTypes: true });
|
|
31750
|
+
} catch {
|
|
31751
|
+
return;
|
|
31752
|
+
}
|
|
31753
|
+
for (const e of entries) {
|
|
31754
|
+
if (e.name.startsWith(".")) continue;
|
|
31755
|
+
const full = path17.join(dir, e.name);
|
|
31756
|
+
if (!e.isDirectory()) continue;
|
|
31757
|
+
walk(full);
|
|
31758
|
+
}
|
|
31759
|
+
};
|
|
31760
|
+
walk(path17.resolve(rootPath));
|
|
31761
|
+
return [...new Set(out)];
|
|
31762
|
+
}
|
|
31616
31763
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
31617
31764
|
const out = [];
|
|
31618
31765
|
const walk = (dir, depth) => {
|
|
@@ -31625,10 +31772,10 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
31625
31772
|
}
|
|
31626
31773
|
for (const e of entries) {
|
|
31627
31774
|
if (e.name.startsWith(".")) continue;
|
|
31628
|
-
const full =
|
|
31775
|
+
const full = path17.join(dir, e.name);
|
|
31629
31776
|
if (!e.isDirectory()) continue;
|
|
31630
31777
|
if (e.name === sessionId) {
|
|
31631
|
-
if (isGitDir(full)) out.push(
|
|
31778
|
+
if (isGitDir(full)) out.push(path17.resolve(full));
|
|
31632
31779
|
} else {
|
|
31633
31780
|
walk(full, depth + 1);
|
|
31634
31781
|
}
|
|
@@ -31637,16 +31784,55 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
31637
31784
|
walk(root, 0);
|
|
31638
31785
|
return out;
|
|
31639
31786
|
}
|
|
31787
|
+
function tryBindingFromSessionDirectory(sessionDir) {
|
|
31788
|
+
let st;
|
|
31789
|
+
try {
|
|
31790
|
+
st = fs17.statSync(sessionDir);
|
|
31791
|
+
} catch {
|
|
31792
|
+
return null;
|
|
31793
|
+
}
|
|
31794
|
+
if (!st.isDirectory()) return null;
|
|
31795
|
+
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
31796
|
+
if (worktreePaths.length === 0) return null;
|
|
31797
|
+
const abs = path17.resolve(sessionDir);
|
|
31798
|
+
return {
|
|
31799
|
+
sessionParentPath: abs,
|
|
31800
|
+
workingTreeRelRoot: abs,
|
|
31801
|
+
repoCheckoutPaths: worktreePaths
|
|
31802
|
+
};
|
|
31803
|
+
}
|
|
31804
|
+
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
31805
|
+
const sid = sessionId.trim();
|
|
31806
|
+
if (!sid) return null;
|
|
31807
|
+
const hintR = path17.resolve(checkoutPath);
|
|
31808
|
+
let best = null;
|
|
31809
|
+
let cur = path17.dirname(hintR);
|
|
31810
|
+
for (let i = 0; i < 40; i++) {
|
|
31811
|
+
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
31812
|
+
if (paths.some((p) => path17.resolve(p) === hintR)) {
|
|
31813
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path17.resolve(paths[0]);
|
|
31814
|
+
best = {
|
|
31815
|
+
sessionParentPath: path17.resolve(isolated),
|
|
31816
|
+
workingTreeRelRoot: path17.resolve(cur),
|
|
31817
|
+
repoCheckoutPaths: paths.map((p) => path17.resolve(p))
|
|
31818
|
+
};
|
|
31819
|
+
}
|
|
31820
|
+
const next = path17.dirname(cur);
|
|
31821
|
+
if (next === cur) break;
|
|
31822
|
+
cur = next;
|
|
31823
|
+
}
|
|
31824
|
+
return best;
|
|
31825
|
+
}
|
|
31640
31826
|
function discoverSessionWorktreeOnDisk(options) {
|
|
31641
|
-
const { sessionId,
|
|
31642
|
-
if (!sessionId.trim() || !fs17.existsSync(
|
|
31643
|
-
const preferredKey = getLauncherDirNameIfPresent(layout,
|
|
31827
|
+
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
31828
|
+
if (!sessionId.trim() || !fs17.existsSync(worktreesRootPath)) return null;
|
|
31829
|
+
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
31644
31830
|
const keys = [];
|
|
31645
31831
|
if (preferredKey) keys.push(preferredKey);
|
|
31646
31832
|
try {
|
|
31647
|
-
for (const name of fs17.readdirSync(
|
|
31833
|
+
for (const name of fs17.readdirSync(worktreesRootPath)) {
|
|
31648
31834
|
if (name.startsWith(".")) continue;
|
|
31649
|
-
const p =
|
|
31835
|
+
const p = path17.join(worktreesRootPath, name);
|
|
31650
31836
|
if (!fs17.statSync(p).isDirectory()) continue;
|
|
31651
31837
|
if (name !== preferredKey) keys.push(name);
|
|
31652
31838
|
}
|
|
@@ -31654,26 +31840,58 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
31654
31840
|
return null;
|
|
31655
31841
|
}
|
|
31656
31842
|
for (const key of keys) {
|
|
31657
|
-
const
|
|
31658
|
-
if (!fs17.existsSync(
|
|
31659
|
-
const
|
|
31660
|
-
|
|
31661
|
-
|
|
31843
|
+
const layoutRoot = path17.join(worktreesRootPath, key);
|
|
31844
|
+
if (!fs17.existsSync(layoutRoot) || !fs17.statSync(layoutRoot).isDirectory()) continue;
|
|
31845
|
+
const sessionDir = path17.join(layoutRoot, sessionId);
|
|
31846
|
+
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
31847
|
+
if (nested) return nested;
|
|
31848
|
+
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
31849
|
+
if (legacyPaths.length > 0) {
|
|
31850
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path17.resolve(legacyPaths[0]);
|
|
31851
|
+
return {
|
|
31852
|
+
sessionParentPath: path17.resolve(isolated),
|
|
31853
|
+
workingTreeRelRoot: path17.resolve(layoutRoot),
|
|
31854
|
+
repoCheckoutPaths: legacyPaths.map((p) => path17.resolve(p))
|
|
31855
|
+
};
|
|
31662
31856
|
}
|
|
31663
31857
|
}
|
|
31664
31858
|
return null;
|
|
31665
31859
|
}
|
|
31666
|
-
function
|
|
31667
|
-
const
|
|
31668
|
-
if (!
|
|
31860
|
+
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
31861
|
+
const sid = sessionId.trim();
|
|
31862
|
+
if (!sid) return null;
|
|
31863
|
+
const hint = path17.resolve(sessionWorktreeRootPathOrHint);
|
|
31864
|
+
const underHint = tryBindingFromSessionDirectory(path17.join(hint, sid));
|
|
31865
|
+
if (underHint) return underHint;
|
|
31866
|
+
const direct = tryBindingFromSessionDirectory(hint);
|
|
31867
|
+
if (direct) {
|
|
31868
|
+
if (path17.basename(hint) === sid && isGitDir(hint)) {
|
|
31869
|
+
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
31870
|
+
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
31871
|
+
return legacyFromCheckout;
|
|
31872
|
+
}
|
|
31873
|
+
}
|
|
31874
|
+
return direct;
|
|
31875
|
+
}
|
|
31876
|
+
if (path17.basename(hint) === sid && isGitDir(hint)) {
|
|
31877
|
+
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
31878
|
+
if (legacyFromCheckout) return legacyFromCheckout;
|
|
31879
|
+
}
|
|
31880
|
+
let st;
|
|
31669
31881
|
try {
|
|
31670
|
-
|
|
31882
|
+
st = fs17.statSync(hint);
|
|
31671
31883
|
} catch {
|
|
31672
31884
|
return null;
|
|
31673
31885
|
}
|
|
31674
|
-
|
|
31675
|
-
|
|
31676
|
-
|
|
31886
|
+
if (!st.isDirectory()) return null;
|
|
31887
|
+
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
31888
|
+
if (legacyPaths.length === 0) return null;
|
|
31889
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path17.resolve(legacyPaths[0]);
|
|
31890
|
+
return {
|
|
31891
|
+
sessionParentPath: path17.resolve(isolated),
|
|
31892
|
+
workingTreeRelRoot: hint,
|
|
31893
|
+
repoCheckoutPaths: legacyPaths.map((p) => path17.resolve(p))
|
|
31894
|
+
};
|
|
31677
31895
|
}
|
|
31678
31896
|
|
|
31679
31897
|
// src/worktrees/session-worktree-manager.ts
|
|
@@ -31683,42 +31901,86 @@ function parseSessionParent(v) {
|
|
|
31683
31901
|
return null;
|
|
31684
31902
|
}
|
|
31685
31903
|
var SessionWorktreeManager = class {
|
|
31686
|
-
|
|
31904
|
+
worktreesRootPath;
|
|
31687
31905
|
log;
|
|
31688
|
-
|
|
31689
|
-
|
|
31906
|
+
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
31907
|
+
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
31908
|
+
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
31690
31909
|
layout;
|
|
31691
31910
|
constructor(options) {
|
|
31692
|
-
this.
|
|
31911
|
+
this.worktreesRootPath = options.worktreesRootPath;
|
|
31693
31912
|
this.log = options.log;
|
|
31694
31913
|
this.layout = loadWorktreeLayout();
|
|
31695
31914
|
}
|
|
31696
|
-
|
|
31697
|
-
|
|
31698
|
-
this.
|
|
31915
|
+
rememberSessionWorktrees(sessionId, binding) {
|
|
31916
|
+
const paths = binding.repoCheckoutPaths.map((p) => path18.resolve(p));
|
|
31917
|
+
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
31918
|
+
this.sessionParentPathBySession.set(sessionId, path18.resolve(binding.sessionParentPath));
|
|
31919
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path18.resolve(binding.workingTreeRelRoot));
|
|
31920
|
+
}
|
|
31921
|
+
sessionParentPathAfterRemember(sessionId) {
|
|
31922
|
+
return this.sessionParentPathBySession.get(sessionId);
|
|
31699
31923
|
}
|
|
31700
31924
|
tryDiscoverFromDisk(sessionId) {
|
|
31701
31925
|
return discoverSessionWorktreeOnDisk({
|
|
31702
31926
|
sessionId,
|
|
31703
|
-
|
|
31927
|
+
worktreesRootPath: this.worktreesRootPath,
|
|
31704
31928
|
layout: this.layout,
|
|
31705
|
-
|
|
31929
|
+
bridgeRoot: getBridgeRoot()
|
|
31706
31930
|
});
|
|
31707
31931
|
}
|
|
31932
|
+
isLegacyNestedLayout(sessionId) {
|
|
31933
|
+
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
31934
|
+
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
31935
|
+
if (!parent || !relRoot) return false;
|
|
31936
|
+
return path18.resolve(parent) !== path18.resolve(relRoot);
|
|
31937
|
+
}
|
|
31938
|
+
/**
|
|
31939
|
+
* Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
|
|
31940
|
+
*/
|
|
31941
|
+
getIsolatedSessionParentPathForSession(sessionId) {
|
|
31942
|
+
if (!sessionId) return null;
|
|
31943
|
+
const sid = sessionId.trim();
|
|
31944
|
+
const cached2 = this.sessionParentPathBySession.get(sid);
|
|
31945
|
+
if (cached2) return path18.resolve(cached2);
|
|
31946
|
+
const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
|
|
31947
|
+
if (!paths?.length) return null;
|
|
31948
|
+
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
31949
|
+
}
|
|
31708
31950
|
/**
|
|
31709
|
-
*
|
|
31951
|
+
* Resolved **session parent path** for the agent: session directory in worktrees mode,
|
|
31952
|
+
* or `undefined` meaning use {@link getBridgeRoot}.
|
|
31710
31953
|
*/
|
|
31711
|
-
async
|
|
31954
|
+
async resolveSessionParentPathForPrompt(sessionId, opts) {
|
|
31712
31955
|
if (!sessionId) return void 0;
|
|
31956
|
+
const sid = sessionId.trim();
|
|
31713
31957
|
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
31714
31958
|
if (parentPathRaw) {
|
|
31715
|
-
const
|
|
31716
|
-
const sid = sessionId?.trim();
|
|
31959
|
+
const resolved = path18.resolve(parentPathRaw);
|
|
31717
31960
|
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
31718
|
-
const
|
|
31719
|
-
if (
|
|
31961
|
+
const diskFirst = this.tryDiscoverFromDisk(sid);
|
|
31962
|
+
if (diskFirst) {
|
|
31963
|
+
this.rememberSessionWorktrees(sid, diskFirst);
|
|
31964
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31965
|
+
}
|
|
31966
|
+
const fromRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, sid);
|
|
31967
|
+
if (fromRoot) {
|
|
31968
|
+
this.rememberSessionWorktrees(sid, fromRoot);
|
|
31969
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31970
|
+
}
|
|
31971
|
+
let cur = resolved;
|
|
31972
|
+
for (let i = 0; i < 16; i++) {
|
|
31973
|
+
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, sid);
|
|
31974
|
+
if (tryRoot) {
|
|
31975
|
+
this.rememberSessionWorktrees(sid, tryRoot);
|
|
31976
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31977
|
+
}
|
|
31978
|
+
const next = path18.dirname(cur);
|
|
31979
|
+
if (next === cur) break;
|
|
31980
|
+
cur = next;
|
|
31981
|
+
}
|
|
31720
31982
|
}
|
|
31721
|
-
return
|
|
31983
|
+
return resolved;
|
|
31722
31984
|
}
|
|
31723
31985
|
const parentKind = parseSessionParent(opts.sessionParent);
|
|
31724
31986
|
if (parentKind === "bridge_root") {
|
|
@@ -31726,78 +31988,102 @@ var SessionWorktreeManager = class {
|
|
|
31726
31988
|
}
|
|
31727
31989
|
if (parentKind === "worktrees_root") {
|
|
31728
31990
|
if (!opts.isNewSession) {
|
|
31729
|
-
const cached2 = this.
|
|
31730
|
-
if (cached2) return
|
|
31731
|
-
const disc = this.tryDiscoverFromDisk(
|
|
31991
|
+
const cached2 = this.sessionParentPathAfterRemember(sid);
|
|
31992
|
+
if (cached2) return cached2;
|
|
31993
|
+
const disc = this.tryDiscoverFromDisk(sid);
|
|
31732
31994
|
if (disc) {
|
|
31733
|
-
this.
|
|
31734
|
-
return
|
|
31995
|
+
this.rememberSessionWorktrees(sid, disc);
|
|
31996
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31735
31997
|
}
|
|
31736
31998
|
return void 0;
|
|
31737
31999
|
}
|
|
31738
32000
|
const prep2 = await prepareNewSessionWorktrees({
|
|
31739
|
-
|
|
31740
|
-
|
|
31741
|
-
sessionId,
|
|
32001
|
+
worktreesRootPath: this.worktreesRootPath,
|
|
32002
|
+
bridgeRoot: getBridgeRoot(),
|
|
32003
|
+
sessionId: sid,
|
|
31742
32004
|
layout: this.layout,
|
|
31743
32005
|
log: this.log
|
|
31744
32006
|
});
|
|
31745
32007
|
if (!prep2) return void 0;
|
|
31746
|
-
this.
|
|
31747
|
-
|
|
32008
|
+
this.rememberSessionWorktrees(sid, {
|
|
32009
|
+
sessionParentPath: prep2.sessionParentPath,
|
|
32010
|
+
workingTreeRelRoot: prep2.workingTreeRelRoot,
|
|
32011
|
+
repoCheckoutPaths: prep2.worktreePaths
|
|
32012
|
+
});
|
|
32013
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31748
32014
|
}
|
|
31749
32015
|
if (!opts.isNewSession) {
|
|
31750
|
-
const cached2 = this.
|
|
31751
|
-
if (cached2) return
|
|
31752
|
-
const disc = this.tryDiscoverFromDisk(
|
|
32016
|
+
const cached2 = this.sessionParentPathAfterRemember(sid);
|
|
32017
|
+
if (cached2) return cached2;
|
|
32018
|
+
const disc = this.tryDiscoverFromDisk(sid);
|
|
31753
32019
|
if (disc) {
|
|
31754
|
-
this.
|
|
31755
|
-
return
|
|
32020
|
+
this.rememberSessionWorktrees(sid, disc);
|
|
32021
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31756
32022
|
}
|
|
31757
32023
|
return void 0;
|
|
31758
32024
|
}
|
|
31759
32025
|
const prep = await prepareNewSessionWorktrees({
|
|
31760
|
-
|
|
31761
|
-
|
|
31762
|
-
sessionId,
|
|
32026
|
+
worktreesRootPath: this.worktreesRootPath,
|
|
32027
|
+
bridgeRoot: getBridgeRoot(),
|
|
32028
|
+
sessionId: sid,
|
|
31763
32029
|
layout: this.layout,
|
|
31764
32030
|
log: this.log
|
|
31765
32031
|
});
|
|
31766
32032
|
if (!prep) return void 0;
|
|
31767
|
-
this.
|
|
31768
|
-
|
|
32033
|
+
this.rememberSessionWorktrees(sid, {
|
|
32034
|
+
sessionParentPath: prep.sessionParentPath,
|
|
32035
|
+
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
32036
|
+
repoCheckoutPaths: prep.worktreePaths
|
|
32037
|
+
});
|
|
32038
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31769
32039
|
}
|
|
31770
32040
|
async renameSessionBranch(sessionId, newBranch) {
|
|
31771
|
-
const paths = this.
|
|
32041
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
31772
32042
|
if (!paths?.length) return;
|
|
31773
32043
|
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
31774
32044
|
}
|
|
31775
|
-
/** True when this session
|
|
32045
|
+
/** True when this session uses an isolated worktree layout (not the bridge root). */
|
|
31776
32046
|
usesWorktreeSession(sessionId) {
|
|
31777
32047
|
if (!sessionId) return false;
|
|
31778
|
-
return this.
|
|
32048
|
+
return this.sessionParentPathBySession.has(sessionId);
|
|
31779
32049
|
}
|
|
31780
|
-
|
|
32050
|
+
/** Per-repo git checkout directories for this session (for snapshots, commits, change lists). */
|
|
32051
|
+
getRepoCheckoutPathsForSession(sessionId) {
|
|
31781
32052
|
if (!sessionId) return void 0;
|
|
31782
|
-
const paths = this.
|
|
32053
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
31783
32054
|
return paths?.length ? [...paths] : void 0;
|
|
31784
32055
|
}
|
|
31785
|
-
/**
|
|
31786
|
-
|
|
31787
|
-
|
|
31788
|
-
|
|
31789
|
-
|
|
32056
|
+
/**
|
|
32057
|
+
* Same paths as {@link getRepoCheckoutPathsForSession}, but loads from disk into memory when the CLI
|
|
32058
|
+
* restarted or maps were not yet populated (avoids discovering every repo under the worktrees root).
|
|
32059
|
+
*/
|
|
32060
|
+
ensureRepoCheckoutPathsForSession(sessionId) {
|
|
32061
|
+
if (!sessionId?.trim()) return void 0;
|
|
32062
|
+
const sid = sessionId.trim();
|
|
32063
|
+
const cached2 = this.sessionRepoCheckoutPaths.get(sid);
|
|
32064
|
+
if (cached2?.length) return [...cached2];
|
|
32065
|
+
const disc = this.tryDiscoverFromDisk(sid);
|
|
32066
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
32067
|
+
this.rememberSessionWorktrees(sid, disc);
|
|
32068
|
+
return [...disc.repoCheckoutPaths];
|
|
32069
|
+
}
|
|
32070
|
+
return void 0;
|
|
32071
|
+
}
|
|
32072
|
+
/** Session parent directory when in worktrees mode; null otherwise (same as {@link getIsolatedSessionParentPathForSession} path). */
|
|
32073
|
+
getSessionWorktreeRootForSession(sessionId) {
|
|
32074
|
+
return this.getIsolatedSessionParentPathForSession(sessionId);
|
|
31790
32075
|
}
|
|
31791
32076
|
async removeSessionWorktrees(sessionId) {
|
|
31792
|
-
const paths = this.
|
|
31793
|
-
this.
|
|
31794
|
-
this.
|
|
32077
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
32078
|
+
this.sessionRepoCheckoutPaths.delete(sessionId);
|
|
32079
|
+
this.sessionParentPathBySession.delete(sessionId);
|
|
32080
|
+
this.sessionWorkingTreeRelRootBySession.delete(sessionId);
|
|
31795
32081
|
if (!paths?.length) return;
|
|
31796
32082
|
await removeSessionWorktrees(paths, this.log);
|
|
31797
32083
|
}
|
|
31798
32084
|
async commitSession(params) {
|
|
31799
|
-
const paths = this.
|
|
31800
|
-
const targets = paths?.length ? paths : [
|
|
32085
|
+
const paths = this.sessionRepoCheckoutPaths.get(params.sessionId);
|
|
32086
|
+
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
31801
32087
|
return commitSessionWorktrees({
|
|
31802
32088
|
paths: targets,
|
|
31803
32089
|
branch: params.branch,
|
|
@@ -31806,14 +32092,14 @@ var SessionWorktreeManager = class {
|
|
|
31806
32092
|
});
|
|
31807
32093
|
}
|
|
31808
32094
|
resolveCommitTargets(sessionId) {
|
|
31809
|
-
const paths = this.
|
|
32095
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
31810
32096
|
if (paths?.length) return paths;
|
|
31811
32097
|
const disc = this.tryDiscoverFromDisk(sessionId);
|
|
31812
|
-
if (disc?.
|
|
31813
|
-
this.
|
|
31814
|
-
return disc.
|
|
32098
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
32099
|
+
this.rememberSessionWorktrees(sessionId, disc);
|
|
32100
|
+
return disc.repoCheckoutPaths;
|
|
31815
32101
|
}
|
|
31816
|
-
return [
|
|
32102
|
+
return [getBridgeRoot()];
|
|
31817
32103
|
}
|
|
31818
32104
|
async getSessionWorkingTreeStatus(sessionId) {
|
|
31819
32105
|
return aggregateSessionPathsWorkingTreeStatus(this.resolveCommitTargets(sessionId));
|
|
@@ -31821,10 +32107,12 @@ var SessionWorktreeManager = class {
|
|
|
31821
32107
|
/** Per-repo changed files vs HEAD (or a single commit vs parent) for the same git roots used for commit/push. */
|
|
31822
32108
|
async getSessionWorkingTreeChangeDetails(sessionId, opts) {
|
|
31823
32109
|
const targets = this.resolveCommitTargets(sessionId);
|
|
31824
|
-
const
|
|
32110
|
+
const sessionWorkingTreeRelRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId) ?? null;
|
|
32111
|
+
const legacyNested = this.isLegacyNestedLayout(sessionId);
|
|
31825
32112
|
return getWorkingTreeChangeRepoDetails({
|
|
31826
|
-
|
|
31827
|
-
|
|
32113
|
+
commitTargetPaths: targets,
|
|
32114
|
+
sessionWorktreeRootPath: sessionWorkingTreeRelRoot,
|
|
32115
|
+
legacyRepoNestedSessionLayout: legacyNested,
|
|
31828
32116
|
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
31829
32117
|
basis: opts?.basis
|
|
31830
32118
|
});
|
|
@@ -31839,31 +32127,31 @@ var SessionWorktreeManager = class {
|
|
|
31839
32127
|
}
|
|
31840
32128
|
}
|
|
31841
32129
|
};
|
|
31842
|
-
function
|
|
31843
|
-
return
|
|
32130
|
+
function defaultWorktreesRootPath() {
|
|
32131
|
+
return path18.join(os4.homedir(), ".buildautomaton", "worktrees");
|
|
31844
32132
|
}
|
|
31845
32133
|
|
|
31846
32134
|
// src/files/watch-file-index.ts
|
|
31847
32135
|
import { watch } from "node:fs";
|
|
31848
|
-
import
|
|
32136
|
+
import path25 from "node:path";
|
|
31849
32137
|
|
|
31850
32138
|
// src/files/index/build-file-index.ts
|
|
31851
|
-
import
|
|
32139
|
+
import path22 from "node:path";
|
|
31852
32140
|
|
|
31853
32141
|
// src/runtime/yield-to-event-loop.ts
|
|
31854
32142
|
function yieldToEventLoop() {
|
|
31855
|
-
return new Promise((
|
|
32143
|
+
return new Promise((resolve16) => setImmediate(resolve16));
|
|
31856
32144
|
}
|
|
31857
32145
|
|
|
31858
32146
|
// src/files/index/walk-workspace-tree.ts
|
|
31859
32147
|
import fs18 from "node:fs";
|
|
31860
|
-
import
|
|
32148
|
+
import path20 from "node:path";
|
|
31861
32149
|
|
|
31862
32150
|
// src/files/index/constants.ts
|
|
31863
|
-
import
|
|
32151
|
+
import path19 from "node:path";
|
|
31864
32152
|
import os5 from "node:os";
|
|
31865
32153
|
var INDEX_WORK_YIELD_EVERY = 256;
|
|
31866
|
-
var INDEX_DIR =
|
|
32154
|
+
var INDEX_DIR = path19.join(os5.homedir(), ".buildautomaton");
|
|
31867
32155
|
var INDEX_HASH_LEN = 16;
|
|
31868
32156
|
var INDEX_VERSION = 2;
|
|
31869
32157
|
var INDEX_LOG_PREFIX = "[file-index]";
|
|
@@ -31878,14 +32166,14 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
|
31878
32166
|
}
|
|
31879
32167
|
for (const name of names) {
|
|
31880
32168
|
if (name.startsWith(".")) continue;
|
|
31881
|
-
const full =
|
|
32169
|
+
const full = path20.join(dir, name);
|
|
31882
32170
|
let stat2;
|
|
31883
32171
|
try {
|
|
31884
32172
|
stat2 = fs18.statSync(full);
|
|
31885
32173
|
} catch {
|
|
31886
32174
|
continue;
|
|
31887
32175
|
}
|
|
31888
|
-
const relative5 =
|
|
32176
|
+
const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
|
|
31889
32177
|
if (stat2.isDirectory()) {
|
|
31890
32178
|
walkWorkspaceTreeSync(full, baseDir, out);
|
|
31891
32179
|
} else if (stat2.isFile()) {
|
|
@@ -31906,14 +32194,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
31906
32194
|
await yieldToEventLoop();
|
|
31907
32195
|
}
|
|
31908
32196
|
state.n++;
|
|
31909
|
-
const full =
|
|
32197
|
+
const full = path20.join(dir, name);
|
|
31910
32198
|
let stat2;
|
|
31911
32199
|
try {
|
|
31912
32200
|
stat2 = await fs18.promises.stat(full);
|
|
31913
32201
|
} catch {
|
|
31914
32202
|
continue;
|
|
31915
32203
|
}
|
|
31916
|
-
const relative5 =
|
|
32204
|
+
const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
|
|
31917
32205
|
if (stat2.isDirectory()) {
|
|
31918
32206
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
31919
32207
|
} else if (stat2.isFile()) {
|
|
@@ -31997,11 +32285,11 @@ async function buildTrigramMapForPathsAsync(paths) {
|
|
|
31997
32285
|
import fs19 from "node:fs";
|
|
31998
32286
|
|
|
31999
32287
|
// src/files/index/paths.ts
|
|
32000
|
-
import
|
|
32288
|
+
import path21 from "node:path";
|
|
32001
32289
|
import crypto2 from "node:crypto";
|
|
32002
32290
|
function getIndexPathForCwd(resolvedCwd) {
|
|
32003
32291
|
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
32004
|
-
return
|
|
32292
|
+
return path21.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
32005
32293
|
}
|
|
32006
32294
|
|
|
32007
32295
|
// src/files/index/write-index-file.ts
|
|
@@ -32032,7 +32320,7 @@ function sortPaths(paths) {
|
|
|
32032
32320
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
32033
32321
|
}
|
|
32034
32322
|
function buildFileIndex(cwd) {
|
|
32035
|
-
const resolved =
|
|
32323
|
+
const resolved = path22.resolve(cwd);
|
|
32036
32324
|
const paths = [];
|
|
32037
32325
|
walkWorkspaceTreeSync(resolved, resolved, paths);
|
|
32038
32326
|
sortPaths(paths);
|
|
@@ -32042,7 +32330,7 @@ function buildFileIndex(cwd) {
|
|
|
32042
32330
|
return data;
|
|
32043
32331
|
}
|
|
32044
32332
|
async function buildFileIndexAsync(cwd) {
|
|
32045
|
-
const resolved =
|
|
32333
|
+
const resolved = path22.resolve(cwd);
|
|
32046
32334
|
const paths = [];
|
|
32047
32335
|
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
32048
32336
|
await yieldToEventLoop();
|
|
@@ -32055,9 +32343,9 @@ async function buildFileIndexAsync(cwd) {
|
|
|
32055
32343
|
|
|
32056
32344
|
// src/files/index/load-file-index.ts
|
|
32057
32345
|
import fs20 from "node:fs";
|
|
32058
|
-
import
|
|
32346
|
+
import path23 from "node:path";
|
|
32059
32347
|
function loadFileIndex(cwd) {
|
|
32060
|
-
const resolved =
|
|
32348
|
+
const resolved = path23.resolve(cwd);
|
|
32061
32349
|
const indexPath = getIndexPathForCwd(resolved);
|
|
32062
32350
|
try {
|
|
32063
32351
|
const raw = fs20.readFileSync(indexPath, "utf8");
|
|
@@ -32079,9 +32367,9 @@ function loadFileIndex(cwd) {
|
|
|
32079
32367
|
}
|
|
32080
32368
|
|
|
32081
32369
|
// src/files/index/ensure-file-index.ts
|
|
32082
|
-
import
|
|
32370
|
+
import path24 from "node:path";
|
|
32083
32371
|
async function ensureFileIndexAsync(cwd) {
|
|
32084
|
-
const resolved =
|
|
32372
|
+
const resolved = path24.resolve(cwd);
|
|
32085
32373
|
const cached2 = loadFileIndex(resolved);
|
|
32086
32374
|
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
32087
32375
|
const data = await buildFileIndexAsync(resolved);
|
|
@@ -32163,8 +32451,8 @@ function createFsWatcher(resolved, schedule) {
|
|
|
32163
32451
|
throw e;
|
|
32164
32452
|
}
|
|
32165
32453
|
}
|
|
32166
|
-
function startFileIndexWatcher(cwd =
|
|
32167
|
-
const resolved =
|
|
32454
|
+
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
32455
|
+
const resolved = path25.resolve(cwd);
|
|
32168
32456
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
32169
32457
|
console.error("[file-index] Initial index build failed:", e);
|
|
32170
32458
|
});
|
|
@@ -32214,15 +32502,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
32214
32502
|
|
|
32215
32503
|
// src/dev-servers/process/terminate-child-process.ts
|
|
32216
32504
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
32217
|
-
const exited = new Promise((
|
|
32218
|
-
proc.once("exit", () =>
|
|
32505
|
+
const exited = new Promise((resolve16) => {
|
|
32506
|
+
proc.once("exit", () => resolve16());
|
|
32219
32507
|
});
|
|
32220
32508
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
32221
32509
|
try {
|
|
32222
32510
|
proc.kill("SIGTERM");
|
|
32223
32511
|
} catch {
|
|
32224
32512
|
}
|
|
32225
|
-
await Promise.race([exited, new Promise((
|
|
32513
|
+
await Promise.race([exited, new Promise((resolve16) => setTimeout(resolve16, graceMs))]);
|
|
32226
32514
|
}
|
|
32227
32515
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
32228
32516
|
log2(
|
|
@@ -32502,10 +32790,10 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
32502
32790
|
import { spawn as spawn7 } from "node:child_process";
|
|
32503
32791
|
import fs23 from "node:fs";
|
|
32504
32792
|
import { tmpdir } from "node:os";
|
|
32505
|
-
import
|
|
32793
|
+
import path26 from "node:path";
|
|
32506
32794
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
32507
|
-
const tmpRoot = fs23.mkdtempSync(
|
|
32508
|
-
const logPath =
|
|
32795
|
+
const tmpRoot = fs23.mkdtempSync(path26.join(tmpdir(), "ba-devsrv-log-"));
|
|
32796
|
+
const logPath = path26.join(tmpRoot, "combined.log");
|
|
32509
32797
|
let logFd;
|
|
32510
32798
|
try {
|
|
32511
32799
|
logFd = fs23.openSync(logPath, "a");
|
|
@@ -32549,15 +32837,15 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
32549
32837
|
import { spawn as spawn8 } from "node:child_process";
|
|
32550
32838
|
import fs24 from "node:fs";
|
|
32551
32839
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
32552
|
-
import
|
|
32840
|
+
import path27 from "node:path";
|
|
32553
32841
|
function shSingleQuote(s) {
|
|
32554
32842
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
32555
32843
|
}
|
|
32556
32844
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
32557
|
-
const tmpRoot = fs24.mkdtempSync(
|
|
32558
|
-
const logPath =
|
|
32559
|
-
const innerPath =
|
|
32560
|
-
const runnerPath =
|
|
32845
|
+
const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
32846
|
+
const logPath = path27.join(tmpRoot, "combined.log");
|
|
32847
|
+
const innerPath = path27.join(tmpRoot, "_cmd.sh");
|
|
32848
|
+
const runnerPath = path27.join(tmpRoot, "_run.sh");
|
|
32561
32849
|
try {
|
|
32562
32850
|
fs24.writeFileSync(innerPath, `#!/bin/sh
|
|
32563
32851
|
${command}
|
|
@@ -32588,9 +32876,9 @@ cd ${shSingleQuote(cwd)}
|
|
|
32588
32876
|
}
|
|
32589
32877
|
}
|
|
32590
32878
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
32591
|
-
const tmpRoot = fs24.mkdtempSync(
|
|
32592
|
-
const logPath =
|
|
32593
|
-
const runnerPath =
|
|
32879
|
+
const tmpRoot = fs24.mkdtempSync(path27.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
32880
|
+
const logPath = path27.join(tmpRoot, "combined.log");
|
|
32881
|
+
const runnerPath = path27.join(tmpRoot, "_run.bat");
|
|
32594
32882
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
32595
32883
|
const com = process.env.ComSpec || "cmd.exe";
|
|
32596
32884
|
try {
|
|
@@ -32800,13 +33088,13 @@ var DevServerManager = class {
|
|
|
32800
33088
|
abortControllersByServerId = /* @__PURE__ */ new Map();
|
|
32801
33089
|
getWs;
|
|
32802
33090
|
log;
|
|
32803
|
-
|
|
33091
|
+
getBridgeRoot;
|
|
32804
33092
|
e2ee;
|
|
32805
33093
|
firehoseSink;
|
|
32806
33094
|
constructor(options) {
|
|
32807
33095
|
this.getWs = options.getWs;
|
|
32808
33096
|
this.log = options.log;
|
|
32809
|
-
this.
|
|
33097
|
+
this.getBridgeRoot = options.getBridgeRoot ?? (() => process.cwd());
|
|
32810
33098
|
this.e2ee = options.e2ee;
|
|
32811
33099
|
this.firehoseSink = new DevServerFirehoseSink({
|
|
32812
33100
|
getTails: (serverId) => this.snapshotTails(serverId),
|
|
@@ -32895,7 +33183,7 @@ var DevServerManager = class {
|
|
|
32895
33183
|
this.sendStatus(serverId, "starting", void 0, emptyTails());
|
|
32896
33184
|
const ac = new AbortController();
|
|
32897
33185
|
this.abortControllersByServerId.set(serverId, ac);
|
|
32898
|
-
const cwd = this.
|
|
33186
|
+
const cwd = this.getBridgeRoot();
|
|
32899
33187
|
const childEnv = envForSpawn(process.env, def.env, def.ports);
|
|
32900
33188
|
const cmd = substituteCommand(def.command.trim(), childEnv);
|
|
32901
33189
|
const title = def.name.trim() || serverId.slice(0, 8);
|
|
@@ -33318,13 +33606,13 @@ function createOnBridgeIdentified(opts) {
|
|
|
33318
33606
|
|
|
33319
33607
|
// src/skills/discover-local-agent-skills.ts
|
|
33320
33608
|
import fs25 from "node:fs";
|
|
33321
|
-
import
|
|
33609
|
+
import path28 from "node:path";
|
|
33322
33610
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
33323
33611
|
function discoverLocalSkills(cwd) {
|
|
33324
33612
|
const out = [];
|
|
33325
33613
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
33326
33614
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
33327
|
-
const base =
|
|
33615
|
+
const base = path28.join(cwd, rel);
|
|
33328
33616
|
if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
|
|
33329
33617
|
let entries = [];
|
|
33330
33618
|
try {
|
|
@@ -33333,13 +33621,13 @@ function discoverLocalSkills(cwd) {
|
|
|
33333
33621
|
continue;
|
|
33334
33622
|
}
|
|
33335
33623
|
for (const name of entries) {
|
|
33336
|
-
const dir =
|
|
33624
|
+
const dir = path28.join(base, name);
|
|
33337
33625
|
try {
|
|
33338
33626
|
if (!fs25.statSync(dir).isDirectory()) continue;
|
|
33339
33627
|
} catch {
|
|
33340
33628
|
continue;
|
|
33341
33629
|
}
|
|
33342
|
-
const skillMd =
|
|
33630
|
+
const skillMd = path28.join(dir, "SKILL.md");
|
|
33343
33631
|
if (!fs25.existsSync(skillMd)) continue;
|
|
33344
33632
|
const key = `${rel}/${name}`;
|
|
33345
33633
|
if (seenKeys.has(key)) continue;
|
|
@@ -33352,7 +33640,7 @@ function discoverLocalSkills(cwd) {
|
|
|
33352
33640
|
function discoverSkillLayoutRoots(cwd) {
|
|
33353
33641
|
const roots = [];
|
|
33354
33642
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
33355
|
-
const base =
|
|
33643
|
+
const base = path28.join(cwd, rel);
|
|
33356
33644
|
if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
|
|
33357
33645
|
let entries = [];
|
|
33358
33646
|
try {
|
|
@@ -33362,13 +33650,13 @@ function discoverSkillLayoutRoots(cwd) {
|
|
|
33362
33650
|
}
|
|
33363
33651
|
const skills2 = [];
|
|
33364
33652
|
for (const name of entries) {
|
|
33365
|
-
const dir =
|
|
33653
|
+
const dir = path28.join(base, name);
|
|
33366
33654
|
try {
|
|
33367
33655
|
if (!fs25.statSync(dir).isDirectory()) continue;
|
|
33368
33656
|
} catch {
|
|
33369
33657
|
continue;
|
|
33370
33658
|
}
|
|
33371
|
-
if (!fs25.existsSync(
|
|
33659
|
+
if (!fs25.existsSync(path28.join(dir, "SKILL.md"))) continue;
|
|
33372
33660
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
33373
33661
|
skills2.push({ name, relPath });
|
|
33374
33662
|
}
|
|
@@ -33412,7 +33700,7 @@ function createSendLocalSkillsReport(getWs, logFn) {
|
|
|
33412
33700
|
try {
|
|
33413
33701
|
const socket = getWs();
|
|
33414
33702
|
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
33415
|
-
const skills2 = discoverLocalSkills(
|
|
33703
|
+
const skills2 = discoverLocalSkills(getBridgeRoot());
|
|
33416
33704
|
sendWsMessage(socket, { type: "local_skills", skills: skills2 });
|
|
33417
33705
|
} catch (e) {
|
|
33418
33706
|
logFn(
|
|
@@ -33473,6 +33761,7 @@ var API_TO_BRIDGE_MESSAGE_TYPES = [
|
|
|
33473
33761
|
"dev_servers_config",
|
|
33474
33762
|
"server_control",
|
|
33475
33763
|
"agent_config",
|
|
33764
|
+
"prompt_queue_state",
|
|
33476
33765
|
"prompt",
|
|
33477
33766
|
"session_git_request",
|
|
33478
33767
|
"rename_session_branch",
|
|
@@ -33549,8 +33838,178 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
33549
33838
|
handleBridgeAgentConfig(msg, deps);
|
|
33550
33839
|
};
|
|
33551
33840
|
|
|
33552
|
-
// src/
|
|
33553
|
-
|
|
33841
|
+
// src/prompt-turn-queue/client-report.ts
|
|
33842
|
+
function sendPromptQueueClientReport(ws, queues) {
|
|
33843
|
+
if (!ws) return false;
|
|
33844
|
+
sendWsMessage(ws, { type: "prompt_queue_client_report", queues });
|
|
33845
|
+
return true;
|
|
33846
|
+
}
|
|
33847
|
+
|
|
33848
|
+
// src/prompt-turn-queue/disk-store.ts
|
|
33849
|
+
import fs27 from "node:fs";
|
|
33850
|
+
|
|
33851
|
+
// src/prompt-turn-queue/paths.ts
|
|
33852
|
+
import crypto3 from "node:crypto";
|
|
33853
|
+
import fs26 from "node:fs";
|
|
33854
|
+
import path29 from "node:path";
|
|
33855
|
+
import os6 from "node:os";
|
|
33856
|
+
var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
|
|
33857
|
+
function queueStateFileSlug(queueKey) {
|
|
33858
|
+
if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
|
|
33859
|
+
return crypto3.createHash("sha256").update(queueKey, "utf8").digest("hex");
|
|
33860
|
+
}
|
|
33861
|
+
function getPromptQueuesDirectory() {
|
|
33862
|
+
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
33863
|
+
if (override) return path29.resolve(override);
|
|
33864
|
+
return path29.join(os6.homedir(), ".buildautomaton", "queues");
|
|
33865
|
+
}
|
|
33866
|
+
function ensurePromptQueuesDirectory() {
|
|
33867
|
+
const dir = getPromptQueuesDirectory();
|
|
33868
|
+
if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
|
|
33869
|
+
}
|
|
33870
|
+
function queueStateFilePath(queueKey) {
|
|
33871
|
+
return path29.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
|
|
33872
|
+
}
|
|
33873
|
+
|
|
33874
|
+
// src/prompt-turn-queue/disk-store.ts
|
|
33875
|
+
function parsePersistedQueueFile(raw) {
|
|
33876
|
+
try {
|
|
33877
|
+
const o = JSON.parse(raw);
|
|
33878
|
+
const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
|
|
33879
|
+
if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
|
|
33880
|
+
return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
|
|
33881
|
+
} catch {
|
|
33882
|
+
return null;
|
|
33883
|
+
}
|
|
33884
|
+
}
|
|
33885
|
+
function readPersistedQueue(queueKey) {
|
|
33886
|
+
const p = queueStateFilePath(queueKey);
|
|
33887
|
+
try {
|
|
33888
|
+
return parsePersistedQueueFile(fs27.readFileSync(p, "utf8"));
|
|
33889
|
+
} catch {
|
|
33890
|
+
return null;
|
|
33891
|
+
}
|
|
33892
|
+
}
|
|
33893
|
+
function writePersistedQueue(file2) {
|
|
33894
|
+
ensurePromptQueuesDirectory();
|
|
33895
|
+
const p = queueStateFilePath(file2.queueKey);
|
|
33896
|
+
fs27.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
|
|
33897
|
+
}
|
|
33898
|
+
function mergeServerQueueSnapshot(queueKey, serverTurns) {
|
|
33899
|
+
const prev = readPersistedQueue(queueKey);
|
|
33900
|
+
const turns = [];
|
|
33901
|
+
for (const raw of serverTurns) {
|
|
33902
|
+
if (!raw || typeof raw !== "object") continue;
|
|
33903
|
+
const o = raw;
|
|
33904
|
+
const turnId = typeof o.turnId === "string" ? o.turnId : "";
|
|
33905
|
+
const sessionId = typeof o.sessionId === "string" ? o.sessionId : "";
|
|
33906
|
+
const turnOrd = typeof o.turnOrd === "number" ? o.turnOrd : Number(o.turnOrd) || 0;
|
|
33907
|
+
const serverState = o.serverState;
|
|
33908
|
+
const lastClientState = o.lastClientState ?? null;
|
|
33909
|
+
const payload = o.payload && typeof o.payload === "object" ? o.payload : {};
|
|
33910
|
+
if (!turnId || !sessionId) continue;
|
|
33911
|
+
if (serverState !== "queued" && serverState !== "stopping" && serverState !== "discarded") continue;
|
|
33912
|
+
const old = prev?.turns.find((t) => t.turnId === turnId);
|
|
33913
|
+
const mergedClient = old?.lastClientState === "running" && lastClientState == null ? "running" : lastClientState;
|
|
33914
|
+
turns.push({
|
|
33915
|
+
turnId,
|
|
33916
|
+
sessionId,
|
|
33917
|
+
turnOrd,
|
|
33918
|
+
serverState,
|
|
33919
|
+
lastClientState: mergedClient,
|
|
33920
|
+
payload
|
|
33921
|
+
});
|
|
33922
|
+
}
|
|
33923
|
+
turns.sort((a, b) => a.turnOrd - b.turnOrd);
|
|
33924
|
+
return { queueKey, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), turns };
|
|
33925
|
+
}
|
|
33926
|
+
|
|
33927
|
+
// src/prompt-turn-queue/runner.ts
|
|
33928
|
+
var runIdToQueueKey = /* @__PURE__ */ new Map();
|
|
33929
|
+
function pickNextRunnableTurn(turns) {
|
|
33930
|
+
for (const t of turns) {
|
|
33931
|
+
if (t.serverState === "discarded" || t.serverState === "stopping") continue;
|
|
33932
|
+
if (t.serverState !== "queued") continue;
|
|
33933
|
+
if (t.lastClientState === "running" || t.lastClientState === "stopped" || t.lastClientState === "failed") continue;
|
|
33934
|
+
return t;
|
|
33935
|
+
}
|
|
33936
|
+
return null;
|
|
33937
|
+
}
|
|
33938
|
+
function hasRunningTurn(turns) {
|
|
33939
|
+
return turns.some((t) => t.lastClientState === "running");
|
|
33940
|
+
}
|
|
33941
|
+
function dispatchLocalPrompt(next, deps) {
|
|
33942
|
+
const pl = next.payload;
|
|
33943
|
+
const rawParent = pl["sessionParent"];
|
|
33944
|
+
const sessionParent = rawParent === "bridge_root" || rawParent === "worktrees_root" ? rawParent : void 0;
|
|
33945
|
+
const rawParentPath = pl["sessionParentPath"];
|
|
33946
|
+
const sessionParentPath = typeof rawParentPath === "string" && rawParentPath.trim() !== "" ? rawParentPath.trim() : void 0;
|
|
33947
|
+
const msg = {
|
|
33948
|
+
type: "prompt",
|
|
33949
|
+
sessionId: next.sessionId,
|
|
33950
|
+
runId: next.turnId,
|
|
33951
|
+
prompt: pl.prompt,
|
|
33952
|
+
mode: typeof pl.mode === "string" ? pl.mode : "agent",
|
|
33953
|
+
isNewSession: pl.isNewSession === true,
|
|
33954
|
+
...sessionParent ? { sessionParent } : {},
|
|
33955
|
+
...sessionParentPath ? { sessionParentPath } : {},
|
|
33956
|
+
...typeof pl.followUpCatalogPromptId === "string" ? { followUpCatalogPromptId: pl.followUpCatalogPromptId } : {},
|
|
33957
|
+
...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
|
|
33958
|
+
...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
|
|
33959
|
+
...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {}
|
|
33960
|
+
};
|
|
33961
|
+
handleBridgePrompt(msg, deps);
|
|
33962
|
+
}
|
|
33963
|
+
function applyPromptQueueStateFromServer(msg, deps) {
|
|
33964
|
+
const raw = msg.queues;
|
|
33965
|
+
if (!raw || typeof raw !== "object") return;
|
|
33966
|
+
const getWs = deps.getWs;
|
|
33967
|
+
for (const [queueKey, serverTurns] of Object.entries(raw)) {
|
|
33968
|
+
if (!Array.isArray(serverTurns)) continue;
|
|
33969
|
+
const file2 = mergeServerQueueSnapshot(queueKey, serverTurns);
|
|
33970
|
+
writePersistedQueue(file2);
|
|
33971
|
+
}
|
|
33972
|
+
const report = {};
|
|
33973
|
+
const startedThisTick = /* @__PURE__ */ new Set();
|
|
33974
|
+
for (const [queueKey, serverTurns] of Object.entries(raw)) {
|
|
33975
|
+
if (!Array.isArray(serverTurns)) continue;
|
|
33976
|
+
const file2 = readPersistedQueue(queueKey);
|
|
33977
|
+
if (!file2) continue;
|
|
33978
|
+
if (hasRunningTurn(file2.turns)) continue;
|
|
33979
|
+
const next = pickNextRunnableTurn(file2.turns);
|
|
33980
|
+
if (!next) continue;
|
|
33981
|
+
next.lastClientState = "running";
|
|
33982
|
+
writePersistedQueue(file2);
|
|
33983
|
+
runIdToQueueKey.set(next.turnId, queueKey);
|
|
33984
|
+
startedThisTick.add(next.turnId);
|
|
33985
|
+
report[queueKey] = [{ turnId: next.turnId, clientState: "running" }];
|
|
33986
|
+
}
|
|
33987
|
+
if (Object.keys(report).length > 0) {
|
|
33988
|
+
sendPromptQueueClientReport(getWs(), report);
|
|
33989
|
+
}
|
|
33990
|
+
for (const [queueKey, serverTurns] of Object.entries(raw)) {
|
|
33991
|
+
if (!Array.isArray(serverTurns)) continue;
|
|
33992
|
+
const file2 = readPersistedQueue(queueKey);
|
|
33993
|
+
if (!file2) continue;
|
|
33994
|
+
const running = file2.turns.find((t) => t.lastClientState === "running");
|
|
33995
|
+
if (!running || !startedThisTick.has(running.turnId)) continue;
|
|
33996
|
+
if (runIdToQueueKey.get(running.turnId) !== queueKey) continue;
|
|
33997
|
+
dispatchLocalPrompt(running, deps);
|
|
33998
|
+
}
|
|
33999
|
+
}
|
|
34000
|
+
function finalizePromptTurnOnBridge(getWs, runId, success2) {
|
|
34001
|
+
if (!runId) return;
|
|
34002
|
+
const queueKey = runIdToQueueKey.get(runId);
|
|
34003
|
+
runIdToQueueKey.delete(runId);
|
|
34004
|
+
if (!queueKey) return;
|
|
34005
|
+
const f = readPersistedQueue(queueKey);
|
|
34006
|
+
if (!f) return;
|
|
34007
|
+
const t = f.turns.find((x) => x.turnId === runId);
|
|
34008
|
+
if (!t) return;
|
|
34009
|
+
t.lastClientState = success2 ? "stopped" : "failed";
|
|
34010
|
+
writePersistedQueue(f);
|
|
34011
|
+
sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, clientState: t.lastClientState }] });
|
|
34012
|
+
}
|
|
33554
34013
|
|
|
33555
34014
|
// src/agents/acp/from-bridge/bridge-prompt-wiring.ts
|
|
33556
34015
|
function createBridgePromptSenders(deps, getWs) {
|
|
@@ -33565,6 +34024,9 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
33565
34024
|
const skipEncryptForChangeSummaryFollowUp = result.type === "prompt_result" && result.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
33566
34025
|
const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
|
|
33567
34026
|
sendBridgeMessage(result, encryptedFields);
|
|
34027
|
+
if (result.type === "prompt_result") {
|
|
34028
|
+
finalizePromptTurnOnBridge(getWs, typeof result.runId === "string" ? result.runId : void 0, result.success === true);
|
|
34029
|
+
}
|
|
33568
34030
|
};
|
|
33569
34031
|
const sendSessionUpdate = (payload) => {
|
|
33570
34032
|
const s = getWs();
|
|
@@ -33589,63 +34051,6 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
33589
34051
|
// src/agents/acp/from-bridge/bridge-prompt-preamble.ts
|
|
33590
34052
|
import { execFile as execFile10 } from "node:child_process";
|
|
33591
34053
|
import { promisify as promisify10 } from "node:util";
|
|
33592
|
-
|
|
33593
|
-
// src/git/bridge-queue-key.ts
|
|
33594
|
-
import * as path28 from "node:path";
|
|
33595
|
-
import { createHash } from "node:crypto";
|
|
33596
|
-
function normalizeCanonicalGitUrl(url2) {
|
|
33597
|
-
let s = url2.trim();
|
|
33598
|
-
if (!s) return s;
|
|
33599
|
-
if (s.toLowerCase().endsWith(".git")) {
|
|
33600
|
-
s = s.slice(0, -4);
|
|
33601
|
-
}
|
|
33602
|
-
s = s.replace(/\/+$/, "");
|
|
33603
|
-
const httpsMatch = /^(https?):\/\/([^/]+)(\/.*)?$/i.exec(s);
|
|
33604
|
-
if (httpsMatch) {
|
|
33605
|
-
const host = httpsMatch[2].toLowerCase();
|
|
33606
|
-
const p = httpsMatch[3] ?? "";
|
|
33607
|
-
s = `${httpsMatch[1].toLowerCase()}://${host}${p}`;
|
|
33608
|
-
} else {
|
|
33609
|
-
const sshMatch = /^git@([^:]+):(.+)$/i.exec(s);
|
|
33610
|
-
if (sshMatch) {
|
|
33611
|
-
const host = sshMatch[1].toLowerCase();
|
|
33612
|
-
s = `git@${host}:${sshMatch[2]}`;
|
|
33613
|
-
}
|
|
33614
|
-
}
|
|
33615
|
-
return s;
|
|
33616
|
-
}
|
|
33617
|
-
function canonicalUrlToRepoIdSync(url2) {
|
|
33618
|
-
const normalized = normalizeCanonicalGitUrl(url2);
|
|
33619
|
-
return createHash("sha256").update(normalized).digest("hex").slice(0, 32);
|
|
33620
|
-
}
|
|
33621
|
-
function fallbackRepoIdFromPath(absPath) {
|
|
33622
|
-
return createHash("sha256").update(path28.resolve(absPath)).digest("hex").slice(0, 32);
|
|
33623
|
-
}
|
|
33624
|
-
async function resolveBridgeQueueBindFields(options) {
|
|
33625
|
-
const { effectiveCwd, worktreePaths, primaryRepoRoots, log: log2 } = options;
|
|
33626
|
-
const cwdAbs = worktreePaths.length > 0 ? path28.resolve(worktreePaths[0]) : path28.resolve(effectiveCwd);
|
|
33627
|
-
if (!primaryRepoRoots.length) {
|
|
33628
|
-
log2("[Bridge service] Prompt queue bind skipped: no Git repository roots under the working directory.");
|
|
33629
|
-
return null;
|
|
33630
|
-
}
|
|
33631
|
-
let primaryRoot = primaryRepoRoots[0];
|
|
33632
|
-
let remote = await getRemoteOriginUrl(primaryRoot);
|
|
33633
|
-
if (!remote) {
|
|
33634
|
-
for (const r of primaryRepoRoots.slice(1)) {
|
|
33635
|
-
const u = await getRemoteOriginUrl(r);
|
|
33636
|
-
if (u) {
|
|
33637
|
-
primaryRoot = r;
|
|
33638
|
-
remote = u;
|
|
33639
|
-
break;
|
|
33640
|
-
}
|
|
33641
|
-
}
|
|
33642
|
-
}
|
|
33643
|
-
const repoId = remote ? canonicalUrlToRepoIdSync(remote) : fallbackRepoIdFromPath(primaryRoot);
|
|
33644
|
-
const canonicalQueueKey = `repo:${repoId}::cwd:${cwdAbs}`;
|
|
33645
|
-
return { canonicalQueueKey, repoId, cwdAbs };
|
|
33646
|
-
}
|
|
33647
|
-
|
|
33648
|
-
// src/agents/acp/from-bridge/bridge-prompt-preamble.ts
|
|
33649
34054
|
var execFileAsync9 = promisify10(execFile10);
|
|
33650
34055
|
async function readGitBranch(cwd) {
|
|
33651
34056
|
try {
|
|
@@ -33659,40 +34064,24 @@ async function readGitBranch(cwd) {
|
|
|
33659
34064
|
async function runBridgePromptPreamble(params) {
|
|
33660
34065
|
const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
|
|
33661
34066
|
const s = getWs();
|
|
33662
|
-
const
|
|
34067
|
+
const repoCheckoutPaths = sessionWorktreeManager.ensureRepoCheckoutPathsForSession(sessionId);
|
|
33663
34068
|
const repoRoots = await resolveSnapshotRepoRoots({
|
|
33664
|
-
worktreePaths,
|
|
34069
|
+
worktreePaths: repoCheckoutPaths,
|
|
33665
34070
|
fallbackCwd: effectiveCwd,
|
|
34071
|
+
sessionId: sessionId?.trim() || void 0,
|
|
33666
34072
|
log: log2
|
|
33667
34073
|
});
|
|
33668
|
-
if (s && sessionId) {
|
|
33669
|
-
const bind = await resolveBridgeQueueBindFields({
|
|
33670
|
-
effectiveCwd,
|
|
33671
|
-
worktreePaths,
|
|
33672
|
-
primaryRepoRoots: repoRoots,
|
|
33673
|
-
log: log2
|
|
33674
|
-
});
|
|
33675
|
-
if (bind) {
|
|
33676
|
-
sendWsMessage(s, {
|
|
33677
|
-
type: "bridge_queue_bind",
|
|
33678
|
-
sessionId,
|
|
33679
|
-
canonicalQueueKey: bind.canonicalQueueKey,
|
|
33680
|
-
repoId: bind.repoId,
|
|
33681
|
-
cwdAbs: bind.cwdAbs
|
|
33682
|
-
});
|
|
33683
|
-
}
|
|
33684
|
-
}
|
|
33685
34074
|
if (s && sessionId) {
|
|
33686
34075
|
const cliGitBranch = await readGitBranch(effectiveCwd);
|
|
33687
34076
|
const usesWt = sessionWorktreeManager.usesWorktreeSession(sessionId);
|
|
33688
|
-
const
|
|
34077
|
+
const isolatedSessionParentPath = sessionWorktreeManager.getIsolatedSessionParentPathForSession(sessionId);
|
|
33689
34078
|
sendWsMessage(s, {
|
|
33690
34079
|
type: "session_git_context_report",
|
|
33691
34080
|
sessionId,
|
|
33692
34081
|
cliGitBranch,
|
|
33693
34082
|
agentUsesWorktree: usesWt,
|
|
33694
34083
|
sessionParent: usesWt ? "worktrees_root" : "bridge_root",
|
|
33695
|
-
sessionParentPath: usesWt ?
|
|
34084
|
+
sessionParentPath: usesWt ? isolatedSessionParentPath ?? effectiveCwd : getBridgeRoot()
|
|
33696
34085
|
});
|
|
33697
34086
|
}
|
|
33698
34087
|
if (s && sessionId && runId) {
|
|
@@ -33845,7 +34234,7 @@ function handleBridgePrompt(msg, deps) {
|
|
|
33845
34234
|
const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
|
|
33846
34235
|
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
33847
34236
|
async function preambleAndPrompt(resolvedCwd) {
|
|
33848
|
-
const effectiveCwd =
|
|
34237
|
+
const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
|
|
33849
34238
|
await runBridgePromptPreamble({
|
|
33850
34239
|
getWs,
|
|
33851
34240
|
log: log2,
|
|
@@ -33878,7 +34267,7 @@ function handleBridgePrompt(msg, deps) {
|
|
|
33878
34267
|
runId,
|
|
33879
34268
|
mode,
|
|
33880
34269
|
agentType,
|
|
33881
|
-
|
|
34270
|
+
sessionParentPath: effectiveCwd,
|
|
33882
34271
|
sendResult: sendResult2,
|
|
33883
34272
|
sendSessionUpdate,
|
|
33884
34273
|
followUpCatalogPromptId,
|
|
@@ -33888,8 +34277,8 @@ function handleBridgePrompt(msg, deps) {
|
|
|
33888
34277
|
e2ee: deps.e2ee
|
|
33889
34278
|
});
|
|
33890
34279
|
}
|
|
33891
|
-
void sessionWorktreeManager.
|
|
33892
|
-
log2(`[Agent]
|
|
34280
|
+
void sessionWorktreeManager.resolveSessionParentPathForPrompt(sessionId, { isNewSession, sessionParent, sessionParentPath }).then((cwd) => preambleAndPrompt(cwd)).catch((err) => {
|
|
34281
|
+
log2(`[Agent] Session parent path resolve failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
33893
34282
|
void preambleAndPrompt(void 0);
|
|
33894
34283
|
});
|
|
33895
34284
|
}
|
|
@@ -33899,6 +34288,11 @@ var handlePromptMessage = (msg, deps) => {
|
|
|
33899
34288
|
handleBridgePrompt(msg, deps);
|
|
33900
34289
|
};
|
|
33901
34290
|
|
|
34291
|
+
// src/bridge/routing/handlers/prompt-queue-state.ts
|
|
34292
|
+
var handlePromptQueueStateMessage = (msg, deps) => {
|
|
34293
|
+
applyPromptQueueStateFromServer(msg, deps);
|
|
34294
|
+
};
|
|
34295
|
+
|
|
33902
34296
|
// src/agents/acp/from-bridge/handle-bridge-cancel-run.ts
|
|
33903
34297
|
async function handleBridgeCancelRun(msg, { log: log2, acpManager, getWs }) {
|
|
33904
34298
|
const runId = msg.runId;
|
|
@@ -33918,6 +34312,7 @@ async function handleBridgeCancelRun(msg, { log: log2, acpManager, getWs }) {
|
|
|
33918
34312
|
error: "Stopped by user",
|
|
33919
34313
|
stopReason: "no_local_run"
|
|
33920
34314
|
});
|
|
34315
|
+
finalizePromptTurnOnBridge(getWs, runId, false);
|
|
33921
34316
|
}
|
|
33922
34317
|
|
|
33923
34318
|
// src/bridge/routing/handlers/cancel-run.ts
|
|
@@ -33961,12 +34356,12 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
33961
34356
|
};
|
|
33962
34357
|
|
|
33963
34358
|
// src/files/list-dir.ts
|
|
33964
|
-
import
|
|
34359
|
+
import fs28 from "node:fs";
|
|
33965
34360
|
import path31 from "node:path";
|
|
33966
34361
|
|
|
33967
34362
|
// src/files/ensure-under-cwd.ts
|
|
33968
34363
|
import path30 from "node:path";
|
|
33969
|
-
function ensureUnderCwd(relativePath, cwd =
|
|
34364
|
+
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
33970
34365
|
const normalized = path30.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
33971
34366
|
const resolved = path30.resolve(cwd, normalized);
|
|
33972
34367
|
if (!resolved.startsWith(cwd + path30.sep) && resolved !== cwd) {
|
|
@@ -33978,12 +34373,12 @@ function ensureUnderCwd(relativePath, cwd = getBridgeWorkspaceDirectory()) {
|
|
|
33978
34373
|
// src/files/list-dir.ts
|
|
33979
34374
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
33980
34375
|
async function listDirAsync(relativePath) {
|
|
33981
|
-
const resolved = ensureUnderCwd(relativePath || ".",
|
|
34376
|
+
const resolved = ensureUnderCwd(relativePath || ".", getBridgeRoot());
|
|
33982
34377
|
if (!resolved) {
|
|
33983
34378
|
return { error: "Path is outside working directory" };
|
|
33984
34379
|
}
|
|
33985
34380
|
try {
|
|
33986
|
-
const names = await
|
|
34381
|
+
const names = await fs28.promises.readdir(resolved, { withFileTypes: true });
|
|
33987
34382
|
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
33988
34383
|
const entries = [];
|
|
33989
34384
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -33996,7 +34391,7 @@ async function listDirAsync(relativePath) {
|
|
|
33996
34391
|
let isDir = d.isDirectory();
|
|
33997
34392
|
if (d.isSymbolicLink()) {
|
|
33998
34393
|
try {
|
|
33999
|
-
const targetStat = await
|
|
34394
|
+
const targetStat = await fs28.promises.stat(fullPath);
|
|
34000
34395
|
isDir = targetStat.isDirectory();
|
|
34001
34396
|
} catch {
|
|
34002
34397
|
isDir = false;
|
|
@@ -34021,25 +34416,25 @@ async function listDirAsync(relativePath) {
|
|
|
34021
34416
|
}
|
|
34022
34417
|
|
|
34023
34418
|
// src/files/read-file.ts
|
|
34024
|
-
import
|
|
34419
|
+
import fs29 from "node:fs";
|
|
34025
34420
|
import { StringDecoder } from "node:string_decoder";
|
|
34026
34421
|
function resolveFilePath(relativePath) {
|
|
34027
|
-
const resolved = ensureUnderCwd(relativePath,
|
|
34422
|
+
const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
|
|
34028
34423
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
34029
34424
|
let real;
|
|
34030
34425
|
try {
|
|
34031
|
-
real =
|
|
34426
|
+
real = fs29.realpathSync(resolved);
|
|
34032
34427
|
} catch {
|
|
34033
34428
|
real = resolved;
|
|
34034
34429
|
}
|
|
34035
|
-
const stat2 =
|
|
34430
|
+
const stat2 = fs29.statSync(real);
|
|
34036
34431
|
if (!stat2.isFile()) return { error: "Not a file" };
|
|
34037
34432
|
return real;
|
|
34038
34433
|
}
|
|
34039
34434
|
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
34040
34435
|
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
34041
|
-
const fileSize =
|
|
34042
|
-
const fd =
|
|
34436
|
+
const fileSize = fs29.statSync(filePath).size;
|
|
34437
|
+
const fd = fs29.openSync(filePath, "r");
|
|
34043
34438
|
const bufSize = 64 * 1024;
|
|
34044
34439
|
const buf = Buffer.alloc(bufSize);
|
|
34045
34440
|
const decoder = new StringDecoder("utf8");
|
|
@@ -34052,7 +34447,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
34052
34447
|
let line0Accum = "";
|
|
34053
34448
|
try {
|
|
34054
34449
|
let bytesRead;
|
|
34055
|
-
while (!done && (bytesRead =
|
|
34450
|
+
while (!done && (bytesRead = fs29.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
34056
34451
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
34057
34452
|
partial2 = "";
|
|
34058
34453
|
let lineStart = 0;
|
|
@@ -34187,7 +34582,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
34187
34582
|
}
|
|
34188
34583
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
34189
34584
|
} finally {
|
|
34190
|
-
|
|
34585
|
+
fs29.closeSync(fd);
|
|
34191
34586
|
}
|
|
34192
34587
|
}
|
|
34193
34588
|
function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
@@ -34198,8 +34593,8 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
34198
34593
|
if (hasRange) {
|
|
34199
34594
|
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
34200
34595
|
}
|
|
34201
|
-
const stat2 =
|
|
34202
|
-
const raw =
|
|
34596
|
+
const stat2 = fs29.statSync(result);
|
|
34597
|
+
const raw = fs29.readFileSync(result, "utf8");
|
|
34203
34598
|
const lines = raw.split(/\r?\n/);
|
|
34204
34599
|
return { content: raw, totalLines: lines.length, size: stat2.size };
|
|
34205
34600
|
} catch (err) {
|
|
@@ -34217,7 +34612,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
34217
34612
|
void (async () => {
|
|
34218
34613
|
await yieldToEventLoop();
|
|
34219
34614
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
34220
|
-
const cwd =
|
|
34615
|
+
const cwd = getBridgeRoot();
|
|
34221
34616
|
const index = loadFileIndex(cwd);
|
|
34222
34617
|
if (index === null) {
|
|
34223
34618
|
const payload2 = {
|
|
@@ -34241,7 +34636,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
34241
34636
|
}
|
|
34242
34637
|
function triggerFileIndexBuild() {
|
|
34243
34638
|
setImmediate(() => {
|
|
34244
|
-
void ensureFileIndexAsync(
|
|
34639
|
+
void ensureFileIndexAsync(getBridgeRoot()).catch((e) => {
|
|
34245
34640
|
console.error("[file-index] Background build failed:", e);
|
|
34246
34641
|
});
|
|
34247
34642
|
});
|
|
@@ -34310,14 +34705,14 @@ function handleFileBrowserSearchMessage(msg, { getWs, e2ee }) {
|
|
|
34310
34705
|
function handleSkillLayoutRequest(msg, deps) {
|
|
34311
34706
|
const socket = deps.getWs();
|
|
34312
34707
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
34313
|
-
const roots = discoverSkillLayoutRoots(
|
|
34708
|
+
const roots = discoverSkillLayoutRoots(getBridgeRoot());
|
|
34314
34709
|
if (socket) {
|
|
34315
34710
|
sendWsMessage(socket, { type: "skill_layout_response", id, roots });
|
|
34316
34711
|
}
|
|
34317
34712
|
}
|
|
34318
34713
|
|
|
34319
34714
|
// src/skills/install-remote-skills.ts
|
|
34320
|
-
import
|
|
34715
|
+
import fs30 from "node:fs";
|
|
34321
34716
|
import path32 from "node:path";
|
|
34322
34717
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
34323
34718
|
const installed2 = [];
|
|
@@ -34333,11 +34728,11 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
34333
34728
|
for (const f of item.files) {
|
|
34334
34729
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
34335
34730
|
const dest = path32.join(skillDir, f.path);
|
|
34336
|
-
|
|
34731
|
+
fs30.mkdirSync(path32.dirname(dest), { recursive: true });
|
|
34337
34732
|
if (f.text !== void 0) {
|
|
34338
|
-
|
|
34733
|
+
fs30.writeFileSync(dest, f.text, "utf8");
|
|
34339
34734
|
} else if (f.base64) {
|
|
34340
|
-
|
|
34735
|
+
fs30.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
34341
34736
|
}
|
|
34342
34737
|
}
|
|
34343
34738
|
installed2.push({
|
|
@@ -34358,7 +34753,7 @@ var handleInstallSkillsMessage = (msg, deps) => {
|
|
|
34358
34753
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
34359
34754
|
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
34360
34755
|
const rawItems = msg.items;
|
|
34361
|
-
const cwd =
|
|
34756
|
+
const cwd = getBridgeRoot();
|
|
34362
34757
|
const result = installRemoteSkills(cwd, targetDir, rawItems);
|
|
34363
34758
|
if (!result.success) {
|
|
34364
34759
|
const err = result.error ?? "Invalid items";
|
|
@@ -34487,7 +34882,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
34487
34882
|
};
|
|
34488
34883
|
|
|
34489
34884
|
// src/bridge/routing/handlers/revert-turn-snapshot.ts
|
|
34490
|
-
import * as
|
|
34885
|
+
import * as fs31 from "node:fs";
|
|
34491
34886
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
34492
34887
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
34493
34888
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -34497,9 +34892,9 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
34497
34892
|
void (async () => {
|
|
34498
34893
|
const s = getWs();
|
|
34499
34894
|
if (!s) return;
|
|
34500
|
-
const agentBase = sessionWorktreeManager.
|
|
34895
|
+
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
34501
34896
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
34502
|
-
if (!
|
|
34897
|
+
if (!fs31.existsSync(file2)) {
|
|
34503
34898
|
sendWsMessage(s, {
|
|
34504
34899
|
type: "revert_turn_snapshot_result",
|
|
34505
34900
|
id,
|
|
@@ -34557,6 +34952,9 @@ function dispatchBridgeMessage(msg, deps) {
|
|
|
34557
34952
|
case "agent_config":
|
|
34558
34953
|
handleAgentConfigMessage(msg, deps);
|
|
34559
34954
|
break;
|
|
34955
|
+
case "prompt_queue_state":
|
|
34956
|
+
handlePromptQueueStateMessage(msg, deps);
|
|
34957
|
+
break;
|
|
34560
34958
|
case "prompt":
|
|
34561
34959
|
handlePromptMessage(msg, deps);
|
|
34562
34960
|
break;
|
|
@@ -34854,9 +35252,9 @@ async function createBridgeConnection(options) {
|
|
|
34854
35252
|
firehoseGeneration: 0,
|
|
34855
35253
|
firehoseQuiet: createEmptyReconnectQuietSlot()
|
|
34856
35254
|
};
|
|
34857
|
-
const
|
|
35255
|
+
const worktreesRootPath = options.worktreesRootPath ?? defaultWorktreesRootPath();
|
|
34858
35256
|
const sessionWorktreeManager = new SessionWorktreeManager({
|
|
34859
|
-
|
|
35257
|
+
worktreesRootPath,
|
|
34860
35258
|
log: logFn
|
|
34861
35259
|
});
|
|
34862
35260
|
const acpManager = await createAcpManager({ log: logFn });
|
|
@@ -34865,7 +35263,7 @@ async function createBridgeConnection(options) {
|
|
|
34865
35263
|
return state.currentWs;
|
|
34866
35264
|
}
|
|
34867
35265
|
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
34868
|
-
const devServerManager = new DevServerManager({ getWs, log: logFn,
|
|
35266
|
+
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
|
|
34869
35267
|
const onBridgeIdentified = createOnBridgeIdentified({
|
|
34870
35268
|
devServerManager,
|
|
34871
35269
|
firehoseServerUrl,
|
|
@@ -34889,8 +35287,8 @@ async function createBridgeConnection(options) {
|
|
|
34889
35287
|
getCloudAccessToken: () => tokens.accessToken
|
|
34890
35288
|
};
|
|
34891
35289
|
const identifyReportedPaths = {
|
|
34892
|
-
bridgeRootPath: path33.resolve(
|
|
34893
|
-
worktreesRootPath: path33.resolve(
|
|
35290
|
+
bridgeRootPath: path33.resolve(getBridgeRoot()),
|
|
35291
|
+
worktreesRootPath: path33.resolve(worktreesRootPath)
|
|
34894
35292
|
};
|
|
34895
35293
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
34896
35294
|
state,
|
|
@@ -34907,7 +35305,7 @@ async function createBridgeConnection(options) {
|
|
|
34907
35305
|
identifyReportedPaths
|
|
34908
35306
|
});
|
|
34909
35307
|
connect();
|
|
34910
|
-
const stopFileIndexWatcher = startFileIndexWatcher(
|
|
35308
|
+
const stopFileIndexWatcher = startFileIndexWatcher(getBridgeRoot());
|
|
34911
35309
|
return {
|
|
34912
35310
|
close: async () => {
|
|
34913
35311
|
stopFileIndexWatcher();
|
|
@@ -34977,7 +35375,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
34977
35375
|
authToken,
|
|
34978
35376
|
refreshToken,
|
|
34979
35377
|
justAuthenticated,
|
|
34980
|
-
|
|
35378
|
+
worktreesRootPath,
|
|
34981
35379
|
e2eCertificate
|
|
34982
35380
|
} = options;
|
|
34983
35381
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
@@ -34989,7 +35387,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
34989
35387
|
refreshToken,
|
|
34990
35388
|
firehoseServerUrl,
|
|
34991
35389
|
justAuthenticated,
|
|
34992
|
-
|
|
35390
|
+
worktreesRootPath,
|
|
34993
35391
|
e2eCertificate,
|
|
34994
35392
|
log,
|
|
34995
35393
|
persistTokens: (t) => {
|
|
@@ -35004,7 +35402,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
35004
35402
|
log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
|
|
35005
35403
|
clearConfigForApi(apiUrl);
|
|
35006
35404
|
void handle.close().then(() => {
|
|
35007
|
-
void restartWithoutAuth({ apiUrl, firehoseServerUrl,
|
|
35405
|
+
void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
|
|
35008
35406
|
});
|
|
35009
35407
|
}
|
|
35010
35408
|
});
|
|
@@ -35052,7 +35450,7 @@ async function runBridge(options) {
|
|
|
35052
35450
|
workspaceId,
|
|
35053
35451
|
authToken,
|
|
35054
35452
|
bridgeName,
|
|
35055
|
-
|
|
35453
|
+
worktreesRootPath,
|
|
35056
35454
|
e2eCertificate
|
|
35057
35455
|
} = options;
|
|
35058
35456
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
@@ -35097,7 +35495,7 @@ async function runBridge(options) {
|
|
|
35097
35495
|
firehoseServerUrl,
|
|
35098
35496
|
bridgeName,
|
|
35099
35497
|
justAuthenticated: true,
|
|
35100
|
-
|
|
35498
|
+
worktreesRootPath,
|
|
35101
35499
|
e2eCertificate
|
|
35102
35500
|
});
|
|
35103
35501
|
return;
|