@buildautomaton/cli 0.1.20 → 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 +678 -412
- package/dist/cli.js.map +4 -4
- package/dist/index.js +650 -388
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -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,
|
|
@@ -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}`;
|
|
@@ -22464,14 +22510,14 @@ async function createSdkStdioAcpClient(options) {
|
|
|
22464
22510
|
} catch {
|
|
22465
22511
|
}
|
|
22466
22512
|
return await new Promise((resolve17) => {
|
|
22467
|
-
|
|
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();
|
|
@@ -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";
|
|
@@ -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,
|
|
@@ -29376,7 +29444,7 @@ async function sendPromptToAgent(options) {
|
|
|
29376
29444
|
|
|
29377
29445
|
// src/agents/acp/ensure-acp-client.ts
|
|
29378
29446
|
import * as fs9 from "node:fs";
|
|
29379
|
-
import * as
|
|
29447
|
+
import * as path11 from "node:path";
|
|
29380
29448
|
|
|
29381
29449
|
// src/error-message.ts
|
|
29382
29450
|
function errorMessage(err) {
|
|
@@ -29477,7 +29545,7 @@ __export(cursor_acp_client_exports, {
|
|
|
29477
29545
|
detectLocalAgentPresence: () => detectLocalAgentPresence3
|
|
29478
29546
|
});
|
|
29479
29547
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
|
|
29480
|
-
import { dirname as
|
|
29548
|
+
import { dirname as dirname3 } from "node:path";
|
|
29481
29549
|
import { spawn as spawn4 } from "node:child_process";
|
|
29482
29550
|
import * as readline from "node:readline";
|
|
29483
29551
|
|
|
@@ -29527,7 +29595,7 @@ function buildCursorAcpSpawnCommand(base, sessionMode) {
|
|
|
29527
29595
|
async function createCursorAcpClient(options) {
|
|
29528
29596
|
const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
|
|
29529
29597
|
const {
|
|
29530
|
-
cwd =
|
|
29598
|
+
cwd = getBridgeRoot(),
|
|
29531
29599
|
backendAgentType,
|
|
29532
29600
|
onSessionUpdate,
|
|
29533
29601
|
onRequest,
|
|
@@ -29569,7 +29637,9 @@ async function createCursorAcpClient(options) {
|
|
|
29569
29637
|
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }) + "\n");
|
|
29570
29638
|
}
|
|
29571
29639
|
function resolveRequest(requestId, result) {
|
|
29572
|
-
|
|
29640
|
+
const pending2 = pendingRequests.get(requestId);
|
|
29641
|
+
const payload = pending2?.method === "session/request_permission" ? enrichAcpPermissionRpcResultFromRequestParams(result, pending2.params) : result;
|
|
29642
|
+
respond(requestId, payload);
|
|
29573
29643
|
pendingRequests.delete(requestId);
|
|
29574
29644
|
}
|
|
29575
29645
|
let promptOutputBuffer = "";
|
|
@@ -29625,14 +29695,14 @@ async function createCursorAcpClient(options) {
|
|
|
29625
29695
|
if (dbgFs) {
|
|
29626
29696
|
console.error(`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""}`);
|
|
29627
29697
|
}
|
|
29628
|
-
const
|
|
29629
|
-
if (!
|
|
29698
|
+
const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
|
|
29699
|
+
if (!resolvedPath) {
|
|
29630
29700
|
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty)`);
|
|
29631
29701
|
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
29632
29702
|
return;
|
|
29633
29703
|
}
|
|
29634
29704
|
try {
|
|
29635
|
-
let content = readFileSync3(
|
|
29705
|
+
let content = readFileSync3(resolvedPath, "utf8");
|
|
29636
29706
|
const line2 = typeof params.line === "number" ? params.line : void 0;
|
|
29637
29707
|
const limit = typeof params.limit === "number" ? params.limit : void 0;
|
|
29638
29708
|
content = sliceLinesByRange(content, line2, limit);
|
|
@@ -29656,15 +29726,15 @@ async function createCursorAcpClient(options) {
|
|
|
29656
29726
|
`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""} newBytes=${newText.length}`
|
|
29657
29727
|
);
|
|
29658
29728
|
}
|
|
29659
|
-
const
|
|
29660
|
-
if (!
|
|
29729
|
+
const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
|
|
29730
|
+
if (!resolvedPath) {
|
|
29661
29731
|
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
|
|
29662
29732
|
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
29663
29733
|
return;
|
|
29664
29734
|
}
|
|
29665
29735
|
let oldText = "";
|
|
29666
29736
|
try {
|
|
29667
|
-
oldText = readFileSync3(
|
|
29737
|
+
oldText = readFileSync3(resolvedPath, "utf8");
|
|
29668
29738
|
} catch (e) {
|
|
29669
29739
|
if (e.code !== "ENOENT") {
|
|
29670
29740
|
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
@@ -29672,13 +29742,13 @@ async function createCursorAcpClient(options) {
|
|
|
29672
29742
|
}
|
|
29673
29743
|
}
|
|
29674
29744
|
try {
|
|
29675
|
-
mkdirSync3(
|
|
29676
|
-
writeFileSync3(
|
|
29745
|
+
mkdirSync3(dirname3(resolvedPath), { recursive: true });
|
|
29746
|
+
writeFileSync3(resolvedPath, newText, "utf8");
|
|
29677
29747
|
} catch (e) {
|
|
29678
29748
|
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
29679
29749
|
return;
|
|
29680
29750
|
}
|
|
29681
|
-
const displayPath = toDisplayPathRelativeToCwd(cwd,
|
|
29751
|
+
const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
|
|
29682
29752
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
29683
29753
|
onFileChange?.({ path: displayPath, oldText, newText, patchContent });
|
|
29684
29754
|
respond(id, null);
|
|
@@ -29794,8 +29864,7 @@ async function createCursorAcpClient(options) {
|
|
|
29794
29864
|
resolveRequest(requestId, result) {
|
|
29795
29865
|
const numericId = Number(requestId);
|
|
29796
29866
|
if (!Number.isFinite(numericId)) return;
|
|
29797
|
-
|
|
29798
|
-
if (!pendingRequest) return;
|
|
29867
|
+
if (!pendingRequests.get(numericId)) return;
|
|
29799
29868
|
resolveRequest(numericId, result);
|
|
29800
29869
|
},
|
|
29801
29870
|
disconnect() {
|
|
@@ -29921,16 +29990,16 @@ import { existsSync, statSync } from "node:fs";
|
|
|
29921
29990
|
|
|
29922
29991
|
// src/git/get-git-repo-root-sync.ts
|
|
29923
29992
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
29924
|
-
import * as
|
|
29993
|
+
import * as path9 from "node:path";
|
|
29925
29994
|
function getGitRepoRootSync(startDir) {
|
|
29926
29995
|
try {
|
|
29927
29996
|
const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
29928
|
-
cwd:
|
|
29997
|
+
cwd: path9.resolve(startDir),
|
|
29929
29998
|
encoding: "utf8",
|
|
29930
29999
|
stdio: ["ignore", "pipe", "ignore"],
|
|
29931
30000
|
maxBuffer: 1024 * 1024
|
|
29932
30001
|
}).trim();
|
|
29933
|
-
return out ?
|
|
30002
|
+
return out ? path9.resolve(out) : null;
|
|
29934
30003
|
} catch {
|
|
29935
30004
|
return null;
|
|
29936
30005
|
}
|
|
@@ -29939,64 +30008,64 @@ function getGitRepoRootSync(startDir) {
|
|
|
29939
30008
|
// src/agents/acp/workspace-files.ts
|
|
29940
30009
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
29941
30010
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
29942
|
-
import * as
|
|
29943
|
-
function resolveWorkspaceFilePath(
|
|
30011
|
+
import * as path10 from "node:path";
|
|
30012
|
+
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
29944
30013
|
const trimmed2 = rawPath.trim();
|
|
29945
30014
|
if (!trimmed2) return null;
|
|
29946
|
-
const
|
|
29947
|
-
let
|
|
29948
|
-
if (!
|
|
29949
|
-
const candidate =
|
|
29950
|
-
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);
|
|
29951
30020
|
if (!gitRoot2) return null;
|
|
29952
|
-
const rel =
|
|
29953
|
-
if (rel.startsWith("..") ||
|
|
29954
|
-
|
|
30021
|
+
const rel = path10.relative(gitRoot2, candidate);
|
|
30022
|
+
if (rel.startsWith("..") || path10.isAbsolute(rel)) return null;
|
|
30023
|
+
resolvedPath = candidate;
|
|
29955
30024
|
}
|
|
29956
|
-
const gitRoot = getGitRepoRootSync(
|
|
30025
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
29957
30026
|
if (gitRoot) {
|
|
29958
|
-
const relFromRoot =
|
|
29959
|
-
if (!relFromRoot.startsWith("..") && !
|
|
29960
|
-
return {
|
|
30027
|
+
const relFromRoot = path10.relative(gitRoot, resolvedPath);
|
|
30028
|
+
if (!relFromRoot.startsWith("..") && !path10.isAbsolute(relFromRoot)) {
|
|
30029
|
+
return { resolvedPath, display: relFromRoot.split(path10.sep).join("/") };
|
|
29961
30030
|
}
|
|
29962
30031
|
}
|
|
29963
|
-
return {
|
|
30032
|
+
return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
|
|
29964
30033
|
}
|
|
29965
|
-
function readUtf8WorkspaceFile(
|
|
30034
|
+
function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
29966
30035
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
29967
|
-
const gitRoot = getGitRepoRootSync(
|
|
30036
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
29968
30037
|
if (gitRoot) {
|
|
29969
|
-
const
|
|
29970
|
-
const rel =
|
|
29971
|
-
if (!rel.startsWith("..") && !
|
|
30038
|
+
const resolvedPath2 = path10.resolve(gitRoot, displayPath);
|
|
30039
|
+
const rel = path10.relative(gitRoot, resolvedPath2);
|
|
30040
|
+
if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
|
|
29972
30041
|
try {
|
|
29973
|
-
return readFileSync4(
|
|
30042
|
+
return readFileSync4(resolvedPath2, "utf8");
|
|
29974
30043
|
} catch {
|
|
29975
30044
|
}
|
|
29976
30045
|
}
|
|
29977
30046
|
}
|
|
29978
|
-
const
|
|
29979
|
-
if (!
|
|
30047
|
+
const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
30048
|
+
if (!resolvedPath) return "";
|
|
29980
30049
|
try {
|
|
29981
|
-
return readFileSync4(
|
|
30050
|
+
return readFileSync4(resolvedPath, "utf8");
|
|
29982
30051
|
} catch {
|
|
29983
30052
|
return "";
|
|
29984
30053
|
}
|
|
29985
30054
|
}
|
|
29986
|
-
function
|
|
30055
|
+
function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
|
|
29987
30056
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
29988
|
-
const gitRoot = getGitRepoRootSync(
|
|
30057
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
29989
30058
|
if (gitRoot) {
|
|
29990
|
-
const
|
|
29991
|
-
const rel =
|
|
29992
|
-
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;
|
|
29993
30062
|
}
|
|
29994
|
-
return resolveSafePathUnderCwd(
|
|
30063
|
+
return resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
29995
30064
|
}
|
|
29996
|
-
function readGitHeadBlob(
|
|
30065
|
+
function readGitHeadBlob(sessionParentPath, displayPath) {
|
|
29997
30066
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
29998
|
-
const gitRoot = getGitRepoRootSync(
|
|
29999
|
-
const execCwd = gitRoot ??
|
|
30067
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30068
|
+
const execCwd = gitRoot ?? sessionParentPath;
|
|
30000
30069
|
try {
|
|
30001
30070
|
return execFileSync3("git", ["show", `HEAD:${displayPath}`], {
|
|
30002
30071
|
cwd: execCwd,
|
|
@@ -30009,9 +30078,9 @@ function readGitHeadBlob(cwd, displayPath) {
|
|
|
30009
30078
|
}
|
|
30010
30079
|
|
|
30011
30080
|
// src/agents/acp/session-file-change-path-kind.ts
|
|
30012
|
-
function gitHeadPathObjectType(
|
|
30081
|
+
function gitHeadPathObjectType(sessionParentPath, displayPath) {
|
|
30013
30082
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
30014
|
-
const gitRoot = getGitRepoRootSync(
|
|
30083
|
+
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30015
30084
|
if (!gitRoot) return null;
|
|
30016
30085
|
try {
|
|
30017
30086
|
return execFileSync4("git", ["cat-file", "-t", `HEAD:${displayPath}`], {
|
|
@@ -30022,11 +30091,11 @@ function gitHeadPathObjectType(cwd, displayPath) {
|
|
|
30022
30091
|
return null;
|
|
30023
30092
|
}
|
|
30024
30093
|
}
|
|
30025
|
-
function getSessionFileChangeDirectoryFlags(
|
|
30026
|
-
const
|
|
30027
|
-
if (
|
|
30094
|
+
function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
|
|
30095
|
+
const resolvedPath = tryWorkspaceDisplayToPath(sessionParentPath, displayPath);
|
|
30096
|
+
if (resolvedPath && existsSync(resolvedPath)) {
|
|
30028
30097
|
try {
|
|
30029
|
-
if (statSync(
|
|
30098
|
+
if (statSync(resolvedPath).isDirectory()) {
|
|
30030
30099
|
return { isDirectory: true, directoryRemoved: false };
|
|
30031
30100
|
}
|
|
30032
30101
|
return { isDirectory: false, directoryRemoved: false };
|
|
@@ -30034,7 +30103,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
|
|
|
30034
30103
|
return { isDirectory: false, directoryRemoved: false };
|
|
30035
30104
|
}
|
|
30036
30105
|
}
|
|
30037
|
-
if (gitHeadPathObjectType(
|
|
30106
|
+
if (gitHeadPathObjectType(sessionParentPath, displayPath) === "tree") {
|
|
30038
30107
|
return { isDirectory: true, directoryRemoved: true };
|
|
30039
30108
|
}
|
|
30040
30109
|
return { isDirectory: false, directoryRemoved: false };
|
|
@@ -30042,7 +30111,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
|
|
|
30042
30111
|
|
|
30043
30112
|
// src/agents/acp/hooks/bridge-on-file-change.ts
|
|
30044
30113
|
function createBridgeOnFileChange(opts) {
|
|
30045
|
-
const { routing, getSendSessionUpdate, log: log2 } = opts;
|
|
30114
|
+
const { routing, getSendSessionUpdate, log: log2, sessionParentPath } = opts;
|
|
30046
30115
|
return (evt) => {
|
|
30047
30116
|
const runId = routing.runId;
|
|
30048
30117
|
const sessionId = routing.sessionId;
|
|
@@ -30053,8 +30122,7 @@ function createBridgeOnFileChange(opts) {
|
|
|
30053
30122
|
);
|
|
30054
30123
|
return;
|
|
30055
30124
|
}
|
|
30056
|
-
const
|
|
30057
|
-
const dirFlags = getSessionFileChangeDirectoryFlags(cwd, evt.path);
|
|
30125
|
+
const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, evt.path);
|
|
30058
30126
|
try {
|
|
30059
30127
|
send({
|
|
30060
30128
|
type: "session_file_change",
|
|
@@ -30131,12 +30199,12 @@ function extractDiffPath(o) {
|
|
|
30131
30199
|
}
|
|
30132
30200
|
|
|
30133
30201
|
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/push-diff.ts
|
|
30134
|
-
function pushDiffIfComplete(o,
|
|
30202
|
+
function pushDiffIfComplete(o, sessionParentPath, out) {
|
|
30135
30203
|
const t = o.type;
|
|
30136
30204
|
if (typeof t !== "string" || t.toLowerCase() !== "diff") return;
|
|
30137
30205
|
const rawPath = extractDiffPath(o);
|
|
30138
30206
|
if (!rawPath) return;
|
|
30139
|
-
const resolved = resolveWorkspaceFilePath(
|
|
30207
|
+
const resolved = resolveWorkspaceFilePath(sessionParentPath, rawPath);
|
|
30140
30208
|
if (!resolved) return;
|
|
30141
30209
|
const oldText = readOptionalTextField(o.oldText ?? o.old_text ?? o.before ?? o.oldContent);
|
|
30142
30210
|
const newText = readOptionalTextField(o.newText ?? o.new_text ?? o.after ?? o.newContent);
|
|
@@ -30155,17 +30223,17 @@ var NEST_KEYS = [
|
|
|
30155
30223
|
"data",
|
|
30156
30224
|
"arguments"
|
|
30157
30225
|
];
|
|
30158
|
-
function walkValue(value,
|
|
30226
|
+
function walkValue(value, sessionParentPath, depth, out) {
|
|
30159
30227
|
if (depth > 12 || value == null) return;
|
|
30160
30228
|
if (Array.isArray(value)) {
|
|
30161
|
-
for (const x of value) walkValue(x,
|
|
30229
|
+
for (const x of value) walkValue(x, sessionParentPath, depth + 1, out);
|
|
30162
30230
|
return;
|
|
30163
30231
|
}
|
|
30164
30232
|
if (typeof value !== "object") return;
|
|
30165
30233
|
const o = value;
|
|
30166
|
-
pushDiffIfComplete(o,
|
|
30234
|
+
pushDiffIfComplete(o, sessionParentPath, out);
|
|
30167
30235
|
if (o.type === "content" && o.content != null && typeof o.content === "object") {
|
|
30168
|
-
walkValue(o.content,
|
|
30236
|
+
walkValue(o.content, sessionParentPath, depth + 1, out);
|
|
30169
30237
|
}
|
|
30170
30238
|
for (const k of NEST_KEYS) {
|
|
30171
30239
|
if (o.type === "content" && k === "content") continue;
|
|
@@ -30173,23 +30241,23 @@ function walkValue(value, cwd, depth, out) {
|
|
|
30173
30241
|
if (v == null) continue;
|
|
30174
30242
|
if (k === "arguments" && typeof v === "string") {
|
|
30175
30243
|
try {
|
|
30176
|
-
walkValue(JSON.parse(v),
|
|
30244
|
+
walkValue(JSON.parse(v), sessionParentPath, depth + 1, out);
|
|
30177
30245
|
} catch {
|
|
30178
30246
|
}
|
|
30179
30247
|
continue;
|
|
30180
30248
|
}
|
|
30181
|
-
walkValue(v,
|
|
30249
|
+
walkValue(v, sessionParentPath, depth + 1, out);
|
|
30182
30250
|
}
|
|
30183
30251
|
}
|
|
30184
30252
|
|
|
30185
30253
|
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/extract.ts
|
|
30186
|
-
function extractAcpFileDiffsFromUpdate(update,
|
|
30254
|
+
function extractAcpFileDiffsFromUpdate(update, sessionParentPath) {
|
|
30187
30255
|
if (!update || typeof update !== "object") return [];
|
|
30188
30256
|
const u = update;
|
|
30189
30257
|
const out = [];
|
|
30190
30258
|
const content = u.content;
|
|
30191
30259
|
if (Array.isArray(content)) {
|
|
30192
|
-
for (const x of content) walkValue(x,
|
|
30260
|
+
for (const x of content) walkValue(x, sessionParentPath, 0, out);
|
|
30193
30261
|
}
|
|
30194
30262
|
const byPath = /* @__PURE__ */ new Map();
|
|
30195
30263
|
for (const d of out) byPath.set(d.path, d);
|
|
@@ -30197,18 +30265,18 @@ function extractAcpFileDiffsFromUpdate(update, cwd) {
|
|
|
30197
30265
|
}
|
|
30198
30266
|
|
|
30199
30267
|
// src/agents/acp/hooks/extract-tool-target-paths.ts
|
|
30200
|
-
function addPath(
|
|
30268
|
+
function addPath(sessionParentPath, raw, out) {
|
|
30201
30269
|
if (typeof raw !== "string") return;
|
|
30202
30270
|
const trimmed2 = raw.trim();
|
|
30203
30271
|
if (!trimmed2) return;
|
|
30204
|
-
const resolved = resolveWorkspaceFilePath(
|
|
30272
|
+
const resolved = resolveWorkspaceFilePath(sessionParentPath, trimmed2);
|
|
30205
30273
|
if (!resolved) return;
|
|
30206
30274
|
out.add(resolved.display);
|
|
30207
30275
|
}
|
|
30208
|
-
function walkLocations(
|
|
30276
|
+
function walkLocations(sessionParentPath, loc, out) {
|
|
30209
30277
|
if (!Array.isArray(loc)) return;
|
|
30210
30278
|
for (const item of loc) {
|
|
30211
|
-
if (item && typeof item === "object") addPath(
|
|
30279
|
+
if (item && typeof item === "object") addPath(sessionParentPath, item.path, out);
|
|
30212
30280
|
}
|
|
30213
30281
|
}
|
|
30214
30282
|
var PATH_KEYS = [
|
|
@@ -30221,56 +30289,56 @@ var PATH_KEYS = [
|
|
|
30221
30289
|
"file_path",
|
|
30222
30290
|
"target_file"
|
|
30223
30291
|
];
|
|
30224
|
-
function collectFromObject(
|
|
30292
|
+
function collectFromObject(sessionParentPath, obj, out, depth) {
|
|
30225
30293
|
if (depth > 10) return;
|
|
30226
30294
|
for (const k of PATH_KEYS) {
|
|
30227
|
-
if (k in obj) addPath(
|
|
30295
|
+
if (k in obj) addPath(sessionParentPath, obj[k], out);
|
|
30228
30296
|
}
|
|
30229
30297
|
for (const v of Object.values(obj)) {
|
|
30230
|
-
if (v != null && typeof v === "object") collectUnknown(
|
|
30298
|
+
if (v != null && typeof v === "object") collectUnknown(sessionParentPath, v, out, depth + 1);
|
|
30231
30299
|
}
|
|
30232
30300
|
}
|
|
30233
|
-
function collectUnknown(
|
|
30301
|
+
function collectUnknown(sessionParentPath, v, out, depth) {
|
|
30234
30302
|
if (depth > 10 || v == null) return;
|
|
30235
30303
|
if (Array.isArray(v)) {
|
|
30236
|
-
for (const x of v) collectUnknown(
|
|
30304
|
+
for (const x of v) collectUnknown(sessionParentPath, x, out, depth + 1);
|
|
30237
30305
|
return;
|
|
30238
30306
|
}
|
|
30239
|
-
if (typeof v === "object") collectFromObject(
|
|
30307
|
+
if (typeof v === "object") collectFromObject(sessionParentPath, v, out, depth);
|
|
30240
30308
|
}
|
|
30241
|
-
function walkContentArray(
|
|
30309
|
+
function walkContentArray(sessionParentPath, content, out) {
|
|
30242
30310
|
if (!Array.isArray(content)) return;
|
|
30243
30311
|
for (const item of content) {
|
|
30244
30312
|
if (!item || typeof item !== "object") continue;
|
|
30245
30313
|
const o = item;
|
|
30246
30314
|
if (typeof o.type === "string" && o.type.toLowerCase() === "diff") {
|
|
30247
|
-
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);
|
|
30248
30316
|
}
|
|
30249
30317
|
if (o.type === "content" && o.content != null && typeof o.content === "object") {
|
|
30250
30318
|
const inner = o.content;
|
|
30251
30319
|
if (typeof inner.type === "string" && inner.type.toLowerCase() === "diff") {
|
|
30252
|
-
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);
|
|
30253
30321
|
}
|
|
30254
30322
|
}
|
|
30255
30323
|
}
|
|
30256
30324
|
}
|
|
30257
|
-
function extractToolTargetDisplayPaths(update,
|
|
30325
|
+
function extractToolTargetDisplayPaths(update, sessionParentPath) {
|
|
30258
30326
|
const out = /* @__PURE__ */ new Set();
|
|
30259
30327
|
if (!update || typeof update !== "object") return [];
|
|
30260
30328
|
const u = update;
|
|
30261
|
-
walkLocations(
|
|
30262
|
-
walkLocations(
|
|
30263
|
-
walkLocations(
|
|
30329
|
+
walkLocations(sessionParentPath, u.locations, out);
|
|
30330
|
+
walkLocations(sessionParentPath, u.fileLocations, out);
|
|
30331
|
+
walkLocations(sessionParentPath, u.file_locations, out);
|
|
30264
30332
|
const tc = u.toolCall ?? u.tool_call;
|
|
30265
30333
|
if (tc && typeof tc.arguments === "string") {
|
|
30266
30334
|
try {
|
|
30267
30335
|
const parsed = JSON.parse(tc.arguments);
|
|
30268
|
-
collectUnknown(
|
|
30336
|
+
collectUnknown(sessionParentPath, parsed, out, 0);
|
|
30269
30337
|
} catch {
|
|
30270
30338
|
}
|
|
30271
30339
|
}
|
|
30272
|
-
walkContentArray(
|
|
30273
|
-
collectFromObject(
|
|
30340
|
+
walkContentArray(sessionParentPath, u.content, out);
|
|
30341
|
+
collectFromObject(sessionParentPath, u, out, 0);
|
|
30274
30342
|
return [...out];
|
|
30275
30343
|
}
|
|
30276
30344
|
|
|
@@ -30336,7 +30404,7 @@ var PathSnapshotTracker = class {
|
|
|
30336
30404
|
this.beforeByToolKey.delete(toolKey);
|
|
30337
30405
|
this.accumulatedPathsByToolKey.delete(toolKey);
|
|
30338
30406
|
}
|
|
30339
|
-
captureBeforeFromDisk(toolKey, paths,
|
|
30407
|
+
captureBeforeFromDisk(toolKey, paths, sessionParentPath) {
|
|
30340
30408
|
if (paths.length === 0) return;
|
|
30341
30409
|
let m = this.beforeByToolKey.get(toolKey);
|
|
30342
30410
|
if (!m) {
|
|
@@ -30345,10 +30413,10 @@ var PathSnapshotTracker = class {
|
|
|
30345
30413
|
}
|
|
30346
30414
|
for (const p of paths) {
|
|
30347
30415
|
if (m.has(p)) continue;
|
|
30348
|
-
m.set(p, readUtf8WorkspaceFile(
|
|
30416
|
+
m.set(p, readUtf8WorkspaceFile(sessionParentPath, p));
|
|
30349
30417
|
}
|
|
30350
30418
|
}
|
|
30351
|
-
ensureBeforeFromHeadForMissing(toolKey, paths,
|
|
30419
|
+
ensureBeforeFromHeadForMissing(toolKey, paths, sessionParentPath) {
|
|
30352
30420
|
let m = this.beforeByToolKey.get(toolKey);
|
|
30353
30421
|
if (!m) {
|
|
30354
30422
|
m = /* @__PURE__ */ new Map();
|
|
@@ -30356,10 +30424,10 @@ var PathSnapshotTracker = class {
|
|
|
30356
30424
|
}
|
|
30357
30425
|
for (const p of paths) {
|
|
30358
30426
|
if (m.has(p)) continue;
|
|
30359
|
-
m.set(p, readGitHeadBlob(
|
|
30427
|
+
m.set(p, readGitHeadBlob(sessionParentPath, p));
|
|
30360
30428
|
}
|
|
30361
30429
|
}
|
|
30362
|
-
flushPathSnapshots(toolKey,
|
|
30430
|
+
flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
|
|
30363
30431
|
const t = this.debouncers.get(toolKey);
|
|
30364
30432
|
if (t) clearTimeout(t);
|
|
30365
30433
|
this.debouncers.delete(toolKey);
|
|
@@ -30368,10 +30436,10 @@ var PathSnapshotTracker = class {
|
|
|
30368
30436
|
this.beforeByToolKey.delete(toolKey);
|
|
30369
30437
|
if (!send || !runId || !sessionId) return;
|
|
30370
30438
|
for (const [displayPath, oldText] of beforeMap) {
|
|
30371
|
-
const newText = readUtf8WorkspaceFile(
|
|
30439
|
+
const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
|
|
30372
30440
|
if (oldText === newText) continue;
|
|
30373
30441
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
30374
|
-
const dirFlags = getSessionFileChangeDirectoryFlags(
|
|
30442
|
+
const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
|
|
30375
30443
|
try {
|
|
30376
30444
|
send({
|
|
30377
30445
|
type: "session_file_change",
|
|
@@ -30390,31 +30458,31 @@ var PathSnapshotTracker = class {
|
|
|
30390
30458
|
}
|
|
30391
30459
|
}
|
|
30392
30460
|
}
|
|
30393
|
-
scheduleDebouncedFlush(toolKey,
|
|
30461
|
+
scheduleDebouncedFlush(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
|
|
30394
30462
|
const prev = this.debouncers.get(toolKey);
|
|
30395
30463
|
if (prev) clearTimeout(prev);
|
|
30396
30464
|
this.debouncers.set(
|
|
30397
30465
|
toolKey,
|
|
30398
30466
|
setTimeout(() => {
|
|
30399
30467
|
this.debouncers.delete(toolKey);
|
|
30400
|
-
this.flushPathSnapshots(toolKey,
|
|
30468
|
+
this.flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
|
|
30401
30469
|
}, PATH_SNAPSHOT_DEBOUNCE_MS)
|
|
30402
30470
|
);
|
|
30403
30471
|
}
|
|
30404
|
-
handleToolCallLifecycle(updateKind, toolKey, toolPaths, status,
|
|
30472
|
+
handleToolCallLifecycle(updateKind, toolKey, toolPaths, status, sessionParentPath, sentPaths, send, runId, sessionId, log2) {
|
|
30405
30473
|
if (updateKind === "tool_call") {
|
|
30406
30474
|
this.resetToolSnapshots(toolKey);
|
|
30407
30475
|
}
|
|
30408
30476
|
if (updateKind === "tool_call") {
|
|
30409
|
-
this.captureBeforeFromDisk(toolKey, toolPaths,
|
|
30477
|
+
this.captureBeforeFromDisk(toolKey, toolPaths, sessionParentPath);
|
|
30410
30478
|
} else if (updateKind === "tool_call_update") {
|
|
30411
30479
|
if (isCompletedToolStatus(status)) {
|
|
30412
|
-
this.ensureBeforeFromHeadForMissing(toolKey, toolPaths,
|
|
30413
|
-
this.flushPathSnapshots(toolKey,
|
|
30480
|
+
this.ensureBeforeFromHeadForMissing(toolKey, toolPaths, sessionParentPath);
|
|
30481
|
+
this.flushPathSnapshots(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
|
|
30414
30482
|
} else {
|
|
30415
|
-
this.captureBeforeFromDisk(toolKey, toolPaths,
|
|
30483
|
+
this.captureBeforeFromDisk(toolKey, toolPaths, sessionParentPath);
|
|
30416
30484
|
if (this.beforeByToolKey.has(toolKey)) {
|
|
30417
|
-
this.scheduleDebouncedFlush(toolKey,
|
|
30485
|
+
this.scheduleDebouncedFlush(toolKey, sessionParentPath, sentPaths, send, runId, sessionId, log2);
|
|
30418
30486
|
}
|
|
30419
30487
|
}
|
|
30420
30488
|
}
|
|
@@ -30422,11 +30490,11 @@ var PathSnapshotTracker = class {
|
|
|
30422
30490
|
};
|
|
30423
30491
|
|
|
30424
30492
|
// src/agents/acp/hooks/bridge-on-session-update/send-structured-file-changes.ts
|
|
30425
|
-
function sendExtractedDiffsAsSessionFileChanges(diffs, send,
|
|
30493
|
+
function sendExtractedDiffsAsSessionFileChanges(diffs, send, sessionParentPath, sessionId, runId, sentPaths, log2) {
|
|
30426
30494
|
for (const d of diffs) {
|
|
30427
30495
|
try {
|
|
30428
30496
|
const patchContent = editSnippetToUnifiedDiff(d.path, d.oldText, d.newText);
|
|
30429
|
-
const dirFlags = getSessionFileChangeDirectoryFlags(
|
|
30497
|
+
const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, d.path);
|
|
30430
30498
|
send({
|
|
30431
30499
|
type: "session_file_change",
|
|
30432
30500
|
sessionId,
|
|
@@ -30444,15 +30512,15 @@ function sendExtractedDiffsAsSessionFileChanges(diffs, send, cwd, sessionId, run
|
|
|
30444
30512
|
}
|
|
30445
30513
|
}
|
|
30446
30514
|
}
|
|
30447
|
-
function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send,
|
|
30515
|
+
function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, sessionParentPath, sessionId, runId, log2) {
|
|
30448
30516
|
for (const displayPath of mergedPaths) {
|
|
30449
30517
|
if (sentPaths.has(displayPath)) continue;
|
|
30450
|
-
const oldText = readGitHeadBlob(
|
|
30451
|
-
const newText = readUtf8WorkspaceFile(
|
|
30518
|
+
const oldText = readGitHeadBlob(sessionParentPath, displayPath);
|
|
30519
|
+
const newText = readUtf8WorkspaceFile(sessionParentPath, displayPath);
|
|
30452
30520
|
if (oldText === newText) continue;
|
|
30453
30521
|
try {
|
|
30454
30522
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
30455
|
-
const dirFlags = getSessionFileChangeDirectoryFlags(
|
|
30523
|
+
const dirFlags = getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath);
|
|
30456
30524
|
send({
|
|
30457
30525
|
type: "session_file_change",
|
|
30458
30526
|
sessionId,
|
|
@@ -30473,13 +30541,12 @@ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, cwd, s
|
|
|
30473
30541
|
|
|
30474
30542
|
// src/agents/acp/hooks/bridge-on-session-update/create-bridge-on-session-update.ts
|
|
30475
30543
|
function createBridgeOnSessionUpdate(opts) {
|
|
30476
|
-
const { routing, getSendSessionUpdate, log: log2 } = opts;
|
|
30544
|
+
const { routing, getSendSessionUpdate, log: log2, sessionParentPath } = opts;
|
|
30477
30545
|
const pathTracker = new PathSnapshotTracker();
|
|
30478
30546
|
return (params) => {
|
|
30479
30547
|
const runId = routing.runId;
|
|
30480
30548
|
const sessionId = routing.sessionId;
|
|
30481
30549
|
pathTracker.onRunIdChanged(runId);
|
|
30482
|
-
const cwd = getBridgeWorkspaceDirectory();
|
|
30483
30550
|
const send = getSendSessionUpdate();
|
|
30484
30551
|
const sentFileChangePaths = /* @__PURE__ */ new Set();
|
|
30485
30552
|
const p = params;
|
|
@@ -30487,7 +30554,7 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
30487
30554
|
const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
|
|
30488
30555
|
const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
|
|
30489
30556
|
const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
|
|
30490
|
-
const toolPaths = isToolUpdate ? extractToolTargetDisplayPaths(params,
|
|
30557
|
+
const toolPaths = isToolUpdate ? extractToolTargetDisplayPaths(params, sessionParentPath) : [];
|
|
30491
30558
|
const toolKey = isToolUpdate ? pathTracker.resolveToolKey(params, updateKind) : "";
|
|
30492
30559
|
if (updateKind === "tool_call") {
|
|
30493
30560
|
pathTracker.resetToolSnapshots(toolKey);
|
|
@@ -30502,7 +30569,7 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
30502
30569
|
toolKey,
|
|
30503
30570
|
toolPaths,
|
|
30504
30571
|
p.status,
|
|
30505
|
-
|
|
30572
|
+
sessionParentPath,
|
|
30506
30573
|
sentFileChangePaths,
|
|
30507
30574
|
deliver,
|
|
30508
30575
|
runId ?? "",
|
|
@@ -30510,9 +30577,17 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
30510
30577
|
log2
|
|
30511
30578
|
);
|
|
30512
30579
|
}
|
|
30513
|
-
const diffs = extractAcpFileDiffsFromUpdate(params,
|
|
30580
|
+
const diffs = extractAcpFileDiffsFromUpdate(params, sessionParentPath);
|
|
30514
30581
|
if (diffs.length > 0 && send && runId && sessionId) {
|
|
30515
|
-
sendExtractedDiffsAsSessionFileChanges(
|
|
30582
|
+
sendExtractedDiffsAsSessionFileChanges(
|
|
30583
|
+
diffs,
|
|
30584
|
+
send,
|
|
30585
|
+
sessionParentPath,
|
|
30586
|
+
sessionId,
|
|
30587
|
+
runId,
|
|
30588
|
+
sentFileChangePaths,
|
|
30589
|
+
log2
|
|
30590
|
+
);
|
|
30516
30591
|
} else if (diffs.length > 0) {
|
|
30517
30592
|
log2(
|
|
30518
30593
|
`[Bridge service] Agent file diff(s) not forwarded (${diffs.length}): session or run not wired to the bridge.`
|
|
@@ -30521,7 +30596,15 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
30521
30596
|
if (isCompletedToolCallUpdate && send && runId && sessionId) {
|
|
30522
30597
|
const acc = pathTracker.accumulatedPathsByToolKey.get(toolKey);
|
|
30523
30598
|
const merged = [.../* @__PURE__ */ new Set([...acc ? [...acc] : [], ...toolPaths])];
|
|
30524
|
-
sendGitHeadVsWorkspaceForToolPaths(
|
|
30599
|
+
sendGitHeadVsWorkspaceForToolPaths(
|
|
30600
|
+
merged,
|
|
30601
|
+
sentFileChangePaths,
|
|
30602
|
+
send,
|
|
30603
|
+
sessionParentPath,
|
|
30604
|
+
sessionId,
|
|
30605
|
+
runId,
|
|
30606
|
+
log2
|
|
30607
|
+
);
|
|
30525
30608
|
pathTracker.accumulatedPathsByToolKey.delete(toolKey);
|
|
30526
30609
|
}
|
|
30527
30610
|
if (runId && send) {
|
|
@@ -30556,11 +30639,12 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
30556
30639
|
|
|
30557
30640
|
// src/agents/acp/ensure-acp-client.ts
|
|
30558
30641
|
async function ensureAcpClient(options) {
|
|
30559
|
-
const { state, preferredAgentType, mode,
|
|
30560
|
-
const
|
|
30561
|
-
|
|
30562
|
-
|
|
30563
|
-
|
|
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)) {
|
|
30564
30648
|
try {
|
|
30565
30649
|
state.acpHandle.disconnect();
|
|
30566
30650
|
} catch {
|
|
@@ -30592,14 +30676,14 @@ async function ensureAcpClient(options) {
|
|
|
30592
30676
|
if (!state.acpStartPromise) {
|
|
30593
30677
|
let statOk = false;
|
|
30594
30678
|
try {
|
|
30595
|
-
const st = fs9.statSync(
|
|
30679
|
+
const st = fs9.statSync(targetSessionParentPath);
|
|
30596
30680
|
statOk = st.isDirectory();
|
|
30597
30681
|
if (!statOk) {
|
|
30598
|
-
state.lastAcpStartError = `Agent cwd is not a directory: ${
|
|
30682
|
+
state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
|
|
30599
30683
|
log2(`[Agent] ${state.lastAcpStartError}`);
|
|
30600
30684
|
}
|
|
30601
30685
|
} catch {
|
|
30602
|
-
state.lastAcpStartError = `Agent cwd missing or inaccessible: ${
|
|
30686
|
+
state.lastAcpStartError = `Agent cwd missing or inaccessible: ${targetSessionParentPath}`;
|
|
30603
30687
|
log2(`[Agent] ${state.lastAcpStartError}`);
|
|
30604
30688
|
}
|
|
30605
30689
|
if (!statOk) {
|
|
@@ -30607,6 +30691,7 @@ async function ensureAcpClient(options) {
|
|
|
30607
30691
|
}
|
|
30608
30692
|
const hooks = buildAcpSessionBridgeHooks({
|
|
30609
30693
|
routing,
|
|
30694
|
+
sessionParentPath: targetSessionParentPath,
|
|
30610
30695
|
getSendSessionUpdate: () => sendSessionUpdate,
|
|
30611
30696
|
getSendRequest: () => sendRequest,
|
|
30612
30697
|
log: log2
|
|
@@ -30614,7 +30699,6 @@ async function ensureAcpClient(options) {
|
|
|
30614
30699
|
state.acpStartPromise = resolved.createClient({
|
|
30615
30700
|
command: resolved.command,
|
|
30616
30701
|
sessionMode: mode,
|
|
30617
|
-
cwd: targetCwd,
|
|
30618
30702
|
backendAgentType: preferredAgentType,
|
|
30619
30703
|
onAgentSubprocessExit: () => {
|
|
30620
30704
|
state.acpHandle = null;
|
|
@@ -30622,11 +30706,12 @@ async function ensureAcpClient(options) {
|
|
|
30622
30706
|
state.acpAgentKey = null;
|
|
30623
30707
|
state.lastAcpStartError = "Agent subprocess exited";
|
|
30624
30708
|
},
|
|
30625
|
-
...hooks
|
|
30709
|
+
...hooks,
|
|
30710
|
+
cwd: targetSessionParentPath
|
|
30626
30711
|
}).then((h) => {
|
|
30627
30712
|
state.lastAcpStartError = null;
|
|
30628
30713
|
state.acpHandle = h;
|
|
30629
|
-
state.lastAcpCwd =
|
|
30714
|
+
state.lastAcpCwd = targetSessionParentPath;
|
|
30630
30715
|
state.acpAgentKey = agentKey;
|
|
30631
30716
|
return h;
|
|
30632
30717
|
}).catch((err) => {
|
|
@@ -30675,7 +30760,7 @@ async function createAcpManager(options) {
|
|
|
30675
30760
|
runId,
|
|
30676
30761
|
mode,
|
|
30677
30762
|
agentType,
|
|
30678
|
-
|
|
30763
|
+
sessionParentPath,
|
|
30679
30764
|
sendResult: sendResult2,
|
|
30680
30765
|
sendSessionUpdate,
|
|
30681
30766
|
followUpCatalogPromptId,
|
|
@@ -30694,7 +30779,7 @@ async function createAcpManager(options) {
|
|
|
30694
30779
|
state,
|
|
30695
30780
|
preferredAgentType: preferredForPrompt,
|
|
30696
30781
|
mode,
|
|
30697
|
-
|
|
30782
|
+
sessionParentPath,
|
|
30698
30783
|
routing: promptRouting,
|
|
30699
30784
|
sendSessionUpdate,
|
|
30700
30785
|
sendRequest: sendSessionUpdate,
|
|
@@ -30743,7 +30828,7 @@ async function createAcpManager(options) {
|
|
|
30743
30828
|
sessionId,
|
|
30744
30829
|
runId,
|
|
30745
30830
|
agentType: preferredForPrompt,
|
|
30746
|
-
agentCwd:
|
|
30831
|
+
agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
|
|
30747
30832
|
sendResult: sendResult2,
|
|
30748
30833
|
sendSessionUpdate,
|
|
30749
30834
|
log: log2,
|
|
@@ -30798,12 +30883,12 @@ async function createAcpManager(options) {
|
|
|
30798
30883
|
}
|
|
30799
30884
|
|
|
30800
30885
|
// src/worktrees/session-worktree-manager.ts
|
|
30801
|
-
import * as
|
|
30886
|
+
import * as path18 from "node:path";
|
|
30802
30887
|
import os4 from "node:os";
|
|
30803
30888
|
|
|
30804
30889
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
30805
30890
|
import * as fs11 from "node:fs";
|
|
30806
|
-
import * as
|
|
30891
|
+
import * as path13 from "node:path";
|
|
30807
30892
|
|
|
30808
30893
|
// src/git/worktree-add.ts
|
|
30809
30894
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -30813,11 +30898,11 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
30813
30898
|
|
|
30814
30899
|
// src/worktrees/worktree-layout-file.ts
|
|
30815
30900
|
import * as fs10 from "node:fs";
|
|
30816
|
-
import * as
|
|
30901
|
+
import * as path12 from "node:path";
|
|
30817
30902
|
import os3 from "node:os";
|
|
30818
30903
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
30819
30904
|
function defaultWorktreeLayoutPath() {
|
|
30820
|
-
return
|
|
30905
|
+
return path12.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
30821
30906
|
}
|
|
30822
30907
|
function normalizeLoadedLayout(raw) {
|
|
30823
30908
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -30838,24 +30923,24 @@ function loadWorktreeLayout() {
|
|
|
30838
30923
|
}
|
|
30839
30924
|
function saveWorktreeLayout(layout) {
|
|
30840
30925
|
try {
|
|
30841
|
-
const dir =
|
|
30926
|
+
const dir = path12.dirname(defaultWorktreeLayoutPath());
|
|
30842
30927
|
fs10.mkdirSync(dir, { recursive: true });
|
|
30843
30928
|
fs10.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
30844
30929
|
} catch {
|
|
30845
30930
|
}
|
|
30846
30931
|
}
|
|
30847
|
-
function baseNameSafe(
|
|
30848
|
-
return
|
|
30932
|
+
function baseNameSafe(pathString) {
|
|
30933
|
+
return path12.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
30849
30934
|
}
|
|
30850
|
-
function getLauncherDirNameIfPresent(layout,
|
|
30851
|
-
const norm =
|
|
30852
|
-
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);
|
|
30853
30938
|
return existing?.dirName;
|
|
30854
30939
|
}
|
|
30855
|
-
function allocateDirNameForLauncherCwd(layout,
|
|
30856
|
-
const existing = getLauncherDirNameIfPresent(layout,
|
|
30940
|
+
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
30941
|
+
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
30857
30942
|
if (existing) return existing;
|
|
30858
|
-
const norm =
|
|
30943
|
+
const norm = path12.resolve(bridgeRootPath2);
|
|
30859
30944
|
const base = baseNameSafe(norm);
|
|
30860
30945
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
30861
30946
|
let name = base;
|
|
@@ -30871,24 +30956,27 @@ function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
|
|
|
30871
30956
|
|
|
30872
30957
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
30873
30958
|
async function prepareNewSessionWorktrees(options) {
|
|
30874
|
-
const {
|
|
30875
|
-
const
|
|
30876
|
-
const cwdKey = allocateDirNameForLauncherCwd(layout,
|
|
30877
|
-
const
|
|
30878
|
-
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);
|
|
30879
30965
|
if (repos.length === 0) {
|
|
30880
|
-
log2("[worktrees] No Git repositories under
|
|
30966
|
+
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
30881
30967
|
return null;
|
|
30882
30968
|
}
|
|
30883
30969
|
const branch = `session-${sessionId}`;
|
|
30884
30970
|
const worktreePaths = [];
|
|
30885
|
-
fs11.mkdirSync(
|
|
30971
|
+
fs11.mkdirSync(sessionDir, { recursive: true });
|
|
30886
30972
|
for (const repo of repos) {
|
|
30887
|
-
let rel =
|
|
30888
|
-
if (rel.startsWith("..") ||
|
|
30973
|
+
let rel = path13.relative(bridgeResolved, repo.absolutePath);
|
|
30974
|
+
if (rel.startsWith("..") || path13.isAbsolute(rel)) continue;
|
|
30889
30975
|
const relNorm = rel === "" ? "." : rel;
|
|
30890
|
-
const wtPath =
|
|
30891
|
-
|
|
30976
|
+
const wtPath = relNorm === "." ? sessionDir : path13.join(sessionDir, relNorm);
|
|
30977
|
+
if (relNorm !== ".") {
|
|
30978
|
+
fs11.mkdirSync(path13.dirname(wtPath), { recursive: true });
|
|
30979
|
+
}
|
|
30892
30980
|
try {
|
|
30893
30981
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
30894
30982
|
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
|
|
@@ -30900,7 +30988,11 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
30900
30988
|
}
|
|
30901
30989
|
}
|
|
30902
30990
|
if (worktreePaths.length === 0) return null;
|
|
30903
|
-
return {
|
|
30991
|
+
return {
|
|
30992
|
+
worktreePaths,
|
|
30993
|
+
sessionParentPath: sessionDir,
|
|
30994
|
+
workingTreeRelRoot: sessionDir
|
|
30995
|
+
};
|
|
30904
30996
|
}
|
|
30905
30997
|
|
|
30906
30998
|
// src/git/rename-branch.ts
|
|
@@ -30932,16 +31024,16 @@ import * as fs13 from "node:fs";
|
|
|
30932
31024
|
|
|
30933
31025
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
30934
31026
|
import * as fs12 from "node:fs";
|
|
30935
|
-
import * as
|
|
31027
|
+
import * as path14 from "node:path";
|
|
30936
31028
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
30937
|
-
const gitDirFile =
|
|
31029
|
+
const gitDirFile = path14.join(wt, ".git");
|
|
30938
31030
|
if (!fs12.existsSync(gitDirFile) || !fs12.statSync(gitDirFile).isFile()) return "";
|
|
30939
31031
|
const first2 = fs12.readFileSync(gitDirFile, "utf8").trim();
|
|
30940
31032
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
30941
31033
|
if (!m) return "";
|
|
30942
|
-
const gitWorktreePath =
|
|
30943
|
-
const gitDir =
|
|
30944
|
-
return
|
|
31034
|
+
const gitWorktreePath = path14.resolve(wt, m[1].trim());
|
|
31035
|
+
const gitDir = path14.dirname(path14.dirname(gitWorktreePath));
|
|
31036
|
+
return path14.dirname(gitDir);
|
|
30945
31037
|
}
|
|
30946
31038
|
|
|
30947
31039
|
// src/git/worktree-remove.ts
|
|
@@ -31183,7 +31275,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
31183
31275
|
}
|
|
31184
31276
|
|
|
31185
31277
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
31186
|
-
import * as
|
|
31278
|
+
import * as path16 from "node:path";
|
|
31187
31279
|
|
|
31188
31280
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
31189
31281
|
function parseNameStatusLines(lines) {
|
|
@@ -31304,16 +31396,16 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
31304
31396
|
|
|
31305
31397
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
31306
31398
|
import * as fs16 from "node:fs";
|
|
31307
|
-
import * as
|
|
31399
|
+
import * as path15 from "node:path";
|
|
31308
31400
|
|
|
31309
31401
|
// src/git/working-directory/changes/count-lines.ts
|
|
31310
31402
|
import { createReadStream } from "node:fs";
|
|
31311
31403
|
import * as readline2 from "node:readline";
|
|
31312
|
-
async function countTextFileLines(
|
|
31404
|
+
async function countTextFileLines(filePath) {
|
|
31313
31405
|
let bytes = 0;
|
|
31314
31406
|
const maxBytes = 512e3;
|
|
31315
31407
|
let lines = 0;
|
|
31316
|
-
const stream = createReadStream(
|
|
31408
|
+
const stream = createReadStream(filePath, { encoding: "utf8" });
|
|
31317
31409
|
const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
|
|
31318
31410
|
for await (const _line of rl) {
|
|
31319
31411
|
lines += 1;
|
|
@@ -31341,15 +31433,15 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
31341
31433
|
return null;
|
|
31342
31434
|
}
|
|
31343
31435
|
}
|
|
31344
|
-
async function readWorktreeFileLines(
|
|
31436
|
+
async function readWorktreeFileLines(filePath) {
|
|
31345
31437
|
try {
|
|
31346
|
-
const raw = await fs15.promises.readFile(
|
|
31438
|
+
const raw = await fs15.promises.readFile(filePath, "utf8");
|
|
31347
31439
|
return raw.split(/\r?\n/);
|
|
31348
31440
|
} catch {
|
|
31349
31441
|
return null;
|
|
31350
31442
|
}
|
|
31351
31443
|
}
|
|
31352
|
-
async function hydrateUnifiedPatchWithFileContext(patch,
|
|
31444
|
+
async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, change) {
|
|
31353
31445
|
if (!patch.trim() || patch.includes("Binary files")) return patch;
|
|
31354
31446
|
const all = patch.split("\n");
|
|
31355
31447
|
const out = [];
|
|
@@ -31366,7 +31458,7 @@ async function hydrateUnifiedPatchWithFileContext(patch, absFile, repoGitCwd, pa
|
|
|
31366
31458
|
};
|
|
31367
31459
|
const diskLines = async () => {
|
|
31368
31460
|
if (diskCache !== void 0) return diskCache;
|
|
31369
|
-
diskCache = await readWorktreeFileLines(
|
|
31461
|
+
diskCache = await readWorktreeFileLines(filePath);
|
|
31370
31462
|
return diskCache;
|
|
31371
31463
|
};
|
|
31372
31464
|
while (i < all.length) {
|
|
@@ -31478,7 +31570,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
31478
31570
|
const rows = [];
|
|
31479
31571
|
for (const pathInRepo of paths) {
|
|
31480
31572
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
31481
|
-
const
|
|
31573
|
+
const repoFilePath = path15.join(repoGitCwd, pathInRepo);
|
|
31482
31574
|
const nums = numByPath.get(pathInRepo);
|
|
31483
31575
|
let additions = nums?.additions ?? 0;
|
|
31484
31576
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -31491,8 +31583,8 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
31491
31583
|
deletions = fromGit.deletions;
|
|
31492
31584
|
} else {
|
|
31493
31585
|
try {
|
|
31494
|
-
const st = await fs16.promises.stat(
|
|
31495
|
-
if (st.isFile()) additions = await countTextFileLines(
|
|
31586
|
+
const st = await fs16.promises.stat(repoFilePath);
|
|
31587
|
+
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
31496
31588
|
else additions = 0;
|
|
31497
31589
|
} catch {
|
|
31498
31590
|
additions = 0;
|
|
@@ -31517,10 +31609,10 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
31517
31609
|
} else {
|
|
31518
31610
|
pathInRepo = row.pathRelLauncher;
|
|
31519
31611
|
}
|
|
31520
|
-
const
|
|
31612
|
+
const filePath = path15.join(repoGitCwd, pathInRepo);
|
|
31521
31613
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
31522
31614
|
if (patch) {
|
|
31523
|
-
patch = await hydrateUnifiedPatchWithFileContext(patch,
|
|
31615
|
+
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
31524
31616
|
}
|
|
31525
31617
|
row.patchContent = patch;
|
|
31526
31618
|
}
|
|
@@ -31533,8 +31625,9 @@ function normRepoRel(p) {
|
|
|
31533
31625
|
return x === "" ? "." : x;
|
|
31534
31626
|
}
|
|
31535
31627
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
31536
|
-
const
|
|
31537
|
-
const
|
|
31628
|
+
const bridgeRoot = path16.resolve(getBridgeRoot());
|
|
31629
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path16.resolve(options.sessionWorktreeRootPath) : null;
|
|
31630
|
+
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
31538
31631
|
const out = [];
|
|
31539
31632
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
31540
31633
|
const basisInput = options.basis ?? { kind: "working" };
|
|
@@ -31545,8 +31638,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
31545
31638
|
throw new Error("commit sha is required for commit changes");
|
|
31546
31639
|
}
|
|
31547
31640
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
31548
|
-
for (const target of options.
|
|
31549
|
-
const t =
|
|
31641
|
+
for (const target of options.commitTargetPaths) {
|
|
31642
|
+
const t = path16.resolve(target);
|
|
31550
31643
|
if (!await isGitRepoDirectory(t)) continue;
|
|
31551
31644
|
const g = simpleGit(t);
|
|
31552
31645
|
let branch = "HEAD";
|
|
@@ -31558,8 +31651,9 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
31558
31651
|
const remoteUrl = await getRemoteOriginUrl(t);
|
|
31559
31652
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
31560
31653
|
let repoRelPath;
|
|
31561
|
-
if (
|
|
31562
|
-
const
|
|
31654
|
+
if (sessionWtRoot) {
|
|
31655
|
+
const anchor = legacyNested ? path16.dirname(t) : t;
|
|
31656
|
+
const relNorm = path16.relative(sessionWtRoot, anchor);
|
|
31563
31657
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
31564
31658
|
} else {
|
|
31565
31659
|
let top = t;
|
|
@@ -31568,8 +31662,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
31568
31662
|
} catch {
|
|
31569
31663
|
top = t;
|
|
31570
31664
|
}
|
|
31571
|
-
const rel =
|
|
31572
|
-
repoRelPath = rel.startsWith("..") ?
|
|
31665
|
+
const rel = path16.relative(bridgeRoot, path16.resolve(top)).replace(/\\/g, "/") || ".";
|
|
31666
|
+
repoRelPath = rel.startsWith("..") ? path16.basename(path16.resolve(top)) : rel;
|
|
31573
31667
|
}
|
|
31574
31668
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
31575
31669
|
if (filter && norm !== filter) continue;
|
|
@@ -31635,14 +31729,37 @@ async function commitSessionWorktrees(options) {
|
|
|
31635
31729
|
|
|
31636
31730
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
31637
31731
|
import * as fs17 from "node:fs";
|
|
31638
|
-
import * as
|
|
31639
|
-
function isGitDir(
|
|
31732
|
+
import * as path17 from "node:path";
|
|
31733
|
+
function isGitDir(dirPath) {
|
|
31640
31734
|
try {
|
|
31641
|
-
return fs17.existsSync(
|
|
31735
|
+
return fs17.existsSync(path17.join(dirPath, ".git"));
|
|
31642
31736
|
} catch {
|
|
31643
31737
|
return false;
|
|
31644
31738
|
}
|
|
31645
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
|
+
}
|
|
31646
31763
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
31647
31764
|
const out = [];
|
|
31648
31765
|
const walk = (dir, depth) => {
|
|
@@ -31655,10 +31772,10 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
31655
31772
|
}
|
|
31656
31773
|
for (const e of entries) {
|
|
31657
31774
|
if (e.name.startsWith(".")) continue;
|
|
31658
|
-
const full =
|
|
31775
|
+
const full = path17.join(dir, e.name);
|
|
31659
31776
|
if (!e.isDirectory()) continue;
|
|
31660
31777
|
if (e.name === sessionId) {
|
|
31661
|
-
if (isGitDir(full)) out.push(
|
|
31778
|
+
if (isGitDir(full)) out.push(path17.resolve(full));
|
|
31662
31779
|
} else {
|
|
31663
31780
|
walk(full, depth + 1);
|
|
31664
31781
|
}
|
|
@@ -31667,16 +31784,55 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
31667
31784
|
walk(root, 0);
|
|
31668
31785
|
return out;
|
|
31669
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
|
+
}
|
|
31670
31826
|
function discoverSessionWorktreeOnDisk(options) {
|
|
31671
|
-
const { sessionId,
|
|
31672
|
-
if (!sessionId.trim() || !fs17.existsSync(
|
|
31673
|
-
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);
|
|
31674
31830
|
const keys = [];
|
|
31675
31831
|
if (preferredKey) keys.push(preferredKey);
|
|
31676
31832
|
try {
|
|
31677
|
-
for (const name of fs17.readdirSync(
|
|
31833
|
+
for (const name of fs17.readdirSync(worktreesRootPath)) {
|
|
31678
31834
|
if (name.startsWith(".")) continue;
|
|
31679
|
-
const p =
|
|
31835
|
+
const p = path17.join(worktreesRootPath, name);
|
|
31680
31836
|
if (!fs17.statSync(p).isDirectory()) continue;
|
|
31681
31837
|
if (name !== preferredKey) keys.push(name);
|
|
31682
31838
|
}
|
|
@@ -31684,26 +31840,58 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
31684
31840
|
return null;
|
|
31685
31841
|
}
|
|
31686
31842
|
for (const key of keys) {
|
|
31687
|
-
const
|
|
31688
|
-
if (!fs17.existsSync(
|
|
31689
|
-
const
|
|
31690
|
-
|
|
31691
|
-
|
|
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
|
+
};
|
|
31692
31856
|
}
|
|
31693
31857
|
}
|
|
31694
31858
|
return null;
|
|
31695
31859
|
}
|
|
31696
|
-
function
|
|
31697
|
-
const
|
|
31698
|
-
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;
|
|
31699
31881
|
try {
|
|
31700
|
-
|
|
31882
|
+
st = fs17.statSync(hint);
|
|
31701
31883
|
} catch {
|
|
31702
31884
|
return null;
|
|
31703
31885
|
}
|
|
31704
|
-
|
|
31705
|
-
|
|
31706
|
-
|
|
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
|
+
};
|
|
31707
31895
|
}
|
|
31708
31896
|
|
|
31709
31897
|
// src/worktrees/session-worktree-manager.ts
|
|
@@ -31713,42 +31901,86 @@ function parseSessionParent(v) {
|
|
|
31713
31901
|
return null;
|
|
31714
31902
|
}
|
|
31715
31903
|
var SessionWorktreeManager = class {
|
|
31716
|
-
|
|
31904
|
+
worktreesRootPath;
|
|
31717
31905
|
log;
|
|
31718
|
-
|
|
31719
|
-
|
|
31906
|
+
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
31907
|
+
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
31908
|
+
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
31720
31909
|
layout;
|
|
31721
31910
|
constructor(options) {
|
|
31722
|
-
this.
|
|
31911
|
+
this.worktreesRootPath = options.worktreesRootPath;
|
|
31723
31912
|
this.log = options.log;
|
|
31724
31913
|
this.layout = loadWorktreeLayout();
|
|
31725
31914
|
}
|
|
31726
|
-
|
|
31727
|
-
|
|
31728
|
-
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);
|
|
31729
31923
|
}
|
|
31730
31924
|
tryDiscoverFromDisk(sessionId) {
|
|
31731
31925
|
return discoverSessionWorktreeOnDisk({
|
|
31732
31926
|
sessionId,
|
|
31733
|
-
|
|
31927
|
+
worktreesRootPath: this.worktreesRootPath,
|
|
31734
31928
|
layout: this.layout,
|
|
31735
|
-
|
|
31929
|
+
bridgeRoot: getBridgeRoot()
|
|
31736
31930
|
});
|
|
31737
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
|
+
}
|
|
31738
31950
|
/**
|
|
31739
|
-
*
|
|
31951
|
+
* Resolved **session parent path** for the agent: session directory in worktrees mode,
|
|
31952
|
+
* or `undefined` meaning use {@link getBridgeRoot}.
|
|
31740
31953
|
*/
|
|
31741
|
-
async
|
|
31954
|
+
async resolveSessionParentPathForPrompt(sessionId, opts) {
|
|
31742
31955
|
if (!sessionId) return void 0;
|
|
31956
|
+
const sid = sessionId.trim();
|
|
31743
31957
|
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
31744
31958
|
if (parentPathRaw) {
|
|
31745
|
-
const
|
|
31746
|
-
const sid = sessionId?.trim();
|
|
31959
|
+
const resolved = path18.resolve(parentPathRaw);
|
|
31747
31960
|
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
31748
|
-
const
|
|
31749
|
-
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
|
+
}
|
|
31750
31982
|
}
|
|
31751
|
-
return
|
|
31983
|
+
return resolved;
|
|
31752
31984
|
}
|
|
31753
31985
|
const parentKind = parseSessionParent(opts.sessionParent);
|
|
31754
31986
|
if (parentKind === "bridge_root") {
|
|
@@ -31756,78 +31988,102 @@ var SessionWorktreeManager = class {
|
|
|
31756
31988
|
}
|
|
31757
31989
|
if (parentKind === "worktrees_root") {
|
|
31758
31990
|
if (!opts.isNewSession) {
|
|
31759
|
-
const cached2 = this.
|
|
31760
|
-
if (cached2) return
|
|
31761
|
-
const disc = this.tryDiscoverFromDisk(
|
|
31991
|
+
const cached2 = this.sessionParentPathAfterRemember(sid);
|
|
31992
|
+
if (cached2) return cached2;
|
|
31993
|
+
const disc = this.tryDiscoverFromDisk(sid);
|
|
31762
31994
|
if (disc) {
|
|
31763
|
-
this.
|
|
31764
|
-
return
|
|
31995
|
+
this.rememberSessionWorktrees(sid, disc);
|
|
31996
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31765
31997
|
}
|
|
31766
31998
|
return void 0;
|
|
31767
31999
|
}
|
|
31768
32000
|
const prep2 = await prepareNewSessionWorktrees({
|
|
31769
|
-
|
|
31770
|
-
|
|
31771
|
-
sessionId,
|
|
32001
|
+
worktreesRootPath: this.worktreesRootPath,
|
|
32002
|
+
bridgeRoot: getBridgeRoot(),
|
|
32003
|
+
sessionId: sid,
|
|
31772
32004
|
layout: this.layout,
|
|
31773
32005
|
log: this.log
|
|
31774
32006
|
});
|
|
31775
32007
|
if (!prep2) return void 0;
|
|
31776
|
-
this.
|
|
31777
|
-
|
|
32008
|
+
this.rememberSessionWorktrees(sid, {
|
|
32009
|
+
sessionParentPath: prep2.sessionParentPath,
|
|
32010
|
+
workingTreeRelRoot: prep2.workingTreeRelRoot,
|
|
32011
|
+
repoCheckoutPaths: prep2.worktreePaths
|
|
32012
|
+
});
|
|
32013
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31778
32014
|
}
|
|
31779
32015
|
if (!opts.isNewSession) {
|
|
31780
|
-
const cached2 = this.
|
|
31781
|
-
if (cached2) return
|
|
31782
|
-
const disc = this.tryDiscoverFromDisk(
|
|
32016
|
+
const cached2 = this.sessionParentPathAfterRemember(sid);
|
|
32017
|
+
if (cached2) return cached2;
|
|
32018
|
+
const disc = this.tryDiscoverFromDisk(sid);
|
|
31783
32019
|
if (disc) {
|
|
31784
|
-
this.
|
|
31785
|
-
return
|
|
32020
|
+
this.rememberSessionWorktrees(sid, disc);
|
|
32021
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31786
32022
|
}
|
|
31787
32023
|
return void 0;
|
|
31788
32024
|
}
|
|
31789
32025
|
const prep = await prepareNewSessionWorktrees({
|
|
31790
|
-
|
|
31791
|
-
|
|
31792
|
-
sessionId,
|
|
32026
|
+
worktreesRootPath: this.worktreesRootPath,
|
|
32027
|
+
bridgeRoot: getBridgeRoot(),
|
|
32028
|
+
sessionId: sid,
|
|
31793
32029
|
layout: this.layout,
|
|
31794
32030
|
log: this.log
|
|
31795
32031
|
});
|
|
31796
32032
|
if (!prep) return void 0;
|
|
31797
|
-
this.
|
|
31798
|
-
|
|
32033
|
+
this.rememberSessionWorktrees(sid, {
|
|
32034
|
+
sessionParentPath: prep.sessionParentPath,
|
|
32035
|
+
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
32036
|
+
repoCheckoutPaths: prep.worktreePaths
|
|
32037
|
+
});
|
|
32038
|
+
return this.sessionParentPathAfterRemember(sid);
|
|
31799
32039
|
}
|
|
31800
32040
|
async renameSessionBranch(sessionId, newBranch) {
|
|
31801
|
-
const paths = this.
|
|
32041
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
31802
32042
|
if (!paths?.length) return;
|
|
31803
32043
|
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
31804
32044
|
}
|
|
31805
|
-
/** True when this session
|
|
32045
|
+
/** True when this session uses an isolated worktree layout (not the bridge root). */
|
|
31806
32046
|
usesWorktreeSession(sessionId) {
|
|
31807
32047
|
if (!sessionId) return false;
|
|
31808
|
-
return this.
|
|
32048
|
+
return this.sessionParentPathBySession.has(sessionId);
|
|
31809
32049
|
}
|
|
31810
|
-
|
|
32050
|
+
/** Per-repo git checkout directories for this session (for snapshots, commits, change lists). */
|
|
32051
|
+
getRepoCheckoutPathsForSession(sessionId) {
|
|
31811
32052
|
if (!sessionId) return void 0;
|
|
31812
|
-
const paths = this.
|
|
32053
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
31813
32054
|
return paths?.length ? [...paths] : void 0;
|
|
31814
32055
|
}
|
|
31815
|
-
/**
|
|
31816
|
-
|
|
31817
|
-
|
|
31818
|
-
|
|
31819
|
-
|
|
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);
|
|
31820
32075
|
}
|
|
31821
32076
|
async removeSessionWorktrees(sessionId) {
|
|
31822
|
-
const paths = this.
|
|
31823
|
-
this.
|
|
31824
|
-
this.
|
|
32077
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
32078
|
+
this.sessionRepoCheckoutPaths.delete(sessionId);
|
|
32079
|
+
this.sessionParentPathBySession.delete(sessionId);
|
|
32080
|
+
this.sessionWorkingTreeRelRootBySession.delete(sessionId);
|
|
31825
32081
|
if (!paths?.length) return;
|
|
31826
32082
|
await removeSessionWorktrees(paths, this.log);
|
|
31827
32083
|
}
|
|
31828
32084
|
async commitSession(params) {
|
|
31829
|
-
const paths = this.
|
|
31830
|
-
const targets = paths?.length ? paths : [
|
|
32085
|
+
const paths = this.sessionRepoCheckoutPaths.get(params.sessionId);
|
|
32086
|
+
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
31831
32087
|
return commitSessionWorktrees({
|
|
31832
32088
|
paths: targets,
|
|
31833
32089
|
branch: params.branch,
|
|
@@ -31836,14 +32092,14 @@ var SessionWorktreeManager = class {
|
|
|
31836
32092
|
});
|
|
31837
32093
|
}
|
|
31838
32094
|
resolveCommitTargets(sessionId) {
|
|
31839
|
-
const paths = this.
|
|
32095
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
31840
32096
|
if (paths?.length) return paths;
|
|
31841
32097
|
const disc = this.tryDiscoverFromDisk(sessionId);
|
|
31842
|
-
if (disc?.
|
|
31843
|
-
this.
|
|
31844
|
-
return disc.
|
|
32098
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
32099
|
+
this.rememberSessionWorktrees(sessionId, disc);
|
|
32100
|
+
return disc.repoCheckoutPaths;
|
|
31845
32101
|
}
|
|
31846
|
-
return [
|
|
32102
|
+
return [getBridgeRoot()];
|
|
31847
32103
|
}
|
|
31848
32104
|
async getSessionWorkingTreeStatus(sessionId) {
|
|
31849
32105
|
return aggregateSessionPathsWorkingTreeStatus(this.resolveCommitTargets(sessionId));
|
|
@@ -31851,10 +32107,12 @@ var SessionWorktreeManager = class {
|
|
|
31851
32107
|
/** Per-repo changed files vs HEAD (or a single commit vs parent) for the same git roots used for commit/push. */
|
|
31852
32108
|
async getSessionWorkingTreeChangeDetails(sessionId, opts) {
|
|
31853
32109
|
const targets = this.resolveCommitTargets(sessionId);
|
|
31854
|
-
const
|
|
32110
|
+
const sessionWorkingTreeRelRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId) ?? null;
|
|
32111
|
+
const legacyNested = this.isLegacyNestedLayout(sessionId);
|
|
31855
32112
|
return getWorkingTreeChangeRepoDetails({
|
|
31856
|
-
|
|
31857
|
-
|
|
32113
|
+
commitTargetPaths: targets,
|
|
32114
|
+
sessionWorktreeRootPath: sessionWorkingTreeRelRoot,
|
|
32115
|
+
legacyRepoNestedSessionLayout: legacyNested,
|
|
31858
32116
|
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
31859
32117
|
basis: opts?.basis
|
|
31860
32118
|
});
|
|
@@ -31869,16 +32127,16 @@ var SessionWorktreeManager = class {
|
|
|
31869
32127
|
}
|
|
31870
32128
|
}
|
|
31871
32129
|
};
|
|
31872
|
-
function
|
|
31873
|
-
return
|
|
32130
|
+
function defaultWorktreesRootPath() {
|
|
32131
|
+
return path18.join(os4.homedir(), ".buildautomaton", "worktrees");
|
|
31874
32132
|
}
|
|
31875
32133
|
|
|
31876
32134
|
// src/files/watch-file-index.ts
|
|
31877
32135
|
import { watch } from "node:fs";
|
|
31878
|
-
import
|
|
32136
|
+
import path25 from "node:path";
|
|
31879
32137
|
|
|
31880
32138
|
// src/files/index/build-file-index.ts
|
|
31881
|
-
import
|
|
32139
|
+
import path22 from "node:path";
|
|
31882
32140
|
|
|
31883
32141
|
// src/runtime/yield-to-event-loop.ts
|
|
31884
32142
|
function yieldToEventLoop() {
|
|
@@ -31887,13 +32145,13 @@ function yieldToEventLoop() {
|
|
|
31887
32145
|
|
|
31888
32146
|
// src/files/index/walk-workspace-tree.ts
|
|
31889
32147
|
import fs18 from "node:fs";
|
|
31890
|
-
import
|
|
32148
|
+
import path20 from "node:path";
|
|
31891
32149
|
|
|
31892
32150
|
// src/files/index/constants.ts
|
|
31893
|
-
import
|
|
32151
|
+
import path19 from "node:path";
|
|
31894
32152
|
import os5 from "node:os";
|
|
31895
32153
|
var INDEX_WORK_YIELD_EVERY = 256;
|
|
31896
|
-
var INDEX_DIR =
|
|
32154
|
+
var INDEX_DIR = path19.join(os5.homedir(), ".buildautomaton");
|
|
31897
32155
|
var INDEX_HASH_LEN = 16;
|
|
31898
32156
|
var INDEX_VERSION = 2;
|
|
31899
32157
|
var INDEX_LOG_PREFIX = "[file-index]";
|
|
@@ -31908,14 +32166,14 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
|
31908
32166
|
}
|
|
31909
32167
|
for (const name of names) {
|
|
31910
32168
|
if (name.startsWith(".")) continue;
|
|
31911
|
-
const full =
|
|
32169
|
+
const full = path20.join(dir, name);
|
|
31912
32170
|
let stat2;
|
|
31913
32171
|
try {
|
|
31914
32172
|
stat2 = fs18.statSync(full);
|
|
31915
32173
|
} catch {
|
|
31916
32174
|
continue;
|
|
31917
32175
|
}
|
|
31918
|
-
const relative5 =
|
|
32176
|
+
const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
|
|
31919
32177
|
if (stat2.isDirectory()) {
|
|
31920
32178
|
walkWorkspaceTreeSync(full, baseDir, out);
|
|
31921
32179
|
} else if (stat2.isFile()) {
|
|
@@ -31936,14 +32194,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
31936
32194
|
await yieldToEventLoop();
|
|
31937
32195
|
}
|
|
31938
32196
|
state.n++;
|
|
31939
|
-
const full =
|
|
32197
|
+
const full = path20.join(dir, name);
|
|
31940
32198
|
let stat2;
|
|
31941
32199
|
try {
|
|
31942
32200
|
stat2 = await fs18.promises.stat(full);
|
|
31943
32201
|
} catch {
|
|
31944
32202
|
continue;
|
|
31945
32203
|
}
|
|
31946
|
-
const relative5 =
|
|
32204
|
+
const relative5 = path20.relative(baseDir, full).replace(/\\/g, "/");
|
|
31947
32205
|
if (stat2.isDirectory()) {
|
|
31948
32206
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
31949
32207
|
} else if (stat2.isFile()) {
|
|
@@ -32027,11 +32285,11 @@ async function buildTrigramMapForPathsAsync(paths) {
|
|
|
32027
32285
|
import fs19 from "node:fs";
|
|
32028
32286
|
|
|
32029
32287
|
// src/files/index/paths.ts
|
|
32030
|
-
import
|
|
32288
|
+
import path21 from "node:path";
|
|
32031
32289
|
import crypto2 from "node:crypto";
|
|
32032
32290
|
function getIndexPathForCwd(resolvedCwd) {
|
|
32033
32291
|
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
32034
|
-
return
|
|
32292
|
+
return path21.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
32035
32293
|
}
|
|
32036
32294
|
|
|
32037
32295
|
// src/files/index/write-index-file.ts
|
|
@@ -32062,7 +32320,7 @@ function sortPaths(paths) {
|
|
|
32062
32320
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
32063
32321
|
}
|
|
32064
32322
|
function buildFileIndex(cwd) {
|
|
32065
|
-
const resolved =
|
|
32323
|
+
const resolved = path22.resolve(cwd);
|
|
32066
32324
|
const paths = [];
|
|
32067
32325
|
walkWorkspaceTreeSync(resolved, resolved, paths);
|
|
32068
32326
|
sortPaths(paths);
|
|
@@ -32072,7 +32330,7 @@ function buildFileIndex(cwd) {
|
|
|
32072
32330
|
return data;
|
|
32073
32331
|
}
|
|
32074
32332
|
async function buildFileIndexAsync(cwd) {
|
|
32075
|
-
const resolved =
|
|
32333
|
+
const resolved = path22.resolve(cwd);
|
|
32076
32334
|
const paths = [];
|
|
32077
32335
|
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
32078
32336
|
await yieldToEventLoop();
|
|
@@ -32085,9 +32343,9 @@ async function buildFileIndexAsync(cwd) {
|
|
|
32085
32343
|
|
|
32086
32344
|
// src/files/index/load-file-index.ts
|
|
32087
32345
|
import fs20 from "node:fs";
|
|
32088
|
-
import
|
|
32346
|
+
import path23 from "node:path";
|
|
32089
32347
|
function loadFileIndex(cwd) {
|
|
32090
|
-
const resolved =
|
|
32348
|
+
const resolved = path23.resolve(cwd);
|
|
32091
32349
|
const indexPath = getIndexPathForCwd(resolved);
|
|
32092
32350
|
try {
|
|
32093
32351
|
const raw = fs20.readFileSync(indexPath, "utf8");
|
|
@@ -32109,9 +32367,9 @@ function loadFileIndex(cwd) {
|
|
|
32109
32367
|
}
|
|
32110
32368
|
|
|
32111
32369
|
// src/files/index/ensure-file-index.ts
|
|
32112
|
-
import
|
|
32370
|
+
import path24 from "node:path";
|
|
32113
32371
|
async function ensureFileIndexAsync(cwd) {
|
|
32114
|
-
const resolved =
|
|
32372
|
+
const resolved = path24.resolve(cwd);
|
|
32115
32373
|
const cached2 = loadFileIndex(resolved);
|
|
32116
32374
|
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
32117
32375
|
const data = await buildFileIndexAsync(resolved);
|
|
@@ -32193,8 +32451,8 @@ function createFsWatcher(resolved, schedule) {
|
|
|
32193
32451
|
throw e;
|
|
32194
32452
|
}
|
|
32195
32453
|
}
|
|
32196
|
-
function startFileIndexWatcher(cwd =
|
|
32197
|
-
const resolved =
|
|
32454
|
+
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
32455
|
+
const resolved = path25.resolve(cwd);
|
|
32198
32456
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
32199
32457
|
console.error("[file-index] Initial index build failed:", e);
|
|
32200
32458
|
});
|
|
@@ -32532,10 +32790,10 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
32532
32790
|
import { spawn as spawn7 } from "node:child_process";
|
|
32533
32791
|
import fs23 from "node:fs";
|
|
32534
32792
|
import { tmpdir } from "node:os";
|
|
32535
|
-
import
|
|
32793
|
+
import path26 from "node:path";
|
|
32536
32794
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
32537
|
-
const tmpRoot = fs23.mkdtempSync(
|
|
32538
|
-
const logPath =
|
|
32795
|
+
const tmpRoot = fs23.mkdtempSync(path26.join(tmpdir(), "ba-devsrv-log-"));
|
|
32796
|
+
const logPath = path26.join(tmpRoot, "combined.log");
|
|
32539
32797
|
let logFd;
|
|
32540
32798
|
try {
|
|
32541
32799
|
logFd = fs23.openSync(logPath, "a");
|
|
@@ -32579,15 +32837,15 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
32579
32837
|
import { spawn as spawn8 } from "node:child_process";
|
|
32580
32838
|
import fs24 from "node:fs";
|
|
32581
32839
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
32582
|
-
import
|
|
32840
|
+
import path27 from "node:path";
|
|
32583
32841
|
function shSingleQuote(s) {
|
|
32584
32842
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
32585
32843
|
}
|
|
32586
32844
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
32587
|
-
const tmpRoot = fs24.mkdtempSync(
|
|
32588
|
-
const logPath =
|
|
32589
|
-
const innerPath =
|
|
32590
|
-
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");
|
|
32591
32849
|
try {
|
|
32592
32850
|
fs24.writeFileSync(innerPath, `#!/bin/sh
|
|
32593
32851
|
${command}
|
|
@@ -32618,9 +32876,9 @@ cd ${shSingleQuote(cwd)}
|
|
|
32618
32876
|
}
|
|
32619
32877
|
}
|
|
32620
32878
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
32621
|
-
const tmpRoot = fs24.mkdtempSync(
|
|
32622
|
-
const logPath =
|
|
32623
|
-
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");
|
|
32624
32882
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
32625
32883
|
const com = process.env.ComSpec || "cmd.exe";
|
|
32626
32884
|
try {
|
|
@@ -32830,13 +33088,13 @@ var DevServerManager = class {
|
|
|
32830
33088
|
abortControllersByServerId = /* @__PURE__ */ new Map();
|
|
32831
33089
|
getWs;
|
|
32832
33090
|
log;
|
|
32833
|
-
|
|
33091
|
+
getBridgeRoot;
|
|
32834
33092
|
e2ee;
|
|
32835
33093
|
firehoseSink;
|
|
32836
33094
|
constructor(options) {
|
|
32837
33095
|
this.getWs = options.getWs;
|
|
32838
33096
|
this.log = options.log;
|
|
32839
|
-
this.
|
|
33097
|
+
this.getBridgeRoot = options.getBridgeRoot ?? (() => process.cwd());
|
|
32840
33098
|
this.e2ee = options.e2ee;
|
|
32841
33099
|
this.firehoseSink = new DevServerFirehoseSink({
|
|
32842
33100
|
getTails: (serverId) => this.snapshotTails(serverId),
|
|
@@ -32925,7 +33183,7 @@ var DevServerManager = class {
|
|
|
32925
33183
|
this.sendStatus(serverId, "starting", void 0, emptyTails());
|
|
32926
33184
|
const ac = new AbortController();
|
|
32927
33185
|
this.abortControllersByServerId.set(serverId, ac);
|
|
32928
|
-
const cwd = this.
|
|
33186
|
+
const cwd = this.getBridgeRoot();
|
|
32929
33187
|
const childEnv = envForSpawn(process.env, def.env, def.ports);
|
|
32930
33188
|
const cmd = substituteCommand(def.command.trim(), childEnv);
|
|
32931
33189
|
const title = def.name.trim() || serverId.slice(0, 8);
|
|
@@ -33348,13 +33606,13 @@ function createOnBridgeIdentified(opts) {
|
|
|
33348
33606
|
|
|
33349
33607
|
// src/skills/discover-local-agent-skills.ts
|
|
33350
33608
|
import fs25 from "node:fs";
|
|
33351
|
-
import
|
|
33609
|
+
import path28 from "node:path";
|
|
33352
33610
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
33353
33611
|
function discoverLocalSkills(cwd) {
|
|
33354
33612
|
const out = [];
|
|
33355
33613
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
33356
33614
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
33357
|
-
const base =
|
|
33615
|
+
const base = path28.join(cwd, rel);
|
|
33358
33616
|
if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
|
|
33359
33617
|
let entries = [];
|
|
33360
33618
|
try {
|
|
@@ -33363,13 +33621,13 @@ function discoverLocalSkills(cwd) {
|
|
|
33363
33621
|
continue;
|
|
33364
33622
|
}
|
|
33365
33623
|
for (const name of entries) {
|
|
33366
|
-
const dir =
|
|
33624
|
+
const dir = path28.join(base, name);
|
|
33367
33625
|
try {
|
|
33368
33626
|
if (!fs25.statSync(dir).isDirectory()) continue;
|
|
33369
33627
|
} catch {
|
|
33370
33628
|
continue;
|
|
33371
33629
|
}
|
|
33372
|
-
const skillMd =
|
|
33630
|
+
const skillMd = path28.join(dir, "SKILL.md");
|
|
33373
33631
|
if (!fs25.existsSync(skillMd)) continue;
|
|
33374
33632
|
const key = `${rel}/${name}`;
|
|
33375
33633
|
if (seenKeys.has(key)) continue;
|
|
@@ -33382,7 +33640,7 @@ function discoverLocalSkills(cwd) {
|
|
|
33382
33640
|
function discoverSkillLayoutRoots(cwd) {
|
|
33383
33641
|
const roots = [];
|
|
33384
33642
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
33385
|
-
const base =
|
|
33643
|
+
const base = path28.join(cwd, rel);
|
|
33386
33644
|
if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
|
|
33387
33645
|
let entries = [];
|
|
33388
33646
|
try {
|
|
@@ -33392,13 +33650,13 @@ function discoverSkillLayoutRoots(cwd) {
|
|
|
33392
33650
|
}
|
|
33393
33651
|
const skills2 = [];
|
|
33394
33652
|
for (const name of entries) {
|
|
33395
|
-
const dir =
|
|
33653
|
+
const dir = path28.join(base, name);
|
|
33396
33654
|
try {
|
|
33397
33655
|
if (!fs25.statSync(dir).isDirectory()) continue;
|
|
33398
33656
|
} catch {
|
|
33399
33657
|
continue;
|
|
33400
33658
|
}
|
|
33401
|
-
if (!fs25.existsSync(
|
|
33659
|
+
if (!fs25.existsSync(path28.join(dir, "SKILL.md"))) continue;
|
|
33402
33660
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
33403
33661
|
skills2.push({ name, relPath });
|
|
33404
33662
|
}
|
|
@@ -33442,7 +33700,7 @@ function createSendLocalSkillsReport(getWs, logFn) {
|
|
|
33442
33700
|
try {
|
|
33443
33701
|
const socket = getWs();
|
|
33444
33702
|
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
33445
|
-
const skills2 = discoverLocalSkills(
|
|
33703
|
+
const skills2 = discoverLocalSkills(getBridgeRoot());
|
|
33446
33704
|
sendWsMessage(socket, { type: "local_skills", skills: skills2 });
|
|
33447
33705
|
} catch (e) {
|
|
33448
33706
|
logFn(
|
|
@@ -33580,9 +33838,6 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
33580
33838
|
handleBridgeAgentConfig(msg, deps);
|
|
33581
33839
|
};
|
|
33582
33840
|
|
|
33583
|
-
// src/agents/acp/from-bridge/handle-bridge-prompt.ts
|
|
33584
|
-
import * as path29 from "node:path";
|
|
33585
|
-
|
|
33586
33841
|
// src/prompt-turn-queue/client-report.ts
|
|
33587
33842
|
function sendPromptQueueClientReport(ws, queues) {
|
|
33588
33843
|
if (!ws) return false;
|
|
@@ -33596,7 +33851,7 @@ import fs27 from "node:fs";
|
|
|
33596
33851
|
// src/prompt-turn-queue/paths.ts
|
|
33597
33852
|
import crypto3 from "node:crypto";
|
|
33598
33853
|
import fs26 from "node:fs";
|
|
33599
|
-
import
|
|
33854
|
+
import path29 from "node:path";
|
|
33600
33855
|
import os6 from "node:os";
|
|
33601
33856
|
var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
|
|
33602
33857
|
function queueStateFileSlug(queueKey) {
|
|
@@ -33605,15 +33860,15 @@ function queueStateFileSlug(queueKey) {
|
|
|
33605
33860
|
}
|
|
33606
33861
|
function getPromptQueuesDirectory() {
|
|
33607
33862
|
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
33608
|
-
if (override) return
|
|
33609
|
-
return
|
|
33863
|
+
if (override) return path29.resolve(override);
|
|
33864
|
+
return path29.join(os6.homedir(), ".buildautomaton", "queues");
|
|
33610
33865
|
}
|
|
33611
33866
|
function ensurePromptQueuesDirectory() {
|
|
33612
33867
|
const dir = getPromptQueuesDirectory();
|
|
33613
33868
|
if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
|
|
33614
33869
|
}
|
|
33615
33870
|
function queueStateFilePath(queueKey) {
|
|
33616
|
-
return
|
|
33871
|
+
return path29.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
|
|
33617
33872
|
}
|
|
33618
33873
|
|
|
33619
33874
|
// src/prompt-turn-queue/disk-store.ts
|
|
@@ -33685,6 +33940,10 @@ function hasRunningTurn(turns) {
|
|
|
33685
33940
|
}
|
|
33686
33941
|
function dispatchLocalPrompt(next, deps) {
|
|
33687
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;
|
|
33688
33947
|
const msg = {
|
|
33689
33948
|
type: "prompt",
|
|
33690
33949
|
sessionId: next.sessionId,
|
|
@@ -33692,6 +33951,8 @@ function dispatchLocalPrompt(next, deps) {
|
|
|
33692
33951
|
prompt: pl.prompt,
|
|
33693
33952
|
mode: typeof pl.mode === "string" ? pl.mode : "agent",
|
|
33694
33953
|
isNewSession: pl.isNewSession === true,
|
|
33954
|
+
...sessionParent ? { sessionParent } : {},
|
|
33955
|
+
...sessionParentPath ? { sessionParentPath } : {},
|
|
33695
33956
|
...typeof pl.followUpCatalogPromptId === "string" ? { followUpCatalogPromptId: pl.followUpCatalogPromptId } : {},
|
|
33696
33957
|
...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
|
|
33697
33958
|
...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
|
|
@@ -33803,23 +34064,24 @@ async function readGitBranch(cwd) {
|
|
|
33803
34064
|
async function runBridgePromptPreamble(params) {
|
|
33804
34065
|
const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
|
|
33805
34066
|
const s = getWs();
|
|
33806
|
-
const
|
|
34067
|
+
const repoCheckoutPaths = sessionWorktreeManager.ensureRepoCheckoutPathsForSession(sessionId);
|
|
33807
34068
|
const repoRoots = await resolveSnapshotRepoRoots({
|
|
33808
|
-
worktreePaths,
|
|
34069
|
+
worktreePaths: repoCheckoutPaths,
|
|
33809
34070
|
fallbackCwd: effectiveCwd,
|
|
34071
|
+
sessionId: sessionId?.trim() || void 0,
|
|
33810
34072
|
log: log2
|
|
33811
34073
|
});
|
|
33812
34074
|
if (s && sessionId) {
|
|
33813
34075
|
const cliGitBranch = await readGitBranch(effectiveCwd);
|
|
33814
34076
|
const usesWt = sessionWorktreeManager.usesWorktreeSession(sessionId);
|
|
33815
|
-
const
|
|
34077
|
+
const isolatedSessionParentPath = sessionWorktreeManager.getIsolatedSessionParentPathForSession(sessionId);
|
|
33816
34078
|
sendWsMessage(s, {
|
|
33817
34079
|
type: "session_git_context_report",
|
|
33818
34080
|
sessionId,
|
|
33819
34081
|
cliGitBranch,
|
|
33820
34082
|
agentUsesWorktree: usesWt,
|
|
33821
34083
|
sessionParent: usesWt ? "worktrees_root" : "bridge_root",
|
|
33822
|
-
sessionParentPath: usesWt ?
|
|
34084
|
+
sessionParentPath: usesWt ? isolatedSessionParentPath ?? effectiveCwd : getBridgeRoot()
|
|
33823
34085
|
});
|
|
33824
34086
|
}
|
|
33825
34087
|
if (s && sessionId && runId) {
|
|
@@ -33972,7 +34234,7 @@ function handleBridgePrompt(msg, deps) {
|
|
|
33972
34234
|
const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
|
|
33973
34235
|
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
33974
34236
|
async function preambleAndPrompt(resolvedCwd) {
|
|
33975
|
-
const effectiveCwd =
|
|
34237
|
+
const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
|
|
33976
34238
|
await runBridgePromptPreamble({
|
|
33977
34239
|
getWs,
|
|
33978
34240
|
log: log2,
|
|
@@ -34005,7 +34267,7 @@ function handleBridgePrompt(msg, deps) {
|
|
|
34005
34267
|
runId,
|
|
34006
34268
|
mode,
|
|
34007
34269
|
agentType,
|
|
34008
|
-
|
|
34270
|
+
sessionParentPath: effectiveCwd,
|
|
34009
34271
|
sendResult: sendResult2,
|
|
34010
34272
|
sendSessionUpdate,
|
|
34011
34273
|
followUpCatalogPromptId,
|
|
@@ -34015,8 +34277,8 @@ function handleBridgePrompt(msg, deps) {
|
|
|
34015
34277
|
e2ee: deps.e2ee
|
|
34016
34278
|
});
|
|
34017
34279
|
}
|
|
34018
|
-
void sessionWorktreeManager.
|
|
34019
|
-
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)}`);
|
|
34020
34282
|
void preambleAndPrompt(void 0);
|
|
34021
34283
|
});
|
|
34022
34284
|
}
|
|
@@ -34099,7 +34361,7 @@ import path31 from "node:path";
|
|
|
34099
34361
|
|
|
34100
34362
|
// src/files/ensure-under-cwd.ts
|
|
34101
34363
|
import path30 from "node:path";
|
|
34102
|
-
function ensureUnderCwd(relativePath, cwd =
|
|
34364
|
+
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
34103
34365
|
const normalized = path30.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
34104
34366
|
const resolved = path30.resolve(cwd, normalized);
|
|
34105
34367
|
if (!resolved.startsWith(cwd + path30.sep) && resolved !== cwd) {
|
|
@@ -34111,7 +34373,7 @@ function ensureUnderCwd(relativePath, cwd = getBridgeWorkspaceDirectory()) {
|
|
|
34111
34373
|
// src/files/list-dir.ts
|
|
34112
34374
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
34113
34375
|
async function listDirAsync(relativePath) {
|
|
34114
|
-
const resolved = ensureUnderCwd(relativePath || ".",
|
|
34376
|
+
const resolved = ensureUnderCwd(relativePath || ".", getBridgeRoot());
|
|
34115
34377
|
if (!resolved) {
|
|
34116
34378
|
return { error: "Path is outside working directory" };
|
|
34117
34379
|
}
|
|
@@ -34157,7 +34419,7 @@ async function listDirAsync(relativePath) {
|
|
|
34157
34419
|
import fs29 from "node:fs";
|
|
34158
34420
|
import { StringDecoder } from "node:string_decoder";
|
|
34159
34421
|
function resolveFilePath(relativePath) {
|
|
34160
|
-
const resolved = ensureUnderCwd(relativePath,
|
|
34422
|
+
const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
|
|
34161
34423
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
34162
34424
|
let real;
|
|
34163
34425
|
try {
|
|
@@ -34350,7 +34612,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
34350
34612
|
void (async () => {
|
|
34351
34613
|
await yieldToEventLoop();
|
|
34352
34614
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
34353
|
-
const cwd =
|
|
34615
|
+
const cwd = getBridgeRoot();
|
|
34354
34616
|
const index = loadFileIndex(cwd);
|
|
34355
34617
|
if (index === null) {
|
|
34356
34618
|
const payload2 = {
|
|
@@ -34374,7 +34636,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
34374
34636
|
}
|
|
34375
34637
|
function triggerFileIndexBuild() {
|
|
34376
34638
|
setImmediate(() => {
|
|
34377
|
-
void ensureFileIndexAsync(
|
|
34639
|
+
void ensureFileIndexAsync(getBridgeRoot()).catch((e) => {
|
|
34378
34640
|
console.error("[file-index] Background build failed:", e);
|
|
34379
34641
|
});
|
|
34380
34642
|
});
|
|
@@ -34443,7 +34705,7 @@ function handleFileBrowserSearchMessage(msg, { getWs, e2ee }) {
|
|
|
34443
34705
|
function handleSkillLayoutRequest(msg, deps) {
|
|
34444
34706
|
const socket = deps.getWs();
|
|
34445
34707
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
34446
|
-
const roots = discoverSkillLayoutRoots(
|
|
34708
|
+
const roots = discoverSkillLayoutRoots(getBridgeRoot());
|
|
34447
34709
|
if (socket) {
|
|
34448
34710
|
sendWsMessage(socket, { type: "skill_layout_response", id, roots });
|
|
34449
34711
|
}
|
|
@@ -34491,7 +34753,7 @@ var handleInstallSkillsMessage = (msg, deps) => {
|
|
|
34491
34753
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
34492
34754
|
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
34493
34755
|
const rawItems = msg.items;
|
|
34494
|
-
const cwd =
|
|
34756
|
+
const cwd = getBridgeRoot();
|
|
34495
34757
|
const result = installRemoteSkills(cwd, targetDir, rawItems);
|
|
34496
34758
|
if (!result.success) {
|
|
34497
34759
|
const err = result.error ?? "Invalid items";
|
|
@@ -34630,7 +34892,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
34630
34892
|
void (async () => {
|
|
34631
34893
|
const s = getWs();
|
|
34632
34894
|
if (!s) return;
|
|
34633
|
-
const agentBase = sessionWorktreeManager.
|
|
34895
|
+
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
34634
34896
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
34635
34897
|
if (!fs31.existsSync(file2)) {
|
|
34636
34898
|
sendWsMessage(s, {
|
|
@@ -34990,9 +35252,9 @@ async function createBridgeConnection(options) {
|
|
|
34990
35252
|
firehoseGeneration: 0,
|
|
34991
35253
|
firehoseQuiet: createEmptyReconnectQuietSlot()
|
|
34992
35254
|
};
|
|
34993
|
-
const
|
|
35255
|
+
const worktreesRootPath = options.worktreesRootPath ?? defaultWorktreesRootPath();
|
|
34994
35256
|
const sessionWorktreeManager = new SessionWorktreeManager({
|
|
34995
|
-
|
|
35257
|
+
worktreesRootPath,
|
|
34996
35258
|
log: logFn
|
|
34997
35259
|
});
|
|
34998
35260
|
const acpManager = await createAcpManager({ log: logFn });
|
|
@@ -35001,7 +35263,7 @@ async function createBridgeConnection(options) {
|
|
|
35001
35263
|
return state.currentWs;
|
|
35002
35264
|
}
|
|
35003
35265
|
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
35004
|
-
const devServerManager = new DevServerManager({ getWs, log: logFn,
|
|
35266
|
+
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
|
|
35005
35267
|
const onBridgeIdentified = createOnBridgeIdentified({
|
|
35006
35268
|
devServerManager,
|
|
35007
35269
|
firehoseServerUrl,
|
|
@@ -35025,8 +35287,8 @@ async function createBridgeConnection(options) {
|
|
|
35025
35287
|
getCloudAccessToken: () => tokens.accessToken
|
|
35026
35288
|
};
|
|
35027
35289
|
const identifyReportedPaths = {
|
|
35028
|
-
bridgeRootPath: path33.resolve(
|
|
35029
|
-
worktreesRootPath: path33.resolve(
|
|
35290
|
+
bridgeRootPath: path33.resolve(getBridgeRoot()),
|
|
35291
|
+
worktreesRootPath: path33.resolve(worktreesRootPath)
|
|
35030
35292
|
};
|
|
35031
35293
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
35032
35294
|
state,
|
|
@@ -35043,7 +35305,7 @@ async function createBridgeConnection(options) {
|
|
|
35043
35305
|
identifyReportedPaths
|
|
35044
35306
|
});
|
|
35045
35307
|
connect();
|
|
35046
|
-
const stopFileIndexWatcher = startFileIndexWatcher(
|
|
35308
|
+
const stopFileIndexWatcher = startFileIndexWatcher(getBridgeRoot());
|
|
35047
35309
|
return {
|
|
35048
35310
|
close: async () => {
|
|
35049
35311
|
stopFileIndexWatcher();
|
|
@@ -35113,7 +35375,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
35113
35375
|
authToken,
|
|
35114
35376
|
refreshToken,
|
|
35115
35377
|
justAuthenticated,
|
|
35116
|
-
|
|
35378
|
+
worktreesRootPath,
|
|
35117
35379
|
e2eCertificate
|
|
35118
35380
|
} = options;
|
|
35119
35381
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
@@ -35125,7 +35387,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
35125
35387
|
refreshToken,
|
|
35126
35388
|
firehoseServerUrl,
|
|
35127
35389
|
justAuthenticated,
|
|
35128
|
-
|
|
35390
|
+
worktreesRootPath,
|
|
35129
35391
|
e2eCertificate,
|
|
35130
35392
|
log,
|
|
35131
35393
|
persistTokens: (t) => {
|
|
@@ -35140,7 +35402,7 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
35140
35402
|
log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
|
|
35141
35403
|
clearConfigForApi(apiUrl);
|
|
35142
35404
|
void handle.close().then(() => {
|
|
35143
|
-
void restartWithoutAuth({ apiUrl, firehoseServerUrl,
|
|
35405
|
+
void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootPath, e2eCertificate });
|
|
35144
35406
|
});
|
|
35145
35407
|
}
|
|
35146
35408
|
});
|
|
@@ -35188,7 +35450,7 @@ async function runBridge(options) {
|
|
|
35188
35450
|
workspaceId,
|
|
35189
35451
|
authToken,
|
|
35190
35452
|
bridgeName,
|
|
35191
|
-
|
|
35453
|
+
worktreesRootPath,
|
|
35192
35454
|
e2eCertificate
|
|
35193
35455
|
} = options;
|
|
35194
35456
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
@@ -35233,7 +35495,7 @@ async function runBridge(options) {
|
|
|
35233
35495
|
firehoseServerUrl,
|
|
35234
35496
|
bridgeName,
|
|
35235
35497
|
justAuthenticated: true,
|
|
35236
|
-
|
|
35498
|
+
worktreesRootPath,
|
|
35237
35499
|
e2eCertificate
|
|
35238
35500
|
});
|
|
35239
35501
|
return;
|