@buildautomaton/cli 0.1.8 → 0.1.9
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 +5163 -4889
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1944 -1670
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4065,8 +4065,8 @@ var init_parseUtil = __esm({
|
|
|
4065
4065
|
init_errors();
|
|
4066
4066
|
init_en();
|
|
4067
4067
|
makeIssue = (params) => {
|
|
4068
|
-
const { data, path:
|
|
4069
|
-
const fullPath = [...
|
|
4068
|
+
const { data, path: path29, errorMaps, issueData } = params;
|
|
4069
|
+
const fullPath = [...path29, ...issueData.path || []];
|
|
4070
4070
|
const fullIssue = {
|
|
4071
4071
|
...issueData,
|
|
4072
4072
|
path: fullPath
|
|
@@ -4374,11 +4374,11 @@ var init_types = __esm({
|
|
|
4374
4374
|
init_parseUtil();
|
|
4375
4375
|
init_util();
|
|
4376
4376
|
ParseInputLazyPath = class {
|
|
4377
|
-
constructor(parent, value,
|
|
4377
|
+
constructor(parent, value, path29, key) {
|
|
4378
4378
|
this._cachedPath = [];
|
|
4379
4379
|
this.parent = parent;
|
|
4380
4380
|
this.data = value;
|
|
4381
|
-
this._path =
|
|
4381
|
+
this._path = path29;
|
|
4382
4382
|
this._key = key;
|
|
4383
4383
|
}
|
|
4384
4384
|
get path() {
|
|
@@ -7993,10 +7993,10 @@ function assignProp(target, prop, value) {
|
|
|
7993
7993
|
configurable: true
|
|
7994
7994
|
});
|
|
7995
7995
|
}
|
|
7996
|
-
function getElementAtPath(obj,
|
|
7997
|
-
if (!
|
|
7996
|
+
function getElementAtPath(obj, path29) {
|
|
7997
|
+
if (!path29)
|
|
7998
7998
|
return obj;
|
|
7999
|
-
return
|
|
7999
|
+
return path29.reduce((acc, key) => acc?.[key], obj);
|
|
8000
8000
|
}
|
|
8001
8001
|
function promiseAllObject(promisesObj) {
|
|
8002
8002
|
const keys = Object.keys(promisesObj);
|
|
@@ -8245,11 +8245,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8245
8245
|
}
|
|
8246
8246
|
return false;
|
|
8247
8247
|
}
|
|
8248
|
-
function prefixIssues(
|
|
8248
|
+
function prefixIssues(path29, issues) {
|
|
8249
8249
|
return issues.map((iss) => {
|
|
8250
8250
|
var _a2;
|
|
8251
8251
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8252
|
-
iss.path.unshift(
|
|
8252
|
+
iss.path.unshift(path29);
|
|
8253
8253
|
return iss;
|
|
8254
8254
|
});
|
|
8255
8255
|
}
|
|
@@ -8438,7 +8438,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8438
8438
|
return issue2.message;
|
|
8439
8439
|
};
|
|
8440
8440
|
const result = { errors: [] };
|
|
8441
|
-
const processError = (error41,
|
|
8441
|
+
const processError = (error41, path29 = []) => {
|
|
8442
8442
|
var _a2, _b;
|
|
8443
8443
|
for (const issue2 of error41.issues) {
|
|
8444
8444
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8448,7 +8448,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8448
8448
|
} else if (issue2.code === "invalid_element") {
|
|
8449
8449
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8450
8450
|
} else {
|
|
8451
|
-
const fullpath = [...
|
|
8451
|
+
const fullpath = [...path29, ...issue2.path];
|
|
8452
8452
|
if (fullpath.length === 0) {
|
|
8453
8453
|
result.errors.push(mapper(issue2));
|
|
8454
8454
|
continue;
|
|
@@ -8478,9 +8478,9 @@ function treeifyError(error40, _mapper) {
|
|
|
8478
8478
|
processError(error40);
|
|
8479
8479
|
return result;
|
|
8480
8480
|
}
|
|
8481
|
-
function toDotPath(
|
|
8481
|
+
function toDotPath(path29) {
|
|
8482
8482
|
const segs = [];
|
|
8483
|
-
for (const seg of
|
|
8483
|
+
for (const seg of path29) {
|
|
8484
8484
|
if (typeof seg === "number")
|
|
8485
8485
|
segs.push(`[${seg}]`);
|
|
8486
8486
|
else if (typeof seg === "symbol")
|
|
@@ -21963,10 +21963,10 @@ var require_src2 = __commonJS({
|
|
|
21963
21963
|
var fs_1 = __require("fs");
|
|
21964
21964
|
var debug_1 = __importDefault(require_src());
|
|
21965
21965
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
21966
|
-
function check2(
|
|
21967
|
-
log2(`checking %s`,
|
|
21966
|
+
function check2(path29, isFile, isDirectory) {
|
|
21967
|
+
log2(`checking %s`, path29);
|
|
21968
21968
|
try {
|
|
21969
|
-
const stat2 = fs_1.statSync(
|
|
21969
|
+
const stat2 = fs_1.statSync(path29);
|
|
21970
21970
|
if (stat2.isFile() && isFile) {
|
|
21971
21971
|
log2(`[OK] path represents a file`);
|
|
21972
21972
|
return true;
|
|
@@ -21986,8 +21986,8 @@ var require_src2 = __commonJS({
|
|
|
21986
21986
|
throw e;
|
|
21987
21987
|
}
|
|
21988
21988
|
}
|
|
21989
|
-
function exists2(
|
|
21990
|
-
return check2(
|
|
21989
|
+
function exists2(path29, type = exports.READABLE) {
|
|
21990
|
+
return check2(path29, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
21991
21991
|
}
|
|
21992
21992
|
exports.exists = exists2;
|
|
21993
21993
|
exports.FILE = 1;
|
|
@@ -22426,7 +22426,7 @@ function localAgentErrorSuggestsAuth(agentType, errorText) {
|
|
|
22426
22426
|
return hints.some((re) => re.test(String(errorText)));
|
|
22427
22427
|
}
|
|
22428
22428
|
|
|
22429
|
-
// src/acp/clients/sdk-stdio-acp-client.ts
|
|
22429
|
+
// src/agents/acp/clients/sdk-stdio-acp-client.ts
|
|
22430
22430
|
import { spawn } from "node:child_process";
|
|
22431
22431
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
22432
22432
|
import { dirname } from "node:path";
|
|
@@ -22488,7 +22488,7 @@ function getBridgeWorkspaceDirectory() {
|
|
|
22488
22488
|
return bridgeWorkspaceDirectory;
|
|
22489
22489
|
}
|
|
22490
22490
|
|
|
22491
|
-
// src/acp/safe-fs-path.ts
|
|
22491
|
+
// src/agents/acp/safe-fs-path.ts
|
|
22492
22492
|
import * as path2 from "node:path";
|
|
22493
22493
|
function resolveSafePathUnderCwd(cwd, filePath) {
|
|
22494
22494
|
const trimmed2 = filePath.trim();
|
|
@@ -22506,7 +22506,7 @@ function toDisplayPathRelativeToCwd(cwd, absolutePath) {
|
|
|
22506
22506
|
return rel.split(path2.sep).join("/");
|
|
22507
22507
|
}
|
|
22508
22508
|
|
|
22509
|
-
// src/acp/clients/agent-stderr-capture.ts
|
|
22509
|
+
// src/agents/acp/clients/agent-stderr-capture.ts
|
|
22510
22510
|
var STDERR_CAPTURE_MAX = 48e3;
|
|
22511
22511
|
function createStderrCapture(child) {
|
|
22512
22512
|
const chunks = [];
|
|
@@ -22553,7 +22553,7 @@ function mergeErrorWithStderr(primary, stderrText) {
|
|
|
22553
22553
|
${s}`;
|
|
22554
22554
|
}
|
|
22555
22555
|
|
|
22556
|
-
// src/acp/clients/kiro-sdk-ext-notifications.ts
|
|
22556
|
+
// src/agents/acp/clients/kiro-sdk-ext-notifications.ts
|
|
22557
22557
|
function createKiroSdkExtNotificationHandler(options) {
|
|
22558
22558
|
const { onSessionUpdate } = options;
|
|
22559
22559
|
return async (method, params) => {
|
|
@@ -22570,7 +22570,7 @@ function createKiroSdkExtNotificationHandler(options) {
|
|
|
22570
22570
|
};
|
|
22571
22571
|
}
|
|
22572
22572
|
|
|
22573
|
-
// src/acp/clients/sdk-stdio-ext-notifications.ts
|
|
22573
|
+
// src/agents/acp/clients/sdk-stdio-ext-notifications.ts
|
|
22574
22574
|
var noopExtNotification = async () => {
|
|
22575
22575
|
};
|
|
22576
22576
|
function createSdkStdioExtNotificationHandler(options) {
|
|
@@ -22583,7 +22583,7 @@ function createSdkStdioExtNotificationHandler(options) {
|
|
|
22583
22583
|
}
|
|
22584
22584
|
}
|
|
22585
22585
|
|
|
22586
|
-
// src/acp/clients/sdk-stdio-acp-client.ts
|
|
22586
|
+
// src/agents/acp/clients/sdk-stdio-acp-client.ts
|
|
22587
22587
|
function formatSpawnError(err, command) {
|
|
22588
22588
|
if (err.code === "ENOENT") {
|
|
22589
22589
|
return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
|
|
@@ -22951,8 +22951,8 @@ function randomSecret() {
|
|
|
22951
22951
|
}
|
|
22952
22952
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
22953
22953
|
}
|
|
22954
|
-
async function requestPreviewApi(port, secret, method,
|
|
22955
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
22954
|
+
async function requestPreviewApi(port, secret, method, path29, body) {
|
|
22955
|
+
const url2 = `http://127.0.0.1:${port}${path29}`;
|
|
22956
22956
|
const headers = {
|
|
22957
22957
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
22958
22958
|
"Content-Type": "application/json"
|
|
@@ -22964,7 +22964,7 @@ async function requestPreviewApi(port, secret, method, path24, body) {
|
|
|
22964
22964
|
});
|
|
22965
22965
|
const data = await res.json().catch(() => ({}));
|
|
22966
22966
|
if (!res.ok) {
|
|
22967
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
22967
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path29}: ${res.status}`);
|
|
22968
22968
|
}
|
|
22969
22969
|
return data;
|
|
22970
22970
|
}
|
|
@@ -23514,13 +23514,64 @@ function runPendingAuth(options) {
|
|
|
23514
23514
|
};
|
|
23515
23515
|
}
|
|
23516
23516
|
|
|
23517
|
-
// src/bridge/connection/
|
|
23518
|
-
function
|
|
23519
|
-
const
|
|
23520
|
-
|
|
23521
|
-
|
|
23517
|
+
// src/bridge/connection/close-bridge-connection.ts
|
|
23518
|
+
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
23519
|
+
const say = log2 ?? logImmediate;
|
|
23520
|
+
say("Cleaning up connections\u2026");
|
|
23521
|
+
await new Promise((resolve14) => setImmediate(resolve14));
|
|
23522
|
+
state.closedByUser = true;
|
|
23523
|
+
clearReconnectQuietTimer(state.mainQuiet);
|
|
23524
|
+
clearReconnectQuietTimer(state.firehoseQuiet);
|
|
23525
|
+
if (state.reconnectTimeout != null) {
|
|
23526
|
+
say("Cancelling bridge reconnect timer\u2026");
|
|
23527
|
+
clearTimeout(state.reconnectTimeout);
|
|
23528
|
+
state.reconnectTimeout = null;
|
|
23529
|
+
}
|
|
23530
|
+
if (state.firehoseReconnectTimeout != null) {
|
|
23531
|
+
say("Cancelling preview tunnel reconnect timer\u2026");
|
|
23532
|
+
clearTimeout(state.firehoseReconnectTimeout);
|
|
23533
|
+
state.firehoseReconnectTimeout = null;
|
|
23534
|
+
}
|
|
23535
|
+
if (state.firehoseHandle) {
|
|
23536
|
+
say("Closing preview tunnel (local HTTP proxy and dev logs)\u2026");
|
|
23537
|
+
state.firehoseHandle.close();
|
|
23538
|
+
state.firehoseHandle = null;
|
|
23539
|
+
}
|
|
23540
|
+
say("Disconnecting local agent\u2026");
|
|
23541
|
+
acpManager.disconnect();
|
|
23542
|
+
if (state.currentWs) {
|
|
23543
|
+
say("Closing bridge connection to the cloud\u2026");
|
|
23544
|
+
state.currentWs.removeAllListeners();
|
|
23545
|
+
const wsState = state.currentWs.readyState;
|
|
23546
|
+
if (wsState === 1 || wsState === 2) {
|
|
23547
|
+
state.currentWs.close();
|
|
23548
|
+
} else {
|
|
23549
|
+
state.currentWs.on("error", () => {
|
|
23550
|
+
});
|
|
23551
|
+
state.currentWs.on("close", () => {
|
|
23552
|
+
});
|
|
23553
|
+
}
|
|
23554
|
+
state.currentWs = null;
|
|
23555
|
+
}
|
|
23556
|
+
if (devServerManager) {
|
|
23557
|
+
say("Stopping local dev server processes\u2026");
|
|
23558
|
+
await devServerManager.shutdownAllGraceful();
|
|
23559
|
+
}
|
|
23560
|
+
say("Shutdown complete.");
|
|
23522
23561
|
}
|
|
23523
23562
|
|
|
23563
|
+
// src/git/session-git-queue.ts
|
|
23564
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
23565
|
+
import { readFile, stat } from "node:fs/promises";
|
|
23566
|
+
import { promisify as promisify2 } from "node:util";
|
|
23567
|
+
import * as path6 from "node:path";
|
|
23568
|
+
|
|
23569
|
+
// src/git/pre-turn-snapshot.ts
|
|
23570
|
+
import * as fs3 from "node:fs";
|
|
23571
|
+
import * as path5 from "node:path";
|
|
23572
|
+
import { execFile } from "node:child_process";
|
|
23573
|
+
import { promisify } from "node:util";
|
|
23574
|
+
|
|
23524
23575
|
// src/git/discover-repos.ts
|
|
23525
23576
|
import * as fs2 from "node:fs";
|
|
23526
23577
|
import * as path4 from "node:path";
|
|
@@ -23562,8 +23613,8 @@ function pathspec(...paths) {
|
|
|
23562
23613
|
cache.set(key, paths);
|
|
23563
23614
|
return key;
|
|
23564
23615
|
}
|
|
23565
|
-
function isPathSpec(
|
|
23566
|
-
return
|
|
23616
|
+
function isPathSpec(path29) {
|
|
23617
|
+
return path29 instanceof String && cache.has(path29);
|
|
23567
23618
|
}
|
|
23568
23619
|
function toPaths(pathSpec) {
|
|
23569
23620
|
return cache.get(pathSpec) || [];
|
|
@@ -23652,8 +23703,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
23652
23703
|
function forEachLineWithContent(input, callback) {
|
|
23653
23704
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
23654
23705
|
}
|
|
23655
|
-
function folderExists(
|
|
23656
|
-
return (0, import_file_exists.exists)(
|
|
23706
|
+
function folderExists(path29) {
|
|
23707
|
+
return (0, import_file_exists.exists)(path29, import_file_exists.FOLDER);
|
|
23657
23708
|
}
|
|
23658
23709
|
function append(target, item) {
|
|
23659
23710
|
if (Array.isArray(target)) {
|
|
@@ -24057,8 +24108,8 @@ function checkIsRepoRootTask() {
|
|
|
24057
24108
|
commands,
|
|
24058
24109
|
format: "utf-8",
|
|
24059
24110
|
onError,
|
|
24060
|
-
parser(
|
|
24061
|
-
return /^\.(git)?$/.test(
|
|
24111
|
+
parser(path29) {
|
|
24112
|
+
return /^\.(git)?$/.test(path29.trim());
|
|
24062
24113
|
}
|
|
24063
24114
|
};
|
|
24064
24115
|
}
|
|
@@ -24492,11 +24543,11 @@ function parseGrep(grep) {
|
|
|
24492
24543
|
const paths = /* @__PURE__ */ new Set();
|
|
24493
24544
|
const results = {};
|
|
24494
24545
|
forEachLineWithContent(grep, (input) => {
|
|
24495
|
-
const [
|
|
24496
|
-
paths.add(
|
|
24497
|
-
(results[
|
|
24546
|
+
const [path29, line, preview] = input.split(NULL);
|
|
24547
|
+
paths.add(path29);
|
|
24548
|
+
(results[path29] = results[path29] || []).push({
|
|
24498
24549
|
line: asNumber(line),
|
|
24499
|
-
path:
|
|
24550
|
+
path: path29,
|
|
24500
24551
|
preview
|
|
24501
24552
|
});
|
|
24502
24553
|
});
|
|
@@ -25261,14 +25312,14 @@ var init_hash_object = __esm2({
|
|
|
25261
25312
|
init_task();
|
|
25262
25313
|
}
|
|
25263
25314
|
});
|
|
25264
|
-
function parseInit(bare,
|
|
25315
|
+
function parseInit(bare, path29, text) {
|
|
25265
25316
|
const response = String(text).trim();
|
|
25266
25317
|
let result;
|
|
25267
25318
|
if (result = initResponseRegex.exec(response)) {
|
|
25268
|
-
return new InitSummary(bare,
|
|
25319
|
+
return new InitSummary(bare, path29, false, result[1]);
|
|
25269
25320
|
}
|
|
25270
25321
|
if (result = reInitResponseRegex.exec(response)) {
|
|
25271
|
-
return new InitSummary(bare,
|
|
25322
|
+
return new InitSummary(bare, path29, true, result[1]);
|
|
25272
25323
|
}
|
|
25273
25324
|
let gitDir = "";
|
|
25274
25325
|
const tokens = response.split(" ");
|
|
@@ -25279,7 +25330,7 @@ function parseInit(bare, path24, text) {
|
|
|
25279
25330
|
break;
|
|
25280
25331
|
}
|
|
25281
25332
|
}
|
|
25282
|
-
return new InitSummary(bare,
|
|
25333
|
+
return new InitSummary(bare, path29, /^re/i.test(response), gitDir);
|
|
25283
25334
|
}
|
|
25284
25335
|
var InitSummary;
|
|
25285
25336
|
var initResponseRegex;
|
|
@@ -25288,9 +25339,9 @@ var init_InitSummary = __esm2({
|
|
|
25288
25339
|
"src/lib/responses/InitSummary.ts"() {
|
|
25289
25340
|
"use strict";
|
|
25290
25341
|
InitSummary = class {
|
|
25291
|
-
constructor(bare,
|
|
25342
|
+
constructor(bare, path29, existing, gitDir) {
|
|
25292
25343
|
this.bare = bare;
|
|
25293
|
-
this.path =
|
|
25344
|
+
this.path = path29;
|
|
25294
25345
|
this.existing = existing;
|
|
25295
25346
|
this.gitDir = gitDir;
|
|
25296
25347
|
}
|
|
@@ -25302,7 +25353,7 @@ var init_InitSummary = __esm2({
|
|
|
25302
25353
|
function hasBareCommand(command) {
|
|
25303
25354
|
return command.includes(bareCommand);
|
|
25304
25355
|
}
|
|
25305
|
-
function initTask(bare = false,
|
|
25356
|
+
function initTask(bare = false, path29, customArgs) {
|
|
25306
25357
|
const commands = ["init", ...customArgs];
|
|
25307
25358
|
if (bare && !hasBareCommand(commands)) {
|
|
25308
25359
|
commands.splice(1, 0, bareCommand);
|
|
@@ -25311,7 +25362,7 @@ function initTask(bare = false, path24, customArgs) {
|
|
|
25311
25362
|
commands,
|
|
25312
25363
|
format: "utf-8",
|
|
25313
25364
|
parser(text) {
|
|
25314
|
-
return parseInit(commands.includes("--bare"),
|
|
25365
|
+
return parseInit(commands.includes("--bare"), path29, text);
|
|
25315
25366
|
}
|
|
25316
25367
|
};
|
|
25317
25368
|
}
|
|
@@ -26127,12 +26178,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
26127
26178
|
"use strict";
|
|
26128
26179
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
26129
26180
|
FileStatusSummary = class {
|
|
26130
|
-
constructor(
|
|
26131
|
-
this.path =
|
|
26181
|
+
constructor(path29, index, working_dir) {
|
|
26182
|
+
this.path = path29;
|
|
26132
26183
|
this.index = index;
|
|
26133
26184
|
this.working_dir = working_dir;
|
|
26134
26185
|
if (index === "R" || working_dir === "R") {
|
|
26135
|
-
const detail = fromPathRegex.exec(
|
|
26186
|
+
const detail = fromPathRegex.exec(path29) || [null, path29, path29];
|
|
26136
26187
|
this.from = detail[2] || "";
|
|
26137
26188
|
this.path = detail[1] || "";
|
|
26138
26189
|
}
|
|
@@ -26163,14 +26214,14 @@ function splitLine(result, lineStr) {
|
|
|
26163
26214
|
default:
|
|
26164
26215
|
return;
|
|
26165
26216
|
}
|
|
26166
|
-
function data(index, workingDir,
|
|
26217
|
+
function data(index, workingDir, path29) {
|
|
26167
26218
|
const raw = `${index}${workingDir}`;
|
|
26168
26219
|
const handler = parsers6.get(raw);
|
|
26169
26220
|
if (handler) {
|
|
26170
|
-
handler(result,
|
|
26221
|
+
handler(result, path29);
|
|
26171
26222
|
}
|
|
26172
26223
|
if (raw !== "##" && raw !== "!!") {
|
|
26173
|
-
result.files.push(new FileStatusSummary(
|
|
26224
|
+
result.files.push(new FileStatusSummary(path29, index, workingDir));
|
|
26174
26225
|
}
|
|
26175
26226
|
}
|
|
26176
26227
|
}
|
|
@@ -26479,9 +26530,9 @@ var init_simple_git_api = __esm2({
|
|
|
26479
26530
|
next
|
|
26480
26531
|
);
|
|
26481
26532
|
}
|
|
26482
|
-
hashObject(
|
|
26533
|
+
hashObject(path29, write) {
|
|
26483
26534
|
return this._runTask(
|
|
26484
|
-
hashObjectTask(
|
|
26535
|
+
hashObjectTask(path29, write === true),
|
|
26485
26536
|
trailingFunctionArgument(arguments)
|
|
26486
26537
|
);
|
|
26487
26538
|
}
|
|
@@ -26834,8 +26885,8 @@ var init_branch = __esm2({
|
|
|
26834
26885
|
}
|
|
26835
26886
|
});
|
|
26836
26887
|
function toPath(input) {
|
|
26837
|
-
const
|
|
26838
|
-
return
|
|
26888
|
+
const path29 = input.trim().replace(/^["']|["']$/g, "");
|
|
26889
|
+
return path29 && normalize2(path29);
|
|
26839
26890
|
}
|
|
26840
26891
|
var parseCheckIgnore;
|
|
26841
26892
|
var init_CheckIgnore = __esm2({
|
|
@@ -27149,8 +27200,8 @@ __export2(sub_module_exports, {
|
|
|
27149
27200
|
subModuleTask: () => subModuleTask,
|
|
27150
27201
|
updateSubModuleTask: () => updateSubModuleTask
|
|
27151
27202
|
});
|
|
27152
|
-
function addSubModuleTask(repo,
|
|
27153
|
-
return subModuleTask(["add", repo,
|
|
27203
|
+
function addSubModuleTask(repo, path29) {
|
|
27204
|
+
return subModuleTask(["add", repo, path29]);
|
|
27154
27205
|
}
|
|
27155
27206
|
function initSubModuleTask(customArgs) {
|
|
27156
27207
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -27483,8 +27534,8 @@ var require_git = __commonJS2({
|
|
|
27483
27534
|
}
|
|
27484
27535
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
27485
27536
|
};
|
|
27486
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
27487
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
27537
|
+
Git2.prototype.submoduleAdd = function(repo, path29, then) {
|
|
27538
|
+
return this._runTask(addSubModuleTask2(repo, path29), trailingFunctionArgument2(arguments));
|
|
27488
27539
|
};
|
|
27489
27540
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
27490
27541
|
return this._runTask(
|
|
@@ -28160,84 +28211,7 @@ async function discoverGitReposUnderRoot(rootAbs) {
|
|
|
28160
28211
|
return out;
|
|
28161
28212
|
}
|
|
28162
28213
|
|
|
28163
|
-
// src/bridge/connection/report-git-repos.ts
|
|
28164
|
-
function reportGitRepos(getWs, log2) {
|
|
28165
|
-
setImmediate(() => {
|
|
28166
|
-
discoverGitRepos().then((repos) => {
|
|
28167
|
-
if (repos.length > 0) {
|
|
28168
|
-
const socket = getWs();
|
|
28169
|
-
if (socket) {
|
|
28170
|
-
sendWsMessage(socket, {
|
|
28171
|
-
type: "git_repos",
|
|
28172
|
-
repos: repos.map((r) => ({ absolutePath: r.absolutePath, remoteUrl: r.remoteUrl }))
|
|
28173
|
-
});
|
|
28174
|
-
}
|
|
28175
|
-
}
|
|
28176
|
-
}).catch((err) => {
|
|
28177
|
-
log2(
|
|
28178
|
-
`[Bridge service] Git repository discovery failed: ${err instanceof Error ? err.message : String(err)}`
|
|
28179
|
-
);
|
|
28180
|
-
});
|
|
28181
|
-
});
|
|
28182
|
-
}
|
|
28183
|
-
|
|
28184
|
-
// src/bridge/connection/close-bridge-connection.ts
|
|
28185
|
-
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
28186
|
-
const say = log2 ?? logImmediate;
|
|
28187
|
-
say("Cleaning up connections\u2026");
|
|
28188
|
-
await new Promise((resolve14) => setImmediate(resolve14));
|
|
28189
|
-
state.closedByUser = true;
|
|
28190
|
-
clearReconnectQuietTimer(state.mainQuiet);
|
|
28191
|
-
clearReconnectQuietTimer(state.firehoseQuiet);
|
|
28192
|
-
if (state.reconnectTimeout != null) {
|
|
28193
|
-
say("Cancelling bridge reconnect timer\u2026");
|
|
28194
|
-
clearTimeout(state.reconnectTimeout);
|
|
28195
|
-
state.reconnectTimeout = null;
|
|
28196
|
-
}
|
|
28197
|
-
if (state.firehoseReconnectTimeout != null) {
|
|
28198
|
-
say("Cancelling preview tunnel reconnect timer\u2026");
|
|
28199
|
-
clearTimeout(state.firehoseReconnectTimeout);
|
|
28200
|
-
state.firehoseReconnectTimeout = null;
|
|
28201
|
-
}
|
|
28202
|
-
if (state.firehoseHandle) {
|
|
28203
|
-
say("Closing preview tunnel (local HTTP proxy and dev logs)\u2026");
|
|
28204
|
-
state.firehoseHandle.close();
|
|
28205
|
-
state.firehoseHandle = null;
|
|
28206
|
-
}
|
|
28207
|
-
say("Disconnecting local agent\u2026");
|
|
28208
|
-
acpManager.disconnect();
|
|
28209
|
-
if (state.currentWs) {
|
|
28210
|
-
say("Closing bridge connection to the cloud\u2026");
|
|
28211
|
-
state.currentWs.removeAllListeners();
|
|
28212
|
-
const wsState = state.currentWs.readyState;
|
|
28213
|
-
if (wsState === 1 || wsState === 2) {
|
|
28214
|
-
state.currentWs.close();
|
|
28215
|
-
} else {
|
|
28216
|
-
state.currentWs.on("error", () => {
|
|
28217
|
-
});
|
|
28218
|
-
state.currentWs.on("close", () => {
|
|
28219
|
-
});
|
|
28220
|
-
}
|
|
28221
|
-
state.currentWs = null;
|
|
28222
|
-
}
|
|
28223
|
-
if (devServerManager) {
|
|
28224
|
-
say("Stopping local dev server processes\u2026");
|
|
28225
|
-
await devServerManager.shutdownAllGraceful();
|
|
28226
|
-
}
|
|
28227
|
-
say("Shutdown complete.");
|
|
28228
|
-
}
|
|
28229
|
-
|
|
28230
|
-
// src/git/session-git-queue.ts
|
|
28231
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
28232
|
-
import { readFile, stat } from "node:fs/promises";
|
|
28233
|
-
import { promisify as promisify2 } from "node:util";
|
|
28234
|
-
import * as path6 from "node:path";
|
|
28235
|
-
|
|
28236
28214
|
// src/git/pre-turn-snapshot.ts
|
|
28237
|
-
import * as fs3 from "node:fs";
|
|
28238
|
-
import * as path5 from "node:path";
|
|
28239
|
-
import { execFile } from "node:child_process";
|
|
28240
|
-
import { promisify } from "node:util";
|
|
28241
28215
|
var execFileAsync = promisify(execFile);
|
|
28242
28216
|
function snapshotsDirForCwd(agentCwd) {
|
|
28243
28217
|
return path5.join(agentCwd, ".buildautomaton", "snapshots");
|
|
@@ -28421,7 +28395,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
28421
28395
|
}
|
|
28422
28396
|
}
|
|
28423
28397
|
|
|
28424
|
-
// src/acp/send-prompt-to-agent.ts
|
|
28398
|
+
// src/agents/acp/send-prompt-to-agent.ts
|
|
28425
28399
|
async function sendPromptToAgent(options) {
|
|
28426
28400
|
const {
|
|
28427
28401
|
handle,
|
|
@@ -28431,7 +28405,7 @@ async function sendPromptToAgent(options) {
|
|
|
28431
28405
|
runId,
|
|
28432
28406
|
agentType,
|
|
28433
28407
|
agentCwd,
|
|
28434
|
-
sendResult,
|
|
28408
|
+
sendResult: sendResult2,
|
|
28435
28409
|
sendSessionUpdate,
|
|
28436
28410
|
log: log2
|
|
28437
28411
|
} = options;
|
|
@@ -28455,7 +28429,7 @@ async function sendPromptToAgent(options) {
|
|
|
28455
28429
|
});
|
|
28456
28430
|
}
|
|
28457
28431
|
const errStr = typeof result.error === "string" ? result.error : void 0;
|
|
28458
|
-
|
|
28432
|
+
sendResult2({
|
|
28459
28433
|
type: "prompt_result",
|
|
28460
28434
|
id: promptId,
|
|
28461
28435
|
...sessionId ? { sessionId } : {},
|
|
@@ -28469,7 +28443,7 @@ async function sendPromptToAgent(options) {
|
|
|
28469
28443
|
} catch (err) {
|
|
28470
28444
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
28471
28445
|
log2(`[Agent] Send failed: ${errMsg}`);
|
|
28472
|
-
|
|
28446
|
+
sendResult2({
|
|
28473
28447
|
type: "prompt_result",
|
|
28474
28448
|
id: promptId,
|
|
28475
28449
|
...sessionId ? { sessionId } : {},
|
|
@@ -28481,7 +28455,7 @@ async function sendPromptToAgent(options) {
|
|
|
28481
28455
|
}
|
|
28482
28456
|
}
|
|
28483
28457
|
|
|
28484
|
-
// src/acp/ensure-acp-client.ts
|
|
28458
|
+
// src/agents/acp/ensure-acp-client.ts
|
|
28485
28459
|
import * as fs4 from "node:fs";
|
|
28486
28460
|
import * as path9 from "node:path";
|
|
28487
28461
|
|
|
@@ -28495,7 +28469,7 @@ function errorMessage(err) {
|
|
|
28495
28469
|
return String(err);
|
|
28496
28470
|
}
|
|
28497
28471
|
|
|
28498
|
-
// src/acp/clients/claude-code-acp-client.ts
|
|
28472
|
+
// src/agents/acp/clients/claude-code-acp-client.ts
|
|
28499
28473
|
var claude_code_acp_client_exports = {};
|
|
28500
28474
|
__export(claude_code_acp_client_exports, {
|
|
28501
28475
|
BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE,
|
|
@@ -28506,7 +28480,7 @@ __export(claude_code_acp_client_exports, {
|
|
|
28506
28480
|
import { execFile as execFile4 } from "node:child_process";
|
|
28507
28481
|
import { promisify as promisify4 } from "node:util";
|
|
28508
28482
|
|
|
28509
|
-
// src/acp/clients/detect-command-on-path.ts
|
|
28483
|
+
// src/agents/acp/clients/detect-command-on-path.ts
|
|
28510
28484
|
import { execFile as execFile3 } from "node:child_process";
|
|
28511
28485
|
import { promisify as promisify3 } from "node:util";
|
|
28512
28486
|
var execFileAsync3 = promisify3(execFile3);
|
|
@@ -28519,7 +28493,7 @@ async function isCommandOnPath(command, timeoutMs = 4e3) {
|
|
|
28519
28493
|
}
|
|
28520
28494
|
}
|
|
28521
28495
|
|
|
28522
|
-
// src/acp/clients/claude-code-acp-client.ts
|
|
28496
|
+
// src/agents/acp/clients/claude-code-acp-client.ts
|
|
28523
28497
|
var execFileAsync4 = promisify4(execFile4);
|
|
28524
28498
|
var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
|
|
28525
28499
|
async function detectLocalAgentPresence() {
|
|
@@ -28547,7 +28521,7 @@ async function createClaudeCodeAcpClient(options) {
|
|
|
28547
28521
|
});
|
|
28548
28522
|
}
|
|
28549
28523
|
|
|
28550
|
-
// src/acp/clients/codex-acp-client.ts
|
|
28524
|
+
// src/agents/acp/clients/codex-acp-client.ts
|
|
28551
28525
|
var codex_acp_client_exports = {};
|
|
28552
28526
|
__export(codex_acp_client_exports, {
|
|
28553
28527
|
BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE2,
|
|
@@ -28575,7 +28549,7 @@ async function createCodexAcpClient(options) {
|
|
|
28575
28549
|
return createSdkStdioAcpClient({ ...options, command });
|
|
28576
28550
|
}
|
|
28577
28551
|
|
|
28578
|
-
// src/acp/clients/cursor-acp-client.ts
|
|
28552
|
+
// src/agents/acp/clients/cursor-acp-client.ts
|
|
28579
28553
|
var cursor_acp_client_exports = {};
|
|
28580
28554
|
__export(cursor_acp_client_exports, {
|
|
28581
28555
|
BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
|
|
@@ -28588,7 +28562,7 @@ import { dirname as dirname2 } from "node:path";
|
|
|
28588
28562
|
import { spawn as spawn4 } from "node:child_process";
|
|
28589
28563
|
import * as readline from "node:readline";
|
|
28590
28564
|
|
|
28591
|
-
// src/acp/format-session-update-kind-for-log.ts
|
|
28565
|
+
// src/agents/acp/format-session-update-kind-for-log.ts
|
|
28592
28566
|
var SESSION_UPDATE_KIND_LABELS = {
|
|
28593
28567
|
tool_call: "Tool call",
|
|
28594
28568
|
tool_call_update: "Tool call status",
|
|
@@ -28601,7 +28575,7 @@ function formatSessionUpdateKindForLog(kind) {
|
|
|
28601
28575
|
return kind.split("_").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
|
|
28602
28576
|
}
|
|
28603
28577
|
|
|
28604
|
-
// src/acp/clients/cursor-acp-client.ts
|
|
28578
|
+
// src/agents/acp/clients/cursor-acp-client.ts
|
|
28605
28579
|
var FS_READ_METHODS = /* @__PURE__ */ new Set(["fs/read_text_file", "fs/readTextFile"]);
|
|
28606
28580
|
var FS_WRITE_METHODS = /* @__PURE__ */ new Set(["fs/write_text_file", "fs/writeTextFile"]);
|
|
28607
28581
|
function formatSpawnError2(err, command) {
|
|
@@ -28922,7 +28896,7 @@ async function detectLocalAgentPresence3() {
|
|
|
28922
28896
|
return isCommandOnPath("agent");
|
|
28923
28897
|
}
|
|
28924
28898
|
|
|
28925
|
-
// src/acp/clients/kiro-acp-client.ts
|
|
28899
|
+
// src/agents/acp/clients/kiro-acp-client.ts
|
|
28926
28900
|
var kiro_acp_client_exports = {};
|
|
28927
28901
|
__export(kiro_acp_client_exports, {
|
|
28928
28902
|
BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE4,
|
|
@@ -28953,7 +28927,7 @@ async function createKiroAcpClient(options) {
|
|
|
28953
28927
|
return createSdkStdioAcpClient({ ...options, command });
|
|
28954
28928
|
}
|
|
28955
28929
|
|
|
28956
|
-
// src/acp/resolve-agent-command.ts
|
|
28930
|
+
// src/agents/acp/resolve-agent-command.ts
|
|
28957
28931
|
var AGENT_TYPE_DEFAULT_COMMANDS = {
|
|
28958
28932
|
[BACKEND_LOCAL_AGENT_TYPE3]: ["agent", "acp"],
|
|
28959
28933
|
[BACKEND_LOCAL_AGENT_TYPE2]: [...DEFAULT_CODEX_ACP_COMMAND],
|
|
@@ -29022,7 +28996,7 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
29022
28996
|
};
|
|
29023
28997
|
}
|
|
29024
28998
|
|
|
29025
|
-
// src/acp/session-file-change-path-kind.ts
|
|
28999
|
+
// src/agents/acp/session-file-change-path-kind.ts
|
|
29026
29000
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
29027
29001
|
import { existsSync, statSync } from "node:fs";
|
|
29028
29002
|
|
|
@@ -29043,7 +29017,7 @@ function getGitRepoRootSync(startDir) {
|
|
|
29043
29017
|
}
|
|
29044
29018
|
}
|
|
29045
29019
|
|
|
29046
|
-
// src/acp/workspace-files.ts
|
|
29020
|
+
// src/agents/acp/workspace-files.ts
|
|
29047
29021
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
29048
29022
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
29049
29023
|
import * as path8 from "node:path";
|
|
@@ -29115,7 +29089,7 @@ function readGitHeadBlob(cwd, displayPath) {
|
|
|
29115
29089
|
}
|
|
29116
29090
|
}
|
|
29117
29091
|
|
|
29118
|
-
// src/acp/session-file-change-path-kind.ts
|
|
29092
|
+
// src/agents/acp/session-file-change-path-kind.ts
|
|
29119
29093
|
function gitHeadPathObjectType(cwd, displayPath) {
|
|
29120
29094
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
29121
29095
|
const gitRoot = getGitRepoRootSync(cwd);
|
|
@@ -29147,7 +29121,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
|
|
|
29147
29121
|
return { isDirectory: false, directoryRemoved: false };
|
|
29148
29122
|
}
|
|
29149
29123
|
|
|
29150
|
-
// src/acp/hooks/bridge-on-file-change.ts
|
|
29124
|
+
// src/agents/acp/hooks/bridge-on-file-change.ts
|
|
29151
29125
|
function createBridgeOnFileChange(opts) {
|
|
29152
29126
|
const { routing, getSendSessionUpdate, log: log2 } = opts;
|
|
29153
29127
|
return (evt) => {
|
|
@@ -29180,7 +29154,7 @@ function createBridgeOnFileChange(opts) {
|
|
|
29180
29154
|
};
|
|
29181
29155
|
}
|
|
29182
29156
|
|
|
29183
|
-
// src/acp/hooks/bridge-on-request.ts
|
|
29157
|
+
// src/agents/acp/hooks/bridge-on-request.ts
|
|
29184
29158
|
function createBridgeOnRequest(opts) {
|
|
29185
29159
|
const { routing, getSendRequest, log: log2 } = opts;
|
|
29186
29160
|
return (request) => {
|
|
@@ -29211,7 +29185,7 @@ function createBridgeOnRequest(opts) {
|
|
|
29211
29185
|
};
|
|
29212
29186
|
}
|
|
29213
29187
|
|
|
29214
|
-
// src/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
|
|
29188
|
+
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
|
|
29215
29189
|
import { fileURLToPath } from "node:url";
|
|
29216
29190
|
function readOptionalTextField(v) {
|
|
29217
29191
|
if (v === null || v === void 0) return "";
|
|
@@ -29237,7 +29211,7 @@ function extractDiffPath(o) {
|
|
|
29237
29211
|
return null;
|
|
29238
29212
|
}
|
|
29239
29213
|
|
|
29240
|
-
// src/acp/hooks/extract-acp-file-diffs-from-update/push-diff.ts
|
|
29214
|
+
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/push-diff.ts
|
|
29241
29215
|
function pushDiffIfComplete(o, cwd, out) {
|
|
29242
29216
|
const t = o.type;
|
|
29243
29217
|
if (typeof t !== "string" || t.toLowerCase() !== "diff") return;
|
|
@@ -29250,7 +29224,7 @@ function pushDiffIfComplete(o, cwd, out) {
|
|
|
29250
29224
|
out.push({ path: resolved.display, oldText, newText });
|
|
29251
29225
|
}
|
|
29252
29226
|
|
|
29253
|
-
// src/acp/hooks/extract-acp-file-diffs-from-update/walk-update-for-diffs.ts
|
|
29227
|
+
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/walk-update-for-diffs.ts
|
|
29254
29228
|
var NEST_KEYS = [
|
|
29255
29229
|
"content",
|
|
29256
29230
|
"contents",
|
|
@@ -29289,7 +29263,7 @@ function walkValue(value, cwd, depth, out) {
|
|
|
29289
29263
|
}
|
|
29290
29264
|
}
|
|
29291
29265
|
|
|
29292
|
-
// src/acp/hooks/extract-acp-file-diffs-from-update/extract.ts
|
|
29266
|
+
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/extract.ts
|
|
29293
29267
|
function extractAcpFileDiffsFromUpdate(update, cwd) {
|
|
29294
29268
|
if (!update || typeof update !== "object") return [];
|
|
29295
29269
|
const u = update;
|
|
@@ -29303,7 +29277,7 @@ function extractAcpFileDiffsFromUpdate(update, cwd) {
|
|
|
29303
29277
|
return [...byPath.values()];
|
|
29304
29278
|
}
|
|
29305
29279
|
|
|
29306
|
-
// src/acp/hooks/extract-tool-target-paths.ts
|
|
29280
|
+
// src/agents/acp/hooks/extract-tool-target-paths.ts
|
|
29307
29281
|
function addPath(cwd, raw, out) {
|
|
29308
29282
|
if (typeof raw !== "string") return;
|
|
29309
29283
|
const trimmed2 = raw.trim();
|
|
@@ -29381,10 +29355,10 @@ function extractToolTargetDisplayPaths(update, cwd) {
|
|
|
29381
29355
|
return [...out];
|
|
29382
29356
|
}
|
|
29383
29357
|
|
|
29384
|
-
// src/acp/hooks/bridge-on-session-update/constants.ts
|
|
29358
|
+
// src/agents/acp/hooks/bridge-on-session-update/constants.ts
|
|
29385
29359
|
var PATH_SNAPSHOT_DEBOUNCE_MS = 500;
|
|
29386
29360
|
|
|
29387
|
-
// src/acp/hooks/bridge-on-session-update/tool-key.ts
|
|
29361
|
+
// src/agents/acp/hooks/bridge-on-session-update/tool-key.ts
|
|
29388
29362
|
function getToolCallId(params) {
|
|
29389
29363
|
if (!params || typeof params !== "object") return "";
|
|
29390
29364
|
const u = params;
|
|
@@ -29406,7 +29380,7 @@ function accumulateToolPaths(toolKey, paths, acc) {
|
|
|
29406
29380
|
for (const p of paths) s.add(p);
|
|
29407
29381
|
}
|
|
29408
29382
|
|
|
29409
|
-
// src/acp/hooks/bridge-on-session-update/path-snapshot-tracker.ts
|
|
29383
|
+
// src/agents/acp/hooks/bridge-on-session-update/path-snapshot-tracker.ts
|
|
29410
29384
|
var PathSnapshotTracker = class {
|
|
29411
29385
|
lastSeenRunId;
|
|
29412
29386
|
anonToolSeq = 0;
|
|
@@ -29528,7 +29502,7 @@ var PathSnapshotTracker = class {
|
|
|
29528
29502
|
}
|
|
29529
29503
|
};
|
|
29530
29504
|
|
|
29531
|
-
// src/acp/hooks/bridge-on-session-update/send-structured-file-changes.ts
|
|
29505
|
+
// src/agents/acp/hooks/bridge-on-session-update/send-structured-file-changes.ts
|
|
29532
29506
|
function sendExtractedDiffsAsSessionFileChanges(diffs, send, cwd, sessionId, runId, sentPaths, log2) {
|
|
29533
29507
|
for (const d of diffs) {
|
|
29534
29508
|
try {
|
|
@@ -29578,7 +29552,7 @@ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, cwd, s
|
|
|
29578
29552
|
}
|
|
29579
29553
|
}
|
|
29580
29554
|
|
|
29581
|
-
// src/acp/hooks/bridge-on-session-update/create-bridge-on-session-update.ts
|
|
29555
|
+
// src/agents/acp/hooks/bridge-on-session-update/create-bridge-on-session-update.ts
|
|
29582
29556
|
function createBridgeOnSessionUpdate(opts) {
|
|
29583
29557
|
const { routing, getSendSessionUpdate, log: log2 } = opts;
|
|
29584
29558
|
const pathTracker = new PathSnapshotTracker();
|
|
@@ -29652,7 +29626,7 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
29652
29626
|
};
|
|
29653
29627
|
}
|
|
29654
29628
|
|
|
29655
|
-
// src/acp/hooks/build-acp-session-bridge-hooks.ts
|
|
29629
|
+
// src/agents/acp/hooks/build-acp-session-bridge-hooks.ts
|
|
29656
29630
|
function buildAcpSessionBridgeHooks(opts) {
|
|
29657
29631
|
return {
|
|
29658
29632
|
onFileChange: createBridgeOnFileChange(opts),
|
|
@@ -29661,7 +29635,7 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
29661
29635
|
};
|
|
29662
29636
|
}
|
|
29663
29637
|
|
|
29664
|
-
// src/acp/ensure-acp-client.ts
|
|
29638
|
+
// src/agents/acp/ensure-acp-client.ts
|
|
29665
29639
|
async function ensureAcpClient(options) {
|
|
29666
29640
|
const { state, preferredAgentType, mode, cwd, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
|
|
29667
29641
|
const targetCwd = path9.resolve(
|
|
@@ -29747,7 +29721,7 @@ async function ensureAcpClient(options) {
|
|
|
29747
29721
|
return state.acpStartPromise;
|
|
29748
29722
|
}
|
|
29749
29723
|
|
|
29750
|
-
// src/acp/create-acp-manager.ts
|
|
29724
|
+
// src/agents/acp/create-acp-manager.ts
|
|
29751
29725
|
async function createAcpManager(options) {
|
|
29752
29726
|
const { log: log2 } = options;
|
|
29753
29727
|
const state = {
|
|
@@ -29783,7 +29757,7 @@ async function createAcpManager(options) {
|
|
|
29783
29757
|
mode,
|
|
29784
29758
|
agentType,
|
|
29785
29759
|
cwd,
|
|
29786
|
-
sendResult,
|
|
29760
|
+
sendResult: sendResult2,
|
|
29787
29761
|
sendSessionUpdate
|
|
29788
29762
|
} = opts;
|
|
29789
29763
|
const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
|
|
@@ -29807,7 +29781,7 @@ async function createAcpManager(options) {
|
|
|
29807
29781
|
const evaluated = Boolean(preferredForPrompt && errMsg.trim());
|
|
29808
29782
|
const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
|
|
29809
29783
|
const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
|
|
29810
|
-
|
|
29784
|
+
sendResult2({
|
|
29811
29785
|
type: "prompt_result",
|
|
29812
29786
|
id: promptId,
|
|
29813
29787
|
...sessionId ? { sessionId } : {},
|
|
@@ -29827,7 +29801,7 @@ async function createAcpManager(options) {
|
|
|
29827
29801
|
await handle.cancel?.();
|
|
29828
29802
|
} catch {
|
|
29829
29803
|
}
|
|
29830
|
-
|
|
29804
|
+
sendResult2({
|
|
29831
29805
|
type: "prompt_result",
|
|
29832
29806
|
id: promptId,
|
|
29833
29807
|
...sessionId ? { sessionId } : {},
|
|
@@ -29846,7 +29820,7 @@ async function createAcpManager(options) {
|
|
|
29846
29820
|
runId,
|
|
29847
29821
|
agentType: preferredForPrompt,
|
|
29848
29822
|
agentCwd: cwd,
|
|
29849
|
-
sendResult,
|
|
29823
|
+
sendResult: sendResult2,
|
|
29850
29824
|
sendSessionUpdate,
|
|
29851
29825
|
log: log2
|
|
29852
29826
|
});
|
|
@@ -29894,1375 +29868,633 @@ async function createAcpManager(options) {
|
|
|
29894
29868
|
};
|
|
29895
29869
|
}
|
|
29896
29870
|
|
|
29897
|
-
// src/
|
|
29898
|
-
|
|
29899
|
-
|
|
29900
|
-
log2("Received auth token. Save it for future runs:");
|
|
29901
|
-
log2(` export BUILDAMATON_AUTH_TOKEN="${msg.token}"`);
|
|
29902
|
-
};
|
|
29871
|
+
// src/worktrees/session-worktree-manager.ts
|
|
29872
|
+
import * as path13 from "node:path";
|
|
29873
|
+
import os3 from "node:os";
|
|
29903
29874
|
|
|
29904
|
-
// src/
|
|
29905
|
-
|
|
29906
|
-
|
|
29907
|
-
deps.onBridgeIdentified(
|
|
29908
|
-
msg
|
|
29909
|
-
);
|
|
29910
|
-
setImmediate(() => {
|
|
29911
|
-
void (async () => {
|
|
29912
|
-
try {
|
|
29913
|
-
await deps.reportAutoDetectedAgents?.();
|
|
29914
|
-
} catch (e) {
|
|
29915
|
-
deps.log(
|
|
29916
|
-
`[Bridge service] Auto-detect agents failed: ${e instanceof Error ? e.message : String(e)}`
|
|
29917
|
-
);
|
|
29918
|
-
}
|
|
29919
|
-
})();
|
|
29920
|
-
});
|
|
29921
|
-
setImmediate(() => {
|
|
29922
|
-
try {
|
|
29923
|
-
deps.sendLocalSkillsReport?.();
|
|
29924
|
-
} catch (e) {
|
|
29925
|
-
deps.log(
|
|
29926
|
-
`[Bridge service] Local skills report failed: ${e instanceof Error ? e.message : String(e)}`
|
|
29927
|
-
);
|
|
29928
|
-
}
|
|
29929
|
-
});
|
|
29930
|
-
};
|
|
29875
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
29876
|
+
import * as fs6 from "node:fs";
|
|
29877
|
+
import * as path11 from "node:path";
|
|
29931
29878
|
|
|
29932
|
-
// src/
|
|
29933
|
-
function
|
|
29934
|
-
|
|
29935
|
-
|
|
29879
|
+
// src/git/worktree-add.ts
|
|
29880
|
+
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
29881
|
+
const mainGit = simpleGit(mainRepoPath);
|
|
29882
|
+
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
|
|
29936
29883
|
}
|
|
29937
29884
|
|
|
29938
|
-
// src/
|
|
29939
|
-
|
|
29940
|
-
handleBridgeAgentConfig(msg, deps);
|
|
29941
|
-
};
|
|
29942
|
-
|
|
29943
|
-
// src/acp/from-bridge/handle-bridge-prompt.ts
|
|
29944
|
-
import * as path11 from "node:path";
|
|
29945
|
-
import { execFile as execFile5 } from "node:child_process";
|
|
29946
|
-
import { promisify as promisify5 } from "node:util";
|
|
29947
|
-
|
|
29948
|
-
// src/git/bridge-queue-key.ts
|
|
29885
|
+
// src/worktrees/worktree-layout-file.ts
|
|
29886
|
+
import * as fs5 from "node:fs";
|
|
29949
29887
|
import * as path10 from "node:path";
|
|
29950
|
-
import
|
|
29951
|
-
|
|
29952
|
-
|
|
29953
|
-
|
|
29954
|
-
|
|
29955
|
-
|
|
29888
|
+
import os2 from "node:os";
|
|
29889
|
+
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
29890
|
+
function defaultWorktreeLayoutPath() {
|
|
29891
|
+
return path10.join(os2.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
29892
|
+
}
|
|
29893
|
+
function normalizeLoadedLayout(raw) {
|
|
29894
|
+
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
29895
|
+
const j = raw;
|
|
29896
|
+
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
29956
29897
|
}
|
|
29957
|
-
|
|
29958
|
-
|
|
29959
|
-
|
|
29960
|
-
|
|
29961
|
-
const p =
|
|
29962
|
-
|
|
29963
|
-
|
|
29964
|
-
|
|
29965
|
-
|
|
29966
|
-
|
|
29967
|
-
s = `git@${host}:${sshMatch[2]}`;
|
|
29968
|
-
}
|
|
29898
|
+
return { launcherCwds: [] };
|
|
29899
|
+
}
|
|
29900
|
+
function loadWorktreeLayout() {
|
|
29901
|
+
try {
|
|
29902
|
+
const p = defaultWorktreeLayoutPath();
|
|
29903
|
+
if (!fs5.existsSync(p)) return { launcherCwds: [] };
|
|
29904
|
+
const raw = JSON.parse(fs5.readFileSync(p, "utf8"));
|
|
29905
|
+
return normalizeLoadedLayout(raw);
|
|
29906
|
+
} catch {
|
|
29907
|
+
return { launcherCwds: [] };
|
|
29969
29908
|
}
|
|
29970
|
-
return s;
|
|
29971
29909
|
}
|
|
29972
|
-
function
|
|
29973
|
-
|
|
29974
|
-
|
|
29910
|
+
function saveWorktreeLayout(layout) {
|
|
29911
|
+
try {
|
|
29912
|
+
const dir = path10.dirname(defaultWorktreeLayoutPath());
|
|
29913
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
29914
|
+
fs5.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
29915
|
+
} catch {
|
|
29916
|
+
}
|
|
29975
29917
|
}
|
|
29976
|
-
function
|
|
29977
|
-
return
|
|
29918
|
+
function baseNameSafe(abs) {
|
|
29919
|
+
return path10.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
29978
29920
|
}
|
|
29979
|
-
|
|
29980
|
-
const
|
|
29981
|
-
const
|
|
29982
|
-
if (
|
|
29983
|
-
|
|
29984
|
-
|
|
29921
|
+
function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
|
|
29922
|
+
const norm = path10.resolve(launcherCwdAbs);
|
|
29923
|
+
const existing = layout.launcherCwds.find((e) => path10.resolve(e.absolutePath) === norm);
|
|
29924
|
+
if (existing) return existing.dirName;
|
|
29925
|
+
const base = baseNameSafe(norm);
|
|
29926
|
+
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
29927
|
+
let name = base;
|
|
29928
|
+
let n = 2;
|
|
29929
|
+
while (used.has(name)) {
|
|
29930
|
+
name = `${base}-${n}`;
|
|
29931
|
+
n += 1;
|
|
29985
29932
|
}
|
|
29986
|
-
|
|
29987
|
-
|
|
29988
|
-
|
|
29989
|
-
for (const r of primaryRepoRoots.slice(1)) {
|
|
29990
|
-
const u = await getRemoteOriginUrl(r);
|
|
29991
|
-
if (u) {
|
|
29992
|
-
primaryRoot = r;
|
|
29993
|
-
remote = u;
|
|
29994
|
-
break;
|
|
29995
|
-
}
|
|
29996
|
-
}
|
|
29997
|
-
}
|
|
29998
|
-
const repoId = remote ? canonicalUrlToRepoIdSync(remote) : fallbackRepoIdFromPath(primaryRoot);
|
|
29999
|
-
const canonicalQueueKey = `repo:${repoId}::cwd:${cwdAbs}`;
|
|
30000
|
-
return { canonicalQueueKey, repoId, cwdAbs };
|
|
29933
|
+
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
29934
|
+
saveWorktreeLayout(layout);
|
|
29935
|
+
return name;
|
|
30001
29936
|
}
|
|
30002
29937
|
|
|
30003
|
-
// src/
|
|
30004
|
-
|
|
30005
|
-
|
|
30006
|
-
|
|
30007
|
-
|
|
30008
|
-
|
|
30009
|
-
|
|
30010
|
-
|
|
29938
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
29939
|
+
async function prepareNewSessionWorktrees(options) {
|
|
29940
|
+
const { rootAbs, launcherCwd, sessionId, layout, log: log2 } = options;
|
|
29941
|
+
const launcherResolved = path11.resolve(launcherCwd);
|
|
29942
|
+
const cwdKey = allocateDirNameForLauncherCwd(layout, launcherResolved);
|
|
29943
|
+
const agentMirrorRoot = path11.join(rootAbs, cwdKey);
|
|
29944
|
+
const repos = await discoverGitReposUnderRoot(launcherResolved);
|
|
29945
|
+
if (repos.length === 0) {
|
|
29946
|
+
log2("[worktrees] No Git repositories under launcher working directory; skipping worktree creation.");
|
|
30011
29947
|
return null;
|
|
30012
29948
|
}
|
|
30013
|
-
}
|
|
30014
|
-
|
|
30015
|
-
|
|
30016
|
-
const
|
|
30017
|
-
|
|
30018
|
-
|
|
30019
|
-
|
|
30020
|
-
|
|
30021
|
-
);
|
|
30022
|
-
|
|
30023
|
-
|
|
30024
|
-
|
|
30025
|
-
|
|
30026
|
-
|
|
30027
|
-
|
|
30028
|
-
|
|
30029
|
-
|
|
30030
|
-
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
30031
|
-
const sendResult = (result) => {
|
|
30032
|
-
const s = getWs();
|
|
30033
|
-
if (s) sendWsMessage(s, result);
|
|
30034
|
-
};
|
|
30035
|
-
const sendSessionUpdate = (payload) => {
|
|
30036
|
-
const s = getWs();
|
|
30037
|
-
if (!s) {
|
|
30038
|
-
log2("[Bridge service] Session update not sent: not connected to the bridge.");
|
|
30039
|
-
return;
|
|
30040
|
-
}
|
|
30041
|
-
const p = payload;
|
|
30042
|
-
sendWsMessage(s, payload);
|
|
30043
|
-
};
|
|
30044
|
-
async function preambleAndPrompt(resolvedCwd) {
|
|
30045
|
-
const s = getWs();
|
|
30046
|
-
const effectiveCwd = path11.resolve(resolvedCwd ?? getBridgeWorkspaceDirectory());
|
|
30047
|
-
const worktreePaths = sessionWorktreeManager.getWorktreePathsForSession(sessionId) ?? [];
|
|
30048
|
-
const repoRoots = await resolveSnapshotRepoRoots({
|
|
30049
|
-
worktreePaths,
|
|
30050
|
-
fallbackCwd: effectiveCwd,
|
|
30051
|
-
log: log2
|
|
30052
|
-
});
|
|
30053
|
-
if (s && sessionId) {
|
|
30054
|
-
const bind = await resolveBridgeQueueBindFields({
|
|
30055
|
-
effectiveCwd,
|
|
30056
|
-
worktreePaths,
|
|
30057
|
-
primaryRepoRoots: repoRoots,
|
|
30058
|
-
log: log2
|
|
30059
|
-
});
|
|
30060
|
-
if (bind) {
|
|
30061
|
-
sendWsMessage(s, {
|
|
30062
|
-
type: "bridge_queue_bind",
|
|
30063
|
-
sessionId,
|
|
30064
|
-
canonicalQueueKey: bind.canonicalQueueKey,
|
|
30065
|
-
repoId: bind.repoId,
|
|
30066
|
-
cwdAbs: bind.cwdAbs
|
|
30067
|
-
});
|
|
30068
|
-
}
|
|
30069
|
-
}
|
|
30070
|
-
if (s && sessionId) {
|
|
30071
|
-
const cliGitBranch = await readGitBranch(effectiveCwd);
|
|
30072
|
-
sendWsMessage(s, {
|
|
30073
|
-
type: "session_git_context_report",
|
|
30074
|
-
sessionId,
|
|
30075
|
-
cliGitBranch,
|
|
30076
|
-
agentUsesWorktree: sessionWorktreeManager.usesWorktreeSession(sessionId)
|
|
30077
|
-
});
|
|
30078
|
-
}
|
|
30079
|
-
if (s && sessionId && runId) {
|
|
30080
|
-
const cap = repoRoots.length > 0 ? await capturePreTurnSnapshot({ runId, repoRoots, agentCwd: effectiveCwd, log: log2 }) : { ok: false, error: "No git repos" };
|
|
30081
|
-
sendWsMessage(s, {
|
|
30082
|
-
type: "pre_turn_snapshot_report",
|
|
30083
|
-
sessionId,
|
|
30084
|
-
turnId: runId,
|
|
30085
|
-
captured: cap.ok
|
|
30086
|
-
});
|
|
29949
|
+
const branch = `session-${sessionId}`;
|
|
29950
|
+
const worktreePaths = [];
|
|
29951
|
+
fs6.mkdirSync(agentMirrorRoot, { recursive: true });
|
|
29952
|
+
for (const repo of repos) {
|
|
29953
|
+
let rel = path11.relative(launcherResolved, repo.absolutePath);
|
|
29954
|
+
if (rel.startsWith("..") || path11.isAbsolute(rel)) continue;
|
|
29955
|
+
const relNorm = rel === "" ? "." : rel;
|
|
29956
|
+
const wtPath = path11.join(agentMirrorRoot, relNorm, sessionId);
|
|
29957
|
+
fs6.mkdirSync(path11.dirname(wtPath), { recursive: true });
|
|
29958
|
+
try {
|
|
29959
|
+
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
29960
|
+
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
|
|
29961
|
+
worktreePaths.push(wtPath);
|
|
29962
|
+
} catch (e) {
|
|
29963
|
+
log2(
|
|
29964
|
+
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
29965
|
+
);
|
|
30087
29966
|
}
|
|
30088
|
-
acpManager.handlePrompt({
|
|
30089
|
-
promptText,
|
|
30090
|
-
promptId: msg.id,
|
|
30091
|
-
sessionId,
|
|
30092
|
-
runId,
|
|
30093
|
-
mode,
|
|
30094
|
-
agentType,
|
|
30095
|
-
cwd: effectiveCwd,
|
|
30096
|
-
sendResult,
|
|
30097
|
-
sendSessionUpdate
|
|
30098
|
-
});
|
|
30099
29967
|
}
|
|
30100
|
-
|
|
30101
|
-
|
|
30102
|
-
void preambleAndPrompt(void 0);
|
|
30103
|
-
});
|
|
29968
|
+
if (worktreePaths.length === 0) return null;
|
|
29969
|
+
return { worktreePaths, agentCwd: agentMirrorRoot };
|
|
30104
29970
|
}
|
|
30105
29971
|
|
|
30106
|
-
// src/
|
|
30107
|
-
|
|
30108
|
-
|
|
30109
|
-
|
|
29972
|
+
// src/git/rename-branch.ts
|
|
29973
|
+
async function gitRenameCurrentBranch(repoDir, newName) {
|
|
29974
|
+
const g = simpleGit(repoDir);
|
|
29975
|
+
await g.raw(["branch", "-m", newName]);
|
|
29976
|
+
}
|
|
30110
29977
|
|
|
30111
|
-
// src/
|
|
30112
|
-
function
|
|
30113
|
-
const
|
|
30114
|
-
|
|
30115
|
-
|
|
30116
|
-
|
|
29978
|
+
// src/worktrees/rename-session-worktree-branches.ts
|
|
29979
|
+
async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
29980
|
+
const safe = newBranch.replace(/[^a-zA-Z0-9/_-]+/g, "-").slice(0, 80) || "session-branch";
|
|
29981
|
+
for (const wt of paths) {
|
|
29982
|
+
try {
|
|
29983
|
+
await gitRenameCurrentBranch(wt, safe);
|
|
29984
|
+
log2(`[worktrees] Renamed branch in ${wt} \u2192 ${safe}`);
|
|
29985
|
+
} catch (e) {
|
|
30117
29986
|
log2(
|
|
30118
|
-
`[
|
|
29987
|
+
`[worktrees] Branch rename failed in ${wt}: ${e instanceof Error ? e.message : String(e)}`
|
|
30119
29988
|
);
|
|
30120
29989
|
}
|
|
30121
|
-
}
|
|
29990
|
+
}
|
|
30122
29991
|
}
|
|
30123
29992
|
|
|
30124
|
-
// src/
|
|
30125
|
-
|
|
30126
|
-
handleBridgeCancelRun(msg, deps);
|
|
30127
|
-
};
|
|
30128
|
-
|
|
30129
|
-
// src/acp/from-bridge/handle-bridge-cursor-request-response.ts
|
|
30130
|
-
function handleBridgeCursorRequestResponse(msg, { acpManager }) {
|
|
30131
|
-
if (typeof msg.requestId !== "string") return;
|
|
30132
|
-
acpManager.resolveRequest(msg.requestId, msg.result ?? {});
|
|
30133
|
-
}
|
|
29993
|
+
// src/worktrees/remove-session-worktrees.ts
|
|
29994
|
+
import * as fs9 from "node:fs";
|
|
30134
29995
|
|
|
30135
|
-
// src/
|
|
30136
|
-
|
|
30137
|
-
handleBridgeCursorRequestResponse(msg, deps);
|
|
30138
|
-
};
|
|
29996
|
+
// src/git/worktree-remove.ts
|
|
29997
|
+
import * as fs8 from "node:fs";
|
|
30139
29998
|
|
|
30140
|
-
// src/
|
|
30141
|
-
|
|
30142
|
-
|
|
30143
|
-
|
|
30144
|
-
|
|
30145
|
-
|
|
30146
|
-
|
|
30147
|
-
|
|
29999
|
+
// src/git/resolve-main-repo-from-git-file.ts
|
|
30000
|
+
import * as fs7 from "node:fs";
|
|
30001
|
+
import * as path12 from "node:path";
|
|
30002
|
+
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
30003
|
+
const gitDirFile = path12.join(wt, ".git");
|
|
30004
|
+
if (!fs7.existsSync(gitDirFile) || !fs7.statSync(gitDirFile).isFile()) return "";
|
|
30005
|
+
const first2 = fs7.readFileSync(gitDirFile, "utf8").trim();
|
|
30006
|
+
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
30007
|
+
if (!m) return "";
|
|
30008
|
+
const gitWorktreePath = path12.resolve(wt, m[1].trim());
|
|
30009
|
+
const gitDir = path12.dirname(path12.dirname(gitWorktreePath));
|
|
30010
|
+
return path12.dirname(gitDir);
|
|
30148
30011
|
}
|
|
30149
30012
|
|
|
30150
|
-
// src/
|
|
30151
|
-
|
|
30152
|
-
|
|
30153
|
-
|
|
30154
|
-
|
|
30155
|
-
|
|
30156
|
-
|
|
30157
|
-
socket,
|
|
30158
|
-
log2
|
|
30159
|
-
);
|
|
30160
|
-
};
|
|
30161
|
-
|
|
30162
|
-
// src/files/list-dir.ts
|
|
30163
|
-
import fs5 from "node:fs";
|
|
30164
|
-
import path13 from "node:path";
|
|
30165
|
-
|
|
30166
|
-
// src/files/ensure-under-cwd.ts
|
|
30167
|
-
import path12 from "node:path";
|
|
30168
|
-
function ensureUnderCwd(relativePath, cwd = getBridgeWorkspaceDirectory()) {
|
|
30169
|
-
const normalized = path12.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
30170
|
-
const resolved = path12.resolve(cwd, normalized);
|
|
30171
|
-
if (!resolved.startsWith(cwd + path12.sep) && resolved !== cwd) {
|
|
30172
|
-
return null;
|
|
30013
|
+
// src/git/worktree-remove.ts
|
|
30014
|
+
async function gitWorktreeRemoveForce(worktreePath) {
|
|
30015
|
+
const mainRepo = resolveMainRepoFromWorktreeGitFile(worktreePath);
|
|
30016
|
+
if (mainRepo) {
|
|
30017
|
+
await simpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
30018
|
+
} else {
|
|
30019
|
+
fs8.rmSync(worktreePath, { recursive: true, force: true });
|
|
30173
30020
|
}
|
|
30174
|
-
return resolved;
|
|
30175
30021
|
}
|
|
30176
30022
|
|
|
30177
|
-
// src/
|
|
30178
|
-
function
|
|
30179
|
-
|
|
30180
|
-
|
|
30181
|
-
|
|
30182
|
-
|
|
30183
|
-
|
|
30184
|
-
|
|
30185
|
-
|
|
30186
|
-
|
|
30187
|
-
|
|
30188
|
-
let isDir = d.isDirectory();
|
|
30189
|
-
if (d.isSymbolicLink()) {
|
|
30190
|
-
try {
|
|
30191
|
-
const targetStat = fs5.statSync(fullPath);
|
|
30192
|
-
isDir = targetStat.isDirectory();
|
|
30193
|
-
} catch {
|
|
30194
|
-
isDir = false;
|
|
30195
|
-
}
|
|
30023
|
+
// src/worktrees/remove-session-worktrees.ts
|
|
30024
|
+
async function removeSessionWorktrees(paths, log2) {
|
|
30025
|
+
for (const wt of paths) {
|
|
30026
|
+
try {
|
|
30027
|
+
await gitWorktreeRemoveForce(wt);
|
|
30028
|
+
log2(`[worktrees] Removed worktree ${wt}`);
|
|
30029
|
+
} catch (e) {
|
|
30030
|
+
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
30031
|
+
try {
|
|
30032
|
+
fs9.rmSync(wt, { recursive: true, force: true });
|
|
30033
|
+
} catch {
|
|
30196
30034
|
}
|
|
30197
|
-
|
|
30198
|
-
name: d.name,
|
|
30199
|
-
path: entryPath,
|
|
30200
|
-
isDir,
|
|
30201
|
-
isSymlink: d.isSymbolicLink()
|
|
30202
|
-
};
|
|
30203
|
-
}).sort((a, b) => {
|
|
30204
|
-
if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
|
|
30205
|
-
return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
30206
|
-
});
|
|
30207
|
-
return { entries };
|
|
30208
|
-
} catch (err) {
|
|
30209
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
30210
|
-
return { error: message };
|
|
30035
|
+
}
|
|
30211
30036
|
}
|
|
30212
30037
|
}
|
|
30213
30038
|
|
|
30214
|
-
// src/
|
|
30215
|
-
|
|
30216
|
-
|
|
30217
|
-
function resolveFilePath(relativePath) {
|
|
30218
|
-
const resolved = ensureUnderCwd(relativePath, getBridgeWorkspaceDirectory());
|
|
30219
|
-
if (!resolved) return { error: "Path is outside working directory" };
|
|
30220
|
-
let real;
|
|
30039
|
+
// src/git/working-tree-status.ts
|
|
30040
|
+
async function commitsAheadOfUpstream(repoDir) {
|
|
30041
|
+
const g = simpleGit(repoDir);
|
|
30221
30042
|
try {
|
|
30222
|
-
|
|
30043
|
+
await g.raw(["rev-parse", "--verify", "@{u}"]);
|
|
30223
30044
|
} catch {
|
|
30224
|
-
|
|
30045
|
+
return 0;
|
|
30225
30046
|
}
|
|
30226
|
-
const
|
|
30227
|
-
|
|
30228
|
-
return
|
|
30047
|
+
const out = await g.raw(["rev-list", "--count", "@{u}..HEAD"]);
|
|
30048
|
+
const n = parseInt(String(out).trim(), 10);
|
|
30049
|
+
return Number.isNaN(n) ? 0 : n;
|
|
30229
30050
|
}
|
|
30230
|
-
|
|
30231
|
-
|
|
30232
|
-
const
|
|
30233
|
-
const
|
|
30234
|
-
const
|
|
30235
|
-
|
|
30236
|
-
|
|
30237
|
-
|
|
30238
|
-
|
|
30239
|
-
let
|
|
30240
|
-
|
|
30241
|
-
|
|
30242
|
-
|
|
30243
|
-
|
|
30244
|
-
try {
|
|
30245
|
-
let bytesRead;
|
|
30246
|
-
while (!done && (bytesRead = fs6.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
30247
|
-
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
30248
|
-
partial2 = "";
|
|
30249
|
-
let lineStart = 0;
|
|
30250
|
-
for (let i = 0; i < text.length; i++) {
|
|
30251
|
-
if (text[i] === "\n") {
|
|
30252
|
-
const lineContent = (() => {
|
|
30253
|
-
let lineEnd = i;
|
|
30254
|
-
if (lineEnd > lineStart && text[lineEnd - 1] === "\r") lineEnd--;
|
|
30255
|
-
return text.slice(lineStart, lineEnd);
|
|
30256
|
-
})();
|
|
30257
|
-
if (currentLine === 0 && (startLine === 0 || lineOffsetIn !== void 0)) {
|
|
30258
|
-
line0Accum += lineContent;
|
|
30259
|
-
const totalLine0 = line0Accum.length;
|
|
30260
|
-
if (skipLine0Chars > 0) {
|
|
30261
|
-
if (totalLine0 <= skipLine0Chars) {
|
|
30262
|
-
skipLine0Chars -= totalLine0;
|
|
30263
|
-
line0Accum = "";
|
|
30264
|
-
currentLine++;
|
|
30265
|
-
lineStart = i + 1;
|
|
30266
|
-
if (currentLine > endLine) {
|
|
30267
|
-
done = true;
|
|
30268
|
-
break;
|
|
30269
|
-
}
|
|
30270
|
-
continue;
|
|
30271
|
-
}
|
|
30272
|
-
const from = skipLine0Chars;
|
|
30273
|
-
const take = Math.min(lineChunkSize, totalLine0 - from);
|
|
30274
|
-
resultLines.push(line0Accum.slice(from, from + take));
|
|
30275
|
-
line0CharsReturned += take;
|
|
30276
|
-
if (from + take < totalLine0) {
|
|
30277
|
-
return {
|
|
30278
|
-
content: resultLines.join("\n"),
|
|
30279
|
-
size: fileSize,
|
|
30280
|
-
lineOffset: lineOffsetIn + line0CharsReturned,
|
|
30281
|
-
totalLines: 1
|
|
30282
|
-
};
|
|
30283
|
-
}
|
|
30284
|
-
line0Accum = "";
|
|
30285
|
-
skipLine0Chars = 0;
|
|
30286
|
-
line0CharsReturned = 0;
|
|
30287
|
-
} else if (totalLine0 > lineChunkSize) {
|
|
30288
|
-
resultLines.push(line0Accum.slice(0, lineChunkSize));
|
|
30289
|
-
return {
|
|
30290
|
-
content: resultLines.join("\n"),
|
|
30291
|
-
size: fileSize,
|
|
30292
|
-
lineOffset: lineChunkSize,
|
|
30293
|
-
totalLines: 1
|
|
30294
|
-
};
|
|
30295
|
-
} else {
|
|
30296
|
-
resultLines.push(line0Accum);
|
|
30297
|
-
line0Accum = "";
|
|
30298
|
-
}
|
|
30299
|
-
} else if (currentLine >= startLine && currentLine <= endLine) {
|
|
30300
|
-
resultLines.push(lineContent);
|
|
30301
|
-
}
|
|
30302
|
-
currentLine++;
|
|
30303
|
-
lineStart = i + 1;
|
|
30304
|
-
if (currentLine > endLine) {
|
|
30305
|
-
done = true;
|
|
30306
|
-
break;
|
|
30307
|
-
}
|
|
30308
|
-
}
|
|
30309
|
-
}
|
|
30310
|
-
if (!done) {
|
|
30311
|
-
const lineContent = text.slice(lineStart);
|
|
30312
|
-
if (currentLine === 0 && (startLine === 0 || lineOffsetIn !== void 0)) {
|
|
30313
|
-
line0Accum += lineContent;
|
|
30314
|
-
const totalLine0 = line0Accum.length;
|
|
30315
|
-
if (skipLine0Chars > 0) {
|
|
30316
|
-
if (totalLine0 <= skipLine0Chars) {
|
|
30317
|
-
skipLine0Chars -= totalLine0;
|
|
30318
|
-
line0Accum = "";
|
|
30319
|
-
} else {
|
|
30320
|
-
const from = skipLine0Chars;
|
|
30321
|
-
const take = Math.min(lineChunkSize, totalLine0 - from);
|
|
30322
|
-
resultLines.push(line0Accum.slice(from, from + take));
|
|
30323
|
-
return {
|
|
30324
|
-
content: resultLines.join("\n"),
|
|
30325
|
-
size: fileSize,
|
|
30326
|
-
lineOffset: (lineOffsetIn ?? 0) + take,
|
|
30327
|
-
totalLines: 1
|
|
30328
|
-
};
|
|
30329
|
-
}
|
|
30330
|
-
} else if (totalLine0 > lineChunkSize) {
|
|
30331
|
-
resultLines.push(line0Accum.slice(0, lineChunkSize));
|
|
30332
|
-
return {
|
|
30333
|
-
content: resultLines.join("\n"),
|
|
30334
|
-
size: fileSize,
|
|
30335
|
-
lineOffset: lineChunkSize,
|
|
30336
|
-
totalLines: 1
|
|
30337
|
-
};
|
|
30338
|
-
}
|
|
30339
|
-
}
|
|
30340
|
-
partial2 = text.slice(lineStart);
|
|
30341
|
-
}
|
|
30342
|
-
}
|
|
30343
|
-
if (!done) {
|
|
30344
|
-
const tail = partial2 + decoder.end();
|
|
30345
|
-
if (currentLine === 0 && (startLine === 0 || lineOffsetIn !== void 0) && tail.length > 0) {
|
|
30346
|
-
line0Accum += tail.endsWith("\r") ? tail.slice(0, -1) : tail;
|
|
30347
|
-
const totalLine0 = line0Accum.length;
|
|
30348
|
-
if (skipLine0Chars > 0) {
|
|
30349
|
-
if (totalLine0 <= skipLine0Chars) {
|
|
30350
|
-
return { content: resultLines.join("\n"), size: fileSize };
|
|
30351
|
-
}
|
|
30352
|
-
const from = skipLine0Chars;
|
|
30353
|
-
const take = Math.min(lineChunkSize, totalLine0 - from);
|
|
30354
|
-
resultLines.push(line0Accum.slice(from, from + take));
|
|
30355
|
-
line0CharsReturned += take;
|
|
30356
|
-
if (from + take < totalLine0) {
|
|
30357
|
-
return {
|
|
30358
|
-
content: resultLines.join("\n"),
|
|
30359
|
-
size: fileSize,
|
|
30360
|
-
lineOffset: (lineOffsetIn ?? 0) + line0CharsReturned,
|
|
30361
|
-
totalLines: 1
|
|
30362
|
-
};
|
|
30363
|
-
}
|
|
30364
|
-
} else if (totalLine0 > lineChunkSize) {
|
|
30365
|
-
resultLines.push(line0Accum.slice(0, lineChunkSize));
|
|
30366
|
-
return {
|
|
30367
|
-
content: resultLines.join("\n"),
|
|
30368
|
-
size: fileSize,
|
|
30369
|
-
lineOffset: lineChunkSize,
|
|
30370
|
-
totalLines: 1
|
|
30371
|
-
};
|
|
30372
|
-
} else {
|
|
30373
|
-
resultLines.push(line0Accum);
|
|
30374
|
-
}
|
|
30375
|
-
} else if (tail.length > 0 && currentLine >= startLine && currentLine <= endLine) {
|
|
30376
|
-
resultLines.push(tail.endsWith("\r") ? tail.slice(0, -1) : tail);
|
|
30377
|
-
}
|
|
30378
|
-
}
|
|
30379
|
-
return { content: resultLines.join("\n"), size: fileSize };
|
|
30380
|
-
} finally {
|
|
30381
|
-
fs6.closeSync(fd);
|
|
30051
|
+
async function getRepoWorkingTreeStatus(repoDir) {
|
|
30052
|
+
const g = simpleGit(repoDir);
|
|
30053
|
+
const st = await g.status();
|
|
30054
|
+
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
30055
|
+
const ahead = await commitsAheadOfUpstream(repoDir);
|
|
30056
|
+
return { hasUncommittedChanges, hasUnpushedCommits: ahead > 0 };
|
|
30057
|
+
}
|
|
30058
|
+
async function aggregateSessionPathsWorkingTreeStatus(paths) {
|
|
30059
|
+
let hasUncommittedChanges = false;
|
|
30060
|
+
let hasUnpushedCommits = false;
|
|
30061
|
+
for (const p of paths) {
|
|
30062
|
+
const s = await getRepoWorkingTreeStatus(p);
|
|
30063
|
+
if (s.hasUncommittedChanges) hasUncommittedChanges = true;
|
|
30064
|
+
if (s.hasUnpushedCommits) hasUnpushedCommits = true;
|
|
30382
30065
|
}
|
|
30066
|
+
return { hasUncommittedChanges, hasUnpushedCommits };
|
|
30383
30067
|
}
|
|
30384
|
-
function
|
|
30385
|
-
|
|
30386
|
-
const
|
|
30387
|
-
|
|
30388
|
-
|
|
30389
|
-
|
|
30390
|
-
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
30391
|
-
}
|
|
30392
|
-
const stat2 = fs6.statSync(result);
|
|
30393
|
-
const raw = fs6.readFileSync(result, "utf8");
|
|
30394
|
-
const lines = raw.split(/\r?\n/);
|
|
30395
|
-
return { content: raw, totalLines: lines.length, size: stat2.size };
|
|
30396
|
-
} catch (err) {
|
|
30397
|
-
return { error: err instanceof Error ? err.message : String(err) };
|
|
30068
|
+
async function pushAheadOfUpstreamForPaths(paths) {
|
|
30069
|
+
for (const p of paths) {
|
|
30070
|
+
const g = simpleGit(p);
|
|
30071
|
+
const ahead = await commitsAheadOfUpstream(p);
|
|
30072
|
+
if (ahead <= 0) continue;
|
|
30073
|
+
await g.push();
|
|
30398
30074
|
}
|
|
30399
30075
|
}
|
|
30400
30076
|
|
|
30401
|
-
// src/
|
|
30402
|
-
|
|
30403
|
-
|
|
30404
|
-
|
|
30405
|
-
|
|
30406
|
-
|
|
30407
|
-
|
|
30408
|
-
|
|
30409
|
-
function getIndexPath(cwd) {
|
|
30410
|
-
const hash = crypto2.createHash("sha256").update(cwd).digest("hex").slice(0, HASH_LEN);
|
|
30411
|
-
return path14.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
30412
|
-
}
|
|
30413
|
-
function getTrigrams(s) {
|
|
30414
|
-
const lower = s.toLowerCase();
|
|
30415
|
-
const out = [];
|
|
30416
|
-
for (let i = 0; i <= lower.length - 3; i++) {
|
|
30417
|
-
out.push(lower.slice(i, i + 3));
|
|
30077
|
+
// src/git/commit-and-push.ts
|
|
30078
|
+
async function gitCommitAllIfDirty(repoDir, message, options) {
|
|
30079
|
+
const g = simpleGit(repoDir);
|
|
30080
|
+
const st = await g.status();
|
|
30081
|
+
if (!st.files?.length) return;
|
|
30082
|
+
const branch = options.branch.trim();
|
|
30083
|
+
if (!branch) {
|
|
30084
|
+
throw new Error("Branch name is required");
|
|
30418
30085
|
}
|
|
30419
|
-
|
|
30420
|
-
|
|
30421
|
-
|
|
30422
|
-
|
|
30423
|
-
|
|
30424
|
-
|
|
30425
|
-
const smallest = byLength[0];
|
|
30426
|
-
const rest = byLength.slice(1);
|
|
30427
|
-
const result = [];
|
|
30428
|
-
for (const idx of smallest) {
|
|
30429
|
-
if (rest.every((arr) => binarySearch(arr, idx) >= 0)) {
|
|
30430
|
-
result.push(idx);
|
|
30431
|
-
}
|
|
30086
|
+
const branches = await g.branchLocal();
|
|
30087
|
+
const localNames = new Set(branches.all.map((b) => b.replace(/^\*\s*/, "").trim()));
|
|
30088
|
+
if (!localNames.has(branch)) {
|
|
30089
|
+
await g.checkoutLocalBranch(branch);
|
|
30090
|
+
} else {
|
|
30091
|
+
await g.checkout(branch);
|
|
30432
30092
|
}
|
|
30433
|
-
|
|
30434
|
-
|
|
30435
|
-
|
|
30436
|
-
|
|
30437
|
-
let hi = arr.length - 1;
|
|
30438
|
-
while (lo <= hi) {
|
|
30439
|
-
const mid = lo + hi >>> 1;
|
|
30440
|
-
if (arr[mid] < x) lo = mid + 1;
|
|
30441
|
-
else if (arr[mid] > x) hi = mid - 1;
|
|
30442
|
-
else return mid;
|
|
30093
|
+
await g.add(".");
|
|
30094
|
+
await g.commit(message);
|
|
30095
|
+
if (options.push) {
|
|
30096
|
+
await g.push(["-u", "origin", branch]);
|
|
30443
30097
|
}
|
|
30444
|
-
return -1;
|
|
30445
30098
|
}
|
|
30446
|
-
|
|
30447
|
-
|
|
30099
|
+
|
|
30100
|
+
// src/worktrees/commit-session-worktrees.ts
|
|
30101
|
+
async function commitSessionWorktrees(options) {
|
|
30102
|
+
const { paths, branch, message, push } = options;
|
|
30448
30103
|
try {
|
|
30449
|
-
|
|
30450
|
-
|
|
30451
|
-
return;
|
|
30452
|
-
}
|
|
30453
|
-
for (const name of names) {
|
|
30454
|
-
if (name.startsWith(".")) continue;
|
|
30455
|
-
const full = path14.join(dir, name);
|
|
30456
|
-
let stat2;
|
|
30457
|
-
try {
|
|
30458
|
-
stat2 = fs7.statSync(full);
|
|
30459
|
-
} catch {
|
|
30460
|
-
continue;
|
|
30461
|
-
}
|
|
30462
|
-
const relative4 = path14.relative(baseDir, full).replace(/\\/g, "/");
|
|
30463
|
-
if (stat2.isDirectory()) {
|
|
30464
|
-
walkDir(full, baseDir, out);
|
|
30465
|
-
} else if (stat2.isFile()) {
|
|
30466
|
-
out.push(relative4);
|
|
30467
|
-
}
|
|
30468
|
-
}
|
|
30469
|
-
}
|
|
30470
|
-
function buildFileIndex(cwd) {
|
|
30471
|
-
const resolved = path14.resolve(cwd);
|
|
30472
|
-
const paths = [];
|
|
30473
|
-
walkDir(resolved, resolved, paths);
|
|
30474
|
-
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
30475
|
-
const trigramIndex = {};
|
|
30476
|
-
for (let i = 0; i < paths.length; i++) {
|
|
30477
|
-
const trigrams = getTrigrams(paths[i]);
|
|
30478
|
-
const seen = /* @__PURE__ */ new Set();
|
|
30479
|
-
for (const tri of trigrams) {
|
|
30480
|
-
if (seen.has(tri)) continue;
|
|
30481
|
-
seen.add(tri);
|
|
30482
|
-
if (!trigramIndex[tri]) trigramIndex[tri] = [];
|
|
30483
|
-
trigramIndex[tri].push(i);
|
|
30104
|
+
for (const wt of paths) {
|
|
30105
|
+
await gitCommitAllIfDirty(wt, message, { push, branch });
|
|
30484
30106
|
}
|
|
30485
|
-
|
|
30486
|
-
const data = { version: INDEX_VERSION, paths, trigramIndex };
|
|
30487
|
-
const indexPath = getIndexPath(resolved);
|
|
30488
|
-
try {
|
|
30489
|
-
if (!fs7.existsSync(INDEX_DIR)) fs7.mkdirSync(INDEX_DIR, { recursive: true });
|
|
30490
|
-
fs7.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
30107
|
+
return { ok: true };
|
|
30491
30108
|
} catch (e) {
|
|
30492
|
-
|
|
30109
|
+
const err = e instanceof Error ? e.message : String(e);
|
|
30110
|
+
return { ok: false, error: err };
|
|
30493
30111
|
}
|
|
30494
|
-
return data;
|
|
30495
30112
|
}
|
|
30496
|
-
|
|
30497
|
-
|
|
30498
|
-
|
|
30499
|
-
|
|
30500
|
-
|
|
30501
|
-
|
|
30502
|
-
|
|
30503
|
-
|
|
30504
|
-
|
|
30505
|
-
|
|
30506
|
-
|
|
30507
|
-
|
|
30113
|
+
|
|
30114
|
+
// src/worktrees/session-worktree-manager.ts
|
|
30115
|
+
var SessionWorktreeManager = class {
|
|
30116
|
+
rootAbs;
|
|
30117
|
+
log;
|
|
30118
|
+
bridgeWantsWorktrees = false;
|
|
30119
|
+
sessionPaths = /* @__PURE__ */ new Map();
|
|
30120
|
+
sessionAgentCwd = /* @__PURE__ */ new Map();
|
|
30121
|
+
layout;
|
|
30122
|
+
constructor(options) {
|
|
30123
|
+
this.rootAbs = options.worktreesRootAbs;
|
|
30124
|
+
this.log = options.log;
|
|
30125
|
+
this.layout = loadWorktreeLayout();
|
|
30126
|
+
}
|
|
30127
|
+
setBridgeSessionWorktrees(enabled) {
|
|
30128
|
+
this.bridgeWantsWorktrees = enabled;
|
|
30129
|
+
}
|
|
30130
|
+
effective() {
|
|
30131
|
+
return this.bridgeWantsWorktrees;
|
|
30132
|
+
}
|
|
30133
|
+
/**
|
|
30134
|
+
* Returns cwd for the agent (mirror of launcher tree), or undefined to use the bridge workspace directory.
|
|
30135
|
+
*/
|
|
30136
|
+
async resolveCwdForPrompt(sessionId, opts) {
|
|
30137
|
+
if (!sessionId || !this.effective() || !opts.sessionWorktreesEnabled) {
|
|
30138
|
+
return void 0;
|
|
30508
30139
|
}
|
|
30509
|
-
if (
|
|
30510
|
-
|
|
30140
|
+
if (!opts.isNewSession) {
|
|
30141
|
+
const agentCwd = this.sessionAgentCwd.get(sessionId);
|
|
30142
|
+
if (agentCwd) return path13.resolve(agentCwd);
|
|
30143
|
+
return void 0;
|
|
30511
30144
|
}
|
|
30512
|
-
|
|
30513
|
-
|
|
30514
|
-
|
|
30145
|
+
const prep = await prepareNewSessionWorktrees({
|
|
30146
|
+
rootAbs: this.rootAbs,
|
|
30147
|
+
launcherCwd: getBridgeWorkspaceDirectory(),
|
|
30148
|
+
sessionId,
|
|
30149
|
+
layout: this.layout,
|
|
30150
|
+
log: this.log
|
|
30151
|
+
});
|
|
30152
|
+
if (!prep) return void 0;
|
|
30153
|
+
this.sessionPaths.set(sessionId, prep.worktreePaths);
|
|
30154
|
+
this.sessionAgentCwd.set(sessionId, prep.agentCwd);
|
|
30155
|
+
return path13.resolve(prep.agentCwd);
|
|
30515
30156
|
}
|
|
30516
|
-
|
|
30517
|
-
|
|
30518
|
-
|
|
30519
|
-
|
|
30520
|
-
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
30521
|
-
const data = buildFileIndex(resolved);
|
|
30522
|
-
return { data, fromCache: false };
|
|
30523
|
-
}
|
|
30524
|
-
function searchFileIndex(index, query, limit = 100) {
|
|
30525
|
-
const q = query.trim().toLowerCase();
|
|
30526
|
-
if (!q) return [];
|
|
30527
|
-
const { paths, trigramIndex } = index;
|
|
30528
|
-
let candidateIndices;
|
|
30529
|
-
if (q.length < 3) {
|
|
30530
|
-
candidateIndices = paths.map((_, i) => i).filter((i) => paths[i].toLowerCase().includes(q));
|
|
30531
|
-
} else {
|
|
30532
|
-
const trigrams = getTrigrams(q);
|
|
30533
|
-
if (trigrams.length === 0) {
|
|
30534
|
-
candidateIndices = paths.map((_, i) => i).filter((i) => paths[i].toLowerCase().includes(q));
|
|
30535
|
-
} else {
|
|
30536
|
-
const arrays = trigrams.map((tri) => trigramIndex[tri]).filter((arr) => arr != null && arr.length > 0);
|
|
30537
|
-
if (arrays.length === 0) return [];
|
|
30538
|
-
candidateIndices = intersectSortedSets(arrays);
|
|
30539
|
-
}
|
|
30157
|
+
async renameSessionBranch(sessionId, newBranch) {
|
|
30158
|
+
const paths = this.sessionPaths.get(sessionId);
|
|
30159
|
+
if (!paths?.length) return;
|
|
30160
|
+
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
30540
30161
|
}
|
|
30541
|
-
|
|
30542
|
-
|
|
30543
|
-
|
|
30544
|
-
|
|
30545
|
-
out.push(p);
|
|
30546
|
-
if (out.length >= limit) break;
|
|
30547
|
-
}
|
|
30162
|
+
/** True when this session runs in an isolated worktree mirror (not launcher cwd). */
|
|
30163
|
+
usesWorktreeSession(sessionId) {
|
|
30164
|
+
if (!sessionId) return false;
|
|
30165
|
+
return this.sessionAgentCwd.has(sessionId);
|
|
30548
30166
|
}
|
|
30549
|
-
|
|
30550
|
-
|
|
30551
|
-
|
|
30552
|
-
|
|
30553
|
-
|
|
30554
|
-
|
|
30555
|
-
|
|
30556
|
-
|
|
30557
|
-
|
|
30558
|
-
|
|
30559
|
-
|
|
30560
|
-
|
|
30561
|
-
|
|
30562
|
-
|
|
30563
|
-
|
|
30167
|
+
getWorktreePathsForSession(sessionId) {
|
|
30168
|
+
if (!sessionId) return void 0;
|
|
30169
|
+
const paths = this.sessionPaths.get(sessionId);
|
|
30170
|
+
return paths?.length ? [...paths] : void 0;
|
|
30171
|
+
}
|
|
30172
|
+
/** Session mirror root (parent of per-repo worktrees), when using worktrees for this session. */
|
|
30173
|
+
getAgentCwdForSession(sessionId) {
|
|
30174
|
+
if (!sessionId) return null;
|
|
30175
|
+
const c = this.sessionAgentCwd.get(sessionId);
|
|
30176
|
+
return c ? path13.resolve(c) : null;
|
|
30177
|
+
}
|
|
30178
|
+
async removeSessionWorktrees(sessionId) {
|
|
30179
|
+
const paths = this.sessionPaths.get(sessionId);
|
|
30180
|
+
this.sessionPaths.delete(sessionId);
|
|
30181
|
+
this.sessionAgentCwd.delete(sessionId);
|
|
30182
|
+
if (!paths?.length) return;
|
|
30183
|
+
await removeSessionWorktrees(paths, this.log);
|
|
30184
|
+
}
|
|
30185
|
+
async commitSession(params) {
|
|
30186
|
+
const paths = this.sessionPaths.get(params.sessionId);
|
|
30187
|
+
const targets = paths?.length ? paths : [getBridgeWorkspaceDirectory()];
|
|
30188
|
+
return commitSessionWorktrees({
|
|
30189
|
+
paths: targets,
|
|
30190
|
+
branch: params.branch,
|
|
30191
|
+
message: params.message,
|
|
30192
|
+
push: params.push
|
|
30564
30193
|
});
|
|
30565
|
-
return;
|
|
30566
30194
|
}
|
|
30567
|
-
|
|
30568
|
-
|
|
30569
|
-
|
|
30570
|
-
|
|
30571
|
-
|
|
30572
|
-
|
|
30573
|
-
}
|
|
30574
|
-
|
|
30575
|
-
function triggerFileIndexBuild() {
|
|
30576
|
-
setImmediate(() => {
|
|
30195
|
+
resolveCommitTargets(sessionId) {
|
|
30196
|
+
const paths = this.sessionPaths.get(sessionId);
|
|
30197
|
+
return paths?.length ? paths : [getBridgeWorkspaceDirectory()];
|
|
30198
|
+
}
|
|
30199
|
+
async getSessionWorkingTreeStatus(sessionId) {
|
|
30200
|
+
return aggregateSessionPathsWorkingTreeStatus(this.resolveCommitTargets(sessionId));
|
|
30201
|
+
}
|
|
30202
|
+
async pushSessionUpstream(sessionId) {
|
|
30577
30203
|
try {
|
|
30578
|
-
|
|
30204
|
+
await pushAheadOfUpstreamForPaths(this.resolveCommitTargets(sessionId));
|
|
30205
|
+
return { ok: true };
|
|
30579
30206
|
} catch (e) {
|
|
30580
|
-
|
|
30581
|
-
|
|
30582
|
-
});
|
|
30583
|
-
}
|
|
30584
|
-
|
|
30585
|
-
// src/files/handle-file-browser-request.ts
|
|
30586
|
-
function handleFileBrowserRequest(msg, socket) {
|
|
30587
|
-
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
30588
|
-
const op = msg.op === "read" ? "read" : "list";
|
|
30589
|
-
if (op === "list") {
|
|
30590
|
-
const result = listDir(reqPath);
|
|
30591
|
-
if ("error" in result) {
|
|
30592
|
-
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
30593
|
-
} else {
|
|
30594
|
-
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, entries: result.entries });
|
|
30595
|
-
if (reqPath === "." || reqPath === "") {
|
|
30596
|
-
triggerFileIndexBuild();
|
|
30597
|
-
}
|
|
30598
|
-
}
|
|
30599
|
-
} else {
|
|
30600
|
-
const startLine = typeof msg.startLine === "number" ? msg.startLine : void 0;
|
|
30601
|
-
const endLine = typeof msg.endLine === "number" ? msg.endLine : void 0;
|
|
30602
|
-
const lineOffset = typeof msg.lineOffset === "number" ? msg.lineOffset : void 0;
|
|
30603
|
-
const lineChunkSize = typeof msg.lineChunkSize === "number" ? msg.lineChunkSize : void 0;
|
|
30604
|
-
const result = readFile2(reqPath, startLine, endLine, lineOffset, lineChunkSize);
|
|
30605
|
-
if ("error" in result) {
|
|
30606
|
-
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
30607
|
-
} else {
|
|
30608
|
-
const payload = {
|
|
30609
|
-
type: "file_browser_response",
|
|
30610
|
-
id: msg.id,
|
|
30611
|
-
content: result.content,
|
|
30612
|
-
totalLines: result.totalLines,
|
|
30613
|
-
size: result.size
|
|
30614
|
-
};
|
|
30615
|
-
if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
|
|
30616
|
-
sendWsMessage(socket, payload);
|
|
30207
|
+
const err = e instanceof Error ? e.message : String(e);
|
|
30208
|
+
return { ok: false, error: err };
|
|
30617
30209
|
}
|
|
30618
30210
|
}
|
|
30211
|
+
};
|
|
30212
|
+
function defaultWorktreesRootAbs() {
|
|
30213
|
+
return path13.join(os3.homedir(), ".buildautomaton", "worktrees");
|
|
30619
30214
|
}
|
|
30620
30215
|
|
|
30621
|
-
// src/
|
|
30622
|
-
|
|
30623
|
-
|
|
30624
|
-
|
|
30625
|
-
|
|
30626
|
-
|
|
30627
|
-
|
|
30628
|
-
|
|
30629
|
-
|
|
30630
|
-
|
|
30631
|
-
function handleFileBrowserSearchMessage(msg, { getWs }) {
|
|
30632
|
-
if (typeof msg.id !== "string") return;
|
|
30633
|
-
const socket = getWs();
|
|
30634
|
-
if (!socket) return;
|
|
30635
|
-
handleFileBrowserSearch(msg, socket);
|
|
30216
|
+
// src/files/watch-file-index.ts
|
|
30217
|
+
import { watch } from "node:fs";
|
|
30218
|
+
import path20 from "node:path";
|
|
30219
|
+
|
|
30220
|
+
// src/files/index/build-file-index.ts
|
|
30221
|
+
import path17 from "node:path";
|
|
30222
|
+
|
|
30223
|
+
// src/runtime/yield-to-event-loop.ts
|
|
30224
|
+
function yieldToEventLoop() {
|
|
30225
|
+
return new Promise((resolve14) => setImmediate(resolve14));
|
|
30636
30226
|
}
|
|
30637
30227
|
|
|
30638
|
-
// src/
|
|
30639
|
-
import
|
|
30228
|
+
// src/files/index/walk-workspace-tree.ts
|
|
30229
|
+
import fs10 from "node:fs";
|
|
30640
30230
|
import path15 from "node:path";
|
|
30641
|
-
|
|
30642
|
-
|
|
30643
|
-
|
|
30644
|
-
|
|
30645
|
-
|
|
30646
|
-
|
|
30647
|
-
|
|
30648
|
-
|
|
30231
|
+
|
|
30232
|
+
// src/files/index/constants.ts
|
|
30233
|
+
import path14 from "node:path";
|
|
30234
|
+
import os4 from "node:os";
|
|
30235
|
+
var INDEX_WORK_YIELD_EVERY = 256;
|
|
30236
|
+
var INDEX_DIR = path14.join(os4.homedir(), ".buildautomaton");
|
|
30237
|
+
var INDEX_HASH_LEN = 16;
|
|
30238
|
+
var INDEX_VERSION = 2;
|
|
30239
|
+
var INDEX_LOG_PREFIX = "[file-index]";
|
|
30240
|
+
|
|
30241
|
+
// src/files/index/walk-workspace-tree.ts
|
|
30242
|
+
function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
30243
|
+
let names;
|
|
30244
|
+
try {
|
|
30245
|
+
names = fs10.readdirSync(dir);
|
|
30246
|
+
} catch {
|
|
30247
|
+
return;
|
|
30248
|
+
}
|
|
30249
|
+
for (const name of names) {
|
|
30250
|
+
if (name.startsWith(".")) continue;
|
|
30251
|
+
const full = path15.join(dir, name);
|
|
30252
|
+
let stat2;
|
|
30649
30253
|
try {
|
|
30650
|
-
|
|
30254
|
+
stat2 = fs10.statSync(full);
|
|
30651
30255
|
} catch {
|
|
30652
30256
|
continue;
|
|
30653
30257
|
}
|
|
30654
|
-
|
|
30655
|
-
|
|
30656
|
-
|
|
30657
|
-
|
|
30658
|
-
|
|
30659
|
-
continue;
|
|
30660
|
-
}
|
|
30661
|
-
const skillMd = path15.join(dir, "SKILL.md");
|
|
30662
|
-
if (!fs8.existsSync(skillMd)) continue;
|
|
30663
|
-
const key = `${rel}/${name}`;
|
|
30664
|
-
if (seenKeys.has(key)) continue;
|
|
30665
|
-
seenKeys.add(key);
|
|
30666
|
-
out.push({ skillKey: name, path: `${rel}/${name}`.replace(/\\/g, "/") });
|
|
30258
|
+
const relative4 = path15.relative(baseDir, full).replace(/\\/g, "/");
|
|
30259
|
+
if (stat2.isDirectory()) {
|
|
30260
|
+
walkWorkspaceTreeSync(full, baseDir, out);
|
|
30261
|
+
} else if (stat2.isFile()) {
|
|
30262
|
+
out.push(relative4);
|
|
30667
30263
|
}
|
|
30668
30264
|
}
|
|
30669
|
-
return out;
|
|
30670
30265
|
}
|
|
30671
|
-
function
|
|
30672
|
-
|
|
30673
|
-
|
|
30674
|
-
|
|
30675
|
-
|
|
30676
|
-
|
|
30266
|
+
async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
30267
|
+
let names;
|
|
30268
|
+
try {
|
|
30269
|
+
names = await fs10.promises.readdir(dir);
|
|
30270
|
+
} catch {
|
|
30271
|
+
return;
|
|
30272
|
+
}
|
|
30273
|
+
for (const name of names) {
|
|
30274
|
+
if (name.startsWith(".")) continue;
|
|
30275
|
+
if (state.n > 0 && state.n % INDEX_WORK_YIELD_EVERY === 0) {
|
|
30276
|
+
await yieldToEventLoop();
|
|
30277
|
+
}
|
|
30278
|
+
state.n++;
|
|
30279
|
+
const full = path15.join(dir, name);
|
|
30280
|
+
let stat2;
|
|
30677
30281
|
try {
|
|
30678
|
-
|
|
30282
|
+
stat2 = await fs10.promises.stat(full);
|
|
30679
30283
|
} catch {
|
|
30680
30284
|
continue;
|
|
30681
30285
|
}
|
|
30682
|
-
const
|
|
30683
|
-
|
|
30684
|
-
|
|
30685
|
-
|
|
30686
|
-
|
|
30687
|
-
} catch {
|
|
30688
|
-
continue;
|
|
30689
|
-
}
|
|
30690
|
-
if (!fs8.existsSync(path15.join(dir, "SKILL.md"))) continue;
|
|
30691
|
-
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
30692
|
-
skills2.push({ name, relPath });
|
|
30693
|
-
}
|
|
30694
|
-
if (skills2.length > 0) {
|
|
30695
|
-
roots.push({ path: rel.replace(/\\/g, "/"), skills: skills2 });
|
|
30286
|
+
const relative4 = path15.relative(baseDir, full).replace(/\\/g, "/");
|
|
30287
|
+
if (stat2.isDirectory()) {
|
|
30288
|
+
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
30289
|
+
} else if (stat2.isFile()) {
|
|
30290
|
+
out.push(relative4);
|
|
30696
30291
|
}
|
|
30697
30292
|
}
|
|
30698
|
-
return roots;
|
|
30699
30293
|
}
|
|
30700
|
-
|
|
30701
|
-
|
|
30702
|
-
function handleSkillLayoutRequest(msg, deps) {
|
|
30703
|
-
const socket = deps.getWs();
|
|
30704
|
-
const id = typeof msg.id === "string" ? msg.id : "";
|
|
30705
|
-
const roots = discoverSkillLayoutRoots(getBridgeWorkspaceDirectory());
|
|
30706
|
-
socket?.send(JSON.stringify({ type: "skill_layout_response", id, roots }));
|
|
30294
|
+
function createWalkYieldState() {
|
|
30295
|
+
return { n: 0 };
|
|
30707
30296
|
}
|
|
30708
30297
|
|
|
30709
|
-
// src/
|
|
30710
|
-
|
|
30711
|
-
|
|
30712
|
-
|
|
30713
|
-
|
|
30714
|
-
|
|
30715
|
-
return { success: false, error: "Invalid items" };
|
|
30716
|
-
}
|
|
30717
|
-
try {
|
|
30718
|
-
for (const item of items) {
|
|
30719
|
-
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
30720
|
-
continue;
|
|
30721
|
-
}
|
|
30722
|
-
const skillDir = path16.join(cwd, targetDir, item.skillName);
|
|
30723
|
-
for (const f of item.files) {
|
|
30724
|
-
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
30725
|
-
const dest = path16.join(skillDir, f.path);
|
|
30726
|
-
fs9.mkdirSync(path16.dirname(dest), { recursive: true });
|
|
30727
|
-
if (f.text !== void 0) {
|
|
30728
|
-
fs9.writeFileSync(dest, f.text, "utf8");
|
|
30729
|
-
} else if (f.base64) {
|
|
30730
|
-
fs9.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
30731
|
-
}
|
|
30732
|
-
}
|
|
30733
|
-
installed.push({
|
|
30734
|
-
sourceId: item.sourceId,
|
|
30735
|
-
skillName: item.skillName,
|
|
30736
|
-
versionHash: item.versionHash
|
|
30737
|
-
});
|
|
30738
|
-
}
|
|
30739
|
-
return { success: true, installed };
|
|
30740
|
-
} catch (e) {
|
|
30741
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
30298
|
+
// src/files/index/trigram-utils.ts
|
|
30299
|
+
function getTrigrams(s) {
|
|
30300
|
+
const lower = s.toLowerCase();
|
|
30301
|
+
const out = [];
|
|
30302
|
+
for (let i = 0; i <= lower.length - 3; i++) {
|
|
30303
|
+
out.push(lower.slice(i, i + 3));
|
|
30742
30304
|
}
|
|
30305
|
+
return out;
|
|
30743
30306
|
}
|
|
30744
|
-
|
|
30745
|
-
|
|
30746
|
-
|
|
30747
|
-
|
|
30748
|
-
|
|
30749
|
-
|
|
30750
|
-
|
|
30751
|
-
|
|
30752
|
-
const result = installRemoteSkills(cwd, targetDir, rawItems);
|
|
30753
|
-
if (!result.success) {
|
|
30754
|
-
const err = result.error ?? "Invalid items";
|
|
30755
|
-
deps.log(`[Bridge service] Install skills failed: ${err}`);
|
|
30756
|
-
socket?.send(JSON.stringify({ type: "install_skills_result", id, success: false, error: err }));
|
|
30757
|
-
return;
|
|
30307
|
+
function binarySearch(arr, x) {
|
|
30308
|
+
let lo = 0;
|
|
30309
|
+
let hi = arr.length - 1;
|
|
30310
|
+
while (lo <= hi) {
|
|
30311
|
+
const mid = lo + hi >>> 1;
|
|
30312
|
+
if (arr[mid] < x) lo = mid + 1;
|
|
30313
|
+
else if (arr[mid] > x) hi = mid - 1;
|
|
30314
|
+
else return mid;
|
|
30758
30315
|
}
|
|
30759
|
-
|
|
30760
|
-
}
|
|
30761
|
-
|
|
30762
|
-
|
|
30763
|
-
|
|
30764
|
-
|
|
30765
|
-
|
|
30766
|
-
|
|
30767
|
-
|
|
30768
|
-
|
|
30769
|
-
|
|
30770
|
-
|
|
30771
|
-
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
30772
|
-
const message = typeof msg.message === "string" ? msg.message : "";
|
|
30773
|
-
const push = msg.push === true;
|
|
30774
|
-
const endSession = msg.endSession === true;
|
|
30775
|
-
if (!sessionId || !branch || !message) return;
|
|
30776
|
-
void deps.sessionWorktreeManager.commitSession({ sessionId, branch, message, push }).then((r) => {
|
|
30777
|
-
const s = deps.getWs();
|
|
30778
|
-
if (s) {
|
|
30779
|
-
sendWsMessage(s, {
|
|
30780
|
-
type: "commit_session_result",
|
|
30781
|
-
id: msg.id,
|
|
30782
|
-
ok: r.ok,
|
|
30783
|
-
...r.error ? { error: r.error } : {},
|
|
30784
|
-
endSession
|
|
30785
|
-
});
|
|
30786
|
-
}
|
|
30787
|
-
}).catch((e) => {
|
|
30788
|
-
const s = deps.getWs();
|
|
30789
|
-
if (s) {
|
|
30790
|
-
sendWsMessage(s, {
|
|
30791
|
-
type: "commit_session_result",
|
|
30792
|
-
id: msg.id,
|
|
30793
|
-
ok: false,
|
|
30794
|
-
error: e instanceof Error ? e.message : String(e),
|
|
30795
|
-
endSession
|
|
30796
|
-
});
|
|
30316
|
+
return -1;
|
|
30317
|
+
}
|
|
30318
|
+
function intersectSortedTrigramSets(arrays) {
|
|
30319
|
+
if (arrays.length === 0) return [];
|
|
30320
|
+
if (arrays.length === 1) return arrays[0];
|
|
30321
|
+
const byLength = arrays.slice().sort((a, b) => a.length - b.length);
|
|
30322
|
+
const smallest = byLength[0];
|
|
30323
|
+
const rest = byLength.slice(1);
|
|
30324
|
+
const result = [];
|
|
30325
|
+
for (const idx of smallest) {
|
|
30326
|
+
if (rest.every((arr) => binarySearch(arr, idx) >= 0)) {
|
|
30327
|
+
result.push(idx);
|
|
30797
30328
|
}
|
|
30798
|
-
}
|
|
30799
|
-
|
|
30800
|
-
|
|
30801
|
-
// src/bridge/routing/handlers/rename-session-branch.ts
|
|
30802
|
-
var handleRenameSessionBranchMessage = (msg, deps) => {
|
|
30803
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
30804
|
-
const newBranch = typeof msg.newBranch === "string" ? msg.newBranch : "";
|
|
30805
|
-
if (!sessionId || !newBranch) return;
|
|
30806
|
-
void deps.sessionWorktreeManager.renameSessionBranch(sessionId, newBranch);
|
|
30807
|
-
};
|
|
30808
|
-
|
|
30809
|
-
// src/bridge/routing/handlers/session-archived.ts
|
|
30810
|
-
var handleSessionArchivedMessage = (msg, deps) => {
|
|
30811
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
30812
|
-
if (!sessionId) return;
|
|
30813
|
-
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
30814
|
-
};
|
|
30815
|
-
|
|
30816
|
-
// src/bridge/routing/handlers/session-discarded.ts
|
|
30817
|
-
var handleSessionDiscardedMessage = (msg, deps) => {
|
|
30818
|
-
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
30819
|
-
if (!sessionId) return;
|
|
30820
|
-
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
30821
|
-
};
|
|
30329
|
+
}
|
|
30330
|
+
return result;
|
|
30331
|
+
}
|
|
30822
30332
|
|
|
30823
|
-
// src/
|
|
30824
|
-
|
|
30825
|
-
|
|
30826
|
-
|
|
30827
|
-
|
|
30828
|
-
|
|
30829
|
-
|
|
30830
|
-
|
|
30831
|
-
|
|
30832
|
-
|
|
30833
|
-
|
|
30834
|
-
const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? getBridgeWorkspaceDirectory();
|
|
30835
|
-
const file2 = snapshotFilePath(agentBase, turnId);
|
|
30836
|
-
if (!fs10.existsSync(file2)) {
|
|
30837
|
-
sendWsMessage(s, {
|
|
30838
|
-
type: "revert_turn_snapshot_result",
|
|
30839
|
-
id,
|
|
30840
|
-
ok: false,
|
|
30841
|
-
error: "No snapshot found for this turn (git state may be unavailable)."
|
|
30842
|
-
});
|
|
30843
|
-
return;
|
|
30333
|
+
// src/files/index/build-trigram-map.ts
|
|
30334
|
+
function buildTrigramMapForPaths(paths) {
|
|
30335
|
+
const trigramIndex = {};
|
|
30336
|
+
for (let i = 0; i < paths.length; i++) {
|
|
30337
|
+
const trigrams = getTrigrams(paths[i]);
|
|
30338
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30339
|
+
for (const tri of trigrams) {
|
|
30340
|
+
if (seen.has(tri)) continue;
|
|
30341
|
+
seen.add(tri);
|
|
30342
|
+
if (!trigramIndex[tri]) trigramIndex[tri] = [];
|
|
30343
|
+
trigramIndex[tri].push(i);
|
|
30844
30344
|
}
|
|
30845
|
-
const res = await applyPreTurnSnapshot(file2, log2);
|
|
30846
|
-
sendWsMessage(s, {
|
|
30847
|
-
type: "revert_turn_snapshot_result",
|
|
30848
|
-
id,
|
|
30849
|
-
ok: res.ok,
|
|
30850
|
-
...res.error ? { error: res.error } : {}
|
|
30851
|
-
});
|
|
30852
|
-
})();
|
|
30853
|
-
};
|
|
30854
|
-
|
|
30855
|
-
// src/bridge/routing/handlers/dev-server-control.ts
|
|
30856
|
-
var handleDevServerControl = (msg, deps) => {
|
|
30857
|
-
const serverId = typeof msg.serverId === "string" ? msg.serverId : "";
|
|
30858
|
-
const action = msg.action === "start" || msg.action === "stop" ? msg.action : null;
|
|
30859
|
-
if (!serverId || !action) return;
|
|
30860
|
-
deps.devServerManager?.handleControl(serverId, action);
|
|
30861
|
-
};
|
|
30862
|
-
|
|
30863
|
-
// src/bridge/routing/handlers/dev-servers-config.ts
|
|
30864
|
-
var handleDevServersConfig = (msg, deps) => {
|
|
30865
|
-
const devServers = msg.devServers;
|
|
30866
|
-
deps.devServerManager?.applyConfig(devServers ?? []);
|
|
30867
|
-
};
|
|
30868
|
-
|
|
30869
|
-
// src/bridge/routing/dispatch-bridge-message.ts
|
|
30870
|
-
function dispatchBridgeMessage(msg, deps) {
|
|
30871
|
-
const type = msg.type;
|
|
30872
|
-
if (typeof type !== "string") return;
|
|
30873
|
-
switch (type) {
|
|
30874
|
-
case "auth_token":
|
|
30875
|
-
handleAuthToken(msg, deps);
|
|
30876
|
-
break;
|
|
30877
|
-
case "bridge_identified":
|
|
30878
|
-
handleBridgeIdentified(msg, deps);
|
|
30879
|
-
break;
|
|
30880
|
-
case "dev_servers_config":
|
|
30881
|
-
handleDevServersConfig(msg, deps);
|
|
30882
|
-
break;
|
|
30883
|
-
case "server_control":
|
|
30884
|
-
handleDevServerControl(msg, deps);
|
|
30885
|
-
break;
|
|
30886
|
-
case "agent_config":
|
|
30887
|
-
handleAgentConfigMessage(msg, deps);
|
|
30888
|
-
break;
|
|
30889
|
-
case "prompt":
|
|
30890
|
-
handlePromptMessage(msg, deps);
|
|
30891
|
-
break;
|
|
30892
|
-
case "commit_session_request":
|
|
30893
|
-
handleCommitSessionRequestMessage(msg, deps);
|
|
30894
|
-
break;
|
|
30895
|
-
case "rename_session_branch":
|
|
30896
|
-
handleRenameSessionBranchMessage(msg, deps);
|
|
30897
|
-
break;
|
|
30898
|
-
case "session_archived":
|
|
30899
|
-
handleSessionArchivedMessage(msg, deps);
|
|
30900
|
-
break;
|
|
30901
|
-
case "session_discarded":
|
|
30902
|
-
handleSessionDiscardedMessage(msg, deps);
|
|
30903
|
-
break;
|
|
30904
|
-
case "revert_turn_snapshot":
|
|
30905
|
-
handleRevertTurnSnapshotMessage(msg, deps);
|
|
30906
|
-
break;
|
|
30907
|
-
case "cancel_run":
|
|
30908
|
-
handleCancelRunMessage(msg, deps);
|
|
30909
|
-
break;
|
|
30910
|
-
case "cursor_request_response":
|
|
30911
|
-
handleCursorRequestResponseMessage(msg, deps);
|
|
30912
|
-
break;
|
|
30913
|
-
case "skill_call":
|
|
30914
|
-
handleSkillCallMessage(msg, deps);
|
|
30915
|
-
break;
|
|
30916
|
-
case "file_browser_request":
|
|
30917
|
-
handleFileBrowserRequestMessage(msg, deps);
|
|
30918
|
-
break;
|
|
30919
|
-
case "file_browser_search":
|
|
30920
|
-
handleFileBrowserSearchMessage(msg, deps);
|
|
30921
|
-
break;
|
|
30922
|
-
case "skill_layout_request":
|
|
30923
|
-
handleSkillLayoutRequest(msg, deps);
|
|
30924
|
-
break;
|
|
30925
|
-
case "install_skills":
|
|
30926
|
-
handleInstallSkillsMessage(msg, deps);
|
|
30927
|
-
break;
|
|
30928
|
-
case "refresh_local_skills":
|
|
30929
|
-
handleRefreshLocalSkills(msg, deps);
|
|
30930
|
-
break;
|
|
30931
|
-
default:
|
|
30932
|
-
deps.log?.(`[Bridge service] unhandled message type: ${type}`);
|
|
30933
30345
|
}
|
|
30346
|
+
return trigramIndex;
|
|
30934
30347
|
}
|
|
30935
|
-
|
|
30936
|
-
|
|
30937
|
-
|
|
30938
|
-
|
|
30939
|
-
|
|
30940
|
-
|
|
30941
|
-
|
|
30942
|
-
|
|
30348
|
+
async function buildTrigramMapForPathsAsync(paths) {
|
|
30349
|
+
const trigramIndex = {};
|
|
30350
|
+
for (let i = 0; i < paths.length; i++) {
|
|
30351
|
+
if (i > 0 && i % INDEX_WORK_YIELD_EVERY === 0) {
|
|
30352
|
+
await yieldToEventLoop();
|
|
30353
|
+
}
|
|
30354
|
+
const trigrams = getTrigrams(paths[i]);
|
|
30355
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30356
|
+
for (const tri of trigrams) {
|
|
30357
|
+
if (seen.has(tri)) continue;
|
|
30358
|
+
seen.add(tri);
|
|
30359
|
+
if (!trigramIndex[tri]) trigramIndex[tri] = [];
|
|
30360
|
+
trigramIndex[tri].push(i);
|
|
30361
|
+
}
|
|
30362
|
+
}
|
|
30363
|
+
return trigramIndex;
|
|
30943
30364
|
}
|
|
30944
30365
|
|
|
30945
|
-
// src/
|
|
30946
|
-
import
|
|
30947
|
-
import os4 from "node:os";
|
|
30948
|
-
|
|
30949
|
-
// src/worktrees/prepare-new-session-worktrees.ts
|
|
30950
|
-
import * as fs12 from "node:fs";
|
|
30951
|
-
import * as path18 from "node:path";
|
|
30366
|
+
// src/files/index/write-index-file.ts
|
|
30367
|
+
import fs11 from "node:fs";
|
|
30952
30368
|
|
|
30953
|
-
// src/
|
|
30954
|
-
|
|
30955
|
-
|
|
30956
|
-
|
|
30369
|
+
// src/files/index/paths.ts
|
|
30370
|
+
import path16 from "node:path";
|
|
30371
|
+
import crypto2 from "node:crypto";
|
|
30372
|
+
function getIndexPathForCwd(resolvedCwd) {
|
|
30373
|
+
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
30374
|
+
return path16.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
30957
30375
|
}
|
|
30958
30376
|
|
|
30959
|
-
// src/
|
|
30960
|
-
|
|
30961
|
-
|
|
30962
|
-
import os3 from "node:os";
|
|
30963
|
-
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
30964
|
-
function defaultWorktreeLayoutPath() {
|
|
30965
|
-
return path17.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
30966
|
-
}
|
|
30967
|
-
function normalizeLoadedLayout(raw) {
|
|
30968
|
-
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
30969
|
-
const j = raw;
|
|
30970
|
-
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
30971
|
-
}
|
|
30972
|
-
return { launcherCwds: [] };
|
|
30973
|
-
}
|
|
30974
|
-
function loadWorktreeLayout() {
|
|
30377
|
+
// src/files/index/write-index-file.ts
|
|
30378
|
+
function writeIndexFileSync(resolvedCwd, data) {
|
|
30379
|
+
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
30975
30380
|
try {
|
|
30976
|
-
|
|
30977
|
-
|
|
30978
|
-
|
|
30979
|
-
|
|
30980
|
-
} catch {
|
|
30981
|
-
return { launcherCwds: [] };
|
|
30381
|
+
if (!fs11.existsSync(INDEX_DIR)) fs11.mkdirSync(INDEX_DIR, { recursive: true });
|
|
30382
|
+
fs11.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
30383
|
+
} catch (e) {
|
|
30384
|
+
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
30982
30385
|
}
|
|
30983
30386
|
}
|
|
30984
|
-
function
|
|
30387
|
+
async function writeIndexFileAsync(resolvedCwd, data) {
|
|
30388
|
+
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
30985
30389
|
try {
|
|
30986
|
-
|
|
30987
|
-
fs11.
|
|
30988
|
-
|
|
30989
|
-
|
|
30390
|
+
await fs11.promises.mkdir(INDEX_DIR, { recursive: true });
|
|
30391
|
+
await fs11.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
|
|
30392
|
+
} catch (e) {
|
|
30393
|
+
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
30990
30394
|
}
|
|
30991
30395
|
}
|
|
30992
|
-
function
|
|
30993
|
-
return
|
|
30994
|
-
}
|
|
30995
|
-
function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
|
|
30996
|
-
const norm = path17.resolve(launcherCwdAbs);
|
|
30997
|
-
const existing = layout.launcherCwds.find((e) => path17.resolve(e.absolutePath) === norm);
|
|
30998
|
-
if (existing) return existing.dirName;
|
|
30999
|
-
const base = baseNameSafe(norm);
|
|
31000
|
-
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
31001
|
-
let name = base;
|
|
31002
|
-
let n = 2;
|
|
31003
|
-
while (used.has(name)) {
|
|
31004
|
-
name = `${base}-${n}`;
|
|
31005
|
-
n += 1;
|
|
31006
|
-
}
|
|
31007
|
-
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
31008
|
-
saveWorktreeLayout(layout);
|
|
31009
|
-
return name;
|
|
30396
|
+
function makeTrigramIndexData(paths, trigramIndex) {
|
|
30397
|
+
return { version: INDEX_VERSION, paths, trigramIndex };
|
|
31010
30398
|
}
|
|
31011
30399
|
|
|
31012
|
-
// src/
|
|
31013
|
-
|
|
31014
|
-
|
|
31015
|
-
const launcherResolved = path18.resolve(launcherCwd);
|
|
31016
|
-
const cwdKey = allocateDirNameForLauncherCwd(layout, launcherResolved);
|
|
31017
|
-
const agentMirrorRoot = path18.join(rootAbs, cwdKey);
|
|
31018
|
-
const repos = await discoverGitReposUnderRoot(launcherResolved);
|
|
31019
|
-
if (repos.length === 0) {
|
|
31020
|
-
log2("[worktrees] No Git repositories under launcher working directory; skipping worktree creation.");
|
|
31021
|
-
return null;
|
|
31022
|
-
}
|
|
31023
|
-
const branch = `session-${sessionId}`;
|
|
31024
|
-
const worktreePaths = [];
|
|
31025
|
-
fs12.mkdirSync(agentMirrorRoot, { recursive: true });
|
|
31026
|
-
for (const repo of repos) {
|
|
31027
|
-
let rel = path18.relative(launcherResolved, repo.absolutePath);
|
|
31028
|
-
if (rel.startsWith("..") || path18.isAbsolute(rel)) continue;
|
|
31029
|
-
const relNorm = rel === "" ? "." : rel;
|
|
31030
|
-
const wtPath = path18.join(agentMirrorRoot, relNorm, sessionId);
|
|
31031
|
-
fs12.mkdirSync(path18.dirname(wtPath), { recursive: true });
|
|
31032
|
-
try {
|
|
31033
|
-
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
31034
|
-
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
|
|
31035
|
-
worktreePaths.push(wtPath);
|
|
31036
|
-
} catch (e) {
|
|
31037
|
-
log2(
|
|
31038
|
-
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
31039
|
-
);
|
|
31040
|
-
}
|
|
31041
|
-
}
|
|
31042
|
-
if (worktreePaths.length === 0) return null;
|
|
31043
|
-
return { worktreePaths, agentCwd: agentMirrorRoot };
|
|
31044
|
-
}
|
|
31045
|
-
|
|
31046
|
-
// src/git/rename-branch.ts
|
|
31047
|
-
async function gitRenameCurrentBranch(repoDir, newName) {
|
|
31048
|
-
const g = simpleGit(repoDir);
|
|
31049
|
-
await g.raw(["branch", "-m", newName]);
|
|
31050
|
-
}
|
|
31051
|
-
|
|
31052
|
-
// src/worktrees/rename-session-worktree-branches.ts
|
|
31053
|
-
async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
31054
|
-
const safe = newBranch.replace(/[^a-zA-Z0-9/_-]+/g, "-").slice(0, 80) || "session-branch";
|
|
31055
|
-
for (const wt of paths) {
|
|
31056
|
-
try {
|
|
31057
|
-
await gitRenameCurrentBranch(wt, safe);
|
|
31058
|
-
log2(`[worktrees] Renamed branch in ${wt} \u2192 ${safe}`);
|
|
31059
|
-
} catch (e) {
|
|
31060
|
-
log2(
|
|
31061
|
-
`[worktrees] Branch rename failed in ${wt}: ${e instanceof Error ? e.message : String(e)}`
|
|
31062
|
-
);
|
|
31063
|
-
}
|
|
31064
|
-
}
|
|
30400
|
+
// src/files/index/build-file-index.ts
|
|
30401
|
+
function sortPaths(paths) {
|
|
30402
|
+
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
31065
30403
|
}
|
|
31066
|
-
|
|
31067
|
-
|
|
31068
|
-
|
|
31069
|
-
|
|
31070
|
-
|
|
31071
|
-
|
|
31072
|
-
|
|
31073
|
-
|
|
31074
|
-
|
|
31075
|
-
import * as path19 from "node:path";
|
|
31076
|
-
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
31077
|
-
const gitDirFile = path19.join(wt, ".git");
|
|
31078
|
-
if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
|
|
31079
|
-
const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
|
|
31080
|
-
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
31081
|
-
if (!m) return "";
|
|
31082
|
-
const gitWorktreePath = path19.resolve(wt, m[1].trim());
|
|
31083
|
-
const gitDir = path19.dirname(path19.dirname(gitWorktreePath));
|
|
31084
|
-
return path19.dirname(gitDir);
|
|
30404
|
+
function buildFileIndex(cwd) {
|
|
30405
|
+
const resolved = path17.resolve(cwd);
|
|
30406
|
+
const paths = [];
|
|
30407
|
+
walkWorkspaceTreeSync(resolved, resolved, paths);
|
|
30408
|
+
sortPaths(paths);
|
|
30409
|
+
const trigramIndex = buildTrigramMapForPaths(paths);
|
|
30410
|
+
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
30411
|
+
writeIndexFileSync(resolved, data);
|
|
30412
|
+
return data;
|
|
31085
30413
|
}
|
|
31086
|
-
|
|
31087
|
-
|
|
31088
|
-
|
|
31089
|
-
|
|
31090
|
-
|
|
31091
|
-
|
|
31092
|
-
|
|
31093
|
-
|
|
31094
|
-
|
|
30414
|
+
async function buildFileIndexAsync(cwd) {
|
|
30415
|
+
const resolved = path17.resolve(cwd);
|
|
30416
|
+
const paths = [];
|
|
30417
|
+
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
30418
|
+
await yieldToEventLoop();
|
|
30419
|
+
sortPaths(paths);
|
|
30420
|
+
const trigramIndex = await buildTrigramMapForPathsAsync(paths);
|
|
30421
|
+
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
30422
|
+
await writeIndexFileAsync(resolved, data);
|
|
30423
|
+
return data;
|
|
31095
30424
|
}
|
|
31096
30425
|
|
|
31097
|
-
// src/
|
|
31098
|
-
|
|
31099
|
-
|
|
31100
|
-
|
|
31101
|
-
|
|
31102
|
-
|
|
31103
|
-
|
|
31104
|
-
|
|
31105
|
-
|
|
31106
|
-
|
|
31107
|
-
|
|
30426
|
+
// src/files/index/load-file-index.ts
|
|
30427
|
+
import fs12 from "node:fs";
|
|
30428
|
+
import path18 from "node:path";
|
|
30429
|
+
function loadFileIndex(cwd) {
|
|
30430
|
+
const resolved = path18.resolve(cwd);
|
|
30431
|
+
const indexPath = getIndexPathForCwd(resolved);
|
|
30432
|
+
try {
|
|
30433
|
+
const raw = fs12.readFileSync(indexPath, "utf8");
|
|
30434
|
+
const parsed = JSON.parse(raw);
|
|
30435
|
+
if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
|
|
30436
|
+
const obj = parsed;
|
|
30437
|
+
if (obj.version === INDEX_VERSION && obj.trigramIndex && typeof obj.trigramIndex === "object") {
|
|
30438
|
+
return obj;
|
|
31108
30439
|
}
|
|
30440
|
+
return buildFileIndex(resolved);
|
|
31109
30441
|
}
|
|
30442
|
+
if (Array.isArray(parsed) && parsed.every((p) => typeof p === "string")) {
|
|
30443
|
+
return buildFileIndex(resolved);
|
|
30444
|
+
}
|
|
30445
|
+
return null;
|
|
30446
|
+
} catch {
|
|
30447
|
+
return null;
|
|
31110
30448
|
}
|
|
31111
30449
|
}
|
|
31112
30450
|
|
|
31113
|
-
// src/
|
|
31114
|
-
|
|
31115
|
-
|
|
31116
|
-
const
|
|
31117
|
-
|
|
31118
|
-
|
|
31119
|
-
|
|
31120
|
-
|
|
31121
|
-
}
|
|
31122
|
-
const branches = await g.branchLocal();
|
|
31123
|
-
const localNames = new Set(branches.all.map((b) => b.replace(/^\*\s*/, "").trim()));
|
|
31124
|
-
if (!localNames.has(branch)) {
|
|
31125
|
-
await g.checkoutLocalBranch(branch);
|
|
31126
|
-
} else {
|
|
31127
|
-
await g.checkout(branch);
|
|
31128
|
-
}
|
|
31129
|
-
await g.add(".");
|
|
31130
|
-
await g.commit(message);
|
|
31131
|
-
if (options.push) {
|
|
31132
|
-
await g.push(["-u", "origin", branch]);
|
|
31133
|
-
}
|
|
31134
|
-
}
|
|
31135
|
-
|
|
31136
|
-
// src/worktrees/commit-session-worktrees.ts
|
|
31137
|
-
async function commitSessionWorktrees(options) {
|
|
31138
|
-
const { paths, branch, message, push } = options;
|
|
31139
|
-
try {
|
|
31140
|
-
for (const wt of paths) {
|
|
31141
|
-
await gitCommitAllIfDirty(wt, message, { push, branch });
|
|
31142
|
-
}
|
|
31143
|
-
return { ok: true };
|
|
31144
|
-
} catch (e) {
|
|
31145
|
-
const err = e instanceof Error ? e.message : String(e);
|
|
31146
|
-
return { ok: false, error: err };
|
|
31147
|
-
}
|
|
30451
|
+
// src/files/index/ensure-file-index.ts
|
|
30452
|
+
import path19 from "node:path";
|
|
30453
|
+
async function ensureFileIndexAsync(cwd) {
|
|
30454
|
+
const resolved = path19.resolve(cwd);
|
|
30455
|
+
const cached2 = loadFileIndex(resolved);
|
|
30456
|
+
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
30457
|
+
const data = await buildFileIndexAsync(resolved);
|
|
30458
|
+
return { data, fromCache: false };
|
|
31148
30459
|
}
|
|
31149
30460
|
|
|
31150
|
-
// src/
|
|
31151
|
-
|
|
31152
|
-
|
|
31153
|
-
|
|
31154
|
-
|
|
31155
|
-
sessionPaths = /* @__PURE__ */ new Map();
|
|
31156
|
-
sessionAgentCwd = /* @__PURE__ */ new Map();
|
|
31157
|
-
layout;
|
|
31158
|
-
constructor(options) {
|
|
31159
|
-
this.rootAbs = options.worktreesRootAbs;
|
|
31160
|
-
this.log = options.log;
|
|
31161
|
-
this.layout = loadWorktreeLayout();
|
|
31162
|
-
}
|
|
31163
|
-
setBridgeSessionWorktrees(enabled) {
|
|
31164
|
-
this.bridgeWantsWorktrees = enabled;
|
|
30461
|
+
// src/files/index/search-file-index.ts
|
|
30462
|
+
function candidatePathIndices(index, q) {
|
|
30463
|
+
const { paths, trigramIndex } = index;
|
|
30464
|
+
if (q.length < 3) {
|
|
30465
|
+
return paths.map((_, i) => i).filter((i) => paths[i].toLowerCase().includes(q));
|
|
31165
30466
|
}
|
|
31166
|
-
|
|
31167
|
-
|
|
30467
|
+
const trigrams = getTrigrams(q);
|
|
30468
|
+
if (trigrams.length === 0) {
|
|
30469
|
+
return paths.map((_, i) => i).filter((i) => paths[i].toLowerCase().includes(q));
|
|
31168
30470
|
}
|
|
31169
|
-
|
|
31170
|
-
|
|
31171
|
-
|
|
31172
|
-
|
|
31173
|
-
|
|
31174
|
-
|
|
30471
|
+
const arrays = trigrams.map((tri) => trigramIndex[tri]).filter((arr) => arr != null && arr.length > 0);
|
|
30472
|
+
if (arrays.length === 0) return [];
|
|
30473
|
+
return intersectSortedTrigramSets(arrays);
|
|
30474
|
+
}
|
|
30475
|
+
async function searchFileIndexAsync(index, query, limit = 100) {
|
|
30476
|
+
await yieldToEventLoop();
|
|
30477
|
+
const q = query.trim().toLowerCase();
|
|
30478
|
+
if (!q) return [];
|
|
30479
|
+
const { paths } = index;
|
|
30480
|
+
const candidateIndices = candidatePathIndices(index, q);
|
|
30481
|
+
const out = [];
|
|
30482
|
+
let n = 0;
|
|
30483
|
+
for (const i of candidateIndices) {
|
|
30484
|
+
if (n > 0 && n % INDEX_WORK_YIELD_EVERY === 0) {
|
|
30485
|
+
await yieldToEventLoop();
|
|
31175
30486
|
}
|
|
31176
|
-
|
|
31177
|
-
|
|
31178
|
-
|
|
31179
|
-
|
|
30487
|
+
const p = paths[i];
|
|
30488
|
+
if (p.toLowerCase().includes(q)) {
|
|
30489
|
+
out.push(p);
|
|
30490
|
+
if (out.length >= limit) break;
|
|
31180
30491
|
}
|
|
31181
|
-
|
|
31182
|
-
rootAbs: this.rootAbs,
|
|
31183
|
-
launcherCwd: getBridgeWorkspaceDirectory(),
|
|
31184
|
-
sessionId,
|
|
31185
|
-
layout: this.layout,
|
|
31186
|
-
log: this.log
|
|
31187
|
-
});
|
|
31188
|
-
if (!prep) return void 0;
|
|
31189
|
-
this.sessionPaths.set(sessionId, prep.worktreePaths);
|
|
31190
|
-
this.sessionAgentCwd.set(sessionId, prep.agentCwd);
|
|
31191
|
-
return path20.resolve(prep.agentCwd);
|
|
31192
|
-
}
|
|
31193
|
-
async renameSessionBranch(sessionId, newBranch) {
|
|
31194
|
-
const paths = this.sessionPaths.get(sessionId);
|
|
31195
|
-
if (!paths?.length) return;
|
|
31196
|
-
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
31197
|
-
}
|
|
31198
|
-
/** True when this session runs in an isolated worktree mirror (not launcher cwd). */
|
|
31199
|
-
usesWorktreeSession(sessionId) {
|
|
31200
|
-
if (!sessionId) return false;
|
|
31201
|
-
return this.sessionAgentCwd.has(sessionId);
|
|
31202
|
-
}
|
|
31203
|
-
getWorktreePathsForSession(sessionId) {
|
|
31204
|
-
if (!sessionId) return void 0;
|
|
31205
|
-
const paths = this.sessionPaths.get(sessionId);
|
|
31206
|
-
return paths?.length ? [...paths] : void 0;
|
|
31207
|
-
}
|
|
31208
|
-
/** Session mirror root (parent of per-repo worktrees), when using worktrees for this session. */
|
|
31209
|
-
getAgentCwdForSession(sessionId) {
|
|
31210
|
-
if (!sessionId) return null;
|
|
31211
|
-
const c = this.sessionAgentCwd.get(sessionId);
|
|
31212
|
-
return c ? path20.resolve(c) : null;
|
|
31213
|
-
}
|
|
31214
|
-
async removeSessionWorktrees(sessionId) {
|
|
31215
|
-
const paths = this.sessionPaths.get(sessionId);
|
|
31216
|
-
this.sessionPaths.delete(sessionId);
|
|
31217
|
-
this.sessionAgentCwd.delete(sessionId);
|
|
31218
|
-
if (!paths?.length) return;
|
|
31219
|
-
await removeSessionWorktrees(paths, this.log);
|
|
31220
|
-
}
|
|
31221
|
-
async commitSession(params) {
|
|
31222
|
-
const paths = this.sessionPaths.get(params.sessionId);
|
|
31223
|
-
const targets = paths?.length ? paths : [getBridgeWorkspaceDirectory()];
|
|
31224
|
-
return commitSessionWorktrees({
|
|
31225
|
-
paths: targets,
|
|
31226
|
-
branch: params.branch,
|
|
31227
|
-
message: params.message,
|
|
31228
|
-
push: params.push
|
|
31229
|
-
});
|
|
31230
|
-
}
|
|
31231
|
-
};
|
|
31232
|
-
function defaultWorktreesRootAbs() {
|
|
31233
|
-
return path20.join(os4.homedir(), ".buildautomaton", "worktrees");
|
|
31234
|
-
}
|
|
31235
|
-
|
|
31236
|
-
// src/auth/refresh-bridge-tokens.ts
|
|
31237
|
-
async function refreshBridgeTokens(params) {
|
|
31238
|
-
const base = params.apiUrl.replace(/\/$/, "");
|
|
31239
|
-
const url2 = `${base}/api/bridges/tokens/refresh`;
|
|
31240
|
-
try {
|
|
31241
|
-
const res = await fetch(url2, {
|
|
31242
|
-
method: "POST",
|
|
31243
|
-
headers: { "Content-Type": "application/json" },
|
|
31244
|
-
body: JSON.stringify({
|
|
31245
|
-
workspaceId: params.workspaceId,
|
|
31246
|
-
refreshToken: params.refreshToken
|
|
31247
|
-
})
|
|
31248
|
-
});
|
|
31249
|
-
if (!res.ok) return null;
|
|
31250
|
-
const data = await res.json();
|
|
31251
|
-
if (typeof data.token !== "string" || typeof data.refreshToken !== "string") return null;
|
|
31252
|
-
return {
|
|
31253
|
-
token: data.token,
|
|
31254
|
-
refreshToken: data.refreshToken,
|
|
31255
|
-
workspaceId: typeof data.workspaceId === "string" ? data.workspaceId : params.workspaceId,
|
|
31256
|
-
tokenId: typeof data.tokenId === "string" ? data.tokenId : ""
|
|
31257
|
-
};
|
|
31258
|
-
} catch {
|
|
31259
|
-
return null;
|
|
30492
|
+
n++;
|
|
31260
30493
|
}
|
|
30494
|
+
return out;
|
|
31261
30495
|
}
|
|
31262
30496
|
|
|
31263
30497
|
// src/files/watch-file-index.ts
|
|
31264
|
-
import { watch } from "node:fs";
|
|
31265
|
-
import path21 from "node:path";
|
|
31266
30498
|
var DEBOUNCE_MS = 900;
|
|
31267
30499
|
function shouldIgnoreRelative(rel) {
|
|
31268
30500
|
const n = rel.replace(/\\/g, "/");
|
|
@@ -31302,19 +30534,15 @@ function createFsWatcher(resolved, schedule) {
|
|
|
31302
30534
|
}
|
|
31303
30535
|
}
|
|
31304
30536
|
function startFileIndexWatcher(cwd = getBridgeWorkspaceDirectory()) {
|
|
31305
|
-
const resolved =
|
|
31306
|
-
|
|
31307
|
-
buildFileIndex(resolved);
|
|
31308
|
-
} catch (e) {
|
|
30537
|
+
const resolved = path20.resolve(cwd);
|
|
30538
|
+
void buildFileIndexAsync(resolved).catch((e) => {
|
|
31309
30539
|
console.error("[file-index] Initial index build failed:", e);
|
|
31310
|
-
}
|
|
30540
|
+
});
|
|
31311
30541
|
let timer = null;
|
|
31312
30542
|
const runRebuild = () => {
|
|
31313
|
-
|
|
31314
|
-
buildFileIndex(resolved);
|
|
31315
|
-
} catch (e) {
|
|
30543
|
+
void buildFileIndexAsync(resolved).catch((e) => {
|
|
31316
30544
|
console.error("[file-index] Watch rebuild failed:", e);
|
|
31317
|
-
}
|
|
30545
|
+
});
|
|
31318
30546
|
};
|
|
31319
30547
|
const schedule = () => {
|
|
31320
30548
|
if (timer) clearTimeout(timer);
|
|
@@ -31375,7 +30603,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
31375
30603
|
}
|
|
31376
30604
|
|
|
31377
30605
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
31378
|
-
import
|
|
30606
|
+
import fs13 from "node:fs";
|
|
31379
30607
|
|
|
31380
30608
|
// src/dev-servers/manager/forward-pipe.ts
|
|
31381
30609
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -31411,7 +30639,7 @@ function wireDevServerChildProcess(d) {
|
|
|
31411
30639
|
d.setPollInterval(void 0);
|
|
31412
30640
|
return;
|
|
31413
30641
|
}
|
|
31414
|
-
|
|
30642
|
+
fs13.readFile(d.mergedLogPath, (err, buf) => {
|
|
31415
30643
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
31416
30644
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
31417
30645
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -31449,7 +30677,7 @@ ${errTail}` : ""}`);
|
|
|
31449
30677
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
31450
30678
|
};
|
|
31451
30679
|
if (mergedPath) {
|
|
31452
|
-
|
|
30680
|
+
fs13.readFile(mergedPath, (err, buf) => {
|
|
31453
30681
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
31454
30682
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
31455
30683
|
if (chunk.length > 0) {
|
|
@@ -31551,13 +30779,13 @@ function parseDevServerDefs(servers) {
|
|
|
31551
30779
|
}
|
|
31552
30780
|
|
|
31553
30781
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
31554
|
-
import
|
|
30782
|
+
import fs14 from "node:fs";
|
|
31555
30783
|
function isSpawnEbadf(e) {
|
|
31556
30784
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
31557
30785
|
}
|
|
31558
30786
|
function rmDirQuiet(dir) {
|
|
31559
30787
|
try {
|
|
31560
|
-
|
|
30788
|
+
fs14.rmSync(dir, { recursive: true, force: true });
|
|
31561
30789
|
} catch {
|
|
31562
30790
|
}
|
|
31563
30791
|
}
|
|
@@ -31565,7 +30793,7 @@ var cachedDevNullReadFd;
|
|
|
31565
30793
|
function devNullReadFd() {
|
|
31566
30794
|
if (cachedDevNullReadFd === void 0) {
|
|
31567
30795
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
31568
|
-
cachedDevNullReadFd =
|
|
30796
|
+
cachedDevNullReadFd = fs14.openSync(devPath, "r");
|
|
31569
30797
|
}
|
|
31570
30798
|
return cachedDevNullReadFd;
|
|
31571
30799
|
}
|
|
@@ -31639,15 +30867,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
31639
30867
|
|
|
31640
30868
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
31641
30869
|
import { spawn as spawn7 } from "node:child_process";
|
|
31642
|
-
import
|
|
30870
|
+
import fs15 from "node:fs";
|
|
31643
30871
|
import { tmpdir } from "node:os";
|
|
31644
|
-
import
|
|
30872
|
+
import path21 from "node:path";
|
|
31645
30873
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
31646
|
-
const tmpRoot =
|
|
31647
|
-
const logPath =
|
|
30874
|
+
const tmpRoot = fs15.mkdtempSync(path21.join(tmpdir(), "ba-devsrv-log-"));
|
|
30875
|
+
const logPath = path21.join(tmpRoot, "combined.log");
|
|
31648
30876
|
let logFd;
|
|
31649
30877
|
try {
|
|
31650
|
-
logFd =
|
|
30878
|
+
logFd = fs15.openSync(logPath, "a");
|
|
31651
30879
|
} catch {
|
|
31652
30880
|
rmDirQuiet(tmpRoot);
|
|
31653
30881
|
return null;
|
|
@@ -31666,7 +30894,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
31666
30894
|
} else {
|
|
31667
30895
|
proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
31668
30896
|
}
|
|
31669
|
-
|
|
30897
|
+
fs15.closeSync(logFd);
|
|
31670
30898
|
return {
|
|
31671
30899
|
proc,
|
|
31672
30900
|
pipedStdoutStderr: true,
|
|
@@ -31675,7 +30903,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
31675
30903
|
};
|
|
31676
30904
|
} catch (e) {
|
|
31677
30905
|
try {
|
|
31678
|
-
|
|
30906
|
+
fs15.closeSync(logFd);
|
|
31679
30907
|
} catch {
|
|
31680
30908
|
}
|
|
31681
30909
|
rmDirQuiet(tmpRoot);
|
|
@@ -31686,22 +30914,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
31686
30914
|
|
|
31687
30915
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
31688
30916
|
import { spawn as spawn8 } from "node:child_process";
|
|
31689
|
-
import
|
|
30917
|
+
import fs16 from "node:fs";
|
|
31690
30918
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
31691
|
-
import
|
|
30919
|
+
import path22 from "node:path";
|
|
31692
30920
|
function shSingleQuote(s) {
|
|
31693
30921
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
31694
30922
|
}
|
|
31695
30923
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
31696
|
-
const tmpRoot =
|
|
31697
|
-
const logPath =
|
|
31698
|
-
const innerPath =
|
|
31699
|
-
const runnerPath =
|
|
30924
|
+
const tmpRoot = fs16.mkdtempSync(path22.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
30925
|
+
const logPath = path22.join(tmpRoot, "combined.log");
|
|
30926
|
+
const innerPath = path22.join(tmpRoot, "_cmd.sh");
|
|
30927
|
+
const runnerPath = path22.join(tmpRoot, "_run.sh");
|
|
31700
30928
|
try {
|
|
31701
|
-
|
|
30929
|
+
fs16.writeFileSync(innerPath, `#!/bin/sh
|
|
31702
30930
|
${command}
|
|
31703
30931
|
`);
|
|
31704
|
-
|
|
30932
|
+
fs16.writeFileSync(
|
|
31705
30933
|
runnerPath,
|
|
31706
30934
|
`#!/bin/sh
|
|
31707
30935
|
cd ${shSingleQuote(cwd)}
|
|
@@ -31727,13 +30955,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
31727
30955
|
}
|
|
31728
30956
|
}
|
|
31729
30957
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
31730
|
-
const tmpRoot =
|
|
31731
|
-
const logPath =
|
|
31732
|
-
const runnerPath =
|
|
30958
|
+
const tmpRoot = fs16.mkdtempSync(path22.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
30959
|
+
const logPath = path22.join(tmpRoot, "combined.log");
|
|
30960
|
+
const runnerPath = path22.join(tmpRoot, "_run.bat");
|
|
31733
30961
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
31734
30962
|
const com = process.env.ComSpec || "cmd.exe";
|
|
31735
30963
|
try {
|
|
31736
|
-
|
|
30964
|
+
fs16.writeFileSync(
|
|
31737
30965
|
runnerPath,
|
|
31738
30966
|
`@ECHO OFF\r
|
|
31739
30967
|
CD /D ${q(cwd)}\r
|
|
@@ -32328,213 +31556,1194 @@ function connectFirehose(options) {
|
|
|
32328
31556
|
};
|
|
32329
31557
|
}
|
|
32330
31558
|
|
|
32331
|
-
// src/bridge/connection/
|
|
32332
|
-
function
|
|
32333
|
-
const {
|
|
32334
|
-
function clearFirehoseReconnectTimer() {
|
|
32335
|
-
if (state.firehoseReconnectTimeout != null) {
|
|
32336
|
-
clearTimeout(state.firehoseReconnectTimeout);
|
|
32337
|
-
state.firehoseReconnectTimeout = null;
|
|
32338
|
-
}
|
|
32339
|
-
}
|
|
32340
|
-
function firehoseCtx() {
|
|
32341
|
-
return {
|
|
32342
|
-
closedByUser: state.closedByUser,
|
|
32343
|
-
currentWs: state.currentWs,
|
|
32344
|
-
firehoseHandle: state.firehoseHandle,
|
|
32345
|
-
firehoseQuiet: state.firehoseQuiet
|
|
32346
|
-
};
|
|
32347
|
-
}
|
|
32348
|
-
|
|
32349
|
-
|
|
32350
|
-
|
|
32351
|
-
|
|
32352
|
-
|
|
32353
|
-
|
|
32354
|
-
|
|
32355
|
-
|
|
32356
|
-
|
|
32357
|
-
|
|
32358
|
-
|
|
32359
|
-
|
|
32360
|
-
|
|
32361
|
-
|
|
32362
|
-
|
|
32363
|
-
|
|
32364
|
-
|
|
32365
|
-
|
|
32366
|
-
|
|
32367
|
-
|
|
32368
|
-
|
|
32369
|
-
|
|
32370
|
-
|
|
32371
|
-
|
|
32372
|
-
|
|
32373
|
-
|
|
32374
|
-
|
|
32375
|
-
|
|
32376
|
-
|
|
32377
|
-
|
|
32378
|
-
|
|
32379
|
-
|
|
32380
|
-
|
|
32381
|
-
|
|
32382
|
-
|
|
32383
|
-
|
|
32384
|
-
|
|
32385
|
-
|
|
32386
|
-
|
|
32387
|
-
|
|
32388
|
-
|
|
32389
|
-
|
|
32390
|
-
|
|
32391
|
-
|
|
32392
|
-
|
|
32393
|
-
|
|
32394
|
-
|
|
32395
|
-
|
|
32396
|
-
|
|
32397
|
-
|
|
32398
|
-
state.firehoseReconnectTimeout =
|
|
32399
|
-
|
|
32400
|
-
|
|
32401
|
-
|
|
32402
|
-
if (
|
|
32403
|
-
|
|
32404
|
-
|
|
32405
|
-
|
|
32406
|
-
|
|
32407
|
-
|
|
32408
|
-
|
|
32409
|
-
|
|
32410
|
-
|
|
32411
|
-
if (
|
|
32412
|
-
|
|
32413
|
-
|
|
32414
|
-
|
|
32415
|
-
|
|
32416
|
-
|
|
32417
|
-
|
|
32418
|
-
|
|
32419
|
-
|
|
32420
|
-
|
|
32421
|
-
|
|
32422
|
-
|
|
32423
|
-
|
|
32424
|
-
|
|
32425
|
-
|
|
32426
|
-
|
|
32427
|
-
|
|
32428
|
-
|
|
32429
|
-
|
|
32430
|
-
|
|
32431
|
-
|
|
32432
|
-
|
|
32433
|
-
|
|
32434
|
-
|
|
32435
|
-
|
|
32436
|
-
|
|
32437
|
-
|
|
32438
|
-
|
|
31559
|
+
// src/bridge/connection/attach-firehose-after-identified.ts
|
|
31560
|
+
function attachFirehoseAfterIdentified(ctx, params) {
|
|
31561
|
+
const { state, devServerManager, logFn } = ctx;
|
|
31562
|
+
function clearFirehoseReconnectTimer() {
|
|
31563
|
+
if (state.firehoseReconnectTimeout != null) {
|
|
31564
|
+
clearTimeout(state.firehoseReconnectTimeout);
|
|
31565
|
+
state.firehoseReconnectTimeout = null;
|
|
31566
|
+
}
|
|
31567
|
+
}
|
|
31568
|
+
function firehoseCtx() {
|
|
31569
|
+
return {
|
|
31570
|
+
closedByUser: state.closedByUser,
|
|
31571
|
+
currentWs: state.currentWs,
|
|
31572
|
+
firehoseHandle: state.firehoseHandle,
|
|
31573
|
+
firehoseQuiet: state.firehoseQuiet
|
|
31574
|
+
};
|
|
31575
|
+
}
|
|
31576
|
+
state.lastFirehoseParams = params;
|
|
31577
|
+
clearFirehoseReconnectTimer();
|
|
31578
|
+
if (state.firehoseReconnectAttempt === 0) {
|
|
31579
|
+
logFn("Connecting to preview tunnel (local HTTP proxy and dev logs)\u2026");
|
|
31580
|
+
}
|
|
31581
|
+
state.firehoseGeneration += 1;
|
|
31582
|
+
const myGen = state.firehoseGeneration;
|
|
31583
|
+
if (state.firehoseHandle) {
|
|
31584
|
+
state.firehoseHandle.close();
|
|
31585
|
+
state.firehoseHandle = null;
|
|
31586
|
+
}
|
|
31587
|
+
state.firehoseHandle = connectFirehose({
|
|
31588
|
+
firehoseServerUrl: params.firehoseServerUrl,
|
|
31589
|
+
workspaceId: params.workspaceId,
|
|
31590
|
+
bridgeName: params.bridgeName,
|
|
31591
|
+
proxyPorts: params.proxyPorts,
|
|
31592
|
+
log: logFn,
|
|
31593
|
+
devServerManager,
|
|
31594
|
+
onOpen: () => {
|
|
31595
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
31596
|
+
clearFirehoseReconnectQuietOnOpen({ firehoseQuiet: state.firehoseQuiet }, logFn);
|
|
31597
|
+
const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
|
|
31598
|
+
state.firehoseReconnectAttempt = 0;
|
|
31599
|
+
if (!logOpenAsFirehoseReconnect) {
|
|
31600
|
+
logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
|
|
31601
|
+
}
|
|
31602
|
+
},
|
|
31603
|
+
onClose: (code, reason) => {
|
|
31604
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
31605
|
+
state.firehoseHandle = null;
|
|
31606
|
+
if (state.closedByUser) return;
|
|
31607
|
+
const main = state.currentWs;
|
|
31608
|
+
if (!main || main.readyState !== wrapper_default.OPEN) {
|
|
31609
|
+
logFn(
|
|
31610
|
+
`${PROXY_AND_LOG_SERVICE_LABEL} Not reconnecting preview and log stream: main bridge connection is not open.`
|
|
31611
|
+
);
|
|
31612
|
+
return;
|
|
31613
|
+
}
|
|
31614
|
+
beginFirehoseDeferredDisconnect(firehoseCtx(), code, reason, logFn);
|
|
31615
|
+
clearFirehoseReconnectTimer();
|
|
31616
|
+
const delay2 = reconnectDelayMs(state.firehoseReconnectAttempt);
|
|
31617
|
+
state.firehoseReconnectAttempt += 1;
|
|
31618
|
+
logNextReconnectAttempt(
|
|
31619
|
+
logFn,
|
|
31620
|
+
PROXY_AND_LOG_SERVICE_LABEL,
|
|
31621
|
+
state.firehoseQuiet,
|
|
31622
|
+
delay2,
|
|
31623
|
+
state.firehoseReconnectAttempt
|
|
31624
|
+
);
|
|
31625
|
+
state.firehoseReconnectTimeout = setTimeout(() => {
|
|
31626
|
+
state.firehoseReconnectTimeout = null;
|
|
31627
|
+
if (state.closedByUser) return;
|
|
31628
|
+
const w = state.currentWs;
|
|
31629
|
+
if (!w || w.readyState !== wrapper_default.OPEN) {
|
|
31630
|
+
if (state.firehoseQuiet.verboseLogs) {
|
|
31631
|
+
logFn(
|
|
31632
|
+
`${PROXY_AND_LOG_SERVICE_LABEL} Reconnect skipped: main bridge connection closed before preview stream could reconnect.`
|
|
31633
|
+
);
|
|
31634
|
+
}
|
|
31635
|
+
return;
|
|
31636
|
+
}
|
|
31637
|
+
const p = state.lastFirehoseParams;
|
|
31638
|
+
if (!p) {
|
|
31639
|
+
if (state.firehoseQuiet.verboseLogs) {
|
|
31640
|
+
logFn(`${PROXY_AND_LOG_SERVICE_LABEL} Reconnect skipped: no stored connection parameters.`);
|
|
31641
|
+
}
|
|
31642
|
+
return;
|
|
31643
|
+
}
|
|
31644
|
+
attachFirehoseAfterIdentified(ctx, p);
|
|
31645
|
+
}, delay2);
|
|
31646
|
+
}
|
|
31647
|
+
});
|
|
31648
|
+
}
|
|
31649
|
+
|
|
31650
|
+
// src/bridge/connection/create-bridge-identified-handler.ts
|
|
31651
|
+
function createOnBridgeIdentified(opts) {
|
|
31652
|
+
const { sessionWorktreeManager, devServerManager, firehoseServerUrl, workspaceId, state, logFn } = opts;
|
|
31653
|
+
const firehoseCtx = { state, devServerManager, logFn };
|
|
31654
|
+
return (msg) => {
|
|
31655
|
+
sessionWorktreeManager.setBridgeSessionWorktrees(msg.sessionWorktreesEnabled === true);
|
|
31656
|
+
const bridgeName = msg.bridgeName;
|
|
31657
|
+
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts : [];
|
|
31658
|
+
const devServers = msg.devServers ?? [];
|
|
31659
|
+
setImmediate(() => {
|
|
31660
|
+
devServerManager.applyConfig(devServers);
|
|
31661
|
+
if (!firehoseServerUrl || typeof bridgeName !== "string" || !bridgeName) return;
|
|
31662
|
+
state.firehoseReconnectAttempt = 0;
|
|
31663
|
+
attachFirehoseAfterIdentified(firehoseCtx, {
|
|
31664
|
+
firehoseServerUrl,
|
|
31665
|
+
workspaceId,
|
|
31666
|
+
bridgeName,
|
|
31667
|
+
proxyPorts
|
|
31668
|
+
});
|
|
31669
|
+
});
|
|
31670
|
+
};
|
|
31671
|
+
}
|
|
31672
|
+
|
|
31673
|
+
// src/skills/discover-local-agent-skills.ts
|
|
31674
|
+
import fs17 from "node:fs";
|
|
31675
|
+
import path23 from "node:path";
|
|
31676
|
+
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
31677
|
+
function discoverLocalSkills(cwd) {
|
|
31678
|
+
const out = [];
|
|
31679
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
31680
|
+
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
31681
|
+
const base = path23.join(cwd, rel);
|
|
31682
|
+
if (!fs17.existsSync(base) || !fs17.statSync(base).isDirectory()) continue;
|
|
31683
|
+
let entries = [];
|
|
31684
|
+
try {
|
|
31685
|
+
entries = fs17.readdirSync(base);
|
|
31686
|
+
} catch {
|
|
31687
|
+
continue;
|
|
31688
|
+
}
|
|
31689
|
+
for (const name of entries) {
|
|
31690
|
+
const dir = path23.join(base, name);
|
|
31691
|
+
try {
|
|
31692
|
+
if (!fs17.statSync(dir).isDirectory()) continue;
|
|
31693
|
+
} catch {
|
|
31694
|
+
continue;
|
|
31695
|
+
}
|
|
31696
|
+
const skillMd = path23.join(dir, "SKILL.md");
|
|
31697
|
+
if (!fs17.existsSync(skillMd)) continue;
|
|
31698
|
+
const key = `${rel}/${name}`;
|
|
31699
|
+
if (seenKeys.has(key)) continue;
|
|
31700
|
+
seenKeys.add(key);
|
|
31701
|
+
out.push({ skillKey: name, path: `${rel}/${name}`.replace(/\\/g, "/") });
|
|
31702
|
+
}
|
|
31703
|
+
}
|
|
31704
|
+
return out;
|
|
31705
|
+
}
|
|
31706
|
+
function discoverSkillLayoutRoots(cwd) {
|
|
31707
|
+
const roots = [];
|
|
31708
|
+
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
31709
|
+
const base = path23.join(cwd, rel);
|
|
31710
|
+
if (!fs17.existsSync(base) || !fs17.statSync(base).isDirectory()) continue;
|
|
31711
|
+
let entries = [];
|
|
31712
|
+
try {
|
|
31713
|
+
entries = fs17.readdirSync(base);
|
|
31714
|
+
} catch {
|
|
31715
|
+
continue;
|
|
31716
|
+
}
|
|
31717
|
+
const skills2 = [];
|
|
31718
|
+
for (const name of entries) {
|
|
31719
|
+
const dir = path23.join(base, name);
|
|
31720
|
+
try {
|
|
31721
|
+
if (!fs17.statSync(dir).isDirectory()) continue;
|
|
31722
|
+
} catch {
|
|
31723
|
+
continue;
|
|
31724
|
+
}
|
|
31725
|
+
if (!fs17.existsSync(path23.join(dir, "SKILL.md"))) continue;
|
|
31726
|
+
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
31727
|
+
skills2.push({ name, relPath });
|
|
31728
|
+
}
|
|
31729
|
+
if (skills2.length > 0) {
|
|
31730
|
+
roots.push({ path: rel.replace(/\\/g, "/"), skills: skills2 });
|
|
31731
|
+
}
|
|
31732
|
+
}
|
|
31733
|
+
return roots;
|
|
31734
|
+
}
|
|
31735
|
+
|
|
31736
|
+
// src/agents/detect-local-agent-types.ts
|
|
31737
|
+
var LOCAL_AGENT_ACP_MODULES = [
|
|
31738
|
+
cursor_acp_client_exports,
|
|
31739
|
+
codex_acp_client_exports,
|
|
31740
|
+
kiro_acp_client_exports,
|
|
31741
|
+
claude_code_acp_client_exports
|
|
31742
|
+
];
|
|
31743
|
+
async function detectLocalAgentTypes() {
|
|
31744
|
+
try {
|
|
31745
|
+
const out = [];
|
|
31746
|
+
for (let i = 0; i < LOCAL_AGENT_ACP_MODULES.length; i++) {
|
|
31747
|
+
if (i > 0) {
|
|
31748
|
+
await yieldToEventLoop();
|
|
31749
|
+
}
|
|
31750
|
+
const mod = LOCAL_AGENT_ACP_MODULES[i];
|
|
31751
|
+
try {
|
|
31752
|
+
if (await mod.detectLocalAgentPresence()) out.push(mod.BACKEND_LOCAL_AGENT_TYPE);
|
|
31753
|
+
} catch {
|
|
31754
|
+
}
|
|
31755
|
+
}
|
|
31756
|
+
return out;
|
|
31757
|
+
} catch {
|
|
31758
|
+
return [];
|
|
31759
|
+
}
|
|
31760
|
+
}
|
|
31761
|
+
|
|
31762
|
+
// src/bridge/connection/create-bridge-local-reports.ts
|
|
31763
|
+
function createSendLocalSkillsReport(getWs, logFn) {
|
|
31764
|
+
return () => {
|
|
31765
|
+
setImmediate(() => {
|
|
31766
|
+
try {
|
|
31767
|
+
const socket = getWs();
|
|
31768
|
+
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
31769
|
+
const skills2 = discoverLocalSkills(getBridgeWorkspaceDirectory());
|
|
31770
|
+
socket.send(JSON.stringify({ type: "local_skills", skills: skills2 }));
|
|
31771
|
+
} catch (e) {
|
|
31772
|
+
logFn(
|
|
31773
|
+
`[Bridge service] Local skills report failed: ${e instanceof Error ? e.message : String(e)}`
|
|
31774
|
+
);
|
|
31775
|
+
}
|
|
31776
|
+
});
|
|
31777
|
+
};
|
|
31778
|
+
}
|
|
31779
|
+
function createReportAutoDetectedAgents(getWs, logFn) {
|
|
31780
|
+
return async () => {
|
|
31781
|
+
try {
|
|
31782
|
+
const types = await detectLocalAgentTypes();
|
|
31783
|
+
const socket = getWs();
|
|
31784
|
+
if (socket && socket.readyState === wrapper_default.OPEN) {
|
|
31785
|
+
sendWsMessage(socket, { type: "auto_detected_agents_report", agentTypes: types });
|
|
31786
|
+
}
|
|
31787
|
+
} catch (e) {
|
|
31788
|
+
logFn(
|
|
31789
|
+
`[Bridge service] Auto-detected agents report failed: ${e instanceof Error ? e.message : String(e)}`
|
|
31790
|
+
);
|
|
31791
|
+
}
|
|
31792
|
+
};
|
|
31793
|
+
}
|
|
31794
|
+
|
|
31795
|
+
// src/bridge/connection/build-bridge-url.ts
|
|
31796
|
+
function buildBridgeUrl(apiUrl, workspaceId, authToken) {
|
|
31797
|
+
const base = apiUrl.startsWith("https") ? apiUrl.replace(/^https/, "wss") : apiUrl.replace(/^http/, "ws");
|
|
31798
|
+
const params = new URLSearchParams({ workspaceId, token: authToken });
|
|
31799
|
+
return `${base}/ws/bridge?${params.toString()}`;
|
|
31800
|
+
}
|
|
31801
|
+
|
|
31802
|
+
// src/bridge/connection/report-git-repos.ts
|
|
31803
|
+
function reportGitRepos(getWs, log2) {
|
|
31804
|
+
setImmediate(() => {
|
|
31805
|
+
discoverGitRepos().then((repos) => {
|
|
31806
|
+
if (repos.length > 0) {
|
|
31807
|
+
const socket = getWs();
|
|
31808
|
+
if (socket) {
|
|
31809
|
+
sendWsMessage(socket, {
|
|
31810
|
+
type: "git_repos",
|
|
31811
|
+
repos: repos.map((r) => ({ absolutePath: r.absolutePath, remoteUrl: r.remoteUrl }))
|
|
31812
|
+
});
|
|
31813
|
+
}
|
|
31814
|
+
}
|
|
31815
|
+
}).catch((err) => {
|
|
31816
|
+
log2(
|
|
31817
|
+
`[Bridge service] Git repository discovery failed: ${err instanceof Error ? err.message : String(err)}`
|
|
31818
|
+
);
|
|
31819
|
+
});
|
|
31820
|
+
});
|
|
31821
|
+
}
|
|
31822
|
+
|
|
31823
|
+
// src/bridge/routing/handlers/auth-token.ts
|
|
31824
|
+
var handleAuthToken = (msg, { log: log2 }) => {
|
|
31825
|
+
if (typeof msg.token !== "string") return;
|
|
31826
|
+
log2("Received auth token. Save it for future runs:");
|
|
31827
|
+
log2(` export BUILDAMATON_AUTH_TOKEN="${msg.token}"`);
|
|
31828
|
+
};
|
|
31829
|
+
|
|
31830
|
+
// src/bridge/routing/handlers/bridge-identified.ts
|
|
31831
|
+
var handleBridgeIdentified = (msg, deps) => {
|
|
31832
|
+
if (typeof msg.bridgeName !== "string") return;
|
|
31833
|
+
deps.onBridgeIdentified(
|
|
31834
|
+
msg
|
|
31835
|
+
);
|
|
31836
|
+
setImmediate(() => {
|
|
31837
|
+
void (async () => {
|
|
31838
|
+
try {
|
|
31839
|
+
await deps.reportAutoDetectedAgents?.();
|
|
31840
|
+
} catch (e) {
|
|
31841
|
+
deps.log(
|
|
31842
|
+
`[Bridge service] Auto-detect agents failed: ${e instanceof Error ? e.message : String(e)}`
|
|
31843
|
+
);
|
|
31844
|
+
}
|
|
31845
|
+
})();
|
|
31846
|
+
});
|
|
31847
|
+
setImmediate(() => {
|
|
31848
|
+
try {
|
|
31849
|
+
deps.sendLocalSkillsReport?.();
|
|
31850
|
+
} catch (e) {
|
|
31851
|
+
deps.log(
|
|
31852
|
+
`[Bridge service] Local skills report failed: ${e instanceof Error ? e.message : String(e)}`
|
|
31853
|
+
);
|
|
31854
|
+
}
|
|
31855
|
+
});
|
|
31856
|
+
};
|
|
31857
|
+
|
|
31858
|
+
// src/agents/acp/from-bridge/handle-bridge-agent-config.ts
|
|
31859
|
+
function handleBridgeAgentConfig(msg, { acpManager }) {
|
|
31860
|
+
if (!Array.isArray(msg.agents) || msg.agents.length === 0) return;
|
|
31861
|
+
acpManager.setPreferredAgentType(msg.agents[0].type);
|
|
31862
|
+
}
|
|
31863
|
+
|
|
31864
|
+
// src/bridge/routing/handlers/agent-config.ts
|
|
31865
|
+
var handleAgentConfigMessage = (msg, deps) => {
|
|
31866
|
+
handleBridgeAgentConfig(msg, deps);
|
|
31867
|
+
};
|
|
31868
|
+
|
|
31869
|
+
// src/agents/acp/from-bridge/handle-bridge-prompt.ts
|
|
31870
|
+
import * as path25 from "node:path";
|
|
31871
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
31872
|
+
import { promisify as promisify5 } from "node:util";
|
|
31873
|
+
|
|
31874
|
+
// src/git/bridge-queue-key.ts
|
|
31875
|
+
import * as path24 from "node:path";
|
|
31876
|
+
import { createHash } from "node:crypto";
|
|
31877
|
+
function normalizeCanonicalGitUrl(url2) {
|
|
31878
|
+
let s = url2.trim();
|
|
31879
|
+
if (!s) return s;
|
|
31880
|
+
if (s.toLowerCase().endsWith(".git")) {
|
|
31881
|
+
s = s.slice(0, -4);
|
|
31882
|
+
}
|
|
31883
|
+
s = s.replace(/\/+$/, "");
|
|
31884
|
+
const httpsMatch = /^(https?):\/\/([^/]+)(\/.*)?$/i.exec(s);
|
|
31885
|
+
if (httpsMatch) {
|
|
31886
|
+
const host = httpsMatch[2].toLowerCase();
|
|
31887
|
+
const p = httpsMatch[3] ?? "";
|
|
31888
|
+
s = `${httpsMatch[1].toLowerCase()}://${host}${p}`;
|
|
31889
|
+
} else {
|
|
31890
|
+
const sshMatch = /^git@([^:]+):(.+)$/i.exec(s);
|
|
31891
|
+
if (sshMatch) {
|
|
31892
|
+
const host = sshMatch[1].toLowerCase();
|
|
31893
|
+
s = `git@${host}:${sshMatch[2]}`;
|
|
31894
|
+
}
|
|
31895
|
+
}
|
|
31896
|
+
return s;
|
|
31897
|
+
}
|
|
31898
|
+
function canonicalUrlToRepoIdSync(url2) {
|
|
31899
|
+
const normalized = normalizeCanonicalGitUrl(url2);
|
|
31900
|
+
return createHash("sha256").update(normalized).digest("hex").slice(0, 32);
|
|
31901
|
+
}
|
|
31902
|
+
function fallbackRepoIdFromPath(absPath) {
|
|
31903
|
+
return createHash("sha256").update(path24.resolve(absPath)).digest("hex").slice(0, 32);
|
|
31904
|
+
}
|
|
31905
|
+
async function resolveBridgeQueueBindFields(options) {
|
|
31906
|
+
const { effectiveCwd, worktreePaths, primaryRepoRoots, log: log2 } = options;
|
|
31907
|
+
const cwdAbs = worktreePaths.length > 0 ? path24.resolve(worktreePaths[0]) : path24.resolve(effectiveCwd);
|
|
31908
|
+
if (!primaryRepoRoots.length) {
|
|
31909
|
+
log2("[Bridge service] Prompt queue bind skipped: no Git repository roots under the working directory.");
|
|
31910
|
+
return null;
|
|
31911
|
+
}
|
|
31912
|
+
let primaryRoot = primaryRepoRoots[0];
|
|
31913
|
+
let remote = await getRemoteOriginUrl(primaryRoot);
|
|
31914
|
+
if (!remote) {
|
|
31915
|
+
for (const r of primaryRepoRoots.slice(1)) {
|
|
31916
|
+
const u = await getRemoteOriginUrl(r);
|
|
31917
|
+
if (u) {
|
|
31918
|
+
primaryRoot = r;
|
|
31919
|
+
remote = u;
|
|
31920
|
+
break;
|
|
31921
|
+
}
|
|
31922
|
+
}
|
|
31923
|
+
}
|
|
31924
|
+
const repoId = remote ? canonicalUrlToRepoIdSync(remote) : fallbackRepoIdFromPath(primaryRoot);
|
|
31925
|
+
const canonicalQueueKey = `repo:${repoId}::cwd:${cwdAbs}`;
|
|
31926
|
+
return { canonicalQueueKey, repoId, cwdAbs };
|
|
31927
|
+
}
|
|
31928
|
+
|
|
31929
|
+
// src/agents/acp/from-bridge/handle-bridge-prompt.ts
|
|
31930
|
+
var execFileAsync5 = promisify5(execFile5);
|
|
31931
|
+
async function readGitBranch(cwd) {
|
|
31932
|
+
try {
|
|
31933
|
+
const { stdout } = await execFileAsync5("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
|
|
31934
|
+
const b = stdout.trim();
|
|
31935
|
+
return b || null;
|
|
31936
|
+
} catch {
|
|
31937
|
+
return null;
|
|
31938
|
+
}
|
|
31939
|
+
}
|
|
31940
|
+
function handleBridgePrompt(msg, deps) {
|
|
31941
|
+
const { getWs, log: log2, acpManager, sessionWorktreeManager } = deps;
|
|
31942
|
+
const rawPrompt = msg.prompt;
|
|
31943
|
+
const promptText = typeof rawPrompt === "string" ? rawPrompt : rawPrompt != null ? String(rawPrompt) : "";
|
|
31944
|
+
if (!promptText.trim()) {
|
|
31945
|
+
log2(
|
|
31946
|
+
`[Bridge service] Prompt ignored: empty or missing prompt text (session ${typeof msg.sessionId === "string" ? msg.sessionId.slice(0, 8) : "\u2014"}\u2026, run ${typeof msg.runId === "string" ? msg.runId.slice(0, 8) : "\u2014"}\u2026).`
|
|
31947
|
+
);
|
|
31948
|
+
return;
|
|
31949
|
+
}
|
|
31950
|
+
const sessionId = msg.sessionId;
|
|
31951
|
+
const isNewSession = msg.isNewSession === true;
|
|
31952
|
+
const sessionWorktreesEnabled = msg.sessionWorktreesEnabled === true;
|
|
31953
|
+
const agentType = typeof msg.agentType === "string" && msg.agentType.trim() ? msg.agentType.trim() : void 0;
|
|
31954
|
+
const runId = typeof msg.runId === "string" ? msg.runId : void 0;
|
|
31955
|
+
const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
|
|
31956
|
+
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
31957
|
+
const sendResult2 = (result) => {
|
|
31958
|
+
const s = getWs();
|
|
31959
|
+
if (s) sendWsMessage(s, result);
|
|
31960
|
+
};
|
|
31961
|
+
const sendSessionUpdate = (payload) => {
|
|
31962
|
+
const s = getWs();
|
|
31963
|
+
if (!s) {
|
|
31964
|
+
log2("[Bridge service] Session update not sent: not connected to the bridge.");
|
|
31965
|
+
return;
|
|
31966
|
+
}
|
|
31967
|
+
const p = payload;
|
|
31968
|
+
sendWsMessage(s, payload);
|
|
31969
|
+
};
|
|
31970
|
+
async function preambleAndPrompt(resolvedCwd) {
|
|
31971
|
+
const s = getWs();
|
|
31972
|
+
const effectiveCwd = path25.resolve(resolvedCwd ?? getBridgeWorkspaceDirectory());
|
|
31973
|
+
const worktreePaths = sessionWorktreeManager.getWorktreePathsForSession(sessionId) ?? [];
|
|
31974
|
+
const repoRoots = await resolveSnapshotRepoRoots({
|
|
31975
|
+
worktreePaths,
|
|
31976
|
+
fallbackCwd: effectiveCwd,
|
|
31977
|
+
log: log2
|
|
31978
|
+
});
|
|
31979
|
+
if (s && sessionId) {
|
|
31980
|
+
const bind = await resolveBridgeQueueBindFields({
|
|
31981
|
+
effectiveCwd,
|
|
31982
|
+
worktreePaths,
|
|
31983
|
+
primaryRepoRoots: repoRoots,
|
|
31984
|
+
log: log2
|
|
31985
|
+
});
|
|
31986
|
+
if (bind) {
|
|
31987
|
+
sendWsMessage(s, {
|
|
31988
|
+
type: "bridge_queue_bind",
|
|
31989
|
+
sessionId,
|
|
31990
|
+
canonicalQueueKey: bind.canonicalQueueKey,
|
|
31991
|
+
repoId: bind.repoId,
|
|
31992
|
+
cwdAbs: bind.cwdAbs
|
|
31993
|
+
});
|
|
31994
|
+
}
|
|
31995
|
+
}
|
|
31996
|
+
if (s && sessionId) {
|
|
31997
|
+
const cliGitBranch = await readGitBranch(effectiveCwd);
|
|
31998
|
+
sendWsMessage(s, {
|
|
31999
|
+
type: "session_git_context_report",
|
|
32000
|
+
sessionId,
|
|
32001
|
+
cliGitBranch,
|
|
32002
|
+
agentUsesWorktree: sessionWorktreeManager.usesWorktreeSession(sessionId)
|
|
32003
|
+
});
|
|
32004
|
+
}
|
|
32005
|
+
if (s && sessionId && runId) {
|
|
32006
|
+
const cap = repoRoots.length > 0 ? await capturePreTurnSnapshot({ runId, repoRoots, agentCwd: effectiveCwd, log: log2 }) : { ok: false, error: "No git repos" };
|
|
32007
|
+
sendWsMessage(s, {
|
|
32008
|
+
type: "pre_turn_snapshot_report",
|
|
32009
|
+
sessionId,
|
|
32010
|
+
turnId: runId,
|
|
32011
|
+
captured: cap.ok
|
|
32012
|
+
});
|
|
32013
|
+
}
|
|
32014
|
+
acpManager.handlePrompt({
|
|
32015
|
+
promptText,
|
|
32016
|
+
promptId: msg.id,
|
|
32017
|
+
sessionId,
|
|
32018
|
+
runId,
|
|
32019
|
+
mode,
|
|
32020
|
+
agentType,
|
|
32021
|
+
cwd: effectiveCwd,
|
|
32022
|
+
sendResult: sendResult2,
|
|
32023
|
+
sendSessionUpdate
|
|
32024
|
+
});
|
|
32025
|
+
}
|
|
32026
|
+
void sessionWorktreeManager.resolveCwdForPrompt(sessionId, { isNewSession, sessionWorktreesEnabled }).then((cwd) => preambleAndPrompt(cwd)).catch((err) => {
|
|
32027
|
+
log2(`[Agent] Worktree resolve failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
32028
|
+
void preambleAndPrompt(void 0);
|
|
32029
|
+
});
|
|
32030
|
+
}
|
|
32031
|
+
|
|
32032
|
+
// src/bridge/routing/handlers/prompt.ts
|
|
32033
|
+
var handlePromptMessage = (msg, deps) => {
|
|
32034
|
+
handleBridgePrompt(msg, deps);
|
|
32035
|
+
};
|
|
32036
|
+
|
|
32037
|
+
// src/agents/acp/from-bridge/handle-bridge-cancel-run.ts
|
|
32038
|
+
function handleBridgeCancelRun(msg, { log: log2, acpManager }) {
|
|
32039
|
+
const runId = msg.runId;
|
|
32040
|
+
if (!runId) return;
|
|
32041
|
+
void acpManager.cancelRun(runId).then((sent) => {
|
|
32042
|
+
if (!sent) {
|
|
32043
|
+
log2(
|
|
32044
|
+
`[Agent] Cancel ignored for run ${runId.slice(0, 8)}\u2026 (no active run or cancel not available).`
|
|
32045
|
+
);
|
|
32046
|
+
}
|
|
32047
|
+
});
|
|
32048
|
+
}
|
|
32049
|
+
|
|
32050
|
+
// src/bridge/routing/handlers/cancel-run.ts
|
|
32051
|
+
var handleCancelRunMessage = (msg, deps) => {
|
|
32052
|
+
handleBridgeCancelRun(msg, deps);
|
|
32053
|
+
};
|
|
32054
|
+
|
|
32055
|
+
// src/agents/acp/from-bridge/handle-bridge-cursor-request-response.ts
|
|
32056
|
+
function handleBridgeCursorRequestResponse(msg, { acpManager }) {
|
|
32057
|
+
if (typeof msg.requestId !== "string") return;
|
|
32058
|
+
acpManager.resolveRequest(msg.requestId, msg.result ?? {});
|
|
32059
|
+
}
|
|
32060
|
+
|
|
32061
|
+
// src/bridge/routing/handlers/cursor-request-response.ts
|
|
32062
|
+
var handleCursorRequestResponseMessage = (msg, deps) => {
|
|
32063
|
+
handleBridgeCursorRequestResponse(msg, deps);
|
|
32064
|
+
};
|
|
32065
|
+
|
|
32066
|
+
// src/skills/handle-skill-call.ts
|
|
32067
|
+
function handleSkillCall(msg, socket, log2) {
|
|
32068
|
+
callSkill(msg.skillId, msg.operationId, msg.params ?? {}).then((result) => {
|
|
32069
|
+
sendWsMessage(socket, { type: "skill_result", id: msg.id, result });
|
|
32070
|
+
}).catch((err) => {
|
|
32071
|
+
sendWsMessage(socket, { type: "skill_result", id: msg.id, error: String(err) });
|
|
32072
|
+
log2(`[Bridge service] Skill invocation failed (${msg.skillId}/${msg.operationId}): ${err}`);
|
|
32073
|
+
});
|
|
32074
|
+
}
|
|
32075
|
+
|
|
32076
|
+
// src/bridge/routing/handlers/skill-call.ts
|
|
32077
|
+
var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
32078
|
+
if (!msg.skillId || msg.operationId === void 0) return;
|
|
32079
|
+
const socket = getWs();
|
|
32080
|
+
if (!socket) return;
|
|
32081
|
+
handleSkillCall(
|
|
32082
|
+
msg,
|
|
32083
|
+
socket,
|
|
32084
|
+
log2
|
|
32085
|
+
);
|
|
32086
|
+
};
|
|
32087
|
+
|
|
32088
|
+
// src/files/list-dir.ts
|
|
32089
|
+
import fs18 from "node:fs";
|
|
32090
|
+
import path27 from "node:path";
|
|
32091
|
+
|
|
32092
|
+
// src/files/ensure-under-cwd.ts
|
|
32093
|
+
import path26 from "node:path";
|
|
32094
|
+
function ensureUnderCwd(relativePath, cwd = getBridgeWorkspaceDirectory()) {
|
|
32095
|
+
const normalized = path26.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
32096
|
+
const resolved = path26.resolve(cwd, normalized);
|
|
32097
|
+
if (!resolved.startsWith(cwd + path26.sep) && resolved !== cwd) {
|
|
32098
|
+
return null;
|
|
32099
|
+
}
|
|
32100
|
+
return resolved;
|
|
32101
|
+
}
|
|
32102
|
+
|
|
32103
|
+
// src/files/list-dir.ts
|
|
32104
|
+
var LIST_DIR_YIELD_EVERY = 256;
|
|
32105
|
+
async function listDirAsync(relativePath) {
|
|
32106
|
+
const resolved = ensureUnderCwd(relativePath || ".", getBridgeWorkspaceDirectory());
|
|
32107
|
+
if (!resolved) {
|
|
32108
|
+
return { error: "Path is outside working directory" };
|
|
32109
|
+
}
|
|
32110
|
+
try {
|
|
32111
|
+
const names = await fs18.promises.readdir(resolved, { withFileTypes: true });
|
|
32112
|
+
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
32113
|
+
const entries = [];
|
|
32114
|
+
for (let i = 0; i < visible.length; i++) {
|
|
32115
|
+
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
32116
|
+
await yieldToEventLoop();
|
|
32117
|
+
}
|
|
32118
|
+
const d = visible[i];
|
|
32119
|
+
const entryPath = path27.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
32120
|
+
const fullPath = path27.join(resolved, d.name);
|
|
32121
|
+
let isDir = d.isDirectory();
|
|
32122
|
+
if (d.isSymbolicLink()) {
|
|
32123
|
+
try {
|
|
32124
|
+
const targetStat = await fs18.promises.stat(fullPath);
|
|
32125
|
+
isDir = targetStat.isDirectory();
|
|
32126
|
+
} catch {
|
|
32127
|
+
isDir = false;
|
|
32128
|
+
}
|
|
32129
|
+
}
|
|
32130
|
+
entries.push({
|
|
32131
|
+
name: d.name,
|
|
32132
|
+
path: entryPath,
|
|
32133
|
+
isDir,
|
|
32134
|
+
isSymlink: d.isSymbolicLink()
|
|
32135
|
+
});
|
|
32136
|
+
}
|
|
32137
|
+
entries.sort((a, b) => {
|
|
32138
|
+
if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
|
|
32139
|
+
return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
32140
|
+
});
|
|
32141
|
+
return { entries };
|
|
32142
|
+
} catch (err) {
|
|
32143
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
32144
|
+
return { error: message };
|
|
32145
|
+
}
|
|
32146
|
+
}
|
|
32147
|
+
|
|
32148
|
+
// src/files/read-file.ts
|
|
32149
|
+
import fs19 from "node:fs";
|
|
32150
|
+
import { StringDecoder } from "node:string_decoder";
|
|
32151
|
+
function resolveFilePath(relativePath) {
|
|
32152
|
+
const resolved = ensureUnderCwd(relativePath, getBridgeWorkspaceDirectory());
|
|
32153
|
+
if (!resolved) return { error: "Path is outside working directory" };
|
|
32154
|
+
let real;
|
|
32155
|
+
try {
|
|
32156
|
+
real = fs19.realpathSync(resolved);
|
|
32157
|
+
} catch {
|
|
32158
|
+
real = resolved;
|
|
32159
|
+
}
|
|
32160
|
+
const stat2 = fs19.statSync(real);
|
|
32161
|
+
if (!stat2.isFile()) return { error: "Not a file" };
|
|
32162
|
+
return real;
|
|
32163
|
+
}
|
|
32164
|
+
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
32165
|
+
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
32166
|
+
const fileSize = fs19.statSync(filePath).size;
|
|
32167
|
+
const fd = fs19.openSync(filePath, "r");
|
|
32168
|
+
const bufSize = 64 * 1024;
|
|
32169
|
+
const buf = Buffer.alloc(bufSize);
|
|
32170
|
+
const decoder = new StringDecoder("utf8");
|
|
32171
|
+
let currentLine = 0;
|
|
32172
|
+
const resultLines = [];
|
|
32173
|
+
let partial2 = "";
|
|
32174
|
+
let done = false;
|
|
32175
|
+
let skipLine0Chars = typeof lineOffsetIn === "number" ? lineOffsetIn : 0;
|
|
32176
|
+
let line0CharsReturned = 0;
|
|
32177
|
+
let line0Accum = "";
|
|
32178
|
+
try {
|
|
32179
|
+
let bytesRead;
|
|
32180
|
+
while (!done && (bytesRead = fs19.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
32181
|
+
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
32182
|
+
partial2 = "";
|
|
32183
|
+
let lineStart = 0;
|
|
32184
|
+
for (let i = 0; i < text.length; i++) {
|
|
32185
|
+
if (text[i] === "\n") {
|
|
32186
|
+
const lineContent = (() => {
|
|
32187
|
+
let lineEnd = i;
|
|
32188
|
+
if (lineEnd > lineStart && text[lineEnd - 1] === "\r") lineEnd--;
|
|
32189
|
+
return text.slice(lineStart, lineEnd);
|
|
32190
|
+
})();
|
|
32191
|
+
if (currentLine === 0 && (startLine === 0 || lineOffsetIn !== void 0)) {
|
|
32192
|
+
line0Accum += lineContent;
|
|
32193
|
+
const totalLine0 = line0Accum.length;
|
|
32194
|
+
if (skipLine0Chars > 0) {
|
|
32195
|
+
if (totalLine0 <= skipLine0Chars) {
|
|
32196
|
+
skipLine0Chars -= totalLine0;
|
|
32197
|
+
line0Accum = "";
|
|
32198
|
+
currentLine++;
|
|
32199
|
+
lineStart = i + 1;
|
|
32200
|
+
if (currentLine > endLine) {
|
|
32201
|
+
done = true;
|
|
32202
|
+
break;
|
|
32203
|
+
}
|
|
32204
|
+
continue;
|
|
32205
|
+
}
|
|
32206
|
+
const from = skipLine0Chars;
|
|
32207
|
+
const take = Math.min(lineChunkSize, totalLine0 - from);
|
|
32208
|
+
resultLines.push(line0Accum.slice(from, from + take));
|
|
32209
|
+
line0CharsReturned += take;
|
|
32210
|
+
if (from + take < totalLine0) {
|
|
32211
|
+
return {
|
|
32212
|
+
content: resultLines.join("\n"),
|
|
32213
|
+
size: fileSize,
|
|
32214
|
+
lineOffset: lineOffsetIn + line0CharsReturned,
|
|
32215
|
+
totalLines: 1
|
|
32216
|
+
};
|
|
32217
|
+
}
|
|
32218
|
+
line0Accum = "";
|
|
32219
|
+
skipLine0Chars = 0;
|
|
32220
|
+
line0CharsReturned = 0;
|
|
32221
|
+
} else if (totalLine0 > lineChunkSize) {
|
|
32222
|
+
resultLines.push(line0Accum.slice(0, lineChunkSize));
|
|
32223
|
+
return {
|
|
32224
|
+
content: resultLines.join("\n"),
|
|
32225
|
+
size: fileSize,
|
|
32226
|
+
lineOffset: lineChunkSize,
|
|
32227
|
+
totalLines: 1
|
|
32228
|
+
};
|
|
32229
|
+
} else {
|
|
32230
|
+
resultLines.push(line0Accum);
|
|
32231
|
+
line0Accum = "";
|
|
32232
|
+
}
|
|
32233
|
+
} else if (currentLine >= startLine && currentLine <= endLine) {
|
|
32234
|
+
resultLines.push(lineContent);
|
|
32235
|
+
}
|
|
32236
|
+
currentLine++;
|
|
32237
|
+
lineStart = i + 1;
|
|
32238
|
+
if (currentLine > endLine) {
|
|
32239
|
+
done = true;
|
|
32240
|
+
break;
|
|
32241
|
+
}
|
|
32242
|
+
}
|
|
32243
|
+
}
|
|
32244
|
+
if (!done) {
|
|
32245
|
+
const lineContent = text.slice(lineStart);
|
|
32246
|
+
if (currentLine === 0 && (startLine === 0 || lineOffsetIn !== void 0)) {
|
|
32247
|
+
line0Accum += lineContent;
|
|
32248
|
+
const totalLine0 = line0Accum.length;
|
|
32249
|
+
if (skipLine0Chars > 0) {
|
|
32250
|
+
if (totalLine0 <= skipLine0Chars) {
|
|
32251
|
+
skipLine0Chars -= totalLine0;
|
|
32252
|
+
line0Accum = "";
|
|
32253
|
+
} else {
|
|
32254
|
+
const from = skipLine0Chars;
|
|
32255
|
+
const take = Math.min(lineChunkSize, totalLine0 - from);
|
|
32256
|
+
resultLines.push(line0Accum.slice(from, from + take));
|
|
32257
|
+
return {
|
|
32258
|
+
content: resultLines.join("\n"),
|
|
32259
|
+
size: fileSize,
|
|
32260
|
+
lineOffset: (lineOffsetIn ?? 0) + take,
|
|
32261
|
+
totalLines: 1
|
|
32262
|
+
};
|
|
32263
|
+
}
|
|
32264
|
+
} else if (totalLine0 > lineChunkSize) {
|
|
32265
|
+
resultLines.push(line0Accum.slice(0, lineChunkSize));
|
|
32266
|
+
return {
|
|
32267
|
+
content: resultLines.join("\n"),
|
|
32268
|
+
size: fileSize,
|
|
32269
|
+
lineOffset: lineChunkSize,
|
|
32270
|
+
totalLines: 1
|
|
32271
|
+
};
|
|
32272
|
+
}
|
|
32273
|
+
}
|
|
32274
|
+
partial2 = text.slice(lineStart);
|
|
32275
|
+
}
|
|
32276
|
+
}
|
|
32277
|
+
if (!done) {
|
|
32278
|
+
const tail = partial2 + decoder.end();
|
|
32279
|
+
if (currentLine === 0 && (startLine === 0 || lineOffsetIn !== void 0) && tail.length > 0) {
|
|
32280
|
+
line0Accum += tail.endsWith("\r") ? tail.slice(0, -1) : tail;
|
|
32281
|
+
const totalLine0 = line0Accum.length;
|
|
32282
|
+
if (skipLine0Chars > 0) {
|
|
32283
|
+
if (totalLine0 <= skipLine0Chars) {
|
|
32284
|
+
return { content: resultLines.join("\n"), size: fileSize };
|
|
32285
|
+
}
|
|
32286
|
+
const from = skipLine0Chars;
|
|
32287
|
+
const take = Math.min(lineChunkSize, totalLine0 - from);
|
|
32288
|
+
resultLines.push(line0Accum.slice(from, from + take));
|
|
32289
|
+
line0CharsReturned += take;
|
|
32290
|
+
if (from + take < totalLine0) {
|
|
32291
|
+
return {
|
|
32292
|
+
content: resultLines.join("\n"),
|
|
32293
|
+
size: fileSize,
|
|
32294
|
+
lineOffset: (lineOffsetIn ?? 0) + line0CharsReturned,
|
|
32295
|
+
totalLines: 1
|
|
32296
|
+
};
|
|
32297
|
+
}
|
|
32298
|
+
} else if (totalLine0 > lineChunkSize) {
|
|
32299
|
+
resultLines.push(line0Accum.slice(0, lineChunkSize));
|
|
32300
|
+
return {
|
|
32301
|
+
content: resultLines.join("\n"),
|
|
32302
|
+
size: fileSize,
|
|
32303
|
+
lineOffset: lineChunkSize,
|
|
32304
|
+
totalLines: 1
|
|
32305
|
+
};
|
|
32306
|
+
} else {
|
|
32307
|
+
resultLines.push(line0Accum);
|
|
32308
|
+
}
|
|
32309
|
+
} else if (tail.length > 0 && currentLine >= startLine && currentLine <= endLine) {
|
|
32310
|
+
resultLines.push(tail.endsWith("\r") ? tail.slice(0, -1) : tail);
|
|
32311
|
+
}
|
|
32312
|
+
}
|
|
32313
|
+
return { content: resultLines.join("\n"), size: fileSize };
|
|
32314
|
+
} finally {
|
|
32315
|
+
fs19.closeSync(fd);
|
|
32316
|
+
}
|
|
32317
|
+
}
|
|
32318
|
+
function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
32319
|
+
try {
|
|
32320
|
+
const result = resolveFilePath(relativePath);
|
|
32321
|
+
if (typeof result === "object") return result;
|
|
32322
|
+
const hasRange = typeof startLine === "number" && typeof endLine === "number";
|
|
32323
|
+
if (hasRange) {
|
|
32324
|
+
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
32325
|
+
}
|
|
32326
|
+
const stat2 = fs19.statSync(result);
|
|
32327
|
+
const raw = fs19.readFileSync(result, "utf8");
|
|
32328
|
+
const lines = raw.split(/\r?\n/);
|
|
32329
|
+
return { content: raw, totalLines: lines.length, size: stat2.size };
|
|
32330
|
+
} catch (err) {
|
|
32331
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
32332
|
+
}
|
|
32333
|
+
}
|
|
32334
|
+
async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
32335
|
+
await yieldToEventLoop();
|
|
32336
|
+
return readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize);
|
|
32337
|
+
}
|
|
32338
|
+
|
|
32339
|
+
// src/files/handle-file-browser-search.ts
|
|
32340
|
+
var SEARCH_LIMIT = 100;
|
|
32341
|
+
function handleFileBrowserSearch(msg, socket) {
|
|
32342
|
+
void (async () => {
|
|
32343
|
+
await yieldToEventLoop();
|
|
32344
|
+
const q = typeof msg.q === "string" ? msg.q : "";
|
|
32345
|
+
const cwd = getBridgeWorkspaceDirectory();
|
|
32346
|
+
const index = loadFileIndex(cwd);
|
|
32347
|
+
if (index === null) {
|
|
32348
|
+
sendWsMessage(socket, {
|
|
32349
|
+
type: "file_browser_search_response",
|
|
32350
|
+
id: msg.id,
|
|
32351
|
+
paths: [],
|
|
32352
|
+
indexReady: false
|
|
32353
|
+
});
|
|
32354
|
+
return;
|
|
32355
|
+
}
|
|
32356
|
+
const results = await searchFileIndexAsync(index, q, SEARCH_LIMIT);
|
|
32357
|
+
sendWsMessage(socket, {
|
|
32358
|
+
type: "file_browser_search_response",
|
|
32359
|
+
id: msg.id,
|
|
32360
|
+
paths: results,
|
|
32361
|
+
indexReady: true
|
|
32362
|
+
});
|
|
32363
|
+
})();
|
|
32364
|
+
}
|
|
32365
|
+
function triggerFileIndexBuild() {
|
|
32366
|
+
setImmediate(() => {
|
|
32367
|
+
void ensureFileIndexAsync(getBridgeWorkspaceDirectory()).catch((e) => {
|
|
32368
|
+
console.error("[file-index] Background build failed:", e);
|
|
32369
|
+
});
|
|
32370
|
+
});
|
|
32371
|
+
}
|
|
32372
|
+
|
|
32373
|
+
// src/files/handle-file-browser-request.ts
|
|
32374
|
+
function handleFileBrowserRequest(msg, socket) {
|
|
32375
|
+
void (async () => {
|
|
32376
|
+
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
32377
|
+
const op = msg.op === "read" ? "read" : "list";
|
|
32378
|
+
if (op === "list") {
|
|
32379
|
+
const result = await listDirAsync(reqPath);
|
|
32380
|
+
if ("error" in result) {
|
|
32381
|
+
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
32382
|
+
} else {
|
|
32383
|
+
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, entries: result.entries });
|
|
32384
|
+
if (reqPath === "." || reqPath === "") {
|
|
32385
|
+
triggerFileIndexBuild();
|
|
32386
|
+
}
|
|
32387
|
+
}
|
|
32388
|
+
} else {
|
|
32389
|
+
const startLine = typeof msg.startLine === "number" ? msg.startLine : void 0;
|
|
32390
|
+
const endLine = typeof msg.endLine === "number" ? msg.endLine : void 0;
|
|
32391
|
+
const lineOffset = typeof msg.lineOffset === "number" ? msg.lineOffset : void 0;
|
|
32392
|
+
const lineChunkSize = typeof msg.lineChunkSize === "number" ? msg.lineChunkSize : void 0;
|
|
32393
|
+
const result = await readFileAsync(reqPath, startLine, endLine, lineOffset, lineChunkSize);
|
|
32394
|
+
if ("error" in result) {
|
|
32395
|
+
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
32396
|
+
} else {
|
|
32397
|
+
const payload = {
|
|
32398
|
+
type: "file_browser_response",
|
|
32399
|
+
id: msg.id,
|
|
32400
|
+
content: result.content,
|
|
32401
|
+
totalLines: result.totalLines,
|
|
32402
|
+
size: result.size
|
|
32403
|
+
};
|
|
32404
|
+
if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
|
|
32405
|
+
sendWsMessage(socket, payload);
|
|
32406
|
+
}
|
|
32407
|
+
}
|
|
32408
|
+
})();
|
|
32409
|
+
}
|
|
32410
|
+
|
|
32411
|
+
// src/bridge/routing/handlers/file-browser-messages.ts
|
|
32412
|
+
function handleFileBrowserRequestMessage(msg, { getWs }) {
|
|
32413
|
+
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
32414
|
+
const socket = getWs();
|
|
32415
|
+
if (!socket) return;
|
|
32416
|
+
handleFileBrowserRequest(
|
|
32417
|
+
msg,
|
|
32418
|
+
socket
|
|
32419
|
+
);
|
|
32420
|
+
}
|
|
32421
|
+
function handleFileBrowserSearchMessage(msg, { getWs }) {
|
|
32422
|
+
if (typeof msg.id !== "string") return;
|
|
32423
|
+
const socket = getWs();
|
|
32424
|
+
if (!socket) return;
|
|
32425
|
+
handleFileBrowserSearch(msg, socket);
|
|
32426
|
+
}
|
|
32427
|
+
|
|
32428
|
+
// src/bridge/routing/handlers/skill-layout-request.ts
|
|
32429
|
+
function handleSkillLayoutRequest(msg, deps) {
|
|
32430
|
+
const socket = deps.getWs();
|
|
32431
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
32432
|
+
const roots = discoverSkillLayoutRoots(getBridgeWorkspaceDirectory());
|
|
32433
|
+
socket?.send(JSON.stringify({ type: "skill_layout_response", id, roots }));
|
|
32434
|
+
}
|
|
32435
|
+
|
|
32436
|
+
// src/skills/install-remote-skills.ts
|
|
32437
|
+
import fs20 from "node:fs";
|
|
32438
|
+
import path28 from "node:path";
|
|
32439
|
+
function installRemoteSkills(cwd, targetDir, items) {
|
|
32440
|
+
const installed = [];
|
|
32441
|
+
if (!Array.isArray(items)) {
|
|
32442
|
+
return { success: false, error: "Invalid items" };
|
|
32443
|
+
}
|
|
32444
|
+
try {
|
|
32445
|
+
for (const item of items) {
|
|
32446
|
+
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
32447
|
+
continue;
|
|
32448
|
+
}
|
|
32449
|
+
const skillDir = path28.join(cwd, targetDir, item.skillName);
|
|
32450
|
+
for (const f of item.files) {
|
|
32451
|
+
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
32452
|
+
const dest = path28.join(skillDir, f.path);
|
|
32453
|
+
fs20.mkdirSync(path28.dirname(dest), { recursive: true });
|
|
32454
|
+
if (f.text !== void 0) {
|
|
32455
|
+
fs20.writeFileSync(dest, f.text, "utf8");
|
|
32456
|
+
} else if (f.base64) {
|
|
32457
|
+
fs20.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
32458
|
+
}
|
|
32459
|
+
}
|
|
32460
|
+
installed.push({
|
|
32461
|
+
sourceId: item.sourceId,
|
|
32462
|
+
skillName: item.skillName,
|
|
32463
|
+
versionHash: item.versionHash
|
|
32464
|
+
});
|
|
32465
|
+
}
|
|
32466
|
+
return { success: true, installed };
|
|
32467
|
+
} catch (e) {
|
|
32468
|
+
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
32469
|
+
}
|
|
32470
|
+
}
|
|
32471
|
+
|
|
32472
|
+
// src/bridge/routing/handlers/install-skills.ts
|
|
32473
|
+
var handleInstallSkillsMessage = (msg, deps) => {
|
|
32474
|
+
const socket = deps.getWs();
|
|
32475
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
32476
|
+
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
32477
|
+
const rawItems = msg.items;
|
|
32478
|
+
const cwd = getBridgeWorkspaceDirectory();
|
|
32479
|
+
const result = installRemoteSkills(cwd, targetDir, rawItems);
|
|
32480
|
+
if (!result.success) {
|
|
32481
|
+
const err = result.error ?? "Invalid items";
|
|
32482
|
+
deps.log(`[Bridge service] Install skills failed: ${err}`);
|
|
32483
|
+
socket?.send(JSON.stringify({ type: "install_skills_result", id, success: false, error: err }));
|
|
32484
|
+
return;
|
|
32485
|
+
}
|
|
32486
|
+
socket?.send(JSON.stringify({ type: "install_skills_result", id, success: true, installed: result.installed }));
|
|
32487
|
+
};
|
|
32488
|
+
|
|
32489
|
+
// src/bridge/routing/handlers/refresh-local-skills.ts
|
|
32490
|
+
var handleRefreshLocalSkills = (_msg, deps) => {
|
|
32491
|
+
deps.sendLocalSkillsReport?.();
|
|
32492
|
+
};
|
|
32493
|
+
|
|
32494
|
+
// src/bridge/routing/handlers/session-git-request.ts
|
|
32495
|
+
function sendResult(ws, id, payload) {
|
|
32496
|
+
if (!ws) return;
|
|
32497
|
+
sendWsMessage(ws, { type: "session_git_result", id, ...payload });
|
|
32498
|
+
}
|
|
32499
|
+
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
32500
|
+
if (typeof msg.id !== "string") return;
|
|
32501
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
32502
|
+
const action = msg.action;
|
|
32503
|
+
if (!sessionId || action !== "status" && action !== "push" && action !== "commit") return;
|
|
32504
|
+
void (async () => {
|
|
32505
|
+
const ws = deps.getWs();
|
|
32506
|
+
const reply = (payload) => sendResult(ws, msg.id, payload);
|
|
32507
|
+
try {
|
|
32508
|
+
if (action === "status") {
|
|
32509
|
+
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
32510
|
+
reply({
|
|
32511
|
+
ok: true,
|
|
32512
|
+
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
32513
|
+
hasUnpushedCommits: r.hasUnpushedCommits
|
|
32514
|
+
});
|
|
32515
|
+
return;
|
|
32516
|
+
}
|
|
32517
|
+
if (action === "push") {
|
|
32518
|
+
const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
|
|
32519
|
+
if (!pushRes.ok) {
|
|
32520
|
+
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
32521
|
+
return;
|
|
32522
|
+
}
|
|
32523
|
+
const st2 = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
32524
|
+
reply({
|
|
32525
|
+
ok: true,
|
|
32526
|
+
hasUncommittedChanges: st2.hasUncommittedChanges,
|
|
32527
|
+
hasUnpushedCommits: st2.hasUnpushedCommits
|
|
32528
|
+
});
|
|
32529
|
+
return;
|
|
32530
|
+
}
|
|
32531
|
+
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
32532
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
32533
|
+
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
32534
|
+
if (!branch.trim() || !message.trim()) {
|
|
32535
|
+
reply({ ok: false, error: "branch and message are required for commit" });
|
|
32536
|
+
return;
|
|
32537
|
+
}
|
|
32538
|
+
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
32539
|
+
sessionId,
|
|
32540
|
+
branch: branch.trim(),
|
|
32541
|
+
message: message.trim(),
|
|
32542
|
+
push: pushAfterCommit
|
|
32543
|
+
});
|
|
32544
|
+
if (!commitRes.ok) {
|
|
32545
|
+
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
32546
|
+
return;
|
|
32547
|
+
}
|
|
32548
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
32549
|
+
reply({
|
|
32550
|
+
ok: true,
|
|
32551
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
32552
|
+
hasUnpushedCommits: st.hasUnpushedCommits
|
|
32553
|
+
});
|
|
32554
|
+
} catch (e) {
|
|
32555
|
+
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
32556
|
+
}
|
|
32557
|
+
})();
|
|
32558
|
+
};
|
|
32559
|
+
|
|
32560
|
+
// src/bridge/routing/handlers/rename-session-branch.ts
|
|
32561
|
+
var handleRenameSessionBranchMessage = (msg, deps) => {
|
|
32562
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
32563
|
+
const newBranch = typeof msg.newBranch === "string" ? msg.newBranch : "";
|
|
32564
|
+
if (!sessionId || !newBranch) return;
|
|
32565
|
+
void deps.sessionWorktreeManager.renameSessionBranch(sessionId, newBranch);
|
|
32566
|
+
};
|
|
32567
|
+
|
|
32568
|
+
// src/bridge/routing/handlers/session-archived.ts
|
|
32569
|
+
var handleSessionArchivedMessage = (msg, deps) => {
|
|
32570
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
32571
|
+
if (!sessionId) return;
|
|
32572
|
+
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
32573
|
+
};
|
|
32574
|
+
|
|
32575
|
+
// src/bridge/routing/handlers/session-discarded.ts
|
|
32576
|
+
var handleSessionDiscardedMessage = (msg, deps) => {
|
|
32577
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
32578
|
+
if (!sessionId) return;
|
|
32579
|
+
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
32580
|
+
};
|
|
32581
|
+
|
|
32582
|
+
// src/bridge/routing/handlers/revert-turn-snapshot.ts
|
|
32583
|
+
import * as fs21 from "node:fs";
|
|
32584
|
+
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
32585
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
32586
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
32587
|
+
const turnId = typeof msg.turnId === "string" ? msg.turnId : "";
|
|
32588
|
+
if (!id || !sessionId || !turnId) return;
|
|
32589
|
+
const { getWs, log: log2, sessionWorktreeManager } = deps;
|
|
32590
|
+
void (async () => {
|
|
32591
|
+
const s = getWs();
|
|
32592
|
+
if (!s) return;
|
|
32593
|
+
const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? getBridgeWorkspaceDirectory();
|
|
32594
|
+
const file2 = snapshotFilePath(agentBase, turnId);
|
|
32595
|
+
if (!fs21.existsSync(file2)) {
|
|
32596
|
+
sendWsMessage(s, {
|
|
32597
|
+
type: "revert_turn_snapshot_result",
|
|
32598
|
+
id,
|
|
32599
|
+
ok: false,
|
|
32600
|
+
error: "No snapshot found for this turn (git state may be unavailable)."
|
|
32601
|
+
});
|
|
32602
|
+
return;
|
|
32603
|
+
}
|
|
32604
|
+
const res = await applyPreTurnSnapshot(file2, log2);
|
|
32605
|
+
sendWsMessage(s, {
|
|
32606
|
+
type: "revert_turn_snapshot_result",
|
|
32607
|
+
id,
|
|
32608
|
+
ok: res.ok,
|
|
32609
|
+
...res.error ? { error: res.error } : {}
|
|
32610
|
+
});
|
|
32611
|
+
})();
|
|
32612
|
+
};
|
|
32613
|
+
|
|
32614
|
+
// src/bridge/routing/handlers/dev-server-control.ts
|
|
32615
|
+
var handleDevServerControl = (msg, deps) => {
|
|
32616
|
+
const serverId = typeof msg.serverId === "string" ? msg.serverId : "";
|
|
32617
|
+
const action = msg.action === "start" || msg.action === "stop" ? msg.action : null;
|
|
32618
|
+
if (!serverId || !action) return;
|
|
32619
|
+
deps.devServerManager?.handleControl(serverId, action);
|
|
32620
|
+
};
|
|
32621
|
+
|
|
32622
|
+
// src/bridge/routing/handlers/dev-servers-config.ts
|
|
32623
|
+
var handleDevServersConfig = (msg, deps) => {
|
|
32624
|
+
const devServers = msg.devServers;
|
|
32625
|
+
deps.devServerManager?.applyConfig(devServers ?? []);
|
|
32626
|
+
};
|
|
32627
|
+
|
|
32628
|
+
// src/bridge/routing/dispatch-bridge-message.ts
|
|
32629
|
+
function dispatchBridgeMessage(msg, deps) {
|
|
32630
|
+
const type = msg.type;
|
|
32631
|
+
if (typeof type !== "string") return;
|
|
32632
|
+
switch (type) {
|
|
32633
|
+
case "auth_token":
|
|
32634
|
+
handleAuthToken(msg, deps);
|
|
32635
|
+
break;
|
|
32636
|
+
case "bridge_identified":
|
|
32637
|
+
handleBridgeIdentified(msg, deps);
|
|
32638
|
+
break;
|
|
32639
|
+
case "dev_servers_config":
|
|
32640
|
+
handleDevServersConfig(msg, deps);
|
|
32641
|
+
break;
|
|
32642
|
+
case "server_control":
|
|
32643
|
+
handleDevServerControl(msg, deps);
|
|
32644
|
+
break;
|
|
32645
|
+
case "agent_config":
|
|
32646
|
+
handleAgentConfigMessage(msg, deps);
|
|
32647
|
+
break;
|
|
32648
|
+
case "prompt":
|
|
32649
|
+
handlePromptMessage(msg, deps);
|
|
32650
|
+
break;
|
|
32651
|
+
case "session_git_request":
|
|
32652
|
+
handleSessionGitRequestMessage(msg, deps);
|
|
32653
|
+
break;
|
|
32654
|
+
case "rename_session_branch":
|
|
32655
|
+
handleRenameSessionBranchMessage(msg, deps);
|
|
32656
|
+
break;
|
|
32657
|
+
case "session_archived":
|
|
32658
|
+
handleSessionArchivedMessage(msg, deps);
|
|
32659
|
+
break;
|
|
32660
|
+
case "session_discarded":
|
|
32661
|
+
handleSessionDiscardedMessage(msg, deps);
|
|
32662
|
+
break;
|
|
32663
|
+
case "revert_turn_snapshot":
|
|
32664
|
+
handleRevertTurnSnapshotMessage(msg, deps);
|
|
32665
|
+
break;
|
|
32666
|
+
case "cancel_run":
|
|
32667
|
+
handleCancelRunMessage(msg, deps);
|
|
32668
|
+
break;
|
|
32669
|
+
case "cursor_request_response":
|
|
32670
|
+
handleCursorRequestResponseMessage(msg, deps);
|
|
32671
|
+
break;
|
|
32672
|
+
case "skill_call":
|
|
32673
|
+
handleSkillCallMessage(msg, deps);
|
|
32674
|
+
break;
|
|
32675
|
+
case "file_browser_request":
|
|
32676
|
+
handleFileBrowserRequestMessage(msg, deps);
|
|
32677
|
+
break;
|
|
32678
|
+
case "file_browser_search":
|
|
32679
|
+
handleFileBrowserSearchMessage(msg, deps);
|
|
32680
|
+
break;
|
|
32681
|
+
case "skill_layout_request":
|
|
32682
|
+
handleSkillLayoutRequest(msg, deps);
|
|
32683
|
+
break;
|
|
32684
|
+
case "install_skills":
|
|
32685
|
+
handleInstallSkillsMessage(msg, deps);
|
|
32686
|
+
break;
|
|
32687
|
+
case "refresh_local_skills":
|
|
32688
|
+
handleRefreshLocalSkills(msg, deps);
|
|
32689
|
+
break;
|
|
32690
|
+
default:
|
|
32691
|
+
deps.log?.(`[Bridge service] unhandled message type: ${type}`);
|
|
32692
|
+
}
|
|
32693
|
+
}
|
|
32694
|
+
|
|
32695
|
+
// src/bridge/routing/handle-bridge-message.ts
|
|
32696
|
+
function handleBridgeMessage(data, deps) {
|
|
32697
|
+
const msg = data;
|
|
32698
|
+
if (!deps.getWs()) return;
|
|
32699
|
+
setImmediate(() => {
|
|
32700
|
+
dispatchBridgeMessage(msg, deps);
|
|
32701
|
+
});
|
|
32439
32702
|
}
|
|
32440
32703
|
|
|
32441
|
-
// src/
|
|
32442
|
-
|
|
32443
|
-
|
|
32444
|
-
|
|
32445
|
-
kiro_acp_client_exports,
|
|
32446
|
-
claude_code_acp_client_exports
|
|
32447
|
-
];
|
|
32448
|
-
async function detectLocalAgentTypes() {
|
|
32704
|
+
// src/auth/refresh-bridge-tokens.ts
|
|
32705
|
+
async function refreshBridgeTokens(params) {
|
|
32706
|
+
const base = params.apiUrl.replace(/\/$/, "");
|
|
32707
|
+
const url2 = `${base}/api/bridges/tokens/refresh`;
|
|
32449
32708
|
try {
|
|
32450
|
-
const
|
|
32451
|
-
|
|
32452
|
-
|
|
32453
|
-
|
|
32454
|
-
|
|
32455
|
-
|
|
32456
|
-
|
|
32457
|
-
|
|
32709
|
+
const res = await fetch(url2, {
|
|
32710
|
+
method: "POST",
|
|
32711
|
+
headers: { "Content-Type": "application/json" },
|
|
32712
|
+
body: JSON.stringify({
|
|
32713
|
+
workspaceId: params.workspaceId,
|
|
32714
|
+
refreshToken: params.refreshToken
|
|
32715
|
+
})
|
|
32716
|
+
});
|
|
32717
|
+
if (!res.ok) return null;
|
|
32718
|
+
const data = await res.json();
|
|
32719
|
+
if (typeof data.token !== "string" || typeof data.refreshToken !== "string") return null;
|
|
32720
|
+
return {
|
|
32721
|
+
token: data.token,
|
|
32722
|
+
refreshToken: data.refreshToken,
|
|
32723
|
+
workspaceId: typeof data.workspaceId === "string" ? data.workspaceId : params.workspaceId,
|
|
32724
|
+
tokenId: typeof data.tokenId === "string" ? data.tokenId : ""
|
|
32725
|
+
};
|
|
32458
32726
|
} catch {
|
|
32459
|
-
return
|
|
32727
|
+
return null;
|
|
32460
32728
|
}
|
|
32461
32729
|
}
|
|
32462
32730
|
|
|
32463
|
-
// src/bridge/connection/
|
|
32464
|
-
function createSendLocalSkillsReport(getWs, logFn) {
|
|
32465
|
-
return () => {
|
|
32466
|
-
try {
|
|
32467
|
-
const socket = getWs();
|
|
32468
|
-
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
32469
|
-
const skills2 = discoverLocalSkills(getBridgeWorkspaceDirectory());
|
|
32470
|
-
socket.send(JSON.stringify({ type: "local_skills", skills: skills2 }));
|
|
32471
|
-
} catch (e) {
|
|
32472
|
-
logFn(
|
|
32473
|
-
`[Bridge service] Local skills report failed: ${e instanceof Error ? e.message : String(e)}`
|
|
32474
|
-
);
|
|
32475
|
-
}
|
|
32476
|
-
};
|
|
32477
|
-
}
|
|
32478
|
-
function createReportAutoDetectedAgents(getWs, logFn) {
|
|
32479
|
-
return async () => {
|
|
32480
|
-
try {
|
|
32481
|
-
const types = await detectLocalAgentTypes();
|
|
32482
|
-
const socket = getWs();
|
|
32483
|
-
if (socket && socket.readyState === wrapper_default.OPEN) {
|
|
32484
|
-
sendWsMessage(socket, { type: "auto_detected_agents_report", agentTypes: types });
|
|
32485
|
-
}
|
|
32486
|
-
} catch (e) {
|
|
32487
|
-
logFn(
|
|
32488
|
-
`[Bridge service] Auto-detected agents report failed: ${e instanceof Error ? e.message : String(e)}`
|
|
32489
|
-
);
|
|
32490
|
-
}
|
|
32491
|
-
};
|
|
32492
|
-
}
|
|
32493
|
-
|
|
32494
|
-
// src/bridge/connection/create-bridge-connection.ts
|
|
32731
|
+
// src/bridge/connection/main-bridge-ws-lifecycle.ts
|
|
32495
32732
|
var BRIDGE_CLIENT_PING_MS = 25e3;
|
|
32496
|
-
|
|
32497
|
-
const {
|
|
32498
|
-
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
32499
|
-
const logFn = options.log ?? log;
|
|
32500
|
-
let accessToken = options.authToken;
|
|
32501
|
-
let refreshTok = options.refreshToken;
|
|
32502
|
-
let authRefreshInFlight = false;
|
|
32503
|
-
const state = {
|
|
32504
|
-
closedByUser: false,
|
|
32505
|
-
reconnectAttempt: 0,
|
|
32506
|
-
logBridgeOpenAsReconnect: false,
|
|
32507
|
-
reconnectTimeout: null,
|
|
32508
|
-
currentWs: null,
|
|
32509
|
-
mainQuiet: createEmptyReconnectQuietSlot(),
|
|
32510
|
-
firehoseHandle: null,
|
|
32511
|
-
lastFirehoseParams: null,
|
|
32512
|
-
firehoseReconnectTimeout: null,
|
|
32513
|
-
firehoseReconnectAttempt: 0,
|
|
32514
|
-
firehoseGeneration: 0,
|
|
32515
|
-
firehoseQuiet: createEmptyReconnectQuietSlot()
|
|
32516
|
-
};
|
|
32517
|
-
const worktreesRootAbs = options.worktreesRootAbs ?? defaultWorktreesRootAbs();
|
|
32518
|
-
const sessionWorktreeManager = new SessionWorktreeManager({
|
|
32519
|
-
worktreesRootAbs,
|
|
32520
|
-
log: logFn
|
|
32521
|
-
});
|
|
32522
|
-
const acpManager = await createAcpManager({ log: logFn });
|
|
32523
|
-
logFn("CLI running. Press Ctrl+C to exit.");
|
|
32524
|
-
function getWs() {
|
|
32525
|
-
return state.currentWs;
|
|
32526
|
-
}
|
|
32527
|
-
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeCwd: getBridgeWorkspaceDirectory });
|
|
32528
|
-
const onBridgeIdentified = createOnBridgeIdentified({
|
|
32529
|
-
sessionWorktreeManager,
|
|
32530
|
-
devServerManager,
|
|
32531
|
-
firehoseServerUrl,
|
|
32532
|
-
workspaceId,
|
|
32733
|
+
function createMainBridgeWebSocketLifecycle(params) {
|
|
32734
|
+
const {
|
|
32533
32735
|
state,
|
|
32534
|
-
|
|
32535
|
-
|
|
32536
|
-
|
|
32537
|
-
|
|
32736
|
+
getWs,
|
|
32737
|
+
apiUrl,
|
|
32738
|
+
workspaceId,
|
|
32739
|
+
justAuthenticated,
|
|
32740
|
+
logFn,
|
|
32741
|
+
messageDeps,
|
|
32742
|
+
tokens,
|
|
32743
|
+
persistTokens,
|
|
32744
|
+
onAuthInvalid
|
|
32745
|
+
} = params;
|
|
32746
|
+
let authRefreshInFlight = false;
|
|
32538
32747
|
function handleOpen() {
|
|
32539
32748
|
const logOpenAsPostRefreshReconnect = state.logBridgeOpenAsReconnect;
|
|
32540
32749
|
clearMainBridgeReconnectQuietOnOpen(state, logFn);
|
|
@@ -32549,8 +32758,10 @@ async function createBridgeConnection(options) {
|
|
|
32549
32758
|
reportGitRepos(getWs, logFn);
|
|
32550
32759
|
}
|
|
32551
32760
|
if (justAuthenticated && socket) {
|
|
32552
|
-
logFn(
|
|
32553
|
-
|
|
32761
|
+
logFn(
|
|
32762
|
+
"Save these for future runs (access token may rotate; refresh token is stored in ~/.buildautomaton/config.json when you use browser auth):"
|
|
32763
|
+
);
|
|
32764
|
+
logFn(` export BUILDAMATON_AUTH_TOKEN="${tokens.accessToken}"`);
|
|
32554
32765
|
logFn(` export BUILDAMATON_WORKSPACE_ID="${workspaceId}"`);
|
|
32555
32766
|
}
|
|
32556
32767
|
}
|
|
@@ -32564,16 +32775,6 @@ async function createBridgeConnection(options) {
|
|
|
32564
32775
|
scheduleMainBridgeReconnect(state, connect, logFn);
|
|
32565
32776
|
}
|
|
32566
32777
|
}
|
|
32567
|
-
const messageDeps = {
|
|
32568
|
-
getWs,
|
|
32569
|
-
log: logFn,
|
|
32570
|
-
acpManager,
|
|
32571
|
-
sessionWorktreeManager,
|
|
32572
|
-
onBridgeIdentified,
|
|
32573
|
-
sendLocalSkillsReport,
|
|
32574
|
-
reportAutoDetectedAgents,
|
|
32575
|
-
devServerManager
|
|
32576
|
-
};
|
|
32577
32778
|
function connect() {
|
|
32578
32779
|
if (state.closedByUser) return;
|
|
32579
32780
|
if (state.reconnectTimeout != null) {
|
|
@@ -32592,7 +32793,7 @@ async function createBridgeConnection(options) {
|
|
|
32592
32793
|
}
|
|
32593
32794
|
state.currentWs = null;
|
|
32594
32795
|
}
|
|
32595
|
-
const url2 = buildBridgeUrl(apiUrl, workspaceId, accessToken);
|
|
32796
|
+
const url2 = buildBridgeUrl(apiUrl, workspaceId, tokens.accessToken);
|
|
32596
32797
|
state.currentWs = createWsBridge({
|
|
32597
32798
|
url: url2,
|
|
32598
32799
|
clientPingIntervalMs: BRIDGE_CLIENT_PING_MS,
|
|
@@ -32601,12 +32802,16 @@ async function createBridgeConnection(options) {
|
|
|
32601
32802
|
void (async () => {
|
|
32602
32803
|
authRefreshInFlight = true;
|
|
32603
32804
|
try {
|
|
32604
|
-
if (
|
|
32605
|
-
const next = await refreshBridgeTokens({
|
|
32805
|
+
if (tokens.refreshToken) {
|
|
32806
|
+
const next = await refreshBridgeTokens({
|
|
32807
|
+
apiUrl,
|
|
32808
|
+
workspaceId,
|
|
32809
|
+
refreshToken: tokens.refreshToken
|
|
32810
|
+
});
|
|
32606
32811
|
if (next?.token && next.refreshToken) {
|
|
32607
|
-
accessToken = next.token;
|
|
32608
|
-
|
|
32609
|
-
persistTokens?.({ token: accessToken, refreshToken:
|
|
32812
|
+
tokens.accessToken = next.token;
|
|
32813
|
+
tokens.refreshToken = next.refreshToken;
|
|
32814
|
+
persistTokens?.({ token: tokens.accessToken, refreshToken: tokens.refreshToken });
|
|
32610
32815
|
logFn("[Bridge service] Access token refreshed; reconnecting\u2026");
|
|
32611
32816
|
state.reconnectAttempt = 0;
|
|
32612
32817
|
state.logBridgeOpenAsReconnect = true;
|
|
@@ -32631,6 +32836,75 @@ async function createBridgeConnection(options) {
|
|
|
32631
32836
|
onMessage: (data) => handleBridgeMessage(data, messageDeps)
|
|
32632
32837
|
});
|
|
32633
32838
|
}
|
|
32839
|
+
return { connect };
|
|
32840
|
+
}
|
|
32841
|
+
|
|
32842
|
+
// src/bridge/connection/create-bridge-connection.ts
|
|
32843
|
+
async function createBridgeConnection(options) {
|
|
32844
|
+
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
32845
|
+
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
32846
|
+
const logFn = options.log ?? log;
|
|
32847
|
+
const tokens = {
|
|
32848
|
+
accessToken: options.authToken,
|
|
32849
|
+
refreshToken: options.refreshToken
|
|
32850
|
+
};
|
|
32851
|
+
const state = {
|
|
32852
|
+
closedByUser: false,
|
|
32853
|
+
reconnectAttempt: 0,
|
|
32854
|
+
logBridgeOpenAsReconnect: false,
|
|
32855
|
+
reconnectTimeout: null,
|
|
32856
|
+
currentWs: null,
|
|
32857
|
+
mainQuiet: createEmptyReconnectQuietSlot(),
|
|
32858
|
+
firehoseHandle: null,
|
|
32859
|
+
lastFirehoseParams: null,
|
|
32860
|
+
firehoseReconnectTimeout: null,
|
|
32861
|
+
firehoseReconnectAttempt: 0,
|
|
32862
|
+
firehoseGeneration: 0,
|
|
32863
|
+
firehoseQuiet: createEmptyReconnectQuietSlot()
|
|
32864
|
+
};
|
|
32865
|
+
const worktreesRootAbs = options.worktreesRootAbs ?? defaultWorktreesRootAbs();
|
|
32866
|
+
const sessionWorktreeManager = new SessionWorktreeManager({
|
|
32867
|
+
worktreesRootAbs,
|
|
32868
|
+
log: logFn
|
|
32869
|
+
});
|
|
32870
|
+
const acpManager = await createAcpManager({ log: logFn });
|
|
32871
|
+
logFn("CLI running. Press Ctrl+C to exit.");
|
|
32872
|
+
function getWs() {
|
|
32873
|
+
return state.currentWs;
|
|
32874
|
+
}
|
|
32875
|
+
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeCwd: getBridgeWorkspaceDirectory });
|
|
32876
|
+
const onBridgeIdentified = createOnBridgeIdentified({
|
|
32877
|
+
sessionWorktreeManager,
|
|
32878
|
+
devServerManager,
|
|
32879
|
+
firehoseServerUrl,
|
|
32880
|
+
workspaceId,
|
|
32881
|
+
state,
|
|
32882
|
+
logFn
|
|
32883
|
+
});
|
|
32884
|
+
const sendLocalSkillsReport = createSendLocalSkillsReport(getWs, logFn);
|
|
32885
|
+
const reportAutoDetectedAgents = createReportAutoDetectedAgents(getWs, logFn);
|
|
32886
|
+
const messageDeps = {
|
|
32887
|
+
getWs,
|
|
32888
|
+
log: logFn,
|
|
32889
|
+
acpManager,
|
|
32890
|
+
sessionWorktreeManager,
|
|
32891
|
+
onBridgeIdentified,
|
|
32892
|
+
sendLocalSkillsReport,
|
|
32893
|
+
reportAutoDetectedAgents,
|
|
32894
|
+
devServerManager
|
|
32895
|
+
};
|
|
32896
|
+
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
32897
|
+
state,
|
|
32898
|
+
getWs,
|
|
32899
|
+
apiUrl,
|
|
32900
|
+
workspaceId,
|
|
32901
|
+
justAuthenticated: justAuthenticated === true,
|
|
32902
|
+
logFn,
|
|
32903
|
+
messageDeps,
|
|
32904
|
+
tokens,
|
|
32905
|
+
persistTokens,
|
|
32906
|
+
onAuthInvalid
|
|
32907
|
+
});
|
|
32634
32908
|
connect();
|
|
32635
32909
|
const stopFileIndexWatcher = startFileIndexWatcher(getBridgeWorkspaceDirectory());
|
|
32636
32910
|
return {
|