@buildautomaton/cli 0.1.1 → 0.1.3
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/README.md +3 -9
- package/dist/cli.js +2214 -1128
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1901 -831
- package/dist/index.js.map +4 -4
- package/package.json +4 -8
package/dist/index.js
CHANGED
|
@@ -2236,7 +2236,7 @@ var require_websocket = __commonJS({
|
|
|
2236
2236
|
"../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js"(exports, module) {
|
|
2237
2237
|
"use strict";
|
|
2238
2238
|
var EventEmitter3 = __require("events");
|
|
2239
|
-
var
|
|
2239
|
+
var https3 = __require("https");
|
|
2240
2240
|
var http = __require("http");
|
|
2241
2241
|
var net = __require("net");
|
|
2242
2242
|
var tls = __require("tls");
|
|
@@ -2771,7 +2771,7 @@ var require_websocket = __commonJS({
|
|
|
2771
2771
|
}
|
|
2772
2772
|
const defaultPort = isSecure ? 443 : 80;
|
|
2773
2773
|
const key = randomBytes(16).toString("base64");
|
|
2774
|
-
const request = isSecure ?
|
|
2774
|
+
const request = isSecure ? https3.request : http.request;
|
|
2775
2775
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
2776
2776
|
let perMessageDeflate;
|
|
2777
2777
|
opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
@@ -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: path24, errorMaps, issueData } = params;
|
|
4069
|
+
const fullPath = [...path24, ...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, path24, key) {
|
|
4378
4378
|
this._cachedPath = [];
|
|
4379
4379
|
this.parent = parent;
|
|
4380
4380
|
this.data = value;
|
|
4381
|
-
this._path =
|
|
4381
|
+
this._path = path24;
|
|
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, path24) {
|
|
7997
|
+
if (!path24)
|
|
7998
7998
|
return obj;
|
|
7999
|
-
return
|
|
7999
|
+
return path24.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(path24, 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(path24);
|
|
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, path24 = []) => {
|
|
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 = [...path24, ...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(path24) {
|
|
8482
8482
|
const segs = [];
|
|
8483
|
-
for (const seg of
|
|
8483
|
+
for (const seg of path24) {
|
|
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(path24, isFile, isDirectory) {
|
|
21967
|
+
log2(`checking %s`, path24);
|
|
21968
21968
|
try {
|
|
21969
|
-
const stat4 = fs_1.statSync(
|
|
21969
|
+
const stat4 = fs_1.statSync(path24);
|
|
21970
21970
|
if (stat4.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(path24, type = exports.READABLE) {
|
|
21990
|
+
return check2(path24, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
21991
21991
|
}
|
|
21992
21992
|
exports.exists = exists2;
|
|
21993
21993
|
exports.FILE = 1;
|
|
@@ -22114,48 +22114,24 @@ function sendWsMessage(ws, payload) {
|
|
|
22114
22114
|
|
|
22115
22115
|
// src/acp/clients/acp-client.ts
|
|
22116
22116
|
import { spawn } from "node:child_process";
|
|
22117
|
-
import path from "node:path";
|
|
22118
22117
|
import { Readable, Writable } from "node:stream";
|
|
22119
|
-
|
|
22120
|
-
// src/acp/format-acp-rpc-error.ts
|
|
22121
|
-
function formatAcpRpcError(err) {
|
|
22122
|
-
if (err instanceof Error) return err.message;
|
|
22123
|
-
if (err != null && typeof err === "object") {
|
|
22124
|
-
const o = err;
|
|
22125
|
-
if (typeof o.message === "string") {
|
|
22126
|
-
const code = typeof o.code === "number" ? ` (code ${o.code})` : "";
|
|
22127
|
-
return `${o.message}${code}`;
|
|
22128
|
-
}
|
|
22129
|
-
}
|
|
22130
|
-
if (typeof err === "string") return err;
|
|
22131
|
-
try {
|
|
22132
|
-
return JSON.stringify(err);
|
|
22133
|
-
} catch {
|
|
22134
|
-
return String(err);
|
|
22135
|
-
}
|
|
22136
|
-
}
|
|
22137
|
-
function isAcpAuthenticationRequiredError(err) {
|
|
22138
|
-
if (err == null || typeof err !== "object") return false;
|
|
22139
|
-
const o = err;
|
|
22140
|
-
if (o.code === -32e3 && typeof o.message === "string") {
|
|
22141
|
-
const m2 = o.message.toLowerCase();
|
|
22142
|
-
if (m2.includes("authentication") || m2.includes("auth")) return true;
|
|
22143
|
-
}
|
|
22144
|
-
const m = typeof o.message === "string" ? o.message.toLowerCase() : "";
|
|
22145
|
-
return m.includes("authentication required") || m.includes("auth_required");
|
|
22146
|
-
}
|
|
22147
|
-
|
|
22148
|
-
// src/acp/clients/acp-client.ts
|
|
22149
22118
|
function formatSpawnError(err, command) {
|
|
22150
22119
|
if (err.code === "ENOENT") {
|
|
22151
22120
|
return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
|
|
22152
22121
|
}
|
|
22153
22122
|
return err.message || String(err);
|
|
22154
22123
|
}
|
|
22124
|
+
function toErrorMessage(err) {
|
|
22125
|
+
if (err instanceof Error) return err.message;
|
|
22126
|
+
if (err != null && typeof err === "object" && "message" in err)
|
|
22127
|
+
return String(err.message);
|
|
22128
|
+
if (typeof err === "string") return err;
|
|
22129
|
+
if (err != null && typeof err === "object") return JSON.stringify(err);
|
|
22130
|
+
return String(err);
|
|
22131
|
+
}
|
|
22155
22132
|
async function createAcpClient(options) {
|
|
22156
|
-
const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2
|
|
22133
|
+
const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
|
|
22157
22134
|
const { command, cwd: cwd3 = process.cwd(), onSessionUpdate } = options;
|
|
22158
|
-
const sessionCwd = path.resolve(cwd3);
|
|
22159
22135
|
const isWindows2 = process.platform === "win32";
|
|
22160
22136
|
const child = spawn(command[0], command.slice(1), {
|
|
22161
22137
|
cwd: cwd3,
|
|
@@ -22186,13 +22162,11 @@ async function createAcpClient(options) {
|
|
|
22186
22162
|
child.kill();
|
|
22187
22163
|
});
|
|
22188
22164
|
await connection.initialize({
|
|
22189
|
-
protocolVersion:
|
|
22165
|
+
protocolVersion: "0.1.0",
|
|
22166
|
+
capabilities: {},
|
|
22190
22167
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
22191
22168
|
});
|
|
22192
|
-
const newSessionRes = await connection.newSession({
|
|
22193
|
-
cwd: sessionCwd,
|
|
22194
|
-
mcpServers: []
|
|
22195
|
-
});
|
|
22169
|
+
const newSessionRes = await connection.newSession({ workingDirectory: cwd3 });
|
|
22196
22170
|
const sessionId = newSessionRes.sessionId;
|
|
22197
22171
|
resolve16({
|
|
22198
22172
|
sessionId,
|
|
@@ -22200,7 +22174,7 @@ async function createAcpClient(options) {
|
|
|
22200
22174
|
try {
|
|
22201
22175
|
const response = await connection.prompt({
|
|
22202
22176
|
sessionId,
|
|
22203
|
-
prompt:
|
|
22177
|
+
prompt: { type: "text", text: prompt }
|
|
22204
22178
|
});
|
|
22205
22179
|
const r = response;
|
|
22206
22180
|
const cancelled = (r?.stopReason ?? "").toLowerCase() === "cancelled";
|
|
@@ -22213,8 +22187,7 @@ async function createAcpClient(options) {
|
|
|
22213
22187
|
} catch (err) {
|
|
22214
22188
|
return {
|
|
22215
22189
|
success: false,
|
|
22216
|
-
error:
|
|
22217
|
-
...isAcpAuthenticationRequiredError(err) ? { authRequired: true } : {}
|
|
22190
|
+
error: err instanceof Error ? err.message : String(err)
|
|
22218
22191
|
};
|
|
22219
22192
|
}
|
|
22220
22193
|
},
|
|
@@ -22232,13 +22205,13 @@ async function createAcpClient(options) {
|
|
|
22232
22205
|
});
|
|
22233
22206
|
} catch (err) {
|
|
22234
22207
|
child.kill();
|
|
22235
|
-
reject(new Error(
|
|
22208
|
+
reject(new Error(toErrorMessage(err)));
|
|
22236
22209
|
}
|
|
22237
22210
|
})();
|
|
22238
22211
|
});
|
|
22239
22212
|
}
|
|
22240
22213
|
|
|
22241
|
-
// src/proxy/local-proxy.ts
|
|
22214
|
+
// src/firehose/proxy/local-proxy.ts
|
|
22242
22215
|
var ALLOWED_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
22243
22216
|
function isAllowedHost(host) {
|
|
22244
22217
|
const h = host.replace(/^\[|\]$/g, "");
|
|
@@ -22366,8 +22339,8 @@ function randomSecret() {
|
|
|
22366
22339
|
}
|
|
22367
22340
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
22368
22341
|
}
|
|
22369
|
-
async function requestPreviewApi(port, secret, method,
|
|
22370
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
22342
|
+
async function requestPreviewApi(port, secret, method, path24, body) {
|
|
22343
|
+
const url2 = `http://127.0.0.1:${port}${path24}`;
|
|
22371
22344
|
const headers = {
|
|
22372
22345
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
22373
22346
|
"Content-Type": "application/json"
|
|
@@ -22379,7 +22352,7 @@ async function requestPreviewApi(port, secret, method, path23, body) {
|
|
|
22379
22352
|
});
|
|
22380
22353
|
const data = await res.json().catch(() => ({}));
|
|
22381
22354
|
if (!res.ok) {
|
|
22382
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
22355
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path24}: ${res.status}`);
|
|
22383
22356
|
}
|
|
22384
22357
|
return data;
|
|
22385
22358
|
}
|
|
@@ -22527,14 +22500,19 @@ function log(line) {
|
|
|
22527
22500
|
const time3 = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
|
|
22528
22501
|
console.log(`[${time3}] ${line}`);
|
|
22529
22502
|
}
|
|
22503
|
+
function logImmediate(line) {
|
|
22504
|
+
const time3 = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
|
|
22505
|
+
process.stdout.write(`[${time3}] ${line}
|
|
22506
|
+
`);
|
|
22507
|
+
}
|
|
22530
22508
|
|
|
22531
22509
|
// src/config.ts
|
|
22532
22510
|
import fs from "node:fs";
|
|
22533
|
-
import
|
|
22511
|
+
import path from "node:path";
|
|
22534
22512
|
import os from "node:os";
|
|
22535
22513
|
function getConfigPath() {
|
|
22536
|
-
const dir =
|
|
22537
|
-
return
|
|
22514
|
+
const dir = path.join(os.homedir(), ".buildautomaton");
|
|
22515
|
+
return path.join(dir, "config.json");
|
|
22538
22516
|
}
|
|
22539
22517
|
function normalizeApiUrl(url2) {
|
|
22540
22518
|
return url2.replace(/\/$/, "");
|
|
@@ -22550,7 +22528,7 @@ function readRawConfig() {
|
|
|
22550
22528
|
}
|
|
22551
22529
|
function writeConfigForApi(apiUrl, auth) {
|
|
22552
22530
|
const p = getConfigPath();
|
|
22553
|
-
const dir =
|
|
22531
|
+
const dir = path.dirname(p);
|
|
22554
22532
|
const key = normalizeApiUrl(apiUrl);
|
|
22555
22533
|
const prev = readRawConfig() ?? {};
|
|
22556
22534
|
const servers = { ...prev.servers ?? {}, [key]: { ...auth } };
|
|
@@ -22621,11 +22599,41 @@ function openBrowser(connectionId, initialWorkspaceId, preferredBridgeName, apiU
|
|
|
22621
22599
|
}
|
|
22622
22600
|
}
|
|
22623
22601
|
|
|
22602
|
+
// src/bridge/connection/ws-close-diagnostics.ts
|
|
22603
|
+
function describeWebSocketCloseCode(code) {
|
|
22604
|
+
const known = {
|
|
22605
|
+
1e3: "normal closure",
|
|
22606
|
+
1001: "going away",
|
|
22607
|
+
1002: "protocol error",
|
|
22608
|
+
1003: "unsupported data",
|
|
22609
|
+
1005: "no status (reserved)",
|
|
22610
|
+
1006: "abnormal closure \u2014 often network loss, proxy, or idle timeout (no close frame)",
|
|
22611
|
+
1007: "invalid payload data",
|
|
22612
|
+
1008: "policy violation",
|
|
22613
|
+
1009: "message too big",
|
|
22614
|
+
1010: "mandatory extension",
|
|
22615
|
+
1011: "internal server error",
|
|
22616
|
+
1012: "service restart",
|
|
22617
|
+
1013: "try again later",
|
|
22618
|
+
1014: "bad gateway",
|
|
22619
|
+
1015: "TLS handshake failed"
|
|
22620
|
+
};
|
|
22621
|
+
if (known[code]) return known[code];
|
|
22622
|
+
if (code >= 3e3 && code <= 3999) return "registered (framework)";
|
|
22623
|
+
if (code >= 4e3 && code <= 4999) return "application-specific";
|
|
22624
|
+
return "non-standard";
|
|
22625
|
+
}
|
|
22626
|
+
function formatWebSocketClose(label, code, reason, extra) {
|
|
22627
|
+
const r = reason.trim();
|
|
22628
|
+
const reasonPart = r ? ` reason="${r}"` : "";
|
|
22629
|
+
const extraPart = extra ? ` ${extra}` : "";
|
|
22630
|
+
return `${label} closed: code=${code} (${describeWebSocketCloseCode(code)})${reasonPart}${extraPart}`;
|
|
22631
|
+
}
|
|
22632
|
+
|
|
22624
22633
|
// src/auth/run-pending-auth.ts
|
|
22625
22634
|
var PENDING_RECONNECT_MS = 2e3;
|
|
22626
22635
|
var PENDING_KEEPALIVE_MS = 25e3;
|
|
22627
22636
|
var BROWSER_OPEN_FALLBACK_MS = 4e3;
|
|
22628
|
-
var WAITING_REMINDER_MS = 15e3;
|
|
22629
22637
|
function buildPendingBridgeUrl(apiUrl, connectionId) {
|
|
22630
22638
|
const base = apiUrl.startsWith("https") ? apiUrl.replace(/^https/, "wss") : apiUrl.replace(/^http/, "ws");
|
|
22631
22639
|
const params = new URLSearchParams({ connectionId });
|
|
@@ -22638,7 +22646,6 @@ function runPendingAuth(options) {
|
|
|
22638
22646
|
let reconnectTimeout = null;
|
|
22639
22647
|
let keepaliveInterval = null;
|
|
22640
22648
|
let browserFallback = null;
|
|
22641
|
-
let waitingReminderInterval = null;
|
|
22642
22649
|
const connectionId = crypto.randomUUID();
|
|
22643
22650
|
let hasOpenedBrowser = false;
|
|
22644
22651
|
let resolved = false;
|
|
@@ -22659,10 +22666,6 @@ function runPendingAuth(options) {
|
|
|
22659
22666
|
clearInterval(keepaliveInterval);
|
|
22660
22667
|
keepaliveInterval = null;
|
|
22661
22668
|
}
|
|
22662
|
-
if (waitingReminderInterval) {
|
|
22663
|
-
clearInterval(waitingReminderInterval);
|
|
22664
|
-
waitingReminderInterval = null;
|
|
22665
|
-
}
|
|
22666
22669
|
if (ws) {
|
|
22667
22670
|
ws.removeAllListeners();
|
|
22668
22671
|
ws.close();
|
|
@@ -22674,7 +22677,6 @@ function runPendingAuth(options) {
|
|
|
22674
22677
|
ws = createWsBridge({
|
|
22675
22678
|
url: url2,
|
|
22676
22679
|
onOpen: () => {
|
|
22677
|
-
logFn("WebSocket connected (pending auth)");
|
|
22678
22680
|
sendWsMessage(ws, { type: "identify", role: "cli" });
|
|
22679
22681
|
keepaliveInterval = setInterval(() => {
|
|
22680
22682
|
if (resolved || !ws || ws.readyState !== 1) return;
|
|
@@ -22694,21 +22696,21 @@ function runPendingAuth(options) {
|
|
|
22694
22696
|
clearInterval(keepaliveInterval);
|
|
22695
22697
|
keepaliveInterval = null;
|
|
22696
22698
|
}
|
|
22697
|
-
logFn(`WebSocket closed: ${code} ${reason}`);
|
|
22698
22699
|
if (resolved) return;
|
|
22699
|
-
logFn(
|
|
22700
|
+
logFn(
|
|
22701
|
+
formatWebSocketClose("[Bridge service]", code, reason, "pending sign-in; will reconnect in 2s")
|
|
22702
|
+
);
|
|
22700
22703
|
reconnectTimeout = setTimeout(() => {
|
|
22701
22704
|
reconnectTimeout = null;
|
|
22702
22705
|
connect();
|
|
22703
22706
|
}, PENDING_RECONNECT_MS);
|
|
22704
22707
|
},
|
|
22705
|
-
onError: (err) => logFn(`WebSocket error: ${err.message}`),
|
|
22708
|
+
onError: (err) => logFn(`[Bridge service] WebSocket error (pending sign-in): ${err.message}`),
|
|
22706
22709
|
onMessage: (data) => {
|
|
22707
22710
|
const msg = data;
|
|
22708
22711
|
if (msg.type === "auth_token" && typeof msg.token === "string") {
|
|
22709
22712
|
resolved = true;
|
|
22710
22713
|
const workspaceId = typeof msg.workspaceId === "string" ? msg.workspaceId : "";
|
|
22711
|
-
logFn("Received auth token; reconnecting as bridge for workspace\u2026");
|
|
22712
22714
|
cleanup();
|
|
22713
22715
|
const refreshToken = typeof msg.refreshToken === "string" ? msg.refreshToken : void 0;
|
|
22714
22716
|
const result = { workspaceId, token: msg.token, refreshToken };
|
|
@@ -22718,7 +22720,6 @@ function runPendingAuth(options) {
|
|
|
22718
22720
|
}
|
|
22719
22721
|
});
|
|
22720
22722
|
}
|
|
22721
|
-
logFn("Connecting to backend (pending auth)\u2026");
|
|
22722
22723
|
browserFallback = setTimeout(() => {
|
|
22723
22724
|
browserFallback = null;
|
|
22724
22725
|
if (!hasOpenedBrowser) {
|
|
@@ -22726,10 +22727,6 @@ function runPendingAuth(options) {
|
|
|
22726
22727
|
openBrowser(connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, logFn);
|
|
22727
22728
|
}
|
|
22728
22729
|
}, BROWSER_OPEN_FALLBACK_MS);
|
|
22729
|
-
waitingReminderInterval = setInterval(() => {
|
|
22730
|
-
if (resolved) return;
|
|
22731
|
-
logFn("Waiting for you to link the CLI in the browser\u2026");
|
|
22732
|
-
}, WAITING_REMINDER_MS);
|
|
22733
22730
|
connect();
|
|
22734
22731
|
return {
|
|
22735
22732
|
close: () => {
|
|
@@ -22740,69 +22737,6 @@ function runPendingAuth(options) {
|
|
|
22740
22737
|
};
|
|
22741
22738
|
}
|
|
22742
22739
|
|
|
22743
|
-
// src/skills/discover-local-agent-skills.ts
|
|
22744
|
-
import fs2 from "node:fs";
|
|
22745
|
-
import path3 from "node:path";
|
|
22746
|
-
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
22747
|
-
function discoverLocalSkills(cwd3) {
|
|
22748
|
-
const out = [];
|
|
22749
|
-
const seenKeys = /* @__PURE__ */ new Set();
|
|
22750
|
-
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
22751
|
-
const base = path3.join(cwd3, rel);
|
|
22752
|
-
if (!fs2.existsSync(base) || !fs2.statSync(base).isDirectory()) continue;
|
|
22753
|
-
let entries = [];
|
|
22754
|
-
try {
|
|
22755
|
-
entries = fs2.readdirSync(base);
|
|
22756
|
-
} catch {
|
|
22757
|
-
continue;
|
|
22758
|
-
}
|
|
22759
|
-
for (const name of entries) {
|
|
22760
|
-
const dir = path3.join(base, name);
|
|
22761
|
-
try {
|
|
22762
|
-
if (!fs2.statSync(dir).isDirectory()) continue;
|
|
22763
|
-
} catch {
|
|
22764
|
-
continue;
|
|
22765
|
-
}
|
|
22766
|
-
const skillMd = path3.join(dir, "SKILL.md");
|
|
22767
|
-
if (!fs2.existsSync(skillMd)) continue;
|
|
22768
|
-
const key = `${rel}/${name}`;
|
|
22769
|
-
if (seenKeys.has(key)) continue;
|
|
22770
|
-
seenKeys.add(key);
|
|
22771
|
-
out.push({ skillKey: name, path: `${rel}/${name}`.replace(/\\/g, "/") });
|
|
22772
|
-
}
|
|
22773
|
-
}
|
|
22774
|
-
return out;
|
|
22775
|
-
}
|
|
22776
|
-
function discoverSkillLayoutRoots(cwd3) {
|
|
22777
|
-
const roots = [];
|
|
22778
|
-
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
22779
|
-
const base = path3.join(cwd3, rel);
|
|
22780
|
-
if (!fs2.existsSync(base) || !fs2.statSync(base).isDirectory()) continue;
|
|
22781
|
-
let entries = [];
|
|
22782
|
-
try {
|
|
22783
|
-
entries = fs2.readdirSync(base);
|
|
22784
|
-
} catch {
|
|
22785
|
-
continue;
|
|
22786
|
-
}
|
|
22787
|
-
const skills2 = [];
|
|
22788
|
-
for (const name of entries) {
|
|
22789
|
-
const dir = path3.join(base, name);
|
|
22790
|
-
try {
|
|
22791
|
-
if (!fs2.statSync(dir).isDirectory()) continue;
|
|
22792
|
-
} catch {
|
|
22793
|
-
continue;
|
|
22794
|
-
}
|
|
22795
|
-
if (!fs2.existsSync(path3.join(dir, "SKILL.md"))) continue;
|
|
22796
|
-
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
22797
|
-
skills2.push({ name, relPath });
|
|
22798
|
-
}
|
|
22799
|
-
if (skills2.length > 0) {
|
|
22800
|
-
roots.push({ path: rel.replace(/\\/g, "/"), skills: skills2 });
|
|
22801
|
-
}
|
|
22802
|
-
}
|
|
22803
|
-
return roots;
|
|
22804
|
-
}
|
|
22805
|
-
|
|
22806
22740
|
// src/bridge/connection/build-bridge-url.ts
|
|
22807
22741
|
function buildBridgeUrl(apiUrl, workspaceId, authToken) {
|
|
22808
22742
|
const base = apiUrl.startsWith("https") ? apiUrl.replace(/^https/, "wss") : apiUrl.replace(/^http/, "ws");
|
|
@@ -22811,8 +22745,8 @@ function buildBridgeUrl(apiUrl, workspaceId, authToken) {
|
|
|
22811
22745
|
}
|
|
22812
22746
|
|
|
22813
22747
|
// src/git/discover-repos.ts
|
|
22814
|
-
import * as
|
|
22815
|
-
import * as
|
|
22748
|
+
import * as fs2 from "node:fs";
|
|
22749
|
+
import * as path2 from "node:path";
|
|
22816
22750
|
|
|
22817
22751
|
// ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
|
|
22818
22752
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -22851,8 +22785,8 @@ function pathspec(...paths) {
|
|
|
22851
22785
|
cache.set(key, paths);
|
|
22852
22786
|
return key;
|
|
22853
22787
|
}
|
|
22854
|
-
function isPathSpec(
|
|
22855
|
-
return
|
|
22788
|
+
function isPathSpec(path24) {
|
|
22789
|
+
return path24 instanceof String && cache.has(path24);
|
|
22856
22790
|
}
|
|
22857
22791
|
function toPaths(pathSpec) {
|
|
22858
22792
|
return cache.get(pathSpec) || [];
|
|
@@ -22941,8 +22875,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
22941
22875
|
function forEachLineWithContent(input, callback) {
|
|
22942
22876
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
22943
22877
|
}
|
|
22944
|
-
function folderExists(
|
|
22945
|
-
return (0, import_file_exists.exists)(
|
|
22878
|
+
function folderExists(path24) {
|
|
22879
|
+
return (0, import_file_exists.exists)(path24, import_file_exists.FOLDER);
|
|
22946
22880
|
}
|
|
22947
22881
|
function append(target, item) {
|
|
22948
22882
|
if (Array.isArray(target)) {
|
|
@@ -23346,8 +23280,8 @@ function checkIsRepoRootTask() {
|
|
|
23346
23280
|
commands,
|
|
23347
23281
|
format: "utf-8",
|
|
23348
23282
|
onError,
|
|
23349
|
-
parser(
|
|
23350
|
-
return /^\.(git)?$/.test(
|
|
23283
|
+
parser(path24) {
|
|
23284
|
+
return /^\.(git)?$/.test(path24.trim());
|
|
23351
23285
|
}
|
|
23352
23286
|
};
|
|
23353
23287
|
}
|
|
@@ -23781,11 +23715,11 @@ function parseGrep(grep) {
|
|
|
23781
23715
|
const paths = /* @__PURE__ */ new Set();
|
|
23782
23716
|
const results = {};
|
|
23783
23717
|
forEachLineWithContent(grep, (input) => {
|
|
23784
|
-
const [
|
|
23785
|
-
paths.add(
|
|
23786
|
-
(results[
|
|
23718
|
+
const [path24, line, preview] = input.split(NULL);
|
|
23719
|
+
paths.add(path24);
|
|
23720
|
+
(results[path24] = results[path24] || []).push({
|
|
23787
23721
|
line: asNumber(line),
|
|
23788
|
-
path:
|
|
23722
|
+
path: path24,
|
|
23789
23723
|
preview
|
|
23790
23724
|
});
|
|
23791
23725
|
});
|
|
@@ -24550,14 +24484,14 @@ var init_hash_object = __esm2({
|
|
|
24550
24484
|
init_task();
|
|
24551
24485
|
}
|
|
24552
24486
|
});
|
|
24553
|
-
function parseInit(bare,
|
|
24487
|
+
function parseInit(bare, path24, text) {
|
|
24554
24488
|
const response = String(text).trim();
|
|
24555
24489
|
let result;
|
|
24556
24490
|
if (result = initResponseRegex.exec(response)) {
|
|
24557
|
-
return new InitSummary(bare,
|
|
24491
|
+
return new InitSummary(bare, path24, false, result[1]);
|
|
24558
24492
|
}
|
|
24559
24493
|
if (result = reInitResponseRegex.exec(response)) {
|
|
24560
|
-
return new InitSummary(bare,
|
|
24494
|
+
return new InitSummary(bare, path24, true, result[1]);
|
|
24561
24495
|
}
|
|
24562
24496
|
let gitDir = "";
|
|
24563
24497
|
const tokens = response.split(" ");
|
|
@@ -24568,7 +24502,7 @@ function parseInit(bare, path23, text) {
|
|
|
24568
24502
|
break;
|
|
24569
24503
|
}
|
|
24570
24504
|
}
|
|
24571
|
-
return new InitSummary(bare,
|
|
24505
|
+
return new InitSummary(bare, path24, /^re/i.test(response), gitDir);
|
|
24572
24506
|
}
|
|
24573
24507
|
var InitSummary;
|
|
24574
24508
|
var initResponseRegex;
|
|
@@ -24577,9 +24511,9 @@ var init_InitSummary = __esm2({
|
|
|
24577
24511
|
"src/lib/responses/InitSummary.ts"() {
|
|
24578
24512
|
"use strict";
|
|
24579
24513
|
InitSummary = class {
|
|
24580
|
-
constructor(bare,
|
|
24514
|
+
constructor(bare, path24, existing, gitDir) {
|
|
24581
24515
|
this.bare = bare;
|
|
24582
|
-
this.path =
|
|
24516
|
+
this.path = path24;
|
|
24583
24517
|
this.existing = existing;
|
|
24584
24518
|
this.gitDir = gitDir;
|
|
24585
24519
|
}
|
|
@@ -24591,7 +24525,7 @@ var init_InitSummary = __esm2({
|
|
|
24591
24525
|
function hasBareCommand(command) {
|
|
24592
24526
|
return command.includes(bareCommand);
|
|
24593
24527
|
}
|
|
24594
|
-
function initTask(bare = false,
|
|
24528
|
+
function initTask(bare = false, path24, customArgs) {
|
|
24595
24529
|
const commands = ["init", ...customArgs];
|
|
24596
24530
|
if (bare && !hasBareCommand(commands)) {
|
|
24597
24531
|
commands.splice(1, 0, bareCommand);
|
|
@@ -24600,7 +24534,7 @@ function initTask(bare = false, path23, customArgs) {
|
|
|
24600
24534
|
commands,
|
|
24601
24535
|
format: "utf-8",
|
|
24602
24536
|
parser(text) {
|
|
24603
|
-
return parseInit(commands.includes("--bare"),
|
|
24537
|
+
return parseInit(commands.includes("--bare"), path24, text);
|
|
24604
24538
|
}
|
|
24605
24539
|
};
|
|
24606
24540
|
}
|
|
@@ -25416,12 +25350,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
25416
25350
|
"use strict";
|
|
25417
25351
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
25418
25352
|
FileStatusSummary = class {
|
|
25419
|
-
constructor(
|
|
25420
|
-
this.path =
|
|
25353
|
+
constructor(path24, index, working_dir) {
|
|
25354
|
+
this.path = path24;
|
|
25421
25355
|
this.index = index;
|
|
25422
25356
|
this.working_dir = working_dir;
|
|
25423
25357
|
if (index === "R" || working_dir === "R") {
|
|
25424
|
-
const detail = fromPathRegex.exec(
|
|
25358
|
+
const detail = fromPathRegex.exec(path24) || [null, path24, path24];
|
|
25425
25359
|
this.from = detail[2] || "";
|
|
25426
25360
|
this.path = detail[1] || "";
|
|
25427
25361
|
}
|
|
@@ -25452,14 +25386,14 @@ function splitLine(result, lineStr) {
|
|
|
25452
25386
|
default:
|
|
25453
25387
|
return;
|
|
25454
25388
|
}
|
|
25455
|
-
function data(index, workingDir,
|
|
25389
|
+
function data(index, workingDir, path24) {
|
|
25456
25390
|
const raw = `${index}${workingDir}`;
|
|
25457
25391
|
const handler = parsers6.get(raw);
|
|
25458
25392
|
if (handler) {
|
|
25459
|
-
handler(result,
|
|
25393
|
+
handler(result, path24);
|
|
25460
25394
|
}
|
|
25461
25395
|
if (raw !== "##" && raw !== "!!") {
|
|
25462
|
-
result.files.push(new FileStatusSummary(
|
|
25396
|
+
result.files.push(new FileStatusSummary(path24, index, workingDir));
|
|
25463
25397
|
}
|
|
25464
25398
|
}
|
|
25465
25399
|
}
|
|
@@ -25768,9 +25702,9 @@ var init_simple_git_api = __esm2({
|
|
|
25768
25702
|
next
|
|
25769
25703
|
);
|
|
25770
25704
|
}
|
|
25771
|
-
hashObject(
|
|
25705
|
+
hashObject(path24, write) {
|
|
25772
25706
|
return this._runTask(
|
|
25773
|
-
hashObjectTask(
|
|
25707
|
+
hashObjectTask(path24, write === true),
|
|
25774
25708
|
trailingFunctionArgument(arguments)
|
|
25775
25709
|
);
|
|
25776
25710
|
}
|
|
@@ -26123,8 +26057,8 @@ var init_branch = __esm2({
|
|
|
26123
26057
|
}
|
|
26124
26058
|
});
|
|
26125
26059
|
function toPath(input) {
|
|
26126
|
-
const
|
|
26127
|
-
return
|
|
26060
|
+
const path24 = input.trim().replace(/^["']|["']$/g, "");
|
|
26061
|
+
return path24 && normalize(path24);
|
|
26128
26062
|
}
|
|
26129
26063
|
var parseCheckIgnore;
|
|
26130
26064
|
var init_CheckIgnore = __esm2({
|
|
@@ -26438,8 +26372,8 @@ __export2(sub_module_exports, {
|
|
|
26438
26372
|
subModuleTask: () => subModuleTask,
|
|
26439
26373
|
updateSubModuleTask: () => updateSubModuleTask
|
|
26440
26374
|
});
|
|
26441
|
-
function addSubModuleTask(repo,
|
|
26442
|
-
return subModuleTask(["add", repo,
|
|
26375
|
+
function addSubModuleTask(repo, path24) {
|
|
26376
|
+
return subModuleTask(["add", repo, path24]);
|
|
26443
26377
|
}
|
|
26444
26378
|
function initSubModuleTask(customArgs) {
|
|
26445
26379
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -26772,8 +26706,8 @@ var require_git = __commonJS2({
|
|
|
26772
26706
|
}
|
|
26773
26707
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
26774
26708
|
};
|
|
26775
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
26776
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
26709
|
+
Git2.prototype.submoduleAdd = function(repo, path24, then) {
|
|
26710
|
+
return this._runTask(addSubModuleTask2(repo, path24), trailingFunctionArgument2(arguments));
|
|
26777
26711
|
};
|
|
26778
26712
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
26779
26713
|
return this._runTask(
|
|
@@ -27399,20 +27333,20 @@ async function isGitRepoDirectory(dirPath) {
|
|
|
27399
27333
|
// src/git/discover-repos.ts
|
|
27400
27334
|
async function discoverGitRepos(cwd3 = process.cwd()) {
|
|
27401
27335
|
const result = [];
|
|
27402
|
-
const cwdResolved =
|
|
27336
|
+
const cwdResolved = path2.resolve(cwd3);
|
|
27403
27337
|
if (await isGitRepoDirectory(cwdResolved)) {
|
|
27404
27338
|
const remoteUrl = await getRemoteOriginUrl(cwdResolved);
|
|
27405
27339
|
result.push({ absolutePath: cwdResolved, remoteUrl });
|
|
27406
27340
|
}
|
|
27407
27341
|
let entries;
|
|
27408
27342
|
try {
|
|
27409
|
-
entries =
|
|
27343
|
+
entries = fs2.readdirSync(cwdResolved, { withFileTypes: true });
|
|
27410
27344
|
} catch {
|
|
27411
27345
|
return result;
|
|
27412
27346
|
}
|
|
27413
27347
|
for (const ent of entries) {
|
|
27414
27348
|
if (!ent.isDirectory()) continue;
|
|
27415
|
-
const childPath =
|
|
27349
|
+
const childPath = path2.join(cwdResolved, ent.name);
|
|
27416
27350
|
if (await isGitRepoDirectory(childPath)) {
|
|
27417
27351
|
const remoteUrl = await getRemoteOriginUrl(childPath);
|
|
27418
27352
|
result.push({ absolutePath: childPath, remoteUrl });
|
|
@@ -27421,22 +27355,22 @@ async function discoverGitRepos(cwd3 = process.cwd()) {
|
|
|
27421
27355
|
return result;
|
|
27422
27356
|
}
|
|
27423
27357
|
async function discoverGitReposUnderRoot(rootAbs) {
|
|
27424
|
-
const root =
|
|
27358
|
+
const root = path2.resolve(rootAbs);
|
|
27425
27359
|
const roots = [];
|
|
27426
27360
|
async function walk(dir) {
|
|
27427
27361
|
if (await isGitRepoDirectory(dir)) {
|
|
27428
|
-
roots.push(
|
|
27362
|
+
roots.push(path2.resolve(dir));
|
|
27429
27363
|
return;
|
|
27430
27364
|
}
|
|
27431
27365
|
let entries;
|
|
27432
27366
|
try {
|
|
27433
|
-
entries =
|
|
27367
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
27434
27368
|
} catch {
|
|
27435
27369
|
return;
|
|
27436
27370
|
}
|
|
27437
27371
|
for (const ent of entries) {
|
|
27438
27372
|
if (!ent.isDirectory() || ent.name === ".git") continue;
|
|
27439
|
-
await walk(
|
|
27373
|
+
await walk(path2.join(dir, ent.name));
|
|
27440
27374
|
}
|
|
27441
27375
|
}
|
|
27442
27376
|
await walk(root);
|
|
@@ -27460,11 +27394,10 @@ function reportGitRepos(getWs, log2) {
|
|
|
27460
27394
|
type: "git_repos",
|
|
27461
27395
|
repos: repos.map((r) => ({ absolutePath: r.absolutePath, remoteUrl: r.remoteUrl }))
|
|
27462
27396
|
});
|
|
27463
|
-
log2(`Reported ${repos.length} git repo(s) to bridge`);
|
|
27464
27397
|
}
|
|
27465
27398
|
}
|
|
27466
27399
|
}).catch((err) => {
|
|
27467
|
-
log2(`
|
|
27400
|
+
log2(`[Bridge service] git repo discovery failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
27468
27401
|
});
|
|
27469
27402
|
});
|
|
27470
27403
|
}
|
|
@@ -27479,7 +27412,7 @@ function scheduleReconnect(state, connect, log2) {
|
|
|
27479
27412
|
RECONNECT_MAX_MS
|
|
27480
27413
|
);
|
|
27481
27414
|
state.reconnectAttempt += 1;
|
|
27482
|
-
log2(`
|
|
27415
|
+
log2(`[Bridge service] reconnect attempt ${state.reconnectAttempt} in ${delay2 / 1e3}s\u2026`);
|
|
27483
27416
|
state.reconnectTimeout = setTimeout(() => {
|
|
27484
27417
|
state.reconnectTimeout = null;
|
|
27485
27418
|
connect();
|
|
@@ -27487,18 +27420,33 @@ function scheduleReconnect(state, connect, log2) {
|
|
|
27487
27420
|
}
|
|
27488
27421
|
|
|
27489
27422
|
// src/bridge/connection/close-bridge-connection.ts
|
|
27490
|
-
function closeBridgeConnection(state, acpManager) {
|
|
27423
|
+
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
27424
|
+
log2?.("Shutting down\u2026");
|
|
27425
|
+
await new Promise((resolve16) => setImmediate(resolve16));
|
|
27426
|
+
if (devServerManager) {
|
|
27427
|
+
log2?.("Requesting dev server processes to stop\u2026");
|
|
27428
|
+
await devServerManager.shutdownAllGraceful();
|
|
27429
|
+
}
|
|
27491
27430
|
state.closedByUser = true;
|
|
27492
27431
|
if (state.reconnectTimeout != null) {
|
|
27432
|
+
log2?.("Cancelling reconnect timer\u2026");
|
|
27493
27433
|
clearTimeout(state.reconnectTimeout);
|
|
27494
27434
|
state.reconnectTimeout = null;
|
|
27495
27435
|
}
|
|
27496
|
-
if (state.
|
|
27497
|
-
|
|
27498
|
-
state.
|
|
27436
|
+
if (state.firehoseReconnectTimeout != null) {
|
|
27437
|
+
log2?.("[Proxy and log service] cancelling reconnect timer\u2026");
|
|
27438
|
+
clearTimeout(state.firehoseReconnectTimeout);
|
|
27439
|
+
state.firehoseReconnectTimeout = null;
|
|
27499
27440
|
}
|
|
27441
|
+
if (state.firehoseHandle) {
|
|
27442
|
+
log2?.("[Proxy and log service] closing connection (CLI shutdown)\u2026");
|
|
27443
|
+
state.firehoseHandle.close();
|
|
27444
|
+
state.firehoseHandle = null;
|
|
27445
|
+
}
|
|
27446
|
+
log2?.("Disconnecting local agents (ACP)\u2026");
|
|
27500
27447
|
acpManager.disconnect();
|
|
27501
27448
|
if (state.currentWs) {
|
|
27449
|
+
log2?.("[Bridge service] closing connection (CLI shutdown)\u2026");
|
|
27502
27450
|
state.currentWs.removeAllListeners();
|
|
27503
27451
|
const wsState = state.currentWs.readyState;
|
|
27504
27452
|
if (wsState === 1 || wsState === 2) {
|
|
@@ -27513,119 +27461,10 @@ function closeBridgeConnection(state, acpManager) {
|
|
|
27513
27461
|
}
|
|
27514
27462
|
}
|
|
27515
27463
|
|
|
27516
|
-
// src/proxy/connect-proxy.ts
|
|
27517
|
-
var PROXY_ID_BYTES = 36;
|
|
27518
|
-
function buildProxyWsUrl(proxyServerUrl) {
|
|
27519
|
-
const base = proxyServerUrl.startsWith("https") ? proxyServerUrl.replace(/^https/, "wss") : proxyServerUrl.replace(/^http/, "ws");
|
|
27520
|
-
return `${base.replace(/\/$/, "")}/ws`;
|
|
27521
|
-
}
|
|
27522
|
-
function connectProxy(options) {
|
|
27523
|
-
const { proxyServerUrl, workspaceId, bridgeName, proxyPorts, log: log2, onClose } = options;
|
|
27524
|
-
const proxyUrl = buildProxyWsUrl(proxyServerUrl);
|
|
27525
|
-
log2(`Proxy: connecting to ${proxyUrl} (workspace: ${workspaceId}, bridge: ${bridgeName}, ports: [${proxyPorts.join(", ")}])`);
|
|
27526
|
-
const ws = new wrapper_default(proxyUrl);
|
|
27527
|
-
const pendingProxyBody = /* @__PURE__ */ new Map();
|
|
27528
|
-
function startStreamingProxy(pr) {
|
|
27529
|
-
proxyToLocalStreaming(pr, {
|
|
27530
|
-
onStart: (statusCode, headers) => {
|
|
27531
|
-
const forwardedHeaders = { ...headers };
|
|
27532
|
-
const ce = "content-encoding";
|
|
27533
|
-
const cl = "content-length";
|
|
27534
|
-
const keys = Object.keys(forwardedHeaders).filter(
|
|
27535
|
-
(k) => k.toLowerCase() !== ce && k.toLowerCase() !== cl
|
|
27536
|
-
);
|
|
27537
|
-
const filtered = {};
|
|
27538
|
-
for (const k of keys) if (forwardedHeaders[k] != null) filtered[k] = forwardedHeaders[k];
|
|
27539
|
-
sendWsMessage(ws, { type: "proxy_result_start", id: pr.id, statusCode, headers: filtered });
|
|
27540
|
-
},
|
|
27541
|
-
onChunk: (chunk) => {
|
|
27542
|
-
const idBuf = Buffer.from(pr.id, "utf8");
|
|
27543
|
-
ws.send(Buffer.concat([idBuf, Buffer.from(chunk)]), { binary: true });
|
|
27544
|
-
},
|
|
27545
|
-
onEnd: () => sendWsMessage(ws, { type: "proxy_result_end", id: pr.id }),
|
|
27546
|
-
onError: (error40) => {
|
|
27547
|
-
log2(`[proxy] ${pr.id.slice(0, 8)}\u2026 (stream) -> error: ${error40}`);
|
|
27548
|
-
sendWsMessage(ws, { type: "proxy_result_error", id: pr.id, error: error40 });
|
|
27549
|
-
}
|
|
27550
|
-
});
|
|
27551
|
-
}
|
|
27552
|
-
ws.on("open", () => {
|
|
27553
|
-
sendWsMessage(ws, { type: "identify", workspaceId, bridgeName, proxyPorts });
|
|
27554
|
-
});
|
|
27555
|
-
ws.on("message", (raw) => {
|
|
27556
|
-
if (Buffer.isBuffer(raw) && raw.length >= PROXY_ID_BYTES) {
|
|
27557
|
-
const id = raw.slice(0, PROXY_ID_BYTES).toString("utf8");
|
|
27558
|
-
const pending = pendingProxyBody.get(id);
|
|
27559
|
-
if (pending) {
|
|
27560
|
-
pendingProxyBody.delete(id);
|
|
27561
|
-
const body = raw.slice(PROXY_ID_BYTES);
|
|
27562
|
-
startStreamingProxy({
|
|
27563
|
-
...pending.pr,
|
|
27564
|
-
body: body.length > 0 ? new Uint8Array(body) : void 0
|
|
27565
|
-
});
|
|
27566
|
-
return;
|
|
27567
|
-
}
|
|
27568
|
-
}
|
|
27569
|
-
try {
|
|
27570
|
-
const data = JSON.parse(Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw));
|
|
27571
|
-
if (data.type === "proxy" && data.proxy && typeof data.proxy === "object") {
|
|
27572
|
-
const pr = data.proxy;
|
|
27573
|
-
if (pr.streamResponse) {
|
|
27574
|
-
const bodyLength = pr.bodyLength ?? 0;
|
|
27575
|
-
if (bodyLength > 0) {
|
|
27576
|
-
pendingProxyBody.set(pr.id, {
|
|
27577
|
-
pr: {
|
|
27578
|
-
id: pr.id,
|
|
27579
|
-
method: pr.method,
|
|
27580
|
-
url: pr.url,
|
|
27581
|
-
headers: pr.headers,
|
|
27582
|
-
streamResponse: true
|
|
27583
|
-
}
|
|
27584
|
-
});
|
|
27585
|
-
} else {
|
|
27586
|
-
startStreamingProxy({
|
|
27587
|
-
id: pr.id,
|
|
27588
|
-
method: pr.method,
|
|
27589
|
-
url: pr.url,
|
|
27590
|
-
headers: pr.headers,
|
|
27591
|
-
streamResponse: true
|
|
27592
|
-
});
|
|
27593
|
-
}
|
|
27594
|
-
} else {
|
|
27595
|
-
proxyToLocal(pr).then((res) => {
|
|
27596
|
-
if (res.error) log2(`[proxy] ${pr.id.slice(0, 8)}\u2026 -> error: ${res.error}`);
|
|
27597
|
-
sendWsMessage(ws, { type: "proxy_result", ...res, id: pr.id });
|
|
27598
|
-
}).catch((err) => {
|
|
27599
|
-
log2(`[proxy] ${pr.id.slice(0, 8)}\u2026 -> error: ${err instanceof Error ? err.message : String(err)}`);
|
|
27600
|
-
sendWsMessage(ws, { type: "proxy_result", id: pr.id, error: String(err) });
|
|
27601
|
-
});
|
|
27602
|
-
}
|
|
27603
|
-
}
|
|
27604
|
-
} catch {
|
|
27605
|
-
}
|
|
27606
|
-
});
|
|
27607
|
-
ws.on("close", (_code, reason) => {
|
|
27608
|
-
if (reason?.length) log2(`Proxy: WebSocket closed (reason: ${reason.toString()})`);
|
|
27609
|
-
onClose?.();
|
|
27610
|
-
});
|
|
27611
|
-
ws.on("error", (err) => {
|
|
27612
|
-
log2(`Proxy: WebSocket error connecting to ${proxyUrl}: ${err.message}`);
|
|
27613
|
-
});
|
|
27614
|
-
return {
|
|
27615
|
-
close() {
|
|
27616
|
-
try {
|
|
27617
|
-
ws.removeAllListeners();
|
|
27618
|
-
ws.close();
|
|
27619
|
-
} catch {
|
|
27620
|
-
}
|
|
27621
|
-
}
|
|
27622
|
-
};
|
|
27623
|
-
}
|
|
27624
|
-
|
|
27625
27464
|
// src/git/session-git-queue.ts
|
|
27626
27465
|
import { execFile } from "node:child_process";
|
|
27627
27466
|
import { promisify } from "node:util";
|
|
27628
|
-
import * as
|
|
27467
|
+
import * as path3 from "node:path";
|
|
27629
27468
|
var execFileAsync = promisify(execFile);
|
|
27630
27469
|
var sessionBoundaryBySessionId = /* @__PURE__ */ new Map();
|
|
27631
27470
|
async function gitStashCreate(repoRoot, log2) {
|
|
@@ -27676,7 +27515,7 @@ async function collectSessionDiffAndNotify(options) {
|
|
|
27676
27515
|
continue;
|
|
27677
27516
|
}
|
|
27678
27517
|
const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
27679
|
-
const slug =
|
|
27518
|
+
const slug = path3.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
|
|
27680
27519
|
for (const rel of lines) {
|
|
27681
27520
|
if (rel.includes("..")) continue;
|
|
27682
27521
|
try {
|
|
@@ -27715,10 +27554,8 @@ async function sendPromptToAgent(options) {
|
|
|
27715
27554
|
sendResult,
|
|
27716
27555
|
sendSessionUpdate,
|
|
27717
27556
|
collectSessionDiffAfterTurn,
|
|
27718
|
-
agentType,
|
|
27719
27557
|
log: log2
|
|
27720
27558
|
} = options;
|
|
27721
|
-
log2("[prompt] Sending to agent\u2026");
|
|
27722
27559
|
try {
|
|
27723
27560
|
const result = await handle.sendPrompt(promptText, {});
|
|
27724
27561
|
if (collectSessionDiffAfterTurn && sessionId && runId && sendSessionUpdate && result.success) {
|
|
@@ -27729,41 +27566,29 @@ async function sendPromptToAgent(options) {
|
|
|
27729
27566
|
id: promptId,
|
|
27730
27567
|
...sessionId ? { sessionId } : {},
|
|
27731
27568
|
...runId ? { runId } : {},
|
|
27732
|
-
|
|
27733
|
-
|
|
27734
|
-
|
|
27735
|
-
|
|
27736
|
-
...result.authRequired ? { authRequired: true } : {},
|
|
27737
|
-
...agentType ? { agentType } : {}
|
|
27738
|
-
});
|
|
27739
|
-
if (result.success) {
|
|
27740
|
-
const out = result.output ?? "";
|
|
27741
|
-
const preview = out.length > 400 ? out.slice(0, 400) + "\u2026" : out;
|
|
27742
|
-
log2(`[prompt] Done; sent response (${out.length} chars)`);
|
|
27743
|
-
if (preview) log2(`[prompt] Response: ${preview}`);
|
|
27744
|
-
} else {
|
|
27745
|
-
log2(`[prompt] Agent error: ${result.error ?? "(unknown)"}`);
|
|
27569
|
+
...result
|
|
27570
|
+
});
|
|
27571
|
+
if (!result.success) {
|
|
27572
|
+
log2(`[agent] ${result.error ?? "error"}`);
|
|
27746
27573
|
}
|
|
27747
27574
|
} catch (err) {
|
|
27748
|
-
const errMsg =
|
|
27749
|
-
|
|
27750
|
-
log2(`[
|
|
27751
|
-
if (err instanceof Error && err.stack) log2(`[prompt] ${err.stack}`);
|
|
27575
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
27576
|
+
log2(`[agent] send failed: ${errMsg}`);
|
|
27577
|
+
if (err instanceof Error && err.stack) log2(`[agent] ${err.stack}`);
|
|
27752
27578
|
sendResult({
|
|
27753
27579
|
type: "prompt_result",
|
|
27754
27580
|
id: promptId,
|
|
27755
27581
|
...sessionId ? { sessionId } : {},
|
|
27756
27582
|
...runId ? { runId } : {},
|
|
27757
27583
|
success: false,
|
|
27758
|
-
error: errMsg
|
|
27759
|
-
...authRequired ? { authRequired: true } : {},
|
|
27760
|
-
...agentType ? { agentType } : {}
|
|
27584
|
+
error: errMsg
|
|
27761
27585
|
});
|
|
27762
27586
|
}
|
|
27763
27587
|
}
|
|
27764
27588
|
|
|
27765
27589
|
// src/acp/ensure-acp-client.ts
|
|
27766
|
-
import * as
|
|
27590
|
+
import * as fs3 from "node:fs";
|
|
27591
|
+
import * as path7 from "node:path";
|
|
27767
27592
|
|
|
27768
27593
|
// src/error-message.ts
|
|
27769
27594
|
function errorMessage(err) {
|
|
@@ -27775,17 +27600,6 @@ function errorMessage(err) {
|
|
|
27775
27600
|
return String(err);
|
|
27776
27601
|
}
|
|
27777
27602
|
|
|
27778
|
-
// src/acp/clients/claude-agent-acp-client.ts
|
|
27779
|
-
var DEFAULT_CLAUDE_AGENT_ACP_COMMAND = ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"];
|
|
27780
|
-
function isClaudeAgentAcpCommand(command) {
|
|
27781
|
-
const i = command.indexOf("@agentclientprotocol/claude-agent-acp");
|
|
27782
|
-
return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
|
|
27783
|
-
}
|
|
27784
|
-
async function createClaudeAgentAcpClient(options) {
|
|
27785
|
-
const command = options.command?.length && options.command.some((a) => a.includes("claude-agent-acp")) ? options.command : [...DEFAULT_CLAUDE_AGENT_ACP_COMMAND];
|
|
27786
|
-
return createAcpClient({ ...options, command });
|
|
27787
|
-
}
|
|
27788
|
-
|
|
27789
27603
|
// src/acp/clients/codex-acp-client.ts
|
|
27790
27604
|
var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", "@zed-industries/codex-acp"];
|
|
27791
27605
|
function isCodexAcpCommand(command) {
|
|
@@ -27804,21 +27618,21 @@ import { spawn as spawn4 } from "node:child_process";
|
|
|
27804
27618
|
import * as readline from "node:readline";
|
|
27805
27619
|
|
|
27806
27620
|
// src/acp/safe-fs-path.ts
|
|
27807
|
-
import * as
|
|
27621
|
+
import * as path4 from "node:path";
|
|
27808
27622
|
function resolveSafePathUnderCwd(cwd3, filePath) {
|
|
27809
27623
|
const trimmed2 = filePath.trim();
|
|
27810
27624
|
if (!trimmed2) return null;
|
|
27811
|
-
const normalizedCwd =
|
|
27812
|
-
const resolved =
|
|
27813
|
-
const rel =
|
|
27814
|
-
if (rel.startsWith("..") ||
|
|
27625
|
+
const normalizedCwd = path4.resolve(cwd3);
|
|
27626
|
+
const resolved = path4.isAbsolute(trimmed2) ? path4.normalize(trimmed2) : path4.resolve(normalizedCwd, trimmed2);
|
|
27627
|
+
const rel = path4.relative(normalizedCwd, resolved);
|
|
27628
|
+
if (rel.startsWith("..") || path4.isAbsolute(rel)) return null;
|
|
27815
27629
|
return resolved;
|
|
27816
27630
|
}
|
|
27817
27631
|
function toDisplayPathRelativeToCwd(cwd3, absolutePath) {
|
|
27818
|
-
const normalizedCwd =
|
|
27819
|
-
const rel =
|
|
27820
|
-
if (!rel || rel === "") return
|
|
27821
|
-
return rel.split(
|
|
27632
|
+
const normalizedCwd = path4.resolve(cwd3);
|
|
27633
|
+
const rel = path4.relative(normalizedCwd, path4.resolve(absolutePath));
|
|
27634
|
+
if (!rel || rel === "") return path4.basename(absolutePath);
|
|
27635
|
+
return rel.split(path4.sep).join("/");
|
|
27822
27636
|
}
|
|
27823
27637
|
|
|
27824
27638
|
// src/files/diff/unified-diff.ts
|
|
@@ -28120,7 +27934,7 @@ async function createCursorAcpClient(options) {
|
|
|
28120
27934
|
var AGENT_TYPE_DEFAULT_COMMANDS = {
|
|
28121
27935
|
"cursor-cli": ["agent", "acp"],
|
|
28122
27936
|
"codex-acp": [...DEFAULT_CODEX_ACP_COMMAND],
|
|
28123
|
-
"claude-code": [
|
|
27937
|
+
"claude-code": ["npx", "--yes", "@anthropic-ai/claude-code"]
|
|
28124
27938
|
};
|
|
28125
27939
|
function useCursorAcp(agentType, command) {
|
|
28126
27940
|
if (agentType === "cursor-cli") return true;
|
|
@@ -28130,17 +27944,12 @@ function useCodexAcp(agentType, command) {
|
|
|
28130
27944
|
if (agentType === "codex-acp") return true;
|
|
28131
27945
|
return isCodexAcpCommand(command);
|
|
28132
27946
|
}
|
|
28133
|
-
function
|
|
28134
|
-
if (
|
|
28135
|
-
|
|
28136
|
-
}
|
|
28137
|
-
function resolveAgentCommand(agentCommand, preferredAgentType) {
|
|
28138
|
-
const explicitCmd = agentCommand?.length ? agentCommand : void 0;
|
|
28139
|
-
const typeCmd = preferredAgentType ? AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType] : void 0;
|
|
28140
|
-
const command = explicitCmd ?? typeCmd;
|
|
27947
|
+
function resolveAgentCommand(preferredAgentType) {
|
|
27948
|
+
if (!preferredAgentType) return null;
|
|
27949
|
+
const command = AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType];
|
|
28141
27950
|
if (!command?.length) return null;
|
|
28142
|
-
const createClient = useCursorAcp(preferredAgentType, command) ? createCursorAcpClient : useCodexAcp(preferredAgentType, command) ? createCodexAcpClient :
|
|
28143
|
-
const label = preferredAgentType
|
|
27951
|
+
const createClient = useCursorAcp(preferredAgentType, command) ? createCursorAcpClient : useCodexAcp(preferredAgentType, command) ? createCodexAcpClient : createAcpClient;
|
|
27952
|
+
const label = preferredAgentType;
|
|
28144
27953
|
return { command, label, createClient };
|
|
28145
27954
|
}
|
|
28146
27955
|
|
|
@@ -28150,16 +27959,16 @@ import { existsSync, statSync } from "node:fs";
|
|
|
28150
27959
|
|
|
28151
27960
|
// src/git/get-git-repo-root-sync.ts
|
|
28152
27961
|
import { execFileSync } from "node:child_process";
|
|
28153
|
-
import * as
|
|
27962
|
+
import * as path5 from "node:path";
|
|
28154
27963
|
function getGitRepoRootSync(startDir) {
|
|
28155
27964
|
try {
|
|
28156
27965
|
const out = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
28157
|
-
cwd:
|
|
27966
|
+
cwd: path5.resolve(startDir),
|
|
28158
27967
|
encoding: "utf8",
|
|
28159
27968
|
stdio: ["ignore", "pipe", "ignore"],
|
|
28160
27969
|
maxBuffer: 1024 * 1024
|
|
28161
27970
|
}).trim();
|
|
28162
|
-
return out ?
|
|
27971
|
+
return out ? path5.resolve(out) : null;
|
|
28163
27972
|
} catch {
|
|
28164
27973
|
return null;
|
|
28165
27974
|
}
|
|
@@ -28168,25 +27977,25 @@ function getGitRepoRootSync(startDir) {
|
|
|
28168
27977
|
// src/acp/workspace-files.ts
|
|
28169
27978
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
28170
27979
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
28171
|
-
import * as
|
|
27980
|
+
import * as path6 from "node:path";
|
|
28172
27981
|
function resolveWorkspaceFilePath(cwd3, rawPath) {
|
|
28173
27982
|
const trimmed2 = rawPath.trim();
|
|
28174
27983
|
if (!trimmed2) return null;
|
|
28175
|
-
const normalizedCwd =
|
|
27984
|
+
const normalizedCwd = path6.resolve(cwd3);
|
|
28176
27985
|
let abs = resolveSafePathUnderCwd(cwd3, trimmed2);
|
|
28177
27986
|
if (!abs) {
|
|
28178
|
-
const candidate =
|
|
27987
|
+
const candidate = path6.isAbsolute(trimmed2) ? path6.normalize(trimmed2) : path6.normalize(path6.resolve(normalizedCwd, trimmed2));
|
|
28179
27988
|
const gitRoot2 = getGitRepoRootSync(cwd3);
|
|
28180
27989
|
if (!gitRoot2) return null;
|
|
28181
|
-
const rel =
|
|
28182
|
-
if (rel.startsWith("..") ||
|
|
27990
|
+
const rel = path6.relative(gitRoot2, candidate);
|
|
27991
|
+
if (rel.startsWith("..") || path6.isAbsolute(rel)) return null;
|
|
28183
27992
|
abs = candidate;
|
|
28184
27993
|
}
|
|
28185
27994
|
const gitRoot = getGitRepoRootSync(cwd3);
|
|
28186
27995
|
if (gitRoot) {
|
|
28187
|
-
const relFromRoot =
|
|
28188
|
-
if (!relFromRoot.startsWith("..") && !
|
|
28189
|
-
return { abs, display: relFromRoot.split(
|
|
27996
|
+
const relFromRoot = path6.relative(gitRoot, abs);
|
|
27997
|
+
if (!relFromRoot.startsWith("..") && !path6.isAbsolute(relFromRoot)) {
|
|
27998
|
+
return { abs, display: relFromRoot.split(path6.sep).join("/") };
|
|
28190
27999
|
}
|
|
28191
28000
|
}
|
|
28192
28001
|
return { abs, display: toDisplayPathRelativeToCwd(cwd3, abs) };
|
|
@@ -28195,9 +28004,9 @@ function readUtf8WorkspaceFile(cwd3, displayPath) {
|
|
|
28195
28004
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
28196
28005
|
const gitRoot = getGitRepoRootSync(cwd3);
|
|
28197
28006
|
if (gitRoot) {
|
|
28198
|
-
const abs2 =
|
|
28199
|
-
const rel =
|
|
28200
|
-
if (!rel.startsWith("..") && !
|
|
28007
|
+
const abs2 = path6.resolve(gitRoot, displayPath);
|
|
28008
|
+
const rel = path6.relative(gitRoot, abs2);
|
|
28009
|
+
if (!rel.startsWith("..") && !path6.isAbsolute(rel)) {
|
|
28201
28010
|
try {
|
|
28202
28011
|
return readFileSync2(abs2, "utf8");
|
|
28203
28012
|
} catch {
|
|
@@ -28216,9 +28025,9 @@ function tryWorkspaceDisplayToAbs(cwd3, displayPath) {
|
|
|
28216
28025
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
28217
28026
|
const gitRoot = getGitRepoRootSync(cwd3);
|
|
28218
28027
|
if (gitRoot) {
|
|
28219
|
-
const abs =
|
|
28220
|
-
const rel =
|
|
28221
|
-
if (!rel.startsWith("..") && !
|
|
28028
|
+
const abs = path6.resolve(gitRoot, displayPath);
|
|
28029
|
+
const rel = path6.relative(gitRoot, abs);
|
|
28030
|
+
if (!rel.startsWith("..") && !path6.isAbsolute(rel)) return abs;
|
|
28222
28031
|
}
|
|
28223
28032
|
return resolveSafePathUnderCwd(cwd3, displayPath);
|
|
28224
28033
|
}
|
|
@@ -28277,7 +28086,7 @@ function createBridgeOnFileChange(opts) {
|
|
|
28277
28086
|
const sessionId = routing.sessionId;
|
|
28278
28087
|
const send = getSendSessionUpdate();
|
|
28279
28088
|
if (!send || !runId || !sessionId) {
|
|
28280
|
-
log2(`[file
|
|
28089
|
+
log2(`[Bridge service] file change not forwarded path=${evt.path} (session/run not wired)`);
|
|
28281
28090
|
return;
|
|
28282
28091
|
}
|
|
28283
28092
|
const cwd3 = process.cwd();
|
|
@@ -28295,7 +28104,7 @@ function createBridgeOnFileChange(opts) {
|
|
|
28295
28104
|
directoryRemoved: dirFlags.directoryRemoved
|
|
28296
28105
|
});
|
|
28297
28106
|
} catch (err) {
|
|
28298
|
-
log2(`[
|
|
28107
|
+
log2(`[Bridge service] session_file_change failed ${evt.path}: ${errorMessage(err)}`);
|
|
28299
28108
|
}
|
|
28300
28109
|
};
|
|
28301
28110
|
}
|
|
@@ -28322,7 +28131,7 @@ function createBridgeOnRequest(opts) {
|
|
|
28322
28131
|
}
|
|
28323
28132
|
});
|
|
28324
28133
|
} catch (err) {
|
|
28325
|
-
log2(`[
|
|
28134
|
+
log2(`[Bridge service] ACP request forward failed (${request.method}): ${errorMessage(err)}`);
|
|
28326
28135
|
}
|
|
28327
28136
|
};
|
|
28328
28137
|
}
|
|
@@ -28512,11 +28321,6 @@ function isCompletedToolStatus(status) {
|
|
|
28512
28321
|
const s = status.toLowerCase();
|
|
28513
28322
|
return s === "completed" || s === "complete" || s === "succeeded" || s === "success";
|
|
28514
28323
|
}
|
|
28515
|
-
function isTerminalToolStatus(status) {
|
|
28516
|
-
if (typeof status !== "string") return false;
|
|
28517
|
-
const s = status.toLowerCase();
|
|
28518
|
-
return isCompletedToolStatus(status) || s === "failed" || s === "cancelled" || s === "canceled";
|
|
28519
|
-
}
|
|
28520
28324
|
function accumulateToolPaths(toolKey, paths, acc) {
|
|
28521
28325
|
if (!toolKey || paths.length === 0) return;
|
|
28522
28326
|
let s = acc.get(toolKey);
|
|
@@ -28614,7 +28418,7 @@ var PathSnapshotTracker = class {
|
|
|
28614
28418
|
});
|
|
28615
28419
|
sentPaths.add(displayPath);
|
|
28616
28420
|
} catch (err) {
|
|
28617
|
-
log2(`[
|
|
28421
|
+
log2(`[Bridge service] session_file_change failed ${displayPath}: ${errorMessage(err)}`);
|
|
28618
28422
|
}
|
|
28619
28423
|
}
|
|
28620
28424
|
}
|
|
@@ -28668,7 +28472,7 @@ function sendExtractedDiffsAsSessionFileChanges(diffs, send, cwd3, sessionId, ru
|
|
|
28668
28472
|
});
|
|
28669
28473
|
sentPaths.add(d.path);
|
|
28670
28474
|
} catch (err) {
|
|
28671
|
-
log2(`[
|
|
28475
|
+
log2(`[Bridge service] session_file_change failed ${d.path}: ${errorMessage(err)}`);
|
|
28672
28476
|
}
|
|
28673
28477
|
}
|
|
28674
28478
|
}
|
|
@@ -28694,7 +28498,7 @@ function sendGitHeadVsWorkspaceForToolPaths(mergedPaths, sentPaths, send, cwd3,
|
|
|
28694
28498
|
});
|
|
28695
28499
|
sentPaths.add(displayPath);
|
|
28696
28500
|
} catch (err) {
|
|
28697
|
-
log2(`[
|
|
28501
|
+
log2(`[Bridge service] session_file_change failed ${displayPath}: ${errorMessage(err)}`);
|
|
28698
28502
|
}
|
|
28699
28503
|
}
|
|
28700
28504
|
}
|
|
@@ -28742,7 +28546,9 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
28742
28546
|
if (diffs.length > 0 && send && runId && sessionId) {
|
|
28743
28547
|
sendExtractedDiffsAsSessionFileChanges(diffs, send, cwd3, sessionId, runId, sentFileChangePaths, log2);
|
|
28744
28548
|
} else if (diffs.length > 0) {
|
|
28745
|
-
log2(
|
|
28549
|
+
log2(
|
|
28550
|
+
`[Bridge service] ACP file diff(s) not forwarded (${diffs.length}): session/run not wired to bridge`
|
|
28551
|
+
);
|
|
28746
28552
|
}
|
|
28747
28553
|
if (isCompletedToolCallUpdate && send && runId && sessionId) {
|
|
28748
28554
|
const acc = pathTracker.accumulatedPathsByToolKey.get(toolKey);
|
|
@@ -28760,7 +28566,7 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
28760
28566
|
payload: params
|
|
28761
28567
|
});
|
|
28762
28568
|
} catch (err) {
|
|
28763
|
-
log2(`[
|
|
28569
|
+
log2(`[Bridge service] session_update send failed (${updateKind}): ${errorMessage(err)}`);
|
|
28764
28570
|
}
|
|
28765
28571
|
}
|
|
28766
28572
|
};
|
|
@@ -28777,9 +28583,11 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
28777
28583
|
|
|
28778
28584
|
// src/acp/ensure-acp-client.ts
|
|
28779
28585
|
async function ensureAcpClient(options) {
|
|
28780
|
-
const { state,
|
|
28781
|
-
const targetCwd =
|
|
28782
|
-
|
|
28586
|
+
const { state, preferredAgentType, mode, cwd: cwd3, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
|
|
28587
|
+
const targetCwd = path7.resolve(
|
|
28588
|
+
cwd3 != null && String(cwd3).trim() !== "" ? String(cwd3).trim() : process.cwd()
|
|
28589
|
+
);
|
|
28590
|
+
if (state.acpHandle && state.lastAcpCwd != null && path7.resolve(state.lastAcpCwd) !== path7.resolve(targetCwd)) {
|
|
28783
28591
|
try {
|
|
28784
28592
|
state.acpHandle.disconnect();
|
|
28785
28593
|
} catch {
|
|
@@ -28788,9 +28596,12 @@ async function ensureAcpClient(options) {
|
|
|
28788
28596
|
state.acpStartPromise = null;
|
|
28789
28597
|
state.acpAgentKey = null;
|
|
28790
28598
|
}
|
|
28791
|
-
const resolved = resolveAgentCommand(
|
|
28599
|
+
const resolved = resolveAgentCommand(preferredAgentType);
|
|
28792
28600
|
if (!resolved) {
|
|
28793
|
-
log2(
|
|
28601
|
+
log2(
|
|
28602
|
+
`[agent] No local agent type (${preferredAgentType === null ? "none" : `"${preferredAgentType}"`}). Send agentType on prompts or agent_config after identify.`
|
|
28603
|
+
);
|
|
28604
|
+
state.lastAcpStartError = "No agent type: ensure the app sends agentType on prompts or agent_config for this bridge.";
|
|
28794
28605
|
return null;
|
|
28795
28606
|
}
|
|
28796
28607
|
const agentKey = `${resolved.label}::${resolved.command.join("\0")}`;
|
|
@@ -28805,9 +28616,23 @@ async function ensureAcpClient(options) {
|
|
|
28805
28616
|
}
|
|
28806
28617
|
if (state.acpHandle) return state.acpHandle;
|
|
28807
28618
|
if (!state.acpStartPromise) {
|
|
28619
|
+
let statOk = false;
|
|
28620
|
+
try {
|
|
28621
|
+
const st = fs3.statSync(targetCwd);
|
|
28622
|
+
statOk = st.isDirectory();
|
|
28623
|
+
if (!statOk) {
|
|
28624
|
+
state.lastAcpStartError = `Agent cwd is not a directory: ${targetCwd}`;
|
|
28625
|
+
log2(`[agent] ${state.lastAcpStartError}`);
|
|
28626
|
+
}
|
|
28627
|
+
} catch {
|
|
28628
|
+
state.lastAcpStartError = `Agent cwd missing or inaccessible: ${targetCwd}`;
|
|
28629
|
+
log2(`[agent] ${state.lastAcpStartError}`);
|
|
28630
|
+
}
|
|
28631
|
+
if (!statOk) {
|
|
28632
|
+
return null;
|
|
28633
|
+
}
|
|
28808
28634
|
const modeFlag = mode && ["ask", "plan"].includes(mode) ? ["--mode", mode] : [];
|
|
28809
28635
|
const fullCmd = [...resolved.command, ...modeFlag];
|
|
28810
|
-
log2(`[prompt] Starting agent (${resolved.label}) on first request\u2026`);
|
|
28811
28636
|
const hooks = buildAcpSessionBridgeHooks({
|
|
28812
28637
|
routing,
|
|
28813
28638
|
getSendSessionUpdate: () => sendSessionUpdate,
|
|
@@ -28823,11 +28648,10 @@ async function ensureAcpClient(options) {
|
|
|
28823
28648
|
state.acpHandle = h;
|
|
28824
28649
|
state.lastAcpCwd = targetCwd;
|
|
28825
28650
|
state.acpAgentKey = agentKey;
|
|
28826
|
-
log2(`ACP client connected (${resolved.label})`);
|
|
28827
28651
|
return h;
|
|
28828
28652
|
}).catch((err) => {
|
|
28829
28653
|
state.lastAcpStartError = errorMessage(err);
|
|
28830
|
-
log2(`
|
|
28654
|
+
log2(`[agent] failed to start: ${state.lastAcpStartError}`);
|
|
28831
28655
|
state.acpStartPromise = null;
|
|
28832
28656
|
state.acpAgentKey = null;
|
|
28833
28657
|
return null;
|
|
@@ -28838,7 +28662,7 @@ async function ensureAcpClient(options) {
|
|
|
28838
28662
|
|
|
28839
28663
|
// src/acp/create-acp-manager.ts
|
|
28840
28664
|
async function createAcpManager(options) {
|
|
28841
|
-
const {
|
|
28665
|
+
const { log: log2 } = options;
|
|
28842
28666
|
const state = {
|
|
28843
28667
|
acpHandle: null,
|
|
28844
28668
|
acpStartPromise: null,
|
|
@@ -28853,7 +28677,6 @@ async function createAcpManager(options) {
|
|
|
28853
28677
|
function setPreferredAgentType(agentType) {
|
|
28854
28678
|
if (!backendFallbackAgentType) {
|
|
28855
28679
|
backendFallbackAgentType = agentType;
|
|
28856
|
-
log2(`Agent type from backend (fallback): ${backendFallbackAgentType}`);
|
|
28857
28680
|
}
|
|
28858
28681
|
}
|
|
28859
28682
|
function handlePrompt(opts) {
|
|
@@ -28869,7 +28692,7 @@ async function createAcpManager(options) {
|
|
|
28869
28692
|
sendSessionUpdate,
|
|
28870
28693
|
collectSessionDiffAfterTurn
|
|
28871
28694
|
} = opts;
|
|
28872
|
-
const preferredForPrompt = agentType ?? backendFallbackAgentType;
|
|
28695
|
+
const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
|
|
28873
28696
|
pendingCancelRunId = void 0;
|
|
28874
28697
|
promptRouting.sessionId = sessionId;
|
|
28875
28698
|
promptRouting.runId = runId;
|
|
@@ -28877,7 +28700,6 @@ async function createAcpManager(options) {
|
|
|
28877
28700
|
async function run() {
|
|
28878
28701
|
const handle = await ensureAcpClient({
|
|
28879
28702
|
state,
|
|
28880
|
-
agentCommand,
|
|
28881
28703
|
preferredAgentType: preferredForPrompt,
|
|
28882
28704
|
mode,
|
|
28883
28705
|
cwd: cwd3,
|
|
@@ -28893,7 +28715,7 @@ async function createAcpManager(options) {
|
|
|
28893
28715
|
...sessionId ? { sessionId } : {},
|
|
28894
28716
|
...runId ? { runId } : {},
|
|
28895
28717
|
success: false,
|
|
28896
|
-
error: state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app
|
|
28718
|
+
error: state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app."
|
|
28897
28719
|
});
|
|
28898
28720
|
return;
|
|
28899
28721
|
}
|
|
@@ -28921,7 +28743,6 @@ async function createAcpManager(options) {
|
|
|
28921
28743
|
promptId,
|
|
28922
28744
|
sessionId,
|
|
28923
28745
|
runId,
|
|
28924
|
-
agentType: preferredForPrompt,
|
|
28925
28746
|
sendResult,
|
|
28926
28747
|
sendSessionUpdate,
|
|
28927
28748
|
collectSessionDiffAfterTurn,
|
|
@@ -28941,15 +28762,13 @@ async function createAcpManager(options) {
|
|
|
28941
28762
|
if (handle?.cancel) {
|
|
28942
28763
|
try {
|
|
28943
28764
|
await handle.cancel();
|
|
28944
|
-
log2(`[prompt] ACP session/cancel sent for run ${runId.slice(0, 8)}\u2026`);
|
|
28945
28765
|
return true;
|
|
28946
28766
|
} catch (err) {
|
|
28947
|
-
log2(`[
|
|
28767
|
+
log2(`[agent] cancel failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
28948
28768
|
return false;
|
|
28949
28769
|
}
|
|
28950
28770
|
}
|
|
28951
28771
|
pendingCancelRunId = runId;
|
|
28952
|
-
log2(`[prompt] Cancel queued for run ${runId.slice(0, 8)}\u2026 (agent still starting)`);
|
|
28953
28772
|
return true;
|
|
28954
28773
|
}
|
|
28955
28774
|
function resolveRequest(requestId, result) {
|
|
@@ -28964,57 +28783,55 @@ async function createAcpManager(options) {
|
|
|
28964
28783
|
return { setPreferredAgentType, handlePrompt, cancelRun, resolveRequest, disconnect };
|
|
28965
28784
|
}
|
|
28966
28785
|
|
|
28967
|
-
// src/bridge/routing/message-router.ts
|
|
28968
|
-
function createMessageRouter() {
|
|
28969
|
-
const handlers = /* @__PURE__ */ new Map();
|
|
28970
|
-
return {
|
|
28971
|
-
register(type, handler) {
|
|
28972
|
-
handlers.set(type, handler);
|
|
28973
|
-
},
|
|
28974
|
-
dispatch(msg, deps) {
|
|
28975
|
-
const type = msg.type;
|
|
28976
|
-
if (!type) return;
|
|
28977
|
-
const handler = handlers.get(type);
|
|
28978
|
-
if (handler) handler(msg, deps);
|
|
28979
|
-
}
|
|
28980
|
-
};
|
|
28981
|
-
}
|
|
28982
|
-
|
|
28983
28786
|
// src/bridge/routing/handlers/auth-token.ts
|
|
28984
28787
|
var handleAuthToken = (msg, { log: log2 }) => {
|
|
28985
|
-
if (typeof msg.token !== "string") return
|
|
28788
|
+
if (typeof msg.token !== "string") return;
|
|
28986
28789
|
log2("Received auth token. Save it for future runs:");
|
|
28987
28790
|
log2(` export BUILDAMATON_AUTH_TOKEN="${msg.token}"`);
|
|
28988
|
-
return true;
|
|
28989
28791
|
};
|
|
28990
28792
|
|
|
28991
28793
|
// src/bridge/routing/handlers/bridge-identified.ts
|
|
28992
|
-
var handleBridgeIdentified = (msg,
|
|
28993
|
-
if (typeof msg.bridgeName !== "string") return
|
|
28994
|
-
onBridgeIdentified(
|
|
28794
|
+
var handleBridgeIdentified = (msg, deps) => {
|
|
28795
|
+
if (typeof msg.bridgeName !== "string") return;
|
|
28796
|
+
deps.onBridgeIdentified(
|
|
28995
28797
|
msg
|
|
28996
28798
|
);
|
|
28997
|
-
|
|
28998
|
-
|
|
28799
|
+
setImmediate(() => {
|
|
28800
|
+
void (async () => {
|
|
28801
|
+
try {
|
|
28802
|
+
await deps.reportAutoDetectedAgents?.();
|
|
28803
|
+
} catch (e) {
|
|
28804
|
+
deps.log(`[Bridge service] auto-detect agents failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
28805
|
+
}
|
|
28806
|
+
})();
|
|
28807
|
+
});
|
|
28808
|
+
setImmediate(() => {
|
|
28809
|
+
try {
|
|
28810
|
+
deps.sendLocalSkillsReport?.();
|
|
28811
|
+
} catch (e) {
|
|
28812
|
+
deps.log(`[Bridge service] local skills report failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
28813
|
+
}
|
|
28814
|
+
});
|
|
28999
28815
|
};
|
|
29000
28816
|
|
|
29001
28817
|
// src/acp/from-bridge/handle-bridge-agent-config.ts
|
|
29002
28818
|
function handleBridgeAgentConfig(msg, { acpManager }) {
|
|
29003
|
-
if (!Array.isArray(msg.agents) || msg.agents.length === 0) return
|
|
28819
|
+
if (!Array.isArray(msg.agents) || msg.agents.length === 0) return;
|
|
29004
28820
|
acpManager.setPreferredAgentType(msg.agents[0].type);
|
|
29005
|
-
return true;
|
|
29006
28821
|
}
|
|
29007
28822
|
|
|
29008
28823
|
// src/bridge/routing/handlers/agent-config.ts
|
|
29009
|
-
var handleAgentConfigMessage = (msg, deps) =>
|
|
28824
|
+
var handleAgentConfigMessage = (msg, deps) => {
|
|
28825
|
+
handleBridgeAgentConfig(msg, deps);
|
|
28826
|
+
};
|
|
29010
28827
|
|
|
29011
28828
|
// src/acp/from-bridge/handle-bridge-prompt.ts
|
|
29012
|
-
import * as
|
|
28829
|
+
import * as path10 from "node:path";
|
|
29013
28830
|
import { execFile as execFile3 } from "node:child_process";
|
|
29014
28831
|
import { promisify as promisify3 } from "node:util";
|
|
29015
28832
|
|
|
29016
28833
|
// src/git/bridge-queue-key.ts
|
|
29017
|
-
import * as
|
|
28834
|
+
import * as path8 from "node:path";
|
|
29018
28835
|
import { createHash } from "node:crypto";
|
|
29019
28836
|
function normalizeCanonicalGitUrl(url2) {
|
|
29020
28837
|
let s = url2.trim();
|
|
@@ -29042,13 +28859,13 @@ function canonicalUrlToRepoIdSync(url2) {
|
|
|
29042
28859
|
return createHash("sha256").update(normalized).digest("hex").slice(0, 32);
|
|
29043
28860
|
}
|
|
29044
28861
|
function fallbackRepoIdFromPath(absPath) {
|
|
29045
|
-
return createHash("sha256").update(
|
|
28862
|
+
return createHash("sha256").update(path8.resolve(absPath)).digest("hex").slice(0, 32);
|
|
29046
28863
|
}
|
|
29047
28864
|
async function resolveBridgeQueueBindFields(options) {
|
|
29048
28865
|
const { effectiveCwd, worktreePaths, primaryRepoRoots, log: log2 } = options;
|
|
29049
|
-
const cwdAbs = worktreePaths.length > 0 ?
|
|
28866
|
+
const cwdAbs = worktreePaths.length > 0 ? path8.resolve(worktreePaths[0]) : path8.resolve(effectiveCwd);
|
|
29050
28867
|
if (!primaryRepoRoots.length) {
|
|
29051
|
-
log2("[
|
|
28868
|
+
log2("[Bridge service] prompt queue bind skipped: no git repo roots under cwd");
|
|
29052
28869
|
return null;
|
|
29053
28870
|
}
|
|
29054
28871
|
let primaryRoot = primaryRepoRoots[0];
|
|
@@ -29070,12 +28887,12 @@ async function resolveBridgeQueueBindFields(options) {
|
|
|
29070
28887
|
|
|
29071
28888
|
// src/git/pre-turn-snapshot.ts
|
|
29072
28889
|
import * as fs4 from "node:fs";
|
|
29073
|
-
import * as
|
|
28890
|
+
import * as path9 from "node:path";
|
|
29074
28891
|
import { execFile as execFile2 } from "node:child_process";
|
|
29075
28892
|
import { promisify as promisify2 } from "node:util";
|
|
29076
28893
|
var execFileAsync2 = promisify2(execFile2);
|
|
29077
28894
|
function snapshotsDirForCwd(agentCwd) {
|
|
29078
|
-
return
|
|
28895
|
+
return path9.join(agentCwd, ".buildautomaton", "snapshots");
|
|
29079
28896
|
}
|
|
29080
28897
|
async function gitStashCreate2(repoRoot, log2) {
|
|
29081
28898
|
try {
|
|
@@ -29102,7 +28919,7 @@ async function gitRun(repoRoot, args, log2, label) {
|
|
|
29102
28919
|
async function resolveSnapshotRepoRoots(options) {
|
|
29103
28920
|
const { worktreePaths, fallbackCwd, log: log2 } = options;
|
|
29104
28921
|
if (worktreePaths?.length) {
|
|
29105
|
-
const uniq = [...new Set(worktreePaths.map((p) =>
|
|
28922
|
+
const uniq = [...new Set(worktreePaths.map((p) => path9.resolve(p)))];
|
|
29106
28923
|
return uniq;
|
|
29107
28924
|
}
|
|
29108
28925
|
try {
|
|
@@ -29134,7 +28951,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
29134
28951
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29135
28952
|
repos
|
|
29136
28953
|
};
|
|
29137
|
-
const filePath =
|
|
28954
|
+
const filePath = path9.join(dir, `${runId}.json`);
|
|
29138
28955
|
try {
|
|
29139
28956
|
fs4.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
29140
28957
|
} catch (e) {
|
|
@@ -29169,7 +28986,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
|
|
|
29169
28986
|
return { ok: true };
|
|
29170
28987
|
}
|
|
29171
28988
|
function snapshotFilePath(agentCwd, runId) {
|
|
29172
|
-
return
|
|
28989
|
+
return path9.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
|
|
29173
28990
|
}
|
|
29174
28991
|
|
|
29175
28992
|
// src/acp/from-bridge/handle-bridge-prompt.ts
|
|
@@ -29184,13 +29001,15 @@ async function readGitBranch(cwd3) {
|
|
|
29184
29001
|
}
|
|
29185
29002
|
}
|
|
29186
29003
|
function handleBridgePrompt(msg, deps) {
|
|
29187
|
-
if (!msg.prompt) return false;
|
|
29188
29004
|
const { getWs, log: log2, acpManager, sessionWorktreeManager } = deps;
|
|
29189
|
-
const
|
|
29190
|
-
const
|
|
29191
|
-
|
|
29192
|
-
|
|
29193
|
-
|
|
29005
|
+
const rawPrompt = msg.prompt;
|
|
29006
|
+
const promptText = typeof rawPrompt === "string" ? rawPrompt : rawPrompt != null ? String(rawPrompt) : "";
|
|
29007
|
+
if (!promptText.trim()) {
|
|
29008
|
+
log2(
|
|
29009
|
+
`[Bridge service] prompt ignored: empty or missing prompt field (sessionId=${typeof msg.sessionId === "string" ? msg.sessionId.slice(0, 8) : "\u2014"}\u2026 runId=${typeof msg.runId === "string" ? msg.runId.slice(0, 8) : "\u2014"}\u2026)`
|
|
29010
|
+
);
|
|
29011
|
+
return;
|
|
29012
|
+
}
|
|
29194
29013
|
const sessionId = msg.sessionId;
|
|
29195
29014
|
const isNewSession = msg.isNewSession === true;
|
|
29196
29015
|
const sessionWorktreesEnabled = msg.sessionWorktreesEnabled === true;
|
|
@@ -29205,31 +29024,15 @@ function handleBridgePrompt(msg, deps) {
|
|
|
29205
29024
|
const sendSessionUpdate = (payload) => {
|
|
29206
29025
|
const s = getWs();
|
|
29207
29026
|
if (!s) {
|
|
29208
|
-
log2("[
|
|
29027
|
+
log2("[Bridge service] session_update not sent: not connected");
|
|
29209
29028
|
return;
|
|
29210
29029
|
}
|
|
29211
29030
|
const p = payload;
|
|
29212
|
-
if (p.type === "session_file_change" && typeof p.path === "string") {
|
|
29213
|
-
log2(
|
|
29214
|
-
`[bridge\u2192ws] session_file_change runId=${p.runId?.slice(0, 8) ?? "?"}\u2026 path=${p.path}`
|
|
29215
|
-
);
|
|
29216
|
-
} else if (p.type === "session_update" && (p.kind === "tool_call_update" || p.kind === "tool_call")) {
|
|
29217
|
-
const inner = p.payload && typeof p.payload === "object" ? p.payload : null;
|
|
29218
|
-
const status = inner?.status;
|
|
29219
|
-
if (isTerminalToolStatus(status)) {
|
|
29220
|
-
const tc = inner?.toolCall ?? inner?.tool_call;
|
|
29221
|
-
const toolName = typeof tc?.name === "string" ? tc.name : "";
|
|
29222
|
-
const st = typeof status === "string" ? status : String(status);
|
|
29223
|
-
log2(
|
|
29224
|
-
`[bridge\u2192ws] tool finished runId=${p.runId?.slice(0, 8) ?? "?"}\u2026 tool=${toolName || "?"} status=${st}`
|
|
29225
|
-
);
|
|
29226
|
-
}
|
|
29227
|
-
}
|
|
29228
29031
|
sendWsMessage(s, payload);
|
|
29229
29032
|
};
|
|
29230
29033
|
async function preambleAndPrompt(resolvedCwd) {
|
|
29231
29034
|
const s = getWs();
|
|
29232
|
-
const effectiveCwd =
|
|
29035
|
+
const effectiveCwd = path10.resolve(resolvedCwd ?? process.cwd());
|
|
29233
29036
|
const worktreePaths = sessionWorktreeManager.getWorktreePathsForSession(sessionId) ?? [];
|
|
29234
29037
|
const repoRoots = await resolveSnapshotRepoRoots({
|
|
29235
29038
|
worktreePaths,
|
|
@@ -29281,84 +29084,84 @@ function handleBridgePrompt(msg, deps) {
|
|
|
29281
29084
|
runId,
|
|
29282
29085
|
mode: msg.mode,
|
|
29283
29086
|
agentType,
|
|
29284
|
-
cwd:
|
|
29087
|
+
cwd: effectiveCwd,
|
|
29285
29088
|
sendResult,
|
|
29286
29089
|
sendSessionUpdate,
|
|
29287
29090
|
collectSessionDiffAfterTurn
|
|
29288
29091
|
});
|
|
29289
29092
|
}
|
|
29290
29093
|
void sessionWorktreeManager.resolveCwdForPrompt(sessionId, { isNewSession, sessionWorktreesEnabled }).then((cwd3) => preambleAndPrompt(cwd3)).catch((err) => {
|
|
29291
|
-
log2(`[
|
|
29094
|
+
log2(`[agent] worktree resolve failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
29292
29095
|
void preambleAndPrompt(void 0);
|
|
29293
29096
|
});
|
|
29294
|
-
return true;
|
|
29295
29097
|
}
|
|
29296
29098
|
|
|
29297
29099
|
// src/bridge/routing/handlers/prompt.ts
|
|
29298
|
-
var handlePromptMessage = (msg, deps) =>
|
|
29100
|
+
var handlePromptMessage = (msg, deps) => {
|
|
29101
|
+
handleBridgePrompt(msg, deps);
|
|
29102
|
+
};
|
|
29299
29103
|
|
|
29300
29104
|
// src/acp/from-bridge/handle-bridge-cancel-run.ts
|
|
29301
29105
|
function handleBridgeCancelRun(msg, { log: log2, acpManager }) {
|
|
29302
29106
|
const runId = msg.runId;
|
|
29303
|
-
if (!runId) return
|
|
29107
|
+
if (!runId) return;
|
|
29304
29108
|
void acpManager.cancelRun(runId).then((sent) => {
|
|
29305
29109
|
if (!sent) {
|
|
29306
29110
|
log2(
|
|
29307
|
-
`[
|
|
29111
|
+
`[agent] cancel ignored for run ${runId.slice(0, 8)}\u2026 (no active run or cancel not available)`
|
|
29308
29112
|
);
|
|
29309
29113
|
}
|
|
29310
29114
|
});
|
|
29311
|
-
return true;
|
|
29312
29115
|
}
|
|
29313
29116
|
|
|
29314
29117
|
// src/bridge/routing/handlers/cancel-run.ts
|
|
29315
|
-
var handleCancelRunMessage = (msg, deps) =>
|
|
29118
|
+
var handleCancelRunMessage = (msg, deps) => {
|
|
29119
|
+
handleBridgeCancelRun(msg, deps);
|
|
29120
|
+
};
|
|
29316
29121
|
|
|
29317
29122
|
// src/acp/from-bridge/handle-bridge-cursor-request-response.ts
|
|
29318
|
-
function handleBridgeCursorRequestResponse(msg, { acpManager
|
|
29319
|
-
if (typeof msg.requestId !== "string") return
|
|
29123
|
+
function handleBridgeCursorRequestResponse(msg, { acpManager }) {
|
|
29124
|
+
if (typeof msg.requestId !== "string") return;
|
|
29320
29125
|
acpManager.resolveRequest(msg.requestId, msg.result ?? {});
|
|
29321
|
-
log2(`[prompt] Resolved Cursor request ${msg.requestId}`);
|
|
29322
|
-
return true;
|
|
29323
29126
|
}
|
|
29324
29127
|
|
|
29325
29128
|
// src/bridge/routing/handlers/cursor-request-response.ts
|
|
29326
|
-
var handleCursorRequestResponseMessage = (msg, deps) =>
|
|
29129
|
+
var handleCursorRequestResponseMessage = (msg, deps) => {
|
|
29130
|
+
handleBridgeCursorRequestResponse(msg, deps);
|
|
29131
|
+
};
|
|
29327
29132
|
|
|
29328
29133
|
// src/skills/handle-skill-call.ts
|
|
29329
29134
|
function handleSkillCall(msg, socket, log2) {
|
|
29330
29135
|
callSkill(msg.skillId, msg.operationId, msg.params ?? {}).then((result) => {
|
|
29331
29136
|
sendWsMessage(socket, { type: "skill_result", id: msg.id, result });
|
|
29332
|
-
log2(`Skill ${msg.skillId}/${msg.operationId} ok`);
|
|
29333
29137
|
}).catch((err) => {
|
|
29334
29138
|
sendWsMessage(socket, { type: "skill_result", id: msg.id, error: String(err) });
|
|
29335
|
-
log2(`
|
|
29139
|
+
log2(`[Bridge service] skill_call failed (${msg.skillId}/${msg.operationId}): ${err}`);
|
|
29336
29140
|
});
|
|
29337
29141
|
}
|
|
29338
29142
|
|
|
29339
29143
|
// src/bridge/routing/handlers/skill-call.ts
|
|
29340
29144
|
var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
29341
|
-
if (!msg.skillId || msg.operationId === void 0) return
|
|
29145
|
+
if (!msg.skillId || msg.operationId === void 0) return;
|
|
29342
29146
|
const socket = getWs();
|
|
29343
|
-
if (!socket) return
|
|
29147
|
+
if (!socket) return;
|
|
29344
29148
|
handleSkillCall(
|
|
29345
29149
|
msg,
|
|
29346
29150
|
socket,
|
|
29347
29151
|
log2
|
|
29348
29152
|
);
|
|
29349
|
-
return true;
|
|
29350
29153
|
};
|
|
29351
29154
|
|
|
29352
29155
|
// src/files/list-dir.ts
|
|
29353
29156
|
import fs5 from "node:fs";
|
|
29354
|
-
import
|
|
29157
|
+
import path12 from "node:path";
|
|
29355
29158
|
|
|
29356
29159
|
// src/files/ensure-under-cwd.ts
|
|
29357
|
-
import
|
|
29160
|
+
import path11 from "node:path";
|
|
29358
29161
|
function ensureUnderCwd(relativePath, cwd3 = process.cwd()) {
|
|
29359
|
-
const normalized =
|
|
29360
|
-
const resolved =
|
|
29361
|
-
if (!resolved.startsWith(cwd3 +
|
|
29162
|
+
const normalized = path11.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
29163
|
+
const resolved = path11.resolve(cwd3, normalized);
|
|
29164
|
+
if (!resolved.startsWith(cwd3 + path11.sep) && resolved !== cwd3) {
|
|
29362
29165
|
return null;
|
|
29363
29166
|
}
|
|
29364
29167
|
return resolved;
|
|
@@ -29374,8 +29177,8 @@ function listDir(relativePath) {
|
|
|
29374
29177
|
try {
|
|
29375
29178
|
const names = fs5.readdirSync(resolved, { withFileTypes: true });
|
|
29376
29179
|
const entries = names.filter((d) => !d.name.startsWith(".")).map((d) => {
|
|
29377
|
-
const entryPath =
|
|
29378
|
-
const fullPath =
|
|
29180
|
+
const entryPath = path12.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
29181
|
+
const fullPath = path12.join(resolved, d.name);
|
|
29379
29182
|
let isDir = d.isDirectory();
|
|
29380
29183
|
if (d.isSymbolicLink()) {
|
|
29381
29184
|
try {
|
|
@@ -29592,15 +29395,15 @@ function readFile(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
29592
29395
|
|
|
29593
29396
|
// src/files/file-index.ts
|
|
29594
29397
|
import fs7 from "node:fs";
|
|
29595
|
-
import
|
|
29398
|
+
import path13 from "node:path";
|
|
29596
29399
|
import os2 from "node:os";
|
|
29597
29400
|
import crypto2 from "node:crypto";
|
|
29598
|
-
var INDEX_DIR =
|
|
29401
|
+
var INDEX_DIR = path13.join(os2.homedir(), ".buildautomaton");
|
|
29599
29402
|
var HASH_LEN = 16;
|
|
29600
29403
|
var INDEX_VERSION = 2;
|
|
29601
29404
|
function getIndexPath(cwd3) {
|
|
29602
29405
|
const hash = crypto2.createHash("sha256").update(cwd3).digest("hex").slice(0, HASH_LEN);
|
|
29603
|
-
return
|
|
29406
|
+
return path13.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
29604
29407
|
}
|
|
29605
29408
|
function getTrigrams(s) {
|
|
29606
29409
|
const lower = s.toLowerCase();
|
|
@@ -29644,14 +29447,14 @@ function walkDir(dir, baseDir, out) {
|
|
|
29644
29447
|
}
|
|
29645
29448
|
for (const name of names) {
|
|
29646
29449
|
if (name.startsWith(".")) continue;
|
|
29647
|
-
const full =
|
|
29450
|
+
const full = path13.join(dir, name);
|
|
29648
29451
|
let stat4;
|
|
29649
29452
|
try {
|
|
29650
29453
|
stat4 = fs7.statSync(full);
|
|
29651
29454
|
} catch {
|
|
29652
29455
|
continue;
|
|
29653
29456
|
}
|
|
29654
|
-
const relative6 =
|
|
29457
|
+
const relative6 = path13.relative(baseDir, full).replace(/\\/g, "/");
|
|
29655
29458
|
if (stat4.isDirectory()) {
|
|
29656
29459
|
walkDir(full, baseDir, out);
|
|
29657
29460
|
} else if (stat4.isFile()) {
|
|
@@ -29660,7 +29463,7 @@ function walkDir(dir, baseDir, out) {
|
|
|
29660
29463
|
}
|
|
29661
29464
|
}
|
|
29662
29465
|
function buildFileIndex(cwd3) {
|
|
29663
|
-
const resolved =
|
|
29466
|
+
const resolved = path13.resolve(cwd3);
|
|
29664
29467
|
const paths = [];
|
|
29665
29468
|
walkDir(resolved, resolved, paths);
|
|
29666
29469
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
@@ -29686,7 +29489,7 @@ function buildFileIndex(cwd3) {
|
|
|
29686
29489
|
return data;
|
|
29687
29490
|
}
|
|
29688
29491
|
function loadFileIndex(cwd3) {
|
|
29689
|
-
const resolved =
|
|
29492
|
+
const resolved = path13.resolve(cwd3);
|
|
29690
29493
|
const indexPath = getIndexPath(resolved);
|
|
29691
29494
|
try {
|
|
29692
29495
|
const raw = fs7.readFileSync(indexPath, "utf8");
|
|
@@ -29707,7 +29510,7 @@ function loadFileIndex(cwd3) {
|
|
|
29707
29510
|
}
|
|
29708
29511
|
}
|
|
29709
29512
|
function ensureFileIndex(cwd3) {
|
|
29710
|
-
const resolved =
|
|
29513
|
+
const resolved = path13.resolve(cwd3);
|
|
29711
29514
|
const cached2 = loadFileIndex(resolved);
|
|
29712
29515
|
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
29713
29516
|
const data = buildFileIndex(resolved);
|
|
@@ -29810,62 +29613,116 @@ function handleFileBrowserRequest(msg, socket) {
|
|
|
29810
29613
|
}
|
|
29811
29614
|
}
|
|
29812
29615
|
|
|
29813
|
-
// src/
|
|
29814
|
-
var handleSkillLayoutRequest = (msg, deps) => {
|
|
29815
|
-
if (msg.type !== "skill_layout_request") return false;
|
|
29816
|
-
const socket = deps.getWs();
|
|
29817
|
-
const id = typeof msg.id === "string" ? msg.id : "";
|
|
29818
|
-
const roots = discoverSkillLayoutRoots(process.cwd());
|
|
29819
|
-
socket?.send(JSON.stringify({ type: "skill_layout_response", id, roots }));
|
|
29820
|
-
return true;
|
|
29821
|
-
};
|
|
29822
|
-
|
|
29823
|
-
// src/bridge/routing/handlers/register-file-browser-handlers.ts
|
|
29616
|
+
// src/bridge/routing/handlers/file-browser-messages.ts
|
|
29824
29617
|
function handleFileBrowserRequestMessage(msg, { getWs }) {
|
|
29825
|
-
if (typeof msg.id !== "string" || typeof msg.path !== "string") return
|
|
29618
|
+
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
29826
29619
|
const socket = getWs();
|
|
29827
|
-
if (!socket) return
|
|
29620
|
+
if (!socket) return;
|
|
29828
29621
|
handleFileBrowserRequest(
|
|
29829
29622
|
msg,
|
|
29830
29623
|
socket
|
|
29831
29624
|
);
|
|
29832
|
-
return true;
|
|
29833
29625
|
}
|
|
29834
29626
|
function handleFileBrowserSearchMessage(msg, { getWs }) {
|
|
29835
|
-
if (typeof msg.id !== "string") return
|
|
29627
|
+
if (typeof msg.id !== "string") return;
|
|
29836
29628
|
const socket = getWs();
|
|
29837
|
-
if (!socket) return
|
|
29629
|
+
if (!socket) return;
|
|
29838
29630
|
handleFileBrowserSearch(msg, socket);
|
|
29839
|
-
return true;
|
|
29840
|
-
}
|
|
29841
|
-
function registerFileBrowserHandlers(router2) {
|
|
29842
|
-
router2.register("file_browser_request", handleFileBrowserRequestMessage);
|
|
29843
|
-
router2.register("file_browser_search", handleFileBrowserSearchMessage);
|
|
29844
|
-
router2.register("skill_layout_request", handleSkillLayoutRequest);
|
|
29845
29631
|
}
|
|
29846
29632
|
|
|
29847
|
-
// src/skills/
|
|
29633
|
+
// src/skills/discover-local-agent-skills.ts
|
|
29848
29634
|
import fs8 from "node:fs";
|
|
29849
|
-
import
|
|
29850
|
-
|
|
29851
|
-
|
|
29852
|
-
|
|
29853
|
-
|
|
29854
|
-
|
|
29855
|
-
|
|
29856
|
-
|
|
29857
|
-
|
|
29635
|
+
import path14 from "node:path";
|
|
29636
|
+
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
29637
|
+
function discoverLocalSkills(cwd3) {
|
|
29638
|
+
const out = [];
|
|
29639
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
29640
|
+
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
29641
|
+
const base = path14.join(cwd3, rel);
|
|
29642
|
+
if (!fs8.existsSync(base) || !fs8.statSync(base).isDirectory()) continue;
|
|
29643
|
+
let entries = [];
|
|
29644
|
+
try {
|
|
29645
|
+
entries = fs8.readdirSync(base);
|
|
29646
|
+
} catch {
|
|
29647
|
+
continue;
|
|
29648
|
+
}
|
|
29649
|
+
for (const name of entries) {
|
|
29650
|
+
const dir = path14.join(base, name);
|
|
29651
|
+
try {
|
|
29652
|
+
if (!fs8.statSync(dir).isDirectory()) continue;
|
|
29653
|
+
} catch {
|
|
29858
29654
|
continue;
|
|
29859
29655
|
}
|
|
29860
|
-
const
|
|
29656
|
+
const skillMd = path14.join(dir, "SKILL.md");
|
|
29657
|
+
if (!fs8.existsSync(skillMd)) continue;
|
|
29658
|
+
const key = `${rel}/${name}`;
|
|
29659
|
+
if (seenKeys.has(key)) continue;
|
|
29660
|
+
seenKeys.add(key);
|
|
29661
|
+
out.push({ skillKey: name, path: `${rel}/${name}`.replace(/\\/g, "/") });
|
|
29662
|
+
}
|
|
29663
|
+
}
|
|
29664
|
+
return out;
|
|
29665
|
+
}
|
|
29666
|
+
function discoverSkillLayoutRoots(cwd3) {
|
|
29667
|
+
const roots = [];
|
|
29668
|
+
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
29669
|
+
const base = path14.join(cwd3, rel);
|
|
29670
|
+
if (!fs8.existsSync(base) || !fs8.statSync(base).isDirectory()) continue;
|
|
29671
|
+
let entries = [];
|
|
29672
|
+
try {
|
|
29673
|
+
entries = fs8.readdirSync(base);
|
|
29674
|
+
} catch {
|
|
29675
|
+
continue;
|
|
29676
|
+
}
|
|
29677
|
+
const skills2 = [];
|
|
29678
|
+
for (const name of entries) {
|
|
29679
|
+
const dir = path14.join(base, name);
|
|
29680
|
+
try {
|
|
29681
|
+
if (!fs8.statSync(dir).isDirectory()) continue;
|
|
29682
|
+
} catch {
|
|
29683
|
+
continue;
|
|
29684
|
+
}
|
|
29685
|
+
if (!fs8.existsSync(path14.join(dir, "SKILL.md"))) continue;
|
|
29686
|
+
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
29687
|
+
skills2.push({ name, relPath });
|
|
29688
|
+
}
|
|
29689
|
+
if (skills2.length > 0) {
|
|
29690
|
+
roots.push({ path: rel.replace(/\\/g, "/"), skills: skills2 });
|
|
29691
|
+
}
|
|
29692
|
+
}
|
|
29693
|
+
return roots;
|
|
29694
|
+
}
|
|
29695
|
+
|
|
29696
|
+
// src/bridge/routing/handlers/skill-layout-request.ts
|
|
29697
|
+
function handleSkillLayoutRequest(msg, deps) {
|
|
29698
|
+
const socket = deps.getWs();
|
|
29699
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
29700
|
+
const roots = discoverSkillLayoutRoots(process.cwd());
|
|
29701
|
+
socket?.send(JSON.stringify({ type: "skill_layout_response", id, roots }));
|
|
29702
|
+
}
|
|
29703
|
+
|
|
29704
|
+
// src/skills/install-remote-skills.ts
|
|
29705
|
+
import fs9 from "node:fs";
|
|
29706
|
+
import path15 from "node:path";
|
|
29707
|
+
function installRemoteSkills(cwd3, targetDir, items) {
|
|
29708
|
+
const installed = [];
|
|
29709
|
+
if (!Array.isArray(items)) {
|
|
29710
|
+
return { success: false, error: "Invalid items" };
|
|
29711
|
+
}
|
|
29712
|
+
try {
|
|
29713
|
+
for (const item of items) {
|
|
29714
|
+
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
29715
|
+
continue;
|
|
29716
|
+
}
|
|
29717
|
+
const skillDir = path15.join(cwd3, targetDir, item.skillName);
|
|
29861
29718
|
for (const f of item.files) {
|
|
29862
29719
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
29863
|
-
const dest =
|
|
29864
|
-
|
|
29720
|
+
const dest = path15.join(skillDir, f.path);
|
|
29721
|
+
fs9.mkdirSync(path15.dirname(dest), { recursive: true });
|
|
29865
29722
|
if (f.text !== void 0) {
|
|
29866
|
-
|
|
29723
|
+
fs9.writeFileSync(dest, f.text, "utf8");
|
|
29867
29724
|
} else if (f.base64) {
|
|
29868
|
-
|
|
29725
|
+
fs9.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
29869
29726
|
}
|
|
29870
29727
|
}
|
|
29871
29728
|
installed.push({
|
|
@@ -29882,7 +29739,6 @@ function installRemoteSkills(cwd3, targetDir, items) {
|
|
|
29882
29739
|
|
|
29883
29740
|
// src/bridge/routing/handlers/install-skills.ts
|
|
29884
29741
|
var handleInstallSkillsMessage = (msg, deps) => {
|
|
29885
|
-
if (msg.type !== "install_skills") return false;
|
|
29886
29742
|
const socket = deps.getWs();
|
|
29887
29743
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
29888
29744
|
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
@@ -29891,30 +29747,27 @@ var handleInstallSkillsMessage = (msg, deps) => {
|
|
|
29891
29747
|
const result = installRemoteSkills(cwd3, targetDir, rawItems);
|
|
29892
29748
|
if (!result.success) {
|
|
29893
29749
|
const err = result.error ?? "Invalid items";
|
|
29894
|
-
deps.log(`install_skills failed: ${err}`);
|
|
29750
|
+
deps.log(`[Bridge service] install_skills failed: ${err}`);
|
|
29895
29751
|
socket?.send(JSON.stringify({ type: "install_skills_result", id, success: false, error: err }));
|
|
29896
|
-
return
|
|
29752
|
+
return;
|
|
29897
29753
|
}
|
|
29898
|
-
deps.log(`Installed ${result.installed?.length ?? 0} remote skill(s) into ${targetDir}`);
|
|
29899
29754
|
socket?.send(JSON.stringify({ type: "install_skills_result", id, success: true, installed: result.installed }));
|
|
29900
|
-
return true;
|
|
29901
29755
|
};
|
|
29902
29756
|
|
|
29903
29757
|
// src/bridge/routing/handlers/refresh-local-skills.ts
|
|
29904
29758
|
var handleRefreshLocalSkills = (_msg, deps) => {
|
|
29905
29759
|
deps.sendLocalSkillsReport?.();
|
|
29906
|
-
return true;
|
|
29907
29760
|
};
|
|
29908
29761
|
|
|
29909
29762
|
// src/bridge/routing/handlers/commit-session-request.ts
|
|
29910
29763
|
var handleCommitSessionRequestMessage = (msg, deps) => {
|
|
29911
|
-
if (
|
|
29764
|
+
if (typeof msg.id !== "string") return;
|
|
29912
29765
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
29913
29766
|
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
29914
29767
|
const message = typeof msg.message === "string" ? msg.message : "";
|
|
29915
29768
|
const push = msg.push === true;
|
|
29916
29769
|
const endSession = msg.endSession === true;
|
|
29917
|
-
if (!sessionId || !branch || !message) return
|
|
29770
|
+
if (!sessionId || !branch || !message) return;
|
|
29918
29771
|
void deps.sessionWorktreeManager.commitSession({ sessionId, branch, message, push }).then((r) => {
|
|
29919
29772
|
const s = deps.getWs();
|
|
29920
29773
|
if (s) {
|
|
@@ -29938,53 +29791,45 @@ var handleCommitSessionRequestMessage = (msg, deps) => {
|
|
|
29938
29791
|
});
|
|
29939
29792
|
}
|
|
29940
29793
|
});
|
|
29941
|
-
return true;
|
|
29942
29794
|
};
|
|
29943
29795
|
|
|
29944
29796
|
// src/bridge/routing/handlers/rename-session-branch.ts
|
|
29945
29797
|
var handleRenameSessionBranchMessage = (msg, deps) => {
|
|
29946
|
-
if (msg.type !== "rename_session_branch") return false;
|
|
29947
29798
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
29948
29799
|
const newBranch = typeof msg.newBranch === "string" ? msg.newBranch : "";
|
|
29949
|
-
if (!sessionId || !newBranch) return
|
|
29800
|
+
if (!sessionId || !newBranch) return;
|
|
29950
29801
|
void deps.sessionWorktreeManager.renameSessionBranch(sessionId, newBranch);
|
|
29951
|
-
return true;
|
|
29952
29802
|
};
|
|
29953
29803
|
|
|
29954
29804
|
// src/bridge/routing/handlers/session-archived.ts
|
|
29955
29805
|
var handleSessionArchivedMessage = (msg, deps) => {
|
|
29956
|
-
if (msg.type !== "session_archived") return false;
|
|
29957
29806
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
29958
|
-
if (!sessionId) return
|
|
29807
|
+
if (!sessionId) return;
|
|
29959
29808
|
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
29960
|
-
return true;
|
|
29961
29809
|
};
|
|
29962
29810
|
|
|
29963
29811
|
// src/bridge/routing/handlers/session-discarded.ts
|
|
29964
29812
|
var handleSessionDiscardedMessage = (msg, deps) => {
|
|
29965
|
-
if (msg.type !== "session_discarded") return false;
|
|
29966
29813
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
29967
|
-
if (!sessionId) return
|
|
29814
|
+
if (!sessionId) return;
|
|
29968
29815
|
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
29969
|
-
return true;
|
|
29970
29816
|
};
|
|
29971
29817
|
|
|
29972
29818
|
// src/bridge/routing/handlers/revert-turn-snapshot.ts
|
|
29973
|
-
import * as
|
|
29974
|
-
import * as
|
|
29819
|
+
import * as fs10 from "node:fs";
|
|
29820
|
+
import * as path16 from "node:path";
|
|
29975
29821
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
29976
|
-
if (msg.type !== "revert_turn_snapshot") return false;
|
|
29977
29822
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
29978
29823
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
29979
29824
|
const turnId = typeof msg.turnId === "string" ? msg.turnId : "";
|
|
29980
|
-
if (!id || !sessionId || !turnId) return
|
|
29825
|
+
if (!id || !sessionId || !turnId) return;
|
|
29981
29826
|
const { getWs, log: log2, sessionWorktreeManager } = deps;
|
|
29982
29827
|
void (async () => {
|
|
29983
29828
|
const s = getWs();
|
|
29984
29829
|
if (!s) return;
|
|
29985
|
-
const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ??
|
|
29830
|
+
const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? path16.resolve(process.cwd());
|
|
29986
29831
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
29987
|
-
if (!
|
|
29832
|
+
if (!fs10.existsSync(file2)) {
|
|
29988
29833
|
sendWsMessage(s, {
|
|
29989
29834
|
type: "revert_turn_snapshot_result",
|
|
29990
29835
|
id,
|
|
@@ -30001,40 +29846,118 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
30001
29846
|
...res.error ? { error: res.error } : {}
|
|
30002
29847
|
});
|
|
30003
29848
|
})();
|
|
30004
|
-
return true;
|
|
30005
29849
|
};
|
|
30006
29850
|
|
|
29851
|
+
// src/bridge/routing/handlers/dev-server-control.ts
|
|
29852
|
+
var handleDevServerControl = (msg, deps) => {
|
|
29853
|
+
const serverId = typeof msg.serverId === "string" ? msg.serverId : "";
|
|
29854
|
+
const action = msg.action === "start" || msg.action === "stop" ? msg.action : null;
|
|
29855
|
+
if (!serverId || !action) return;
|
|
29856
|
+
deps.devServerManager?.handleControl(serverId, action);
|
|
29857
|
+
};
|
|
29858
|
+
|
|
29859
|
+
// src/bridge/routing/handlers/dev-servers-config.ts
|
|
29860
|
+
var handleDevServersConfig = (msg, deps) => {
|
|
29861
|
+
const devServers = msg.devServers;
|
|
29862
|
+
deps.devServerManager?.applyConfig(devServers ?? []);
|
|
29863
|
+
};
|
|
29864
|
+
|
|
29865
|
+
// src/bridge/routing/dispatch-bridge-message.ts
|
|
29866
|
+
function dispatchBridgeMessage(msg, deps) {
|
|
29867
|
+
const type = msg.type;
|
|
29868
|
+
if (typeof type !== "string") return;
|
|
29869
|
+
switch (type) {
|
|
29870
|
+
case "auth_token":
|
|
29871
|
+
handleAuthToken(msg, deps);
|
|
29872
|
+
break;
|
|
29873
|
+
case "bridge_identified":
|
|
29874
|
+
handleBridgeIdentified(msg, deps);
|
|
29875
|
+
break;
|
|
29876
|
+
case "dev_servers_config":
|
|
29877
|
+
handleDevServersConfig(msg, deps);
|
|
29878
|
+
break;
|
|
29879
|
+
case "server_control":
|
|
29880
|
+
handleDevServerControl(msg, deps);
|
|
29881
|
+
break;
|
|
29882
|
+
case "agent_config":
|
|
29883
|
+
handleAgentConfigMessage(msg, deps);
|
|
29884
|
+
break;
|
|
29885
|
+
case "prompt":
|
|
29886
|
+
handlePromptMessage(msg, deps);
|
|
29887
|
+
break;
|
|
29888
|
+
case "commit_session_request":
|
|
29889
|
+
handleCommitSessionRequestMessage(msg, deps);
|
|
29890
|
+
break;
|
|
29891
|
+
case "rename_session_branch":
|
|
29892
|
+
handleRenameSessionBranchMessage(msg, deps);
|
|
29893
|
+
break;
|
|
29894
|
+
case "session_archived":
|
|
29895
|
+
handleSessionArchivedMessage(msg, deps);
|
|
29896
|
+
break;
|
|
29897
|
+
case "session_discarded":
|
|
29898
|
+
handleSessionDiscardedMessage(msg, deps);
|
|
29899
|
+
break;
|
|
29900
|
+
case "revert_turn_snapshot":
|
|
29901
|
+
handleRevertTurnSnapshotMessage(msg, deps);
|
|
29902
|
+
break;
|
|
29903
|
+
case "cancel_run":
|
|
29904
|
+
handleCancelRunMessage(msg, deps);
|
|
29905
|
+
break;
|
|
29906
|
+
case "cursor_request_response":
|
|
29907
|
+
handleCursorRequestResponseMessage(msg, deps);
|
|
29908
|
+
break;
|
|
29909
|
+
case "skill_call":
|
|
29910
|
+
handleSkillCallMessage(msg, deps);
|
|
29911
|
+
break;
|
|
29912
|
+
case "file_browser_request":
|
|
29913
|
+
handleFileBrowserRequestMessage(msg, deps);
|
|
29914
|
+
break;
|
|
29915
|
+
case "file_browser_search":
|
|
29916
|
+
handleFileBrowserSearchMessage(msg, deps);
|
|
29917
|
+
break;
|
|
29918
|
+
case "skill_layout_request":
|
|
29919
|
+
handleSkillLayoutRequest(msg, deps);
|
|
29920
|
+
break;
|
|
29921
|
+
case "install_skills":
|
|
29922
|
+
handleInstallSkillsMessage(msg, deps);
|
|
29923
|
+
break;
|
|
29924
|
+
case "refresh_local_skills":
|
|
29925
|
+
handleRefreshLocalSkills(msg, deps);
|
|
29926
|
+
break;
|
|
29927
|
+
default:
|
|
29928
|
+
deps.log?.(`[Bridge service] unhandled message type: ${type}`);
|
|
29929
|
+
}
|
|
29930
|
+
}
|
|
29931
|
+
|
|
30007
29932
|
// src/bridge/routing/handle-bridge-message.ts
|
|
30008
|
-
var
|
|
30009
|
-
|
|
30010
|
-
|
|
30011
|
-
|
|
30012
|
-
|
|
30013
|
-
|
|
30014
|
-
|
|
30015
|
-
router.register("session_archived", handleSessionArchivedMessage);
|
|
30016
|
-
router.register("session_discarded", handleSessionDiscardedMessage);
|
|
30017
|
-
router.register("revert_turn_snapshot", handleRevertTurnSnapshotMessage);
|
|
30018
|
-
router.register("cancel_run", handleCancelRunMessage);
|
|
30019
|
-
router.register("cursor_request_response", handleCursorRequestResponseMessage);
|
|
30020
|
-
router.register("skill_call", handleSkillCallMessage);
|
|
30021
|
-
registerFileBrowserHandlers(router);
|
|
30022
|
-
router.register("install_skills", handleInstallSkillsMessage);
|
|
30023
|
-
router.register("refresh_local_skills", handleRefreshLocalSkills);
|
|
29933
|
+
var DEFERRED_INBOUND_TYPES = /* @__PURE__ */ new Set([
|
|
29934
|
+
"server_control",
|
|
29935
|
+
"prompt",
|
|
29936
|
+
"install_skills",
|
|
29937
|
+
"refresh_local_skills",
|
|
29938
|
+
"dev_servers_config"
|
|
29939
|
+
]);
|
|
30024
29940
|
function handleBridgeMessage(data, deps) {
|
|
30025
29941
|
const msg = data;
|
|
30026
29942
|
const socket = deps.getWs();
|
|
30027
29943
|
if (!socket) return;
|
|
30028
|
-
|
|
29944
|
+
const type = msg.type;
|
|
29945
|
+
if (typeof type === "string" && DEFERRED_INBOUND_TYPES.has(type)) {
|
|
29946
|
+
setImmediate(() => {
|
|
29947
|
+
dispatchBridgeMessage(msg, deps);
|
|
29948
|
+
});
|
|
29949
|
+
return;
|
|
29950
|
+
}
|
|
29951
|
+
dispatchBridgeMessage(msg, deps);
|
|
30029
29952
|
}
|
|
30030
29953
|
|
|
30031
29954
|
// src/worktrees/session-worktree-manager.ts
|
|
30032
|
-
import * as
|
|
29955
|
+
import * as path20 from "node:path";
|
|
30033
29956
|
import os4 from "node:os";
|
|
30034
29957
|
|
|
30035
29958
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
30036
|
-
import * as
|
|
30037
|
-
import * as
|
|
29959
|
+
import * as fs12 from "node:fs";
|
|
29960
|
+
import * as path18 from "node:path";
|
|
30038
29961
|
|
|
30039
29962
|
// src/git/worktree-add.ts
|
|
30040
29963
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -30043,12 +29966,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
30043
29966
|
}
|
|
30044
29967
|
|
|
30045
29968
|
// src/worktrees/worktree-layout-file.ts
|
|
30046
|
-
import * as
|
|
30047
|
-
import * as
|
|
29969
|
+
import * as fs11 from "node:fs";
|
|
29970
|
+
import * as path17 from "node:path";
|
|
30048
29971
|
import os3 from "node:os";
|
|
30049
29972
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
30050
29973
|
function defaultWorktreeLayoutPath() {
|
|
30051
|
-
return
|
|
29974
|
+
return path17.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
30052
29975
|
}
|
|
30053
29976
|
function normalizeLoadedLayout(raw) {
|
|
30054
29977
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -30060,8 +29983,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
30060
29983
|
function loadWorktreeLayout() {
|
|
30061
29984
|
try {
|
|
30062
29985
|
const p = defaultWorktreeLayoutPath();
|
|
30063
|
-
if (!
|
|
30064
|
-
const raw = JSON.parse(
|
|
29986
|
+
if (!fs11.existsSync(p)) return { launcherCwds: [] };
|
|
29987
|
+
const raw = JSON.parse(fs11.readFileSync(p, "utf8"));
|
|
30065
29988
|
return normalizeLoadedLayout(raw);
|
|
30066
29989
|
} catch {
|
|
30067
29990
|
return { launcherCwds: [] };
|
|
@@ -30069,18 +29992,18 @@ function loadWorktreeLayout() {
|
|
|
30069
29992
|
}
|
|
30070
29993
|
function saveWorktreeLayout(layout) {
|
|
30071
29994
|
try {
|
|
30072
|
-
const dir =
|
|
30073
|
-
|
|
30074
|
-
|
|
29995
|
+
const dir = path17.dirname(defaultWorktreeLayoutPath());
|
|
29996
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
29997
|
+
fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
30075
29998
|
} catch {
|
|
30076
29999
|
}
|
|
30077
30000
|
}
|
|
30078
30001
|
function baseNameSafe(abs) {
|
|
30079
|
-
return
|
|
30002
|
+
return path17.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
30080
30003
|
}
|
|
30081
30004
|
function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
|
|
30082
|
-
const norm =
|
|
30083
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
30005
|
+
const norm = path17.resolve(launcherCwdAbs);
|
|
30006
|
+
const existing = layout.launcherCwds.find((e) => path17.resolve(e.absolutePath) === norm);
|
|
30084
30007
|
if (existing) return existing.dirName;
|
|
30085
30008
|
const base = baseNameSafe(norm);
|
|
30086
30009
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
@@ -30098,9 +30021,9 @@ function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
|
|
|
30098
30021
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
30099
30022
|
async function prepareNewSessionWorktrees(options) {
|
|
30100
30023
|
const { rootAbs, launcherCwd, sessionId, layout, log: log2 } = options;
|
|
30101
|
-
const launcherResolved =
|
|
30024
|
+
const launcherResolved = path18.resolve(launcherCwd);
|
|
30102
30025
|
const cwdKey = allocateDirNameForLauncherCwd(layout, launcherResolved);
|
|
30103
|
-
const agentMirrorRoot =
|
|
30026
|
+
const agentMirrorRoot = path18.join(rootAbs, cwdKey);
|
|
30104
30027
|
const repos = await discoverGitReposUnderRoot(launcherResolved);
|
|
30105
30028
|
if (repos.length === 0) {
|
|
30106
30029
|
log2("[worktrees] No git repos under launcher cwd; skipping worktree creation");
|
|
@@ -30108,13 +30031,13 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
30108
30031
|
}
|
|
30109
30032
|
const branch = `session-${sessionId}`;
|
|
30110
30033
|
const worktreePaths = [];
|
|
30111
|
-
|
|
30034
|
+
fs12.mkdirSync(agentMirrorRoot, { recursive: true });
|
|
30112
30035
|
for (const repo of repos) {
|
|
30113
|
-
let rel =
|
|
30114
|
-
if (rel.startsWith("..") ||
|
|
30036
|
+
let rel = path18.relative(launcherResolved, repo.absolutePath);
|
|
30037
|
+
if (rel.startsWith("..") || path18.isAbsolute(rel)) continue;
|
|
30115
30038
|
const relNorm = rel === "" ? "." : rel;
|
|
30116
|
-
const wtPath =
|
|
30117
|
-
|
|
30039
|
+
const wtPath = path18.join(agentMirrorRoot, relNorm, sessionId);
|
|
30040
|
+
fs12.mkdirSync(path18.dirname(wtPath), { recursive: true });
|
|
30118
30041
|
try {
|
|
30119
30042
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
30120
30043
|
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch})`);
|
|
@@ -30149,23 +30072,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
30149
30072
|
}
|
|
30150
30073
|
|
|
30151
30074
|
// src/worktrees/remove-session-worktrees.ts
|
|
30152
|
-
import * as
|
|
30075
|
+
import * as fs15 from "node:fs";
|
|
30153
30076
|
|
|
30154
30077
|
// src/git/worktree-remove.ts
|
|
30155
|
-
import * as
|
|
30078
|
+
import * as fs14 from "node:fs";
|
|
30156
30079
|
|
|
30157
30080
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
30158
|
-
import * as
|
|
30159
|
-
import * as
|
|
30081
|
+
import * as fs13 from "node:fs";
|
|
30082
|
+
import * as path19 from "node:path";
|
|
30160
30083
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
30161
|
-
const gitDirFile =
|
|
30162
|
-
if (!
|
|
30163
|
-
const first2 =
|
|
30084
|
+
const gitDirFile = path19.join(wt, ".git");
|
|
30085
|
+
if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
|
|
30086
|
+
const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
|
|
30164
30087
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
30165
30088
|
if (!m) return "";
|
|
30166
|
-
const gitWorktreePath =
|
|
30167
|
-
const gitDir =
|
|
30168
|
-
return
|
|
30089
|
+
const gitWorktreePath = path19.resolve(wt, m[1].trim());
|
|
30090
|
+
const gitDir = path19.dirname(path19.dirname(gitWorktreePath));
|
|
30091
|
+
return path19.dirname(gitDir);
|
|
30169
30092
|
}
|
|
30170
30093
|
|
|
30171
30094
|
// src/git/worktree-remove.ts
|
|
@@ -30174,7 +30097,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
30174
30097
|
if (mainRepo) {
|
|
30175
30098
|
await simpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
30176
30099
|
} else {
|
|
30177
|
-
|
|
30100
|
+
fs14.rmSync(worktreePath, { recursive: true, force: true });
|
|
30178
30101
|
}
|
|
30179
30102
|
}
|
|
30180
30103
|
|
|
@@ -30187,7 +30110,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
30187
30110
|
} catch (e) {
|
|
30188
30111
|
log2(`[worktrees] remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
30189
30112
|
try {
|
|
30190
|
-
|
|
30113
|
+
fs15.rmSync(wt, { recursive: true, force: true });
|
|
30191
30114
|
} catch {
|
|
30192
30115
|
}
|
|
30193
30116
|
}
|
|
@@ -30199,10 +30122,21 @@ async function gitCommitAllIfDirty(repoDir, message, options) {
|
|
|
30199
30122
|
const g = simpleGit(repoDir);
|
|
30200
30123
|
const st = await g.status();
|
|
30201
30124
|
if (!st.files?.length) return;
|
|
30125
|
+
const branch = options.branch.trim();
|
|
30126
|
+
if (!branch) {
|
|
30127
|
+
throw new Error("Branch name is required");
|
|
30128
|
+
}
|
|
30129
|
+
const branches = await g.branchLocal();
|
|
30130
|
+
const localNames = new Set(branches.all.map((b) => b.replace(/^\*\s*/, "").trim()));
|
|
30131
|
+
if (!localNames.has(branch)) {
|
|
30132
|
+
await g.checkoutLocalBranch(branch);
|
|
30133
|
+
} else {
|
|
30134
|
+
await g.checkout(branch);
|
|
30135
|
+
}
|
|
30202
30136
|
await g.add(".");
|
|
30203
30137
|
await g.commit(message);
|
|
30204
30138
|
if (options.push) {
|
|
30205
|
-
await g.push("origin",
|
|
30139
|
+
await g.push(["-u", "origin", branch]);
|
|
30206
30140
|
}
|
|
30207
30141
|
}
|
|
30208
30142
|
|
|
@@ -30248,7 +30182,7 @@ var SessionWorktreeManager = class {
|
|
|
30248
30182
|
}
|
|
30249
30183
|
if (!opts.isNewSession) {
|
|
30250
30184
|
const agentCwd = this.sessionAgentCwd.get(sessionId);
|
|
30251
|
-
if (agentCwd) return
|
|
30185
|
+
if (agentCwd) return path20.resolve(agentCwd);
|
|
30252
30186
|
return void 0;
|
|
30253
30187
|
}
|
|
30254
30188
|
const prep = await prepareNewSessionWorktrees({
|
|
@@ -30261,7 +30195,7 @@ var SessionWorktreeManager = class {
|
|
|
30261
30195
|
if (!prep) return void 0;
|
|
30262
30196
|
this.sessionPaths.set(sessionId, prep.worktreePaths);
|
|
30263
30197
|
this.sessionAgentCwd.set(sessionId, prep.agentCwd);
|
|
30264
|
-
return
|
|
30198
|
+
return path20.resolve(prep.agentCwd);
|
|
30265
30199
|
}
|
|
30266
30200
|
async renameSessionBranch(sessionId, newBranch) {
|
|
30267
30201
|
const paths = this.sessionPaths.get(sessionId);
|
|
@@ -30282,7 +30216,7 @@ var SessionWorktreeManager = class {
|
|
|
30282
30216
|
getAgentCwdForSession(sessionId) {
|
|
30283
30217
|
if (!sessionId) return null;
|
|
30284
30218
|
const c = this.sessionAgentCwd.get(sessionId);
|
|
30285
|
-
return c ?
|
|
30219
|
+
return c ? path20.resolve(c) : null;
|
|
30286
30220
|
}
|
|
30287
30221
|
async removeSessionWorktrees(sessionId) {
|
|
30288
30222
|
const paths = this.sessionPaths.get(sessionId);
|
|
@@ -30303,7 +30237,7 @@ var SessionWorktreeManager = class {
|
|
|
30303
30237
|
}
|
|
30304
30238
|
};
|
|
30305
30239
|
function defaultWorktreesRootAbs() {
|
|
30306
|
-
return
|
|
30240
|
+
return path20.join(os4.homedir(), ".buildautomaton", "worktrees");
|
|
30307
30241
|
}
|
|
30308
30242
|
|
|
30309
30243
|
// src/auth/refresh-bridge-tokens.ts
|
|
@@ -30334,7 +30268,7 @@ async function refreshBridgeTokens(params) {
|
|
|
30334
30268
|
}
|
|
30335
30269
|
|
|
30336
30270
|
// src/files/watch-file-index.ts
|
|
30337
|
-
import
|
|
30271
|
+
import path21 from "node:path";
|
|
30338
30272
|
|
|
30339
30273
|
// ../../node_modules/.pnpm/chokidar@4.0.3/node_modules/chokidar/esm/index.js
|
|
30340
30274
|
import { stat as statcb } from "fs";
|
|
@@ -30412,7 +30346,7 @@ var ReaddirpStream = class extends Readable2 {
|
|
|
30412
30346
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
30413
30347
|
const statMethod = opts.lstat ? lstat : stat;
|
|
30414
30348
|
if (wantBigintFsStats) {
|
|
30415
|
-
this._stat = (
|
|
30349
|
+
this._stat = (path24) => statMethod(path24, { bigint: true });
|
|
30416
30350
|
} else {
|
|
30417
30351
|
this._stat = statMethod;
|
|
30418
30352
|
}
|
|
@@ -30437,8 +30371,8 @@ var ReaddirpStream = class extends Readable2 {
|
|
|
30437
30371
|
const par = this.parent;
|
|
30438
30372
|
const fil = par && par.files;
|
|
30439
30373
|
if (fil && fil.length > 0) {
|
|
30440
|
-
const { path:
|
|
30441
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
30374
|
+
const { path: path24, depth } = par;
|
|
30375
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path24));
|
|
30442
30376
|
const awaited = await Promise.all(slice);
|
|
30443
30377
|
for (const entry of awaited) {
|
|
30444
30378
|
if (!entry)
|
|
@@ -30478,20 +30412,20 @@ var ReaddirpStream = class extends Readable2 {
|
|
|
30478
30412
|
this.reading = false;
|
|
30479
30413
|
}
|
|
30480
30414
|
}
|
|
30481
|
-
async _exploreDir(
|
|
30415
|
+
async _exploreDir(path24, depth) {
|
|
30482
30416
|
let files;
|
|
30483
30417
|
try {
|
|
30484
|
-
files = await readdir(
|
|
30418
|
+
files = await readdir(path24, this._rdOptions);
|
|
30485
30419
|
} catch (error40) {
|
|
30486
30420
|
this._onError(error40);
|
|
30487
30421
|
}
|
|
30488
|
-
return { files, depth, path:
|
|
30422
|
+
return { files, depth, path: path24 };
|
|
30489
30423
|
}
|
|
30490
|
-
async _formatEntry(dirent,
|
|
30424
|
+
async _formatEntry(dirent, path24) {
|
|
30491
30425
|
let entry;
|
|
30492
30426
|
const basename6 = this._isDirent ? dirent.name : dirent;
|
|
30493
30427
|
try {
|
|
30494
|
-
const fullPath = presolve(pjoin(
|
|
30428
|
+
const fullPath = presolve(pjoin(path24, basename6));
|
|
30495
30429
|
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename6 };
|
|
30496
30430
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
30497
30431
|
} catch (err) {
|
|
@@ -30891,16 +30825,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
30891
30825
|
};
|
|
30892
30826
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
30893
30827
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
30894
|
-
function createFsWatchInstance(
|
|
30828
|
+
function createFsWatchInstance(path24, options, listener, errHandler, emitRaw) {
|
|
30895
30829
|
const handleEvent = (rawEvent, evPath) => {
|
|
30896
|
-
listener(
|
|
30897
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
30898
|
-
if (evPath &&
|
|
30899
|
-
fsWatchBroadcast(sysPath.resolve(
|
|
30830
|
+
listener(path24);
|
|
30831
|
+
emitRaw(rawEvent, evPath, { watchedPath: path24 });
|
|
30832
|
+
if (evPath && path24 !== evPath) {
|
|
30833
|
+
fsWatchBroadcast(sysPath.resolve(path24, evPath), KEY_LISTENERS, sysPath.join(path24, evPath));
|
|
30900
30834
|
}
|
|
30901
30835
|
};
|
|
30902
30836
|
try {
|
|
30903
|
-
return fs_watch(
|
|
30837
|
+
return fs_watch(path24, {
|
|
30904
30838
|
persistent: options.persistent
|
|
30905
30839
|
}, handleEvent);
|
|
30906
30840
|
} catch (error40) {
|
|
@@ -30916,12 +30850,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
30916
30850
|
listener(val1, val2, val3);
|
|
30917
30851
|
});
|
|
30918
30852
|
};
|
|
30919
|
-
var setFsWatchListener = (
|
|
30853
|
+
var setFsWatchListener = (path24, fullPath, options, handlers) => {
|
|
30920
30854
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
30921
30855
|
let cont = FsWatchInstances.get(fullPath);
|
|
30922
30856
|
let watcher;
|
|
30923
30857
|
if (!options.persistent) {
|
|
30924
|
-
watcher = createFsWatchInstance(
|
|
30858
|
+
watcher = createFsWatchInstance(path24, options, listener, errHandler, rawEmitter);
|
|
30925
30859
|
if (!watcher)
|
|
30926
30860
|
return;
|
|
30927
30861
|
return watcher.close.bind(watcher);
|
|
@@ -30932,7 +30866,7 @@ var setFsWatchListener = (path23, fullPath, options, handlers) => {
|
|
|
30932
30866
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
30933
30867
|
} else {
|
|
30934
30868
|
watcher = createFsWatchInstance(
|
|
30935
|
-
|
|
30869
|
+
path24,
|
|
30936
30870
|
options,
|
|
30937
30871
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
30938
30872
|
errHandler,
|
|
@@ -30947,7 +30881,7 @@ var setFsWatchListener = (path23, fullPath, options, handlers) => {
|
|
|
30947
30881
|
cont.watcherUnusable = true;
|
|
30948
30882
|
if (isWindows && error40.code === "EPERM") {
|
|
30949
30883
|
try {
|
|
30950
|
-
const fd = await open(
|
|
30884
|
+
const fd = await open(path24, "r");
|
|
30951
30885
|
await fd.close();
|
|
30952
30886
|
broadcastErr(error40);
|
|
30953
30887
|
} catch (err) {
|
|
@@ -30978,7 +30912,7 @@ var setFsWatchListener = (path23, fullPath, options, handlers) => {
|
|
|
30978
30912
|
};
|
|
30979
30913
|
};
|
|
30980
30914
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
30981
|
-
var setFsWatchFileListener = (
|
|
30915
|
+
var setFsWatchFileListener = (path24, fullPath, options, handlers) => {
|
|
30982
30916
|
const { listener, rawEmitter } = handlers;
|
|
30983
30917
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
30984
30918
|
const copts = cont && cont.options;
|
|
@@ -31000,7 +30934,7 @@ var setFsWatchFileListener = (path23, fullPath, options, handlers) => {
|
|
|
31000
30934
|
});
|
|
31001
30935
|
const currmtime = curr.mtimeMs;
|
|
31002
30936
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
31003
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
30937
|
+
foreach(cont.listeners, (listener2) => listener2(path24, curr));
|
|
31004
30938
|
}
|
|
31005
30939
|
})
|
|
31006
30940
|
};
|
|
@@ -31028,13 +30962,13 @@ var NodeFsHandler = class {
|
|
|
31028
30962
|
* @param listener on fs change
|
|
31029
30963
|
* @returns closer for the watcher instance
|
|
31030
30964
|
*/
|
|
31031
|
-
_watchWithNodeFs(
|
|
30965
|
+
_watchWithNodeFs(path24, listener) {
|
|
31032
30966
|
const opts = this.fsw.options;
|
|
31033
|
-
const directory = sysPath.dirname(
|
|
31034
|
-
const basename6 = sysPath.basename(
|
|
30967
|
+
const directory = sysPath.dirname(path24);
|
|
30968
|
+
const basename6 = sysPath.basename(path24);
|
|
31035
30969
|
const parent = this.fsw._getWatchedDir(directory);
|
|
31036
30970
|
parent.add(basename6);
|
|
31037
|
-
const absolutePath = sysPath.resolve(
|
|
30971
|
+
const absolutePath = sysPath.resolve(path24);
|
|
31038
30972
|
const options = {
|
|
31039
30973
|
persistent: opts.persistent
|
|
31040
30974
|
};
|
|
@@ -31044,12 +30978,12 @@ var NodeFsHandler = class {
|
|
|
31044
30978
|
if (opts.usePolling) {
|
|
31045
30979
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
31046
30980
|
options.interval = enableBin && isBinaryPath(basename6) ? opts.binaryInterval : opts.interval;
|
|
31047
|
-
closer = setFsWatchFileListener(
|
|
30981
|
+
closer = setFsWatchFileListener(path24, absolutePath, options, {
|
|
31048
30982
|
listener,
|
|
31049
30983
|
rawEmitter: this.fsw._emitRaw
|
|
31050
30984
|
});
|
|
31051
30985
|
} else {
|
|
31052
|
-
closer = setFsWatchListener(
|
|
30986
|
+
closer = setFsWatchListener(path24, absolutePath, options, {
|
|
31053
30987
|
listener,
|
|
31054
30988
|
errHandler: this._boundHandleError,
|
|
31055
30989
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -31071,7 +31005,7 @@ var NodeFsHandler = class {
|
|
|
31071
31005
|
let prevStats = stats;
|
|
31072
31006
|
if (parent.has(basename6))
|
|
31073
31007
|
return;
|
|
31074
|
-
const listener = async (
|
|
31008
|
+
const listener = async (path24, newStats) => {
|
|
31075
31009
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
|
|
31076
31010
|
return;
|
|
31077
31011
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -31085,11 +31019,11 @@ var NodeFsHandler = class {
|
|
|
31085
31019
|
this.fsw._emit(EV.CHANGE, file2, newStats2);
|
|
31086
31020
|
}
|
|
31087
31021
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
31088
|
-
this.fsw._closeFile(
|
|
31022
|
+
this.fsw._closeFile(path24);
|
|
31089
31023
|
prevStats = newStats2;
|
|
31090
31024
|
const closer2 = this._watchWithNodeFs(file2, listener);
|
|
31091
31025
|
if (closer2)
|
|
31092
|
-
this.fsw._addPathCloser(
|
|
31026
|
+
this.fsw._addPathCloser(path24, closer2);
|
|
31093
31027
|
} else {
|
|
31094
31028
|
prevStats = newStats2;
|
|
31095
31029
|
}
|
|
@@ -31121,7 +31055,7 @@ var NodeFsHandler = class {
|
|
|
31121
31055
|
* @param item basename of this item
|
|
31122
31056
|
* @returns true if no more processing is needed for this entry.
|
|
31123
31057
|
*/
|
|
31124
|
-
async _handleSymlink(entry, directory,
|
|
31058
|
+
async _handleSymlink(entry, directory, path24, item) {
|
|
31125
31059
|
if (this.fsw.closed) {
|
|
31126
31060
|
return;
|
|
31127
31061
|
}
|
|
@@ -31131,7 +31065,7 @@ var NodeFsHandler = class {
|
|
|
31131
31065
|
this.fsw._incrReadyCount();
|
|
31132
31066
|
let linkPath;
|
|
31133
31067
|
try {
|
|
31134
|
-
linkPath = await fsrealpath(
|
|
31068
|
+
linkPath = await fsrealpath(path24);
|
|
31135
31069
|
} catch (e) {
|
|
31136
31070
|
this.fsw._emitReady();
|
|
31137
31071
|
return true;
|
|
@@ -31141,12 +31075,12 @@ var NodeFsHandler = class {
|
|
|
31141
31075
|
if (dir.has(item)) {
|
|
31142
31076
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
31143
31077
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
31144
|
-
this.fsw._emit(EV.CHANGE,
|
|
31078
|
+
this.fsw._emit(EV.CHANGE, path24, entry.stats);
|
|
31145
31079
|
}
|
|
31146
31080
|
} else {
|
|
31147
31081
|
dir.add(item);
|
|
31148
31082
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
31149
|
-
this.fsw._emit(EV.ADD,
|
|
31083
|
+
this.fsw._emit(EV.ADD, path24, entry.stats);
|
|
31150
31084
|
}
|
|
31151
31085
|
this.fsw._emitReady();
|
|
31152
31086
|
return true;
|
|
@@ -31175,9 +31109,9 @@ var NodeFsHandler = class {
|
|
|
31175
31109
|
return;
|
|
31176
31110
|
}
|
|
31177
31111
|
const item = entry.path;
|
|
31178
|
-
let
|
|
31112
|
+
let path24 = sysPath.join(directory, item);
|
|
31179
31113
|
current.add(item);
|
|
31180
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
31114
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path24, item)) {
|
|
31181
31115
|
return;
|
|
31182
31116
|
}
|
|
31183
31117
|
if (this.fsw.closed) {
|
|
@@ -31186,8 +31120,8 @@ var NodeFsHandler = class {
|
|
|
31186
31120
|
}
|
|
31187
31121
|
if (item === target || !target && !previous.has(item)) {
|
|
31188
31122
|
this.fsw._incrReadyCount();
|
|
31189
|
-
|
|
31190
|
-
this._addToNodeFs(
|
|
31123
|
+
path24 = sysPath.join(dir, sysPath.relative(dir, path24));
|
|
31124
|
+
this._addToNodeFs(path24, initialAdd, wh, depth + 1);
|
|
31191
31125
|
}
|
|
31192
31126
|
}).on(EV.ERROR, this._boundHandleError);
|
|
31193
31127
|
return new Promise((resolve16, reject) => {
|
|
@@ -31256,13 +31190,13 @@ var NodeFsHandler = class {
|
|
|
31256
31190
|
* @param depth Child path actually targeted for watch
|
|
31257
31191
|
* @param target Child path actually targeted for watch
|
|
31258
31192
|
*/
|
|
31259
|
-
async _addToNodeFs(
|
|
31193
|
+
async _addToNodeFs(path24, initialAdd, priorWh, depth, target) {
|
|
31260
31194
|
const ready = this.fsw._emitReady;
|
|
31261
|
-
if (this.fsw._isIgnored(
|
|
31195
|
+
if (this.fsw._isIgnored(path24) || this.fsw.closed) {
|
|
31262
31196
|
ready();
|
|
31263
31197
|
return false;
|
|
31264
31198
|
}
|
|
31265
|
-
const wh = this.fsw._getWatchHelpers(
|
|
31199
|
+
const wh = this.fsw._getWatchHelpers(path24);
|
|
31266
31200
|
if (priorWh) {
|
|
31267
31201
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
31268
31202
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -31278,8 +31212,8 @@ var NodeFsHandler = class {
|
|
|
31278
31212
|
const follow = this.fsw.options.followSymlinks;
|
|
31279
31213
|
let closer;
|
|
31280
31214
|
if (stats.isDirectory()) {
|
|
31281
|
-
const absPath = sysPath.resolve(
|
|
31282
|
-
const targetPath = follow ? await fsrealpath(
|
|
31215
|
+
const absPath = sysPath.resolve(path24);
|
|
31216
|
+
const targetPath = follow ? await fsrealpath(path24) : path24;
|
|
31283
31217
|
if (this.fsw.closed)
|
|
31284
31218
|
return;
|
|
31285
31219
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -31289,29 +31223,29 @@ var NodeFsHandler = class {
|
|
|
31289
31223
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
31290
31224
|
}
|
|
31291
31225
|
} else if (stats.isSymbolicLink()) {
|
|
31292
|
-
const targetPath = follow ? await fsrealpath(
|
|
31226
|
+
const targetPath = follow ? await fsrealpath(path24) : path24;
|
|
31293
31227
|
if (this.fsw.closed)
|
|
31294
31228
|
return;
|
|
31295
31229
|
const parent = sysPath.dirname(wh.watchPath);
|
|
31296
31230
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
31297
31231
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
31298
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
31232
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path24, wh, targetPath);
|
|
31299
31233
|
if (this.fsw.closed)
|
|
31300
31234
|
return;
|
|
31301
31235
|
if (targetPath !== void 0) {
|
|
31302
|
-
this.fsw._symlinkPaths.set(sysPath.resolve(
|
|
31236
|
+
this.fsw._symlinkPaths.set(sysPath.resolve(path24), targetPath);
|
|
31303
31237
|
}
|
|
31304
31238
|
} else {
|
|
31305
31239
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
31306
31240
|
}
|
|
31307
31241
|
ready();
|
|
31308
31242
|
if (closer)
|
|
31309
|
-
this.fsw._addPathCloser(
|
|
31243
|
+
this.fsw._addPathCloser(path24, closer);
|
|
31310
31244
|
return false;
|
|
31311
31245
|
} catch (error40) {
|
|
31312
31246
|
if (this.fsw._handleError(error40)) {
|
|
31313
31247
|
ready();
|
|
31314
|
-
return
|
|
31248
|
+
return path24;
|
|
31315
31249
|
}
|
|
31316
31250
|
}
|
|
31317
31251
|
}
|
|
@@ -31354,26 +31288,26 @@ function createPattern(matcher) {
|
|
|
31354
31288
|
}
|
|
31355
31289
|
return () => false;
|
|
31356
31290
|
}
|
|
31357
|
-
function normalizePath(
|
|
31358
|
-
if (typeof
|
|
31291
|
+
function normalizePath(path24) {
|
|
31292
|
+
if (typeof path24 !== "string")
|
|
31359
31293
|
throw new Error("string expected");
|
|
31360
|
-
|
|
31361
|
-
|
|
31294
|
+
path24 = sysPath2.normalize(path24);
|
|
31295
|
+
path24 = path24.replace(/\\/g, "/");
|
|
31362
31296
|
let prepend = false;
|
|
31363
|
-
if (
|
|
31297
|
+
if (path24.startsWith("//"))
|
|
31364
31298
|
prepend = true;
|
|
31365
31299
|
const DOUBLE_SLASH_RE2 = /\/\//;
|
|
31366
|
-
while (
|
|
31367
|
-
|
|
31300
|
+
while (path24.match(DOUBLE_SLASH_RE2))
|
|
31301
|
+
path24 = path24.replace(DOUBLE_SLASH_RE2, "/");
|
|
31368
31302
|
if (prepend)
|
|
31369
|
-
|
|
31370
|
-
return
|
|
31303
|
+
path24 = "/" + path24;
|
|
31304
|
+
return path24;
|
|
31371
31305
|
}
|
|
31372
31306
|
function matchPatterns(patterns, testString, stats) {
|
|
31373
|
-
const
|
|
31307
|
+
const path24 = normalizePath(testString);
|
|
31374
31308
|
for (let index = 0; index < patterns.length; index++) {
|
|
31375
31309
|
const pattern = patterns[index];
|
|
31376
|
-
if (pattern(
|
|
31310
|
+
if (pattern(path24, stats)) {
|
|
31377
31311
|
return true;
|
|
31378
31312
|
}
|
|
31379
31313
|
}
|
|
@@ -31413,19 +31347,19 @@ var toUnix = (string4) => {
|
|
|
31413
31347
|
}
|
|
31414
31348
|
return str;
|
|
31415
31349
|
};
|
|
31416
|
-
var normalizePathToUnix = (
|
|
31417
|
-
var normalizeIgnored = (cwd3 = "") => (
|
|
31418
|
-
if (typeof
|
|
31419
|
-
return normalizePathToUnix(sysPath2.isAbsolute(
|
|
31350
|
+
var normalizePathToUnix = (path24) => toUnix(sysPath2.normalize(toUnix(path24)));
|
|
31351
|
+
var normalizeIgnored = (cwd3 = "") => (path24) => {
|
|
31352
|
+
if (typeof path24 === "string") {
|
|
31353
|
+
return normalizePathToUnix(sysPath2.isAbsolute(path24) ? path24 : sysPath2.join(cwd3, path24));
|
|
31420
31354
|
} else {
|
|
31421
|
-
return
|
|
31355
|
+
return path24;
|
|
31422
31356
|
}
|
|
31423
31357
|
};
|
|
31424
|
-
var getAbsolutePath = (
|
|
31425
|
-
if (sysPath2.isAbsolute(
|
|
31426
|
-
return
|
|
31358
|
+
var getAbsolutePath = (path24, cwd3) => {
|
|
31359
|
+
if (sysPath2.isAbsolute(path24)) {
|
|
31360
|
+
return path24;
|
|
31427
31361
|
}
|
|
31428
|
-
return sysPath2.join(cwd3,
|
|
31362
|
+
return sysPath2.join(cwd3, path24);
|
|
31429
31363
|
};
|
|
31430
31364
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
31431
31365
|
var DirEntry = class {
|
|
@@ -31480,10 +31414,10 @@ var DirEntry = class {
|
|
|
31480
31414
|
var STAT_METHOD_F = "stat";
|
|
31481
31415
|
var STAT_METHOD_L = "lstat";
|
|
31482
31416
|
var WatchHelper = class {
|
|
31483
|
-
constructor(
|
|
31417
|
+
constructor(path24, follow, fsw) {
|
|
31484
31418
|
this.fsw = fsw;
|
|
31485
|
-
const watchPath =
|
|
31486
|
-
this.path =
|
|
31419
|
+
const watchPath = path24;
|
|
31420
|
+
this.path = path24 = path24.replace(REPLACER_RE, "");
|
|
31487
31421
|
this.watchPath = watchPath;
|
|
31488
31422
|
this.fullWatchPath = sysPath2.resolve(watchPath);
|
|
31489
31423
|
this.dirParts = [];
|
|
@@ -31605,20 +31539,20 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31605
31539
|
this._closePromise = void 0;
|
|
31606
31540
|
let paths = unifyPaths(paths_);
|
|
31607
31541
|
if (cwd3) {
|
|
31608
|
-
paths = paths.map((
|
|
31609
|
-
const absPath = getAbsolutePath(
|
|
31542
|
+
paths = paths.map((path24) => {
|
|
31543
|
+
const absPath = getAbsolutePath(path24, cwd3);
|
|
31610
31544
|
return absPath;
|
|
31611
31545
|
});
|
|
31612
31546
|
}
|
|
31613
|
-
paths.forEach((
|
|
31614
|
-
this._removeIgnoredPath(
|
|
31547
|
+
paths.forEach((path24) => {
|
|
31548
|
+
this._removeIgnoredPath(path24);
|
|
31615
31549
|
});
|
|
31616
31550
|
this._userIgnored = void 0;
|
|
31617
31551
|
if (!this._readyCount)
|
|
31618
31552
|
this._readyCount = 0;
|
|
31619
31553
|
this._readyCount += paths.length;
|
|
31620
|
-
Promise.all(paths.map(async (
|
|
31621
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
31554
|
+
Promise.all(paths.map(async (path24) => {
|
|
31555
|
+
const res = await this._nodeFsHandler._addToNodeFs(path24, !_internal, void 0, 0, _origAdd);
|
|
31622
31556
|
if (res)
|
|
31623
31557
|
this._emitReady();
|
|
31624
31558
|
return res;
|
|
@@ -31640,17 +31574,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31640
31574
|
return this;
|
|
31641
31575
|
const paths = unifyPaths(paths_);
|
|
31642
31576
|
const { cwd: cwd3 } = this.options;
|
|
31643
|
-
paths.forEach((
|
|
31644
|
-
if (!sysPath2.isAbsolute(
|
|
31577
|
+
paths.forEach((path24) => {
|
|
31578
|
+
if (!sysPath2.isAbsolute(path24) && !this._closers.has(path24)) {
|
|
31645
31579
|
if (cwd3)
|
|
31646
|
-
|
|
31647
|
-
|
|
31580
|
+
path24 = sysPath2.join(cwd3, path24);
|
|
31581
|
+
path24 = sysPath2.resolve(path24);
|
|
31648
31582
|
}
|
|
31649
|
-
this._closePath(
|
|
31650
|
-
this._addIgnoredPath(
|
|
31651
|
-
if (this._watched.has(
|
|
31583
|
+
this._closePath(path24);
|
|
31584
|
+
this._addIgnoredPath(path24);
|
|
31585
|
+
if (this._watched.has(path24)) {
|
|
31652
31586
|
this._addIgnoredPath({
|
|
31653
|
-
path:
|
|
31587
|
+
path: path24,
|
|
31654
31588
|
recursive: true
|
|
31655
31589
|
});
|
|
31656
31590
|
}
|
|
@@ -31714,38 +31648,38 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31714
31648
|
* @param stats arguments to be passed with event
|
|
31715
31649
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
31716
31650
|
*/
|
|
31717
|
-
async _emit(event,
|
|
31651
|
+
async _emit(event, path24, stats) {
|
|
31718
31652
|
if (this.closed)
|
|
31719
31653
|
return;
|
|
31720
31654
|
const opts = this.options;
|
|
31721
31655
|
if (isWindows)
|
|
31722
|
-
|
|
31656
|
+
path24 = sysPath2.normalize(path24);
|
|
31723
31657
|
if (opts.cwd)
|
|
31724
|
-
|
|
31725
|
-
const args = [
|
|
31658
|
+
path24 = sysPath2.relative(opts.cwd, path24);
|
|
31659
|
+
const args = [path24];
|
|
31726
31660
|
if (stats != null)
|
|
31727
31661
|
args.push(stats);
|
|
31728
31662
|
const awf = opts.awaitWriteFinish;
|
|
31729
31663
|
let pw;
|
|
31730
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
31664
|
+
if (awf && (pw = this._pendingWrites.get(path24))) {
|
|
31731
31665
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
31732
31666
|
return this;
|
|
31733
31667
|
}
|
|
31734
31668
|
if (opts.atomic) {
|
|
31735
31669
|
if (event === EVENTS.UNLINK) {
|
|
31736
|
-
this._pendingUnlinks.set(
|
|
31670
|
+
this._pendingUnlinks.set(path24, [event, ...args]);
|
|
31737
31671
|
setTimeout(() => {
|
|
31738
|
-
this._pendingUnlinks.forEach((entry,
|
|
31672
|
+
this._pendingUnlinks.forEach((entry, path25) => {
|
|
31739
31673
|
this.emit(...entry);
|
|
31740
31674
|
this.emit(EVENTS.ALL, ...entry);
|
|
31741
|
-
this._pendingUnlinks.delete(
|
|
31675
|
+
this._pendingUnlinks.delete(path25);
|
|
31742
31676
|
});
|
|
31743
31677
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
31744
31678
|
return this;
|
|
31745
31679
|
}
|
|
31746
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
31680
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path24)) {
|
|
31747
31681
|
event = EVENTS.CHANGE;
|
|
31748
|
-
this._pendingUnlinks.delete(
|
|
31682
|
+
this._pendingUnlinks.delete(path24);
|
|
31749
31683
|
}
|
|
31750
31684
|
}
|
|
31751
31685
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -31763,16 +31697,16 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31763
31697
|
this.emitWithAll(event, args);
|
|
31764
31698
|
}
|
|
31765
31699
|
};
|
|
31766
|
-
this._awaitWriteFinish(
|
|
31700
|
+
this._awaitWriteFinish(path24, awf.stabilityThreshold, event, awfEmit);
|
|
31767
31701
|
return this;
|
|
31768
31702
|
}
|
|
31769
31703
|
if (event === EVENTS.CHANGE) {
|
|
31770
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
31704
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path24, 50);
|
|
31771
31705
|
if (isThrottled)
|
|
31772
31706
|
return this;
|
|
31773
31707
|
}
|
|
31774
31708
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
31775
|
-
const fullPath = opts.cwd ? sysPath2.join(opts.cwd,
|
|
31709
|
+
const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path24) : path24;
|
|
31776
31710
|
let stats2;
|
|
31777
31711
|
try {
|
|
31778
31712
|
stats2 = await stat3(fullPath);
|
|
@@ -31803,23 +31737,23 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31803
31737
|
* @param timeout duration of time to suppress duplicate actions
|
|
31804
31738
|
* @returns tracking object or false if action should be suppressed
|
|
31805
31739
|
*/
|
|
31806
|
-
_throttle(actionType,
|
|
31740
|
+
_throttle(actionType, path24, timeout) {
|
|
31807
31741
|
if (!this._throttled.has(actionType)) {
|
|
31808
31742
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
31809
31743
|
}
|
|
31810
31744
|
const action = this._throttled.get(actionType);
|
|
31811
31745
|
if (!action)
|
|
31812
31746
|
throw new Error("invalid throttle");
|
|
31813
|
-
const actionPath = action.get(
|
|
31747
|
+
const actionPath = action.get(path24);
|
|
31814
31748
|
if (actionPath) {
|
|
31815
31749
|
actionPath.count++;
|
|
31816
31750
|
return false;
|
|
31817
31751
|
}
|
|
31818
31752
|
let timeoutObject;
|
|
31819
31753
|
const clear = () => {
|
|
31820
|
-
const item = action.get(
|
|
31754
|
+
const item = action.get(path24);
|
|
31821
31755
|
const count = item ? item.count : 0;
|
|
31822
|
-
action.delete(
|
|
31756
|
+
action.delete(path24);
|
|
31823
31757
|
clearTimeout(timeoutObject);
|
|
31824
31758
|
if (item)
|
|
31825
31759
|
clearTimeout(item.timeoutObject);
|
|
@@ -31827,7 +31761,7 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31827
31761
|
};
|
|
31828
31762
|
timeoutObject = setTimeout(clear, timeout);
|
|
31829
31763
|
const thr = { timeoutObject, clear, count: 0 };
|
|
31830
|
-
action.set(
|
|
31764
|
+
action.set(path24, thr);
|
|
31831
31765
|
return thr;
|
|
31832
31766
|
}
|
|
31833
31767
|
_incrReadyCount() {
|
|
@@ -31841,44 +31775,44 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31841
31775
|
* @param event
|
|
31842
31776
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
31843
31777
|
*/
|
|
31844
|
-
_awaitWriteFinish(
|
|
31778
|
+
_awaitWriteFinish(path24, threshold, event, awfEmit) {
|
|
31845
31779
|
const awf = this.options.awaitWriteFinish;
|
|
31846
31780
|
if (typeof awf !== "object")
|
|
31847
31781
|
return;
|
|
31848
31782
|
const pollInterval = awf.pollInterval;
|
|
31849
31783
|
let timeoutHandler;
|
|
31850
|
-
let fullPath =
|
|
31851
|
-
if (this.options.cwd && !sysPath2.isAbsolute(
|
|
31852
|
-
fullPath = sysPath2.join(this.options.cwd,
|
|
31784
|
+
let fullPath = path24;
|
|
31785
|
+
if (this.options.cwd && !sysPath2.isAbsolute(path24)) {
|
|
31786
|
+
fullPath = sysPath2.join(this.options.cwd, path24);
|
|
31853
31787
|
}
|
|
31854
31788
|
const now = /* @__PURE__ */ new Date();
|
|
31855
31789
|
const writes = this._pendingWrites;
|
|
31856
31790
|
function awaitWriteFinishFn(prevStat) {
|
|
31857
31791
|
statcb(fullPath, (err, curStat) => {
|
|
31858
|
-
if (err || !writes.has(
|
|
31792
|
+
if (err || !writes.has(path24)) {
|
|
31859
31793
|
if (err && err.code !== "ENOENT")
|
|
31860
31794
|
awfEmit(err);
|
|
31861
31795
|
return;
|
|
31862
31796
|
}
|
|
31863
31797
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
31864
31798
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
31865
|
-
writes.get(
|
|
31799
|
+
writes.get(path24).lastChange = now2;
|
|
31866
31800
|
}
|
|
31867
|
-
const pw = writes.get(
|
|
31801
|
+
const pw = writes.get(path24);
|
|
31868
31802
|
const df = now2 - pw.lastChange;
|
|
31869
31803
|
if (df >= threshold) {
|
|
31870
|
-
writes.delete(
|
|
31804
|
+
writes.delete(path24);
|
|
31871
31805
|
awfEmit(void 0, curStat);
|
|
31872
31806
|
} else {
|
|
31873
31807
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
31874
31808
|
}
|
|
31875
31809
|
});
|
|
31876
31810
|
}
|
|
31877
|
-
if (!writes.has(
|
|
31878
|
-
writes.set(
|
|
31811
|
+
if (!writes.has(path24)) {
|
|
31812
|
+
writes.set(path24, {
|
|
31879
31813
|
lastChange: now,
|
|
31880
31814
|
cancelWait: () => {
|
|
31881
|
-
writes.delete(
|
|
31815
|
+
writes.delete(path24);
|
|
31882
31816
|
clearTimeout(timeoutHandler);
|
|
31883
31817
|
return event;
|
|
31884
31818
|
}
|
|
@@ -31889,8 +31823,8 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31889
31823
|
/**
|
|
31890
31824
|
* Determines whether user has asked to ignore this path.
|
|
31891
31825
|
*/
|
|
31892
|
-
_isIgnored(
|
|
31893
|
-
if (this.options.atomic && DOT_RE.test(
|
|
31826
|
+
_isIgnored(path24, stats) {
|
|
31827
|
+
if (this.options.atomic && DOT_RE.test(path24))
|
|
31894
31828
|
return true;
|
|
31895
31829
|
if (!this._userIgnored) {
|
|
31896
31830
|
const { cwd: cwd3 } = this.options;
|
|
@@ -31900,17 +31834,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31900
31834
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd3)), ...ignored];
|
|
31901
31835
|
this._userIgnored = anymatch(list, void 0);
|
|
31902
31836
|
}
|
|
31903
|
-
return this._userIgnored(
|
|
31837
|
+
return this._userIgnored(path24, stats);
|
|
31904
31838
|
}
|
|
31905
|
-
_isntIgnored(
|
|
31906
|
-
return !this._isIgnored(
|
|
31839
|
+
_isntIgnored(path24, stat4) {
|
|
31840
|
+
return !this._isIgnored(path24, stat4);
|
|
31907
31841
|
}
|
|
31908
31842
|
/**
|
|
31909
31843
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
31910
31844
|
* @param path file or directory pattern being watched
|
|
31911
31845
|
*/
|
|
31912
|
-
_getWatchHelpers(
|
|
31913
|
-
return new WatchHelper(
|
|
31846
|
+
_getWatchHelpers(path24) {
|
|
31847
|
+
return new WatchHelper(path24, this.options.followSymlinks, this);
|
|
31914
31848
|
}
|
|
31915
31849
|
// Directory helpers
|
|
31916
31850
|
// -----------------
|
|
@@ -31942,63 +31876,63 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
31942
31876
|
* @param item base path of item/directory
|
|
31943
31877
|
*/
|
|
31944
31878
|
_remove(directory, item, isDirectory) {
|
|
31945
|
-
const
|
|
31946
|
-
const fullPath = sysPath2.resolve(
|
|
31947
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
31948
|
-
if (!this._throttle("remove",
|
|
31879
|
+
const path24 = sysPath2.join(directory, item);
|
|
31880
|
+
const fullPath = sysPath2.resolve(path24);
|
|
31881
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path24) || this._watched.has(fullPath);
|
|
31882
|
+
if (!this._throttle("remove", path24, 100))
|
|
31949
31883
|
return;
|
|
31950
31884
|
if (!isDirectory && this._watched.size === 1) {
|
|
31951
31885
|
this.add(directory, item, true);
|
|
31952
31886
|
}
|
|
31953
|
-
const wp = this._getWatchedDir(
|
|
31887
|
+
const wp = this._getWatchedDir(path24);
|
|
31954
31888
|
const nestedDirectoryChildren = wp.getChildren();
|
|
31955
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
31889
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path24, nested));
|
|
31956
31890
|
const parent = this._getWatchedDir(directory);
|
|
31957
31891
|
const wasTracked = parent.has(item);
|
|
31958
31892
|
parent.remove(item);
|
|
31959
31893
|
if (this._symlinkPaths.has(fullPath)) {
|
|
31960
31894
|
this._symlinkPaths.delete(fullPath);
|
|
31961
31895
|
}
|
|
31962
|
-
let relPath =
|
|
31896
|
+
let relPath = path24;
|
|
31963
31897
|
if (this.options.cwd)
|
|
31964
|
-
relPath = sysPath2.relative(this.options.cwd,
|
|
31898
|
+
relPath = sysPath2.relative(this.options.cwd, path24);
|
|
31965
31899
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
31966
31900
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
31967
31901
|
if (event === EVENTS.ADD)
|
|
31968
31902
|
return;
|
|
31969
31903
|
}
|
|
31970
|
-
this._watched.delete(
|
|
31904
|
+
this._watched.delete(path24);
|
|
31971
31905
|
this._watched.delete(fullPath);
|
|
31972
31906
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
31973
|
-
if (wasTracked && !this._isIgnored(
|
|
31974
|
-
this._emit(eventName,
|
|
31975
|
-
this._closePath(
|
|
31907
|
+
if (wasTracked && !this._isIgnored(path24))
|
|
31908
|
+
this._emit(eventName, path24);
|
|
31909
|
+
this._closePath(path24);
|
|
31976
31910
|
}
|
|
31977
31911
|
/**
|
|
31978
31912
|
* Closes all watchers for a path
|
|
31979
31913
|
*/
|
|
31980
|
-
_closePath(
|
|
31981
|
-
this._closeFile(
|
|
31982
|
-
const dir = sysPath2.dirname(
|
|
31983
|
-
this._getWatchedDir(dir).remove(sysPath2.basename(
|
|
31914
|
+
_closePath(path24) {
|
|
31915
|
+
this._closeFile(path24);
|
|
31916
|
+
const dir = sysPath2.dirname(path24);
|
|
31917
|
+
this._getWatchedDir(dir).remove(sysPath2.basename(path24));
|
|
31984
31918
|
}
|
|
31985
31919
|
/**
|
|
31986
31920
|
* Closes only file-specific watchers
|
|
31987
31921
|
*/
|
|
31988
|
-
_closeFile(
|
|
31989
|
-
const closers = this._closers.get(
|
|
31922
|
+
_closeFile(path24) {
|
|
31923
|
+
const closers = this._closers.get(path24);
|
|
31990
31924
|
if (!closers)
|
|
31991
31925
|
return;
|
|
31992
31926
|
closers.forEach((closer) => closer());
|
|
31993
|
-
this._closers.delete(
|
|
31927
|
+
this._closers.delete(path24);
|
|
31994
31928
|
}
|
|
31995
|
-
_addPathCloser(
|
|
31929
|
+
_addPathCloser(path24, closer) {
|
|
31996
31930
|
if (!closer)
|
|
31997
31931
|
return;
|
|
31998
|
-
let list = this._closers.get(
|
|
31932
|
+
let list = this._closers.get(path24);
|
|
31999
31933
|
if (!list) {
|
|
32000
31934
|
list = [];
|
|
32001
|
-
this._closers.set(
|
|
31935
|
+
this._closers.set(path24, list);
|
|
32002
31936
|
}
|
|
32003
31937
|
list.push(closer);
|
|
32004
31938
|
}
|
|
@@ -32037,7 +31971,7 @@ function shouldIgnoreRelative(rel) {
|
|
|
32037
31971
|
return false;
|
|
32038
31972
|
}
|
|
32039
31973
|
function startFileIndexWatcher(cwd3 = process.cwd()) {
|
|
32040
|
-
const resolved =
|
|
31974
|
+
const resolved = path21.resolve(cwd3);
|
|
32041
31975
|
let timer = null;
|
|
32042
31976
|
const runRebuild = () => {
|
|
32043
31977
|
try {
|
|
@@ -32058,7 +31992,7 @@ function startFileIndexWatcher(cwd3 = process.cwd()) {
|
|
|
32058
31992
|
ignoreInitial: true,
|
|
32059
31993
|
persistent: true,
|
|
32060
31994
|
ignored: (p) => {
|
|
32061
|
-
const rel =
|
|
31995
|
+
const rel = path21.isAbsolute(p) ? path21.relative(resolved, p).replace(/\\/g, "/") : p.replace(/\\/g, "/");
|
|
32062
31996
|
return shouldIgnoreRelative(rel || ".");
|
|
32063
31997
|
},
|
|
32064
31998
|
awaitWriteFinish: { stabilityThreshold: 250, pollInterval: 100 }
|
|
@@ -32077,9 +32011,1149 @@ function startFileIndexWatcher(cwd3 = process.cwd()) {
|
|
|
32077
32011
|
};
|
|
32078
32012
|
}
|
|
32079
32013
|
|
|
32014
|
+
// src/dev-servers/manager/dev-server-manager.ts
|
|
32015
|
+
import { rm } from "node:fs/promises";
|
|
32016
|
+
|
|
32017
|
+
// src/dev-servers/process/send-server-status.ts
|
|
32018
|
+
function sendDevServerStatus(getWs, serverId, status, options) {
|
|
32019
|
+
const payload = { type: "server_status", serverId, status };
|
|
32020
|
+
if (options?.detail) payload.detail = options.detail;
|
|
32021
|
+
if (options?.tails) {
|
|
32022
|
+
payload.stdoutTail = options.tails.stdout;
|
|
32023
|
+
payload.stderrTail = options.tails.stderr;
|
|
32024
|
+
}
|
|
32025
|
+
setImmediate(() => {
|
|
32026
|
+
const ws = getWs();
|
|
32027
|
+
if (!ws) return;
|
|
32028
|
+
sendWsMessage(ws, payload);
|
|
32029
|
+
});
|
|
32030
|
+
}
|
|
32031
|
+
|
|
32032
|
+
// src/dev-servers/process/terminate-child-process.ts
|
|
32033
|
+
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
32034
|
+
const exited = new Promise((resolve16) => {
|
|
32035
|
+
proc.once("exit", () => resolve16());
|
|
32036
|
+
});
|
|
32037
|
+
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"})\u2026`);
|
|
32038
|
+
try {
|
|
32039
|
+
proc.kill("SIGTERM");
|
|
32040
|
+
} catch {
|
|
32041
|
+
}
|
|
32042
|
+
await Promise.race([exited, new Promise((resolve16) => setTimeout(resolve16, graceMs))]);
|
|
32043
|
+
}
|
|
32044
|
+
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
32045
|
+
log2(`[dev-server] ${shortId} did not exit within ${graceMs}ms; sending SIGKILL (pid=${proc.pid ?? "?"})\u2026`);
|
|
32046
|
+
proc.removeAllListeners();
|
|
32047
|
+
try {
|
|
32048
|
+
proc.kill("SIGKILL");
|
|
32049
|
+
} catch {
|
|
32050
|
+
}
|
|
32051
|
+
}
|
|
32052
|
+
|
|
32053
|
+
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
32054
|
+
import fs16 from "node:fs";
|
|
32055
|
+
|
|
32056
|
+
// src/dev-servers/manager/forward-pipe.ts
|
|
32057
|
+
function forwardChildPipe(childReadable, terminal, onData) {
|
|
32058
|
+
if (!childReadable) return;
|
|
32059
|
+
childReadable.on("data", (chunk) => {
|
|
32060
|
+
onData(chunk);
|
|
32061
|
+
if (!terminal || terminal.writableEnded) return;
|
|
32062
|
+
const ok = terminal.write(chunk);
|
|
32063
|
+
if (!ok) {
|
|
32064
|
+
childReadable.pause();
|
|
32065
|
+
terminal.once("drain", () => {
|
|
32066
|
+
childReadable.resume();
|
|
32067
|
+
});
|
|
32068
|
+
}
|
|
32069
|
+
});
|
|
32070
|
+
}
|
|
32071
|
+
|
|
32072
|
+
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
32073
|
+
function wireDevServerChildProcess(d) {
|
|
32074
|
+
const { proc, serverId, title } = d;
|
|
32075
|
+
forwardChildPipe(proc.stdout, null, (chunk) => {
|
|
32076
|
+
d.stdoutTail.push(chunk);
|
|
32077
|
+
d.pushRemoteLogChunk(serverId, "stdout", chunk);
|
|
32078
|
+
});
|
|
32079
|
+
forwardChildPipe(proc.stderr, null, (chunk) => {
|
|
32080
|
+
d.stderrTail.push(chunk);
|
|
32081
|
+
d.pushRemoteLogChunk(serverId, "stderr", chunk);
|
|
32082
|
+
});
|
|
32083
|
+
if (d.mergedLogPath && d.mergedCleanupDir) {
|
|
32084
|
+
const pollIv = setInterval(() => {
|
|
32085
|
+
if ((d.getSpawnGeneration() ?? 0) !== d.scheduledGen) {
|
|
32086
|
+
clearInterval(pollIv);
|
|
32087
|
+
d.setPollInterval(void 0);
|
|
32088
|
+
return;
|
|
32089
|
+
}
|
|
32090
|
+
fs16.readFile(d.mergedLogPath, (err, buf) => {
|
|
32091
|
+
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
32092
|
+
if (buf.length <= d.mergedReadPos.value) return;
|
|
32093
|
+
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
32094
|
+
d.mergedReadPos.value = buf.length;
|
|
32095
|
+
if (chunk.length === 0) return;
|
|
32096
|
+
d.stdoutTail.push(chunk);
|
|
32097
|
+
d.pushRemoteLogChunk(serverId, "stdout", chunk);
|
|
32098
|
+
});
|
|
32099
|
+
}, 100);
|
|
32100
|
+
d.setPollInterval(pollIv);
|
|
32101
|
+
}
|
|
32102
|
+
proc.on("exit", (code, signal) => {
|
|
32103
|
+
const poll = d.getPollInterval();
|
|
32104
|
+
if (poll) {
|
|
32105
|
+
clearInterval(poll);
|
|
32106
|
+
d.setPollInterval(void 0);
|
|
32107
|
+
}
|
|
32108
|
+
const cleanupDir = d.mergedCleanupDir;
|
|
32109
|
+
const mergedPath = d.mergedLogPath;
|
|
32110
|
+
const finishExit = () => {
|
|
32111
|
+
if (cleanupDir) {
|
|
32112
|
+
d.rmMergedCleanupDir(cleanupDir);
|
|
32113
|
+
}
|
|
32114
|
+
if (signal) {
|
|
32115
|
+
d.log(`[dev-server] ${title} stopped (signal ${String(signal)})`);
|
|
32116
|
+
} else if (code !== null && code !== 0) {
|
|
32117
|
+
const errTail = d.stderrTail.getTail().slice(-3).join("\n");
|
|
32118
|
+
d.log(`[dev-server] ${title} exited with code ${code}${errTail ? `
|
|
32119
|
+
${errTail}` : ""}`);
|
|
32120
|
+
}
|
|
32121
|
+
d.detachProcessFromManager();
|
|
32122
|
+
const tails = { stdout: d.stdoutTail.getTail(), stderr: d.stderrTail.getTail() };
|
|
32123
|
+
d.clearTailBuffers();
|
|
32124
|
+
const detail = signal ? `signal=${String(signal)}` : code != null && code !== 0 ? `exit=${code}` : void 0;
|
|
32125
|
+
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
32126
|
+
};
|
|
32127
|
+
if (mergedPath) {
|
|
32128
|
+
fs16.readFile(mergedPath, (err, buf) => {
|
|
32129
|
+
if (!err && buf.length > d.mergedReadPos.value) {
|
|
32130
|
+
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
32131
|
+
if (chunk.length > 0) {
|
|
32132
|
+
d.stdoutTail.push(chunk);
|
|
32133
|
+
d.pushRemoteLogChunk(serverId, "stdout", chunk);
|
|
32134
|
+
}
|
|
32135
|
+
}
|
|
32136
|
+
finishExit();
|
|
32137
|
+
});
|
|
32138
|
+
} else {
|
|
32139
|
+
finishExit();
|
|
32140
|
+
}
|
|
32141
|
+
});
|
|
32142
|
+
proc.on("error", (err) => {
|
|
32143
|
+
const poll = d.getPollInterval();
|
|
32144
|
+
if (poll) {
|
|
32145
|
+
clearInterval(poll);
|
|
32146
|
+
d.setPollInterval(void 0);
|
|
32147
|
+
}
|
|
32148
|
+
const cleanupDir = d.mergedCleanupDir;
|
|
32149
|
+
if (cleanupDir) {
|
|
32150
|
+
d.rmMergedCleanupDir(cleanupDir);
|
|
32151
|
+
}
|
|
32152
|
+
d.detachProcessFromManager();
|
|
32153
|
+
const tails = { stdout: d.stdoutTail.getTail(), stderr: d.stderrTail.getTail() };
|
|
32154
|
+
d.clearTailBuffers();
|
|
32155
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32156
|
+
const errno = typeof err === "object" && err && "code" in err ? String(err.code) : "";
|
|
32157
|
+
d.log(`[dev-server] ${title} process error: ${msg}${errno ? ` (${errno})` : ""}`);
|
|
32158
|
+
d.sendStatus("error", msg, tails);
|
|
32159
|
+
});
|
|
32160
|
+
}
|
|
32161
|
+
|
|
32162
|
+
// src/dev-servers/manager/dev-server-env.ts
|
|
32163
|
+
function substituteCommand(cmd, env) {
|
|
32164
|
+
return cmd.replace(/\$\{([^}]+)\}/g, (_, key) => env[key] != null ? String(env[key]) : "");
|
|
32165
|
+
}
|
|
32166
|
+
function envForSpawn(base, userEnv, ports) {
|
|
32167
|
+
const userKeys = new Set(
|
|
32168
|
+
userEnv.map((e) => e.name.trim()).filter((name) => Boolean(name))
|
|
32169
|
+
);
|
|
32170
|
+
const out = {};
|
|
32171
|
+
for (const key of Object.keys(base)) {
|
|
32172
|
+
const v = base[key];
|
|
32173
|
+
if (typeof v === "string") {
|
|
32174
|
+
out[key] = v;
|
|
32175
|
+
}
|
|
32176
|
+
}
|
|
32177
|
+
for (const { name, value } of userEnv) {
|
|
32178
|
+
if (name) out[name] = value;
|
|
32179
|
+
}
|
|
32180
|
+
ports.forEach((p, i) => {
|
|
32181
|
+
out[`PORT.${i}`] = String(p);
|
|
32182
|
+
});
|
|
32183
|
+
if (ports.length > 0) {
|
|
32184
|
+
out.PORTS = ports.join(",");
|
|
32185
|
+
}
|
|
32186
|
+
if (!userKeys.has("NO_COLOR")) {
|
|
32187
|
+
delete out.NO_COLOR;
|
|
32188
|
+
}
|
|
32189
|
+
if (out.FORCE_COLOR === void 0) {
|
|
32190
|
+
out.FORCE_COLOR = "1";
|
|
32191
|
+
}
|
|
32192
|
+
if (out.CLICOLOR_FORCE === void 0) {
|
|
32193
|
+
out.CLICOLOR_FORCE = "1";
|
|
32194
|
+
}
|
|
32195
|
+
return out;
|
|
32196
|
+
}
|
|
32197
|
+
|
|
32198
|
+
// src/dev-servers/manager/parse-config.ts
|
|
32199
|
+
function parseDevServerDefs(servers) {
|
|
32200
|
+
const out = [];
|
|
32201
|
+
if (!Array.isArray(servers)) return out;
|
|
32202
|
+
for (const s of servers) {
|
|
32203
|
+
if (!s || typeof s !== "object") continue;
|
|
32204
|
+
const o = s;
|
|
32205
|
+
const serverId = typeof o.serverId === "string" ? o.serverId : "";
|
|
32206
|
+
if (!serverId) continue;
|
|
32207
|
+
const envRaw = o.env;
|
|
32208
|
+
const env = Array.isArray(envRaw) ? envRaw.map((e) => {
|
|
32209
|
+
if (!e || typeof e !== "object") return null;
|
|
32210
|
+
const r = e;
|
|
32211
|
+
return {
|
|
32212
|
+
name: typeof r.name === "string" ? r.name : "",
|
|
32213
|
+
value: typeof r.value === "string" ? r.value : ""
|
|
32214
|
+
};
|
|
32215
|
+
}).filter((e) => e != null && e.name.length > 0) : [];
|
|
32216
|
+
const portsRaw = o.ports;
|
|
32217
|
+
const ports = Array.isArray(portsRaw) ? portsRaw.filter((p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536) : [];
|
|
32218
|
+
out.push({
|
|
32219
|
+
serverId,
|
|
32220
|
+
name: typeof o.name === "string" ? o.name : "",
|
|
32221
|
+
command: typeof o.command === "string" ? o.command : "",
|
|
32222
|
+
env,
|
|
32223
|
+
ports
|
|
32224
|
+
});
|
|
32225
|
+
}
|
|
32226
|
+
return out;
|
|
32227
|
+
}
|
|
32228
|
+
|
|
32229
|
+
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
32230
|
+
import fs17 from "node:fs";
|
|
32231
|
+
function isSpawnEbadf(e) {
|
|
32232
|
+
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
32233
|
+
}
|
|
32234
|
+
function rmDirQuiet(dir) {
|
|
32235
|
+
try {
|
|
32236
|
+
fs17.rmSync(dir, { recursive: true, force: true });
|
|
32237
|
+
} catch {
|
|
32238
|
+
}
|
|
32239
|
+
}
|
|
32240
|
+
var cachedDevNullReadFd;
|
|
32241
|
+
function devNullReadFd() {
|
|
32242
|
+
if (cachedDevNullReadFd === void 0) {
|
|
32243
|
+
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
32244
|
+
cachedDevNullReadFd = fs17.openSync(devPath, "r");
|
|
32245
|
+
}
|
|
32246
|
+
return cachedDevNullReadFd;
|
|
32247
|
+
}
|
|
32248
|
+
function pipedStdoutStderrFor(attemptStdio) {
|
|
32249
|
+
return attemptStdio !== "inherit" && Array.isArray(attemptStdio) && attemptStdio[1] === "pipe" && attemptStdio[2] === "pipe";
|
|
32250
|
+
}
|
|
32251
|
+
|
|
32252
|
+
// src/dev-servers/manager/shell-spawn/try-spawn-piped-via-sh.ts
|
|
32253
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
32254
|
+
function trySpawnPipedViaSh(command, env, cwd3, signal) {
|
|
32255
|
+
const attempts = [
|
|
32256
|
+
{ stdio: [devNullReadFd(), "pipe", "pipe"], endStdin: false },
|
|
32257
|
+
{ stdio: ["ignore", "pipe", "pipe"], endStdin: true },
|
|
32258
|
+
{ stdio: ["pipe", "pipe", "pipe"], endStdin: true }
|
|
32259
|
+
];
|
|
32260
|
+
let lastErr;
|
|
32261
|
+
for (let i = 0; i < attempts.length; i++) {
|
|
32262
|
+
const attempt = attempts[i];
|
|
32263
|
+
const opts = {
|
|
32264
|
+
env,
|
|
32265
|
+
cwd: cwd3,
|
|
32266
|
+
stdio: attempt.stdio,
|
|
32267
|
+
...signal ? { signal } : {}
|
|
32268
|
+
};
|
|
32269
|
+
try {
|
|
32270
|
+
let proc;
|
|
32271
|
+
if (process.platform === "win32") {
|
|
32272
|
+
opts.windowsHide = true;
|
|
32273
|
+
const com = process.env.ComSpec || "cmd.exe";
|
|
32274
|
+
proc = spawn5(com, ["/d", "/s", "/c", command], opts);
|
|
32275
|
+
} else {
|
|
32276
|
+
proc = spawn5("/bin/sh", ["-c", command], opts);
|
|
32277
|
+
}
|
|
32278
|
+
if (attempt.endStdin) {
|
|
32279
|
+
proc.stdin?.end();
|
|
32280
|
+
}
|
|
32281
|
+
return {
|
|
32282
|
+
ok: true,
|
|
32283
|
+
result: { proc, pipedStdoutStderr: pipedStdoutStderrFor(attempt.stdio) }
|
|
32284
|
+
};
|
|
32285
|
+
} catch (e) {
|
|
32286
|
+
lastErr = e;
|
|
32287
|
+
if (!isSpawnEbadf(e)) throw e;
|
|
32288
|
+
if (i < attempts.length - 1) continue;
|
|
32289
|
+
break;
|
|
32290
|
+
}
|
|
32291
|
+
}
|
|
32292
|
+
return { ok: false, lastErr };
|
|
32293
|
+
}
|
|
32294
|
+
|
|
32295
|
+
// src/dev-servers/manager/shell-spawn/try-spawn-shell-true-piped.ts
|
|
32296
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
32297
|
+
function trySpawnShellTruePiped(command, env, cwd3, devNullFd, signal) {
|
|
32298
|
+
try {
|
|
32299
|
+
const opts = {
|
|
32300
|
+
env,
|
|
32301
|
+
cwd: cwd3,
|
|
32302
|
+
stdio: [devNullFd, "pipe", "pipe"],
|
|
32303
|
+
shell: true,
|
|
32304
|
+
...signal ? { signal } : {}
|
|
32305
|
+
};
|
|
32306
|
+
if (process.platform === "win32") {
|
|
32307
|
+
opts.windowsHide = true;
|
|
32308
|
+
}
|
|
32309
|
+
return spawn6(command, opts);
|
|
32310
|
+
} catch (e) {
|
|
32311
|
+
if (isSpawnEbadf(e)) return null;
|
|
32312
|
+
throw e;
|
|
32313
|
+
}
|
|
32314
|
+
}
|
|
32315
|
+
|
|
32316
|
+
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
32317
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
32318
|
+
import fs18 from "node:fs";
|
|
32319
|
+
import { tmpdir } from "node:os";
|
|
32320
|
+
import path22 from "node:path";
|
|
32321
|
+
function trySpawnMergedLogFile(command, env, cwd3, signal) {
|
|
32322
|
+
const tmpRoot = fs18.mkdtempSync(path22.join(tmpdir(), "ba-devsrv-log-"));
|
|
32323
|
+
const logPath = path22.join(tmpRoot, "combined.log");
|
|
32324
|
+
let logFd;
|
|
32325
|
+
try {
|
|
32326
|
+
logFd = fs18.openSync(logPath, "a");
|
|
32327
|
+
} catch {
|
|
32328
|
+
rmDirQuiet(tmpRoot);
|
|
32329
|
+
return null;
|
|
32330
|
+
}
|
|
32331
|
+
const stdio = ["ignore", logFd, logFd];
|
|
32332
|
+
try {
|
|
32333
|
+
let proc;
|
|
32334
|
+
if (process.platform === "win32") {
|
|
32335
|
+
proc = spawn7(process.env.ComSpec || "cmd.exe", ["/d", "/s", "/c", command], {
|
|
32336
|
+
env,
|
|
32337
|
+
cwd: cwd3,
|
|
32338
|
+
stdio,
|
|
32339
|
+
windowsHide: true,
|
|
32340
|
+
...signal ? { signal } : {}
|
|
32341
|
+
});
|
|
32342
|
+
} else {
|
|
32343
|
+
proc = spawn7("/bin/sh", ["-c", command], { env, cwd: cwd3, stdio, ...signal ? { signal } : {} });
|
|
32344
|
+
}
|
|
32345
|
+
fs18.closeSync(logFd);
|
|
32346
|
+
return {
|
|
32347
|
+
proc,
|
|
32348
|
+
pipedStdoutStderr: true,
|
|
32349
|
+
mergedLogPath: logPath,
|
|
32350
|
+
mergedLogCleanupDir: tmpRoot
|
|
32351
|
+
};
|
|
32352
|
+
} catch (e) {
|
|
32353
|
+
try {
|
|
32354
|
+
fs18.closeSync(logFd);
|
|
32355
|
+
} catch {
|
|
32356
|
+
}
|
|
32357
|
+
rmDirQuiet(tmpRoot);
|
|
32358
|
+
if (isSpawnEbadf(e)) return null;
|
|
32359
|
+
throw e;
|
|
32360
|
+
}
|
|
32361
|
+
}
|
|
32362
|
+
|
|
32363
|
+
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
32364
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
32365
|
+
import fs19 from "node:fs";
|
|
32366
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
32367
|
+
import path23 from "node:path";
|
|
32368
|
+
function shSingleQuote(s) {
|
|
32369
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
32370
|
+
}
|
|
32371
|
+
function trySpawnShellScriptLogRedirectUnix(command, env, cwd3, signal) {
|
|
32372
|
+
const tmpRoot = fs19.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
32373
|
+
const logPath = path23.join(tmpRoot, "combined.log");
|
|
32374
|
+
const innerPath = path23.join(tmpRoot, "_cmd.sh");
|
|
32375
|
+
const runnerPath = path23.join(tmpRoot, "_run.sh");
|
|
32376
|
+
try {
|
|
32377
|
+
fs19.writeFileSync(innerPath, `#!/bin/sh
|
|
32378
|
+
${command}
|
|
32379
|
+
`);
|
|
32380
|
+
fs19.writeFileSync(
|
|
32381
|
+
runnerPath,
|
|
32382
|
+
`#!/bin/sh
|
|
32383
|
+
cd ${shSingleQuote(cwd3)}
|
|
32384
|
+
/bin/sh ${shSingleQuote(innerPath)} >>${shSingleQuote(logPath)} 2>&1
|
|
32385
|
+
`
|
|
32386
|
+
);
|
|
32387
|
+
const proc = spawn8("/bin/sh", [runnerPath], {
|
|
32388
|
+
env,
|
|
32389
|
+
cwd: tmpRoot,
|
|
32390
|
+
stdio: "ignore",
|
|
32391
|
+
...signal ? { signal } : {}
|
|
32392
|
+
});
|
|
32393
|
+
return {
|
|
32394
|
+
proc,
|
|
32395
|
+
pipedStdoutStderr: true,
|
|
32396
|
+
mergedLogPath: logPath,
|
|
32397
|
+
mergedLogCleanupDir: tmpRoot
|
|
32398
|
+
};
|
|
32399
|
+
} catch (e) {
|
|
32400
|
+
rmDirQuiet(tmpRoot);
|
|
32401
|
+
if (isSpawnEbadf(e)) return null;
|
|
32402
|
+
throw e;
|
|
32403
|
+
}
|
|
32404
|
+
}
|
|
32405
|
+
function trySpawnShellScriptLogRedirectWin(command, env, cwd3, signal) {
|
|
32406
|
+
const tmpRoot = fs19.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
32407
|
+
const logPath = path23.join(tmpRoot, "combined.log");
|
|
32408
|
+
const runnerPath = path23.join(tmpRoot, "_run.bat");
|
|
32409
|
+
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
32410
|
+
const com = process.env.ComSpec || "cmd.exe";
|
|
32411
|
+
try {
|
|
32412
|
+
fs19.writeFileSync(
|
|
32413
|
+
runnerPath,
|
|
32414
|
+
`@ECHO OFF\r
|
|
32415
|
+
CD /D ${q(cwd3)}\r
|
|
32416
|
+
${command} >> ${q(logPath)} 2>&1\r
|
|
32417
|
+
`
|
|
32418
|
+
);
|
|
32419
|
+
const proc = spawn8(com, ["/d", "/s", "/c", q(runnerPath)], {
|
|
32420
|
+
env,
|
|
32421
|
+
cwd: tmpRoot,
|
|
32422
|
+
stdio: "ignore",
|
|
32423
|
+
windowsHide: true,
|
|
32424
|
+
...signal ? { signal } : {}
|
|
32425
|
+
});
|
|
32426
|
+
return {
|
|
32427
|
+
proc,
|
|
32428
|
+
pipedStdoutStderr: true,
|
|
32429
|
+
mergedLogPath: logPath,
|
|
32430
|
+
mergedLogCleanupDir: tmpRoot
|
|
32431
|
+
};
|
|
32432
|
+
} catch (e) {
|
|
32433
|
+
rmDirQuiet(tmpRoot);
|
|
32434
|
+
if (isSpawnEbadf(e)) return null;
|
|
32435
|
+
throw e;
|
|
32436
|
+
}
|
|
32437
|
+
}
|
|
32438
|
+
|
|
32439
|
+
// src/dev-servers/manager/shell-spawn/try-spawn-inherit.ts
|
|
32440
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
32441
|
+
function trySpawnInheritStdio(command, env, cwd3, signal) {
|
|
32442
|
+
const opts = {
|
|
32443
|
+
env,
|
|
32444
|
+
cwd: cwd3,
|
|
32445
|
+
stdio: "inherit",
|
|
32446
|
+
...signal ? { signal } : {}
|
|
32447
|
+
};
|
|
32448
|
+
let proc;
|
|
32449
|
+
if (process.platform === "win32") {
|
|
32450
|
+
opts.windowsHide = true;
|
|
32451
|
+
const com = process.env.ComSpec || "cmd.exe";
|
|
32452
|
+
proc = spawn9(com, ["/d", "/s", "/c", command], opts);
|
|
32453
|
+
} else {
|
|
32454
|
+
proc = spawn9("/bin/sh", ["-c", command], opts);
|
|
32455
|
+
}
|
|
32456
|
+
return { proc, pipedStdoutStderr: false };
|
|
32457
|
+
}
|
|
32458
|
+
|
|
32459
|
+
// src/dev-servers/manager/shell-spawn/shell-spawn.ts
|
|
32460
|
+
function shellSpawn(command, env, cwd3, options) {
|
|
32461
|
+
const signal = options?.signal;
|
|
32462
|
+
const piped = trySpawnPipedViaSh(command, env, cwd3, signal);
|
|
32463
|
+
if (piped.ok) {
|
|
32464
|
+
return piped.result;
|
|
32465
|
+
}
|
|
32466
|
+
let lastErr = piped.lastErr;
|
|
32467
|
+
const shellTrueProc = trySpawnShellTruePiped(command, env, cwd3, devNullReadFd(), signal);
|
|
32468
|
+
if (shellTrueProc) {
|
|
32469
|
+
return { proc: shellTrueProc, pipedStdoutStderr: true };
|
|
32470
|
+
}
|
|
32471
|
+
const fileCapture = trySpawnMergedLogFile(command, env, cwd3, signal);
|
|
32472
|
+
if (fileCapture) {
|
|
32473
|
+
return fileCapture;
|
|
32474
|
+
}
|
|
32475
|
+
const scriptCapture = process.platform === "win32" ? trySpawnShellScriptLogRedirectWin(command, env, cwd3, signal) : trySpawnShellScriptLogRedirectUnix(command, env, cwd3, signal);
|
|
32476
|
+
if (scriptCapture) {
|
|
32477
|
+
return scriptCapture;
|
|
32478
|
+
}
|
|
32479
|
+
try {
|
|
32480
|
+
return trySpawnInheritStdio(command, env, cwd3, signal);
|
|
32481
|
+
} catch (e) {
|
|
32482
|
+
throw lastErr instanceof Error ? lastErr : e instanceof Error ? e : new Error(String(e));
|
|
32483
|
+
}
|
|
32484
|
+
}
|
|
32485
|
+
|
|
32486
|
+
// src/dev-servers/manager/stream-tail.ts
|
|
32487
|
+
var MAX_TAIL_LINES = 80;
|
|
32488
|
+
var MAX_LINE_CHARS = 8192;
|
|
32489
|
+
var MAX_PENDING_CHARS = 65536;
|
|
32490
|
+
function truncateLine(s) {
|
|
32491
|
+
return s.length > MAX_LINE_CHARS ? `${s.slice(0, MAX_LINE_CHARS)}\u2026` : s;
|
|
32492
|
+
}
|
|
32493
|
+
var StreamTail = class {
|
|
32494
|
+
pending = "";
|
|
32495
|
+
lines = [];
|
|
32496
|
+
push(chunk) {
|
|
32497
|
+
this.pending += chunk.toString("utf8");
|
|
32498
|
+
if (this.pending.length > MAX_PENDING_CHARS) {
|
|
32499
|
+
this.pending = this.pending.slice(-MAX_PENDING_CHARS);
|
|
32500
|
+
}
|
|
32501
|
+
const parts = this.pending.split("\n");
|
|
32502
|
+
this.pending = parts.pop() ?? "";
|
|
32503
|
+
if (this.pending.length > MAX_PENDING_CHARS) {
|
|
32504
|
+
this.pending = this.pending.slice(-MAX_PENDING_CHARS);
|
|
32505
|
+
}
|
|
32506
|
+
for (const line of parts) {
|
|
32507
|
+
this.lines.push(truncateLine(line));
|
|
32508
|
+
if (this.lines.length > MAX_TAIL_LINES) this.lines.shift();
|
|
32509
|
+
}
|
|
32510
|
+
}
|
|
32511
|
+
/** Up to last 80 lines; any incomplete final line (no trailing newline) is included as the last entry. */
|
|
32512
|
+
getTail() {
|
|
32513
|
+
const out = [...this.lines];
|
|
32514
|
+
if (this.pending !== "") {
|
|
32515
|
+
out.push(truncateLine(this.pending));
|
|
32516
|
+
}
|
|
32517
|
+
if (out.length > MAX_TAIL_LINES) return out.slice(-MAX_TAIL_LINES);
|
|
32518
|
+
return out;
|
|
32519
|
+
}
|
|
32520
|
+
};
|
|
32521
|
+
|
|
32522
|
+
// src/dev-servers/manager/dev-server-manager.ts
|
|
32523
|
+
var BRIDGE_SHUTDOWN_GRACE_MS = 8e3;
|
|
32524
|
+
var emptyTails = () => ({ stdout: [], stderr: [] });
|
|
32525
|
+
var DevServerManager = class {
|
|
32526
|
+
defsById = /* @__PURE__ */ new Map();
|
|
32527
|
+
processes = /* @__PURE__ */ new Map();
|
|
32528
|
+
streamTailsByServerId = /* @__PURE__ */ new Map();
|
|
32529
|
+
spawnGenerationByServerId = /* @__PURE__ */ new Map();
|
|
32530
|
+
pipedCaptureByServerId = /* @__PURE__ */ new Map();
|
|
32531
|
+
logViewerRefCountByServerId = /* @__PURE__ */ new Map();
|
|
32532
|
+
firehoseSend = null;
|
|
32533
|
+
mergedLogPollByServerId = /* @__PURE__ */ new Map();
|
|
32534
|
+
mergedLogCleanupDirByServerId = /* @__PURE__ */ new Map();
|
|
32535
|
+
abortControllersByServerId = /* @__PURE__ */ new Map();
|
|
32536
|
+
getWs;
|
|
32537
|
+
log;
|
|
32538
|
+
constructor(options) {
|
|
32539
|
+
this.getWs = options.getWs;
|
|
32540
|
+
this.log = options.log;
|
|
32541
|
+
}
|
|
32542
|
+
attachFirehose(send) {
|
|
32543
|
+
this.firehoseSend = send;
|
|
32544
|
+
}
|
|
32545
|
+
detachFirehose() {
|
|
32546
|
+
this.firehoseSend = null;
|
|
32547
|
+
this.logViewerRefCountByServerId.clear();
|
|
32548
|
+
}
|
|
32549
|
+
handleFirehoseLogViewerOpen(serverId, _viewerId) {
|
|
32550
|
+
const next = (this.logViewerRefCountByServerId.get(serverId) ?? 0) + 1;
|
|
32551
|
+
this.logViewerRefCountByServerId.set(serverId, next);
|
|
32552
|
+
this.sendSnapshotToFirehose(serverId, _viewerId);
|
|
32553
|
+
}
|
|
32554
|
+
handleFirehoseLogViewerClose(serverId, _viewerId) {
|
|
32555
|
+
const n = (this.logViewerRefCountByServerId.get(serverId) ?? 0) - 1;
|
|
32556
|
+
if (n <= 0) this.logViewerRefCountByServerId.delete(serverId);
|
|
32557
|
+
else this.logViewerRefCountByServerId.set(serverId, n);
|
|
32558
|
+
}
|
|
32559
|
+
sendSnapshotToFirehose(serverId, viewerId) {
|
|
32560
|
+
const tails = this.streamTailsByServerId.get(serverId);
|
|
32561
|
+
const payload = {
|
|
32562
|
+
type: "log_snapshot",
|
|
32563
|
+
serverId,
|
|
32564
|
+
viewerId,
|
|
32565
|
+
stdoutTail: tails?.stdout.getTail() ?? [],
|
|
32566
|
+
stderrTail: tails?.stderr.getTail() ?? []
|
|
32567
|
+
};
|
|
32568
|
+
setImmediate(() => {
|
|
32569
|
+
const send = this.firehoseSend;
|
|
32570
|
+
if (!send) return;
|
|
32571
|
+
send(payload);
|
|
32572
|
+
});
|
|
32573
|
+
}
|
|
32574
|
+
pushRemoteLogChunk(serverId, stream, chunk) {
|
|
32575
|
+
if ((this.logViewerRefCountByServerId.get(serverId) ?? 0) <= 0) return;
|
|
32576
|
+
if (!this.pipedCaptureByServerId.get(serverId)) return;
|
|
32577
|
+
const send = this.firehoseSend;
|
|
32578
|
+
if (!send) return;
|
|
32579
|
+
const text = chunk.toString("utf8");
|
|
32580
|
+
setImmediate(() => {
|
|
32581
|
+
if (!this.firehoseSend) return;
|
|
32582
|
+
this.firehoseSend({
|
|
32583
|
+
type: "log_chunk",
|
|
32584
|
+
serverId,
|
|
32585
|
+
stream,
|
|
32586
|
+
text
|
|
32587
|
+
});
|
|
32588
|
+
});
|
|
32589
|
+
}
|
|
32590
|
+
applyConfig(servers) {
|
|
32591
|
+
this.defsById.clear();
|
|
32592
|
+
for (const d of parseDevServerDefs(servers)) {
|
|
32593
|
+
this.defsById.set(d.serverId, d);
|
|
32594
|
+
}
|
|
32595
|
+
}
|
|
32596
|
+
snapshotTails(serverId) {
|
|
32597
|
+
const t = this.streamTailsByServerId.get(serverId);
|
|
32598
|
+
if (!t) return { stdout: [], stderr: [] };
|
|
32599
|
+
return { stdout: t.stdout.getTail(), stderr: t.stderr.getTail() };
|
|
32600
|
+
}
|
|
32601
|
+
clearTails(serverId) {
|
|
32602
|
+
this.streamTailsByServerId.delete(serverId);
|
|
32603
|
+
}
|
|
32604
|
+
sendStatus(serverId, status, detail, tails) {
|
|
32605
|
+
sendDevServerStatus(this.getWs, serverId, status, { detail, tails });
|
|
32606
|
+
}
|
|
32607
|
+
bumpGeneration(serverId) {
|
|
32608
|
+
const nextGen = (this.spawnGenerationByServerId.get(serverId) ?? 0) + 1;
|
|
32609
|
+
this.spawnGenerationByServerId.set(serverId, nextGen);
|
|
32610
|
+
}
|
|
32611
|
+
clearPoll(serverId) {
|
|
32612
|
+
const poll = this.mergedLogPollByServerId.get(serverId);
|
|
32613
|
+
if (poll) {
|
|
32614
|
+
clearInterval(poll);
|
|
32615
|
+
this.mergedLogPollByServerId.delete(serverId);
|
|
32616
|
+
}
|
|
32617
|
+
}
|
|
32618
|
+
abortSpawn(serverId) {
|
|
32619
|
+
this.abortControllersByServerId.get(serverId)?.abort();
|
|
32620
|
+
this.abortControllersByServerId.delete(serverId);
|
|
32621
|
+
}
|
|
32622
|
+
stop(serverId) {
|
|
32623
|
+
const tails = this.snapshotTails(serverId);
|
|
32624
|
+
if (this.processes.has(serverId)) {
|
|
32625
|
+
this.sendStatus(serverId, "stopping", void 0, tails);
|
|
32626
|
+
}
|
|
32627
|
+
this.bumpGeneration(serverId);
|
|
32628
|
+
this.abortSpawn(serverId);
|
|
32629
|
+
this.clearPoll(serverId);
|
|
32630
|
+
const proc = this.processes.get(serverId);
|
|
32631
|
+
if (proc) {
|
|
32632
|
+
proc.removeAllListeners();
|
|
32633
|
+
try {
|
|
32634
|
+
proc.kill("SIGTERM");
|
|
32635
|
+
} catch {
|
|
32636
|
+
}
|
|
32637
|
+
this.processes.delete(serverId);
|
|
32638
|
+
}
|
|
32639
|
+
this.clearTails(serverId);
|
|
32640
|
+
this.pipedCaptureByServerId.delete(serverId);
|
|
32641
|
+
const mergedDir = this.mergedLogCleanupDirByServerId.get(serverId);
|
|
32642
|
+
if (mergedDir) {
|
|
32643
|
+
this.mergedLogCleanupDirByServerId.delete(serverId);
|
|
32644
|
+
void rm(mergedDir, { recursive: true, force: true }).catch(() => {
|
|
32645
|
+
});
|
|
32646
|
+
}
|
|
32647
|
+
this.sendStatus(serverId, "stopped", void 0, tails);
|
|
32648
|
+
}
|
|
32649
|
+
start(serverId) {
|
|
32650
|
+
const def = this.defsById.get(serverId);
|
|
32651
|
+
if (!def) {
|
|
32652
|
+
this.log(`[dev-server] Unknown server id ${serverId.slice(0, 8)}\u2026`);
|
|
32653
|
+
this.sendStatus(serverId, "error", "Unknown server", emptyTails());
|
|
32654
|
+
return;
|
|
32655
|
+
}
|
|
32656
|
+
if (!def.command.trim()) {
|
|
32657
|
+
this.sendStatus(serverId, "idle", "No command configured", emptyTails());
|
|
32658
|
+
return;
|
|
32659
|
+
}
|
|
32660
|
+
this.stop(serverId);
|
|
32661
|
+
this.sendStatus(serverId, "starting", void 0, emptyTails());
|
|
32662
|
+
const ac = new AbortController();
|
|
32663
|
+
this.abortControllersByServerId.set(serverId, ac);
|
|
32664
|
+
const cwd3 = process.cwd();
|
|
32665
|
+
const childEnv = envForSpawn(process.env, def.env, def.ports);
|
|
32666
|
+
const cmd = substituteCommand(def.command.trim(), childEnv);
|
|
32667
|
+
const title = def.name.trim() || serverId.slice(0, 8);
|
|
32668
|
+
this.log(`[dev-server] Starting ${title}: ${cmd.slice(0, 120)}${cmd.length > 120 ? "\u2026" : ""}`);
|
|
32669
|
+
const scheduledGen = this.spawnGenerationByServerId.get(serverId) ?? 0;
|
|
32670
|
+
setImmediate(() => {
|
|
32671
|
+
if ((this.spawnGenerationByServerId.get(serverId) ?? 0) !== scheduledGen) {
|
|
32672
|
+
return;
|
|
32673
|
+
}
|
|
32674
|
+
let proc;
|
|
32675
|
+
let pipedStdoutStderr;
|
|
32676
|
+
let mergedLogPath;
|
|
32677
|
+
let mergedCleanupDir;
|
|
32678
|
+
try {
|
|
32679
|
+
const spawned = shellSpawn(cmd, childEnv, cwd3, {
|
|
32680
|
+
signal: ac.signal
|
|
32681
|
+
});
|
|
32682
|
+
proc = spawned.proc;
|
|
32683
|
+
pipedStdoutStderr = spawned.pipedStdoutStderr;
|
|
32684
|
+
mergedLogPath = spawned.mergedLogPath;
|
|
32685
|
+
mergedCleanupDir = spawned.mergedLogCleanupDir;
|
|
32686
|
+
} catch (e) {
|
|
32687
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
32688
|
+
this.log(`[dev-server] ${title} failed to start: ${msg}`);
|
|
32689
|
+
this.abortControllersByServerId.delete(serverId);
|
|
32690
|
+
this.sendStatus(serverId, "error", msg, emptyTails());
|
|
32691
|
+
return;
|
|
32692
|
+
}
|
|
32693
|
+
if ((this.spawnGenerationByServerId.get(serverId) ?? 0) !== scheduledGen) {
|
|
32694
|
+
try {
|
|
32695
|
+
proc.removeAllListeners();
|
|
32696
|
+
proc.kill("SIGTERM");
|
|
32697
|
+
} catch {
|
|
32698
|
+
}
|
|
32699
|
+
return;
|
|
32700
|
+
}
|
|
32701
|
+
if (!pipedStdoutStderr) {
|
|
32702
|
+
this.log(`[dev-server] ${title} running (inherited stdio; bridge log preview disabled)`);
|
|
32703
|
+
} else if (mergedLogPath && mergedCleanupDir) {
|
|
32704
|
+
this.log(
|
|
32705
|
+
`[dev-server] ${title} running (logs captured via temp file; open the browser log viewer for live output)`
|
|
32706
|
+
);
|
|
32707
|
+
}
|
|
32708
|
+
this.pipedCaptureByServerId.set(serverId, pipedStdoutStderr);
|
|
32709
|
+
const stdoutTail = new StreamTail();
|
|
32710
|
+
const stderrTail = new StreamTail();
|
|
32711
|
+
this.streamTailsByServerId.set(serverId, { stdout: stdoutTail, stderr: stderrTail });
|
|
32712
|
+
if (mergedLogPath && mergedCleanupDir) {
|
|
32713
|
+
this.mergedLogCleanupDirByServerId.set(serverId, mergedCleanupDir);
|
|
32714
|
+
}
|
|
32715
|
+
const mergedReadPos = { value: 0 };
|
|
32716
|
+
this.processes.set(serverId, proc);
|
|
32717
|
+
wireDevServerChildProcess({
|
|
32718
|
+
serverId,
|
|
32719
|
+
title,
|
|
32720
|
+
proc,
|
|
32721
|
+
mergedLogPath,
|
|
32722
|
+
mergedCleanupDir,
|
|
32723
|
+
mergedReadPos,
|
|
32724
|
+
scheduledGen,
|
|
32725
|
+
getSpawnGeneration: () => this.spawnGenerationByServerId.get(serverId) ?? 0,
|
|
32726
|
+
log: this.log,
|
|
32727
|
+
stdoutTail,
|
|
32728
|
+
stderrTail,
|
|
32729
|
+
pushRemoteLogChunk: (sid, stream, chunk) => this.pushRemoteLogChunk(sid, stream, chunk),
|
|
32730
|
+
sendStatus: (status, detail, tails) => this.sendStatus(serverId, status, detail, tails),
|
|
32731
|
+
setPollInterval: (iv) => {
|
|
32732
|
+
if (iv) this.mergedLogPollByServerId.set(serverId, iv);
|
|
32733
|
+
else this.mergedLogPollByServerId.delete(serverId);
|
|
32734
|
+
},
|
|
32735
|
+
getPollInterval: () => this.mergedLogPollByServerId.get(serverId),
|
|
32736
|
+
detachProcessFromManager: () => {
|
|
32737
|
+
this.processes.delete(serverId);
|
|
32738
|
+
this.pipedCaptureByServerId.delete(serverId);
|
|
32739
|
+
this.abortControllersByServerId.delete(serverId);
|
|
32740
|
+
this.mergedLogCleanupDirByServerId.delete(serverId);
|
|
32741
|
+
},
|
|
32742
|
+
rmMergedCleanupDir: (dir) => {
|
|
32743
|
+
void rm(dir, { recursive: true, force: true }).catch(() => {
|
|
32744
|
+
});
|
|
32745
|
+
},
|
|
32746
|
+
clearTailBuffers: () => this.clearTails(serverId)
|
|
32747
|
+
});
|
|
32748
|
+
this.sendStatus(serverId, "running", `pid=${proc.pid ?? "?"}`, {
|
|
32749
|
+
stdout: stdoutTail.getTail(),
|
|
32750
|
+
stderr: stderrTail.getTail()
|
|
32751
|
+
});
|
|
32752
|
+
});
|
|
32753
|
+
}
|
|
32754
|
+
handleControl(serverId, action) {
|
|
32755
|
+
if (action === "stop") {
|
|
32756
|
+
this.stop(serverId);
|
|
32757
|
+
return;
|
|
32758
|
+
}
|
|
32759
|
+
this.start(serverId);
|
|
32760
|
+
}
|
|
32761
|
+
async shutdownAllGraceful() {
|
|
32762
|
+
const pairs = [...this.processes.entries()];
|
|
32763
|
+
if (pairs.length === 0) return;
|
|
32764
|
+
this.log(`[dev-server] Stopping ${pairs.length} dev server process(es) (bridge shutting down)\u2026`);
|
|
32765
|
+
await Promise.all(pairs.map(([serverId, proc]) => this.gracefulTerminateOrUnknown(serverId, proc)));
|
|
32766
|
+
}
|
|
32767
|
+
async gracefulTerminateOrUnknown(serverId, proc) {
|
|
32768
|
+
const shortId = `${serverId.slice(0, 8)}\u2026`;
|
|
32769
|
+
await sigtermAndWaitForExit(proc, BRIDGE_SHUTDOWN_GRACE_MS, this.log, shortId);
|
|
32770
|
+
if (!this.processes.has(serverId) || this.processes.get(serverId) !== proc) {
|
|
32771
|
+
return;
|
|
32772
|
+
}
|
|
32773
|
+
this.bumpGeneration(serverId);
|
|
32774
|
+
forceKillChild(proc, this.log, shortId, BRIDGE_SHUTDOWN_GRACE_MS);
|
|
32775
|
+
this.processes.delete(serverId);
|
|
32776
|
+
this.clearPoll(serverId);
|
|
32777
|
+
this.pipedCaptureByServerId.delete(serverId);
|
|
32778
|
+
const mergedDir = this.mergedLogCleanupDirByServerId.get(serverId);
|
|
32779
|
+
if (mergedDir) {
|
|
32780
|
+
this.mergedLogCleanupDirByServerId.delete(serverId);
|
|
32781
|
+
void rm(mergedDir, { recursive: true, force: true }).catch(() => {
|
|
32782
|
+
});
|
|
32783
|
+
}
|
|
32784
|
+
const tails = this.snapshotTails(serverId);
|
|
32785
|
+
this.clearTails(serverId);
|
|
32786
|
+
this.sendStatus(serverId, "unknown", "Bridge closed before process exited", tails);
|
|
32787
|
+
}
|
|
32788
|
+
};
|
|
32789
|
+
|
|
32790
|
+
// src/firehose/connect-firehose.ts
|
|
32791
|
+
import https2 from "node:https";
|
|
32792
|
+
|
|
32793
|
+
// src/firehose/proxy/start-streaming-proxy.ts
|
|
32794
|
+
function startStreamingProxy(ws, log2, pr) {
|
|
32795
|
+
proxyToLocalStreaming(pr, {
|
|
32796
|
+
onStart: (statusCode, headers) => {
|
|
32797
|
+
const forwardedHeaders = { ...headers };
|
|
32798
|
+
const ce = "content-encoding";
|
|
32799
|
+
const cl = "content-length";
|
|
32800
|
+
const keys = Object.keys(forwardedHeaders).filter(
|
|
32801
|
+
(k) => k.toLowerCase() !== ce && k.toLowerCase() !== cl
|
|
32802
|
+
);
|
|
32803
|
+
const filtered = {};
|
|
32804
|
+
for (const k of keys) if (forwardedHeaders[k] != null) filtered[k] = forwardedHeaders[k];
|
|
32805
|
+
sendWsMessage(ws, { type: "proxy_result_start", id: pr.id, statusCode, headers: filtered });
|
|
32806
|
+
},
|
|
32807
|
+
onChunk: (chunk) => {
|
|
32808
|
+
const idBuf = Buffer.from(pr.id, "utf8");
|
|
32809
|
+
ws.send(Buffer.concat([idBuf, Buffer.from(chunk)]), { binary: true });
|
|
32810
|
+
},
|
|
32811
|
+
onEnd: () => sendWsMessage(ws, { type: "proxy_result_end", id: pr.id }),
|
|
32812
|
+
onError: (error40) => {
|
|
32813
|
+
log2(`[Proxy and log service] streaming preview failed: ${error40}`);
|
|
32814
|
+
sendWsMessage(ws, { type: "proxy_result_error", id: pr.id, error: error40 });
|
|
32815
|
+
}
|
|
32816
|
+
});
|
|
32817
|
+
}
|
|
32818
|
+
|
|
32819
|
+
// src/firehose/build-cli-ws-url.ts
|
|
32820
|
+
function buildFirehoseCliWsUrl(baseUrl) {
|
|
32821
|
+
const base = baseUrl.startsWith("https") ? baseUrl.replace(/^https/, "wss") : baseUrl.replace(/^http/, "ws");
|
|
32822
|
+
return `${base.replace(/\/$/, "")}/ws`;
|
|
32823
|
+
}
|
|
32824
|
+
|
|
32825
|
+
// src/firehose/routing/firehose-message-router.ts
|
|
32826
|
+
function createFirehoseMessageRouter() {
|
|
32827
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
32828
|
+
return {
|
|
32829
|
+
register(type, handler) {
|
|
32830
|
+
handlers.set(type, handler);
|
|
32831
|
+
},
|
|
32832
|
+
dispatch(msg, deps) {
|
|
32833
|
+
const type = msg.type;
|
|
32834
|
+
if (!type) return;
|
|
32835
|
+
const handler = handlers.get(type);
|
|
32836
|
+
if (handler) handler(msg, deps);
|
|
32837
|
+
}
|
|
32838
|
+
};
|
|
32839
|
+
}
|
|
32840
|
+
|
|
32841
|
+
// src/firehose/routing/handlers/dev-server-logs-viewer-open.ts
|
|
32842
|
+
var handleDevServerLogsViewerOpen = (msg, deps) => {
|
|
32843
|
+
const serverId = typeof msg.serverId === "string" ? msg.serverId : "";
|
|
32844
|
+
const viewerId = typeof msg.viewerId === "string" ? msg.viewerId : "";
|
|
32845
|
+
if (!serverId || !viewerId) return;
|
|
32846
|
+
deps.devServerManager.handleFirehoseLogViewerOpen(serverId, viewerId);
|
|
32847
|
+
};
|
|
32848
|
+
|
|
32849
|
+
// src/firehose/routing/handlers/dev-server-logs-viewer-close.ts
|
|
32850
|
+
var handleDevServerLogsViewerClose = (msg, deps) => {
|
|
32851
|
+
const serverId = typeof msg.serverId === "string" ? msg.serverId : "";
|
|
32852
|
+
const viewerId = typeof msg.viewerId === "string" ? msg.viewerId : "";
|
|
32853
|
+
if (!serverId || !viewerId) return;
|
|
32854
|
+
deps.devServerManager.handleFirehoseLogViewerClose(serverId, viewerId);
|
|
32855
|
+
};
|
|
32856
|
+
|
|
32857
|
+
// src/firehose/routing/handlers/proxy-message.ts
|
|
32858
|
+
var handleProxyMessage = (msg, deps) => {
|
|
32859
|
+
const proxy = msg.proxy;
|
|
32860
|
+
if (!proxy || typeof proxy !== "object") return;
|
|
32861
|
+
const pr = proxy;
|
|
32862
|
+
if (pr.streamResponse) {
|
|
32863
|
+
const bodyLength = pr.bodyLength ?? 0;
|
|
32864
|
+
if (bodyLength > 0) {
|
|
32865
|
+
deps.pendingProxyBody.set(pr.id, {
|
|
32866
|
+
pr: {
|
|
32867
|
+
id: pr.id,
|
|
32868
|
+
method: pr.method,
|
|
32869
|
+
url: pr.url,
|
|
32870
|
+
headers: pr.headers,
|
|
32871
|
+
streamResponse: true
|
|
32872
|
+
}
|
|
32873
|
+
});
|
|
32874
|
+
} else {
|
|
32875
|
+
deps.startStreamingProxy({
|
|
32876
|
+
id: pr.id,
|
|
32877
|
+
method: pr.method,
|
|
32878
|
+
url: pr.url,
|
|
32879
|
+
headers: pr.headers,
|
|
32880
|
+
streamResponse: true
|
|
32881
|
+
});
|
|
32882
|
+
}
|
|
32883
|
+
return;
|
|
32884
|
+
}
|
|
32885
|
+
void proxyToLocal(pr).then((res) => {
|
|
32886
|
+
if (res.error) deps.log(`[Proxy and log service] preview proxy failed: ${res.error}`);
|
|
32887
|
+
sendWsMessage(deps.ws, { type: "proxy_result", ...res, id: pr.id });
|
|
32888
|
+
}).catch((err) => {
|
|
32889
|
+
deps.log(
|
|
32890
|
+
`[Proxy and log service] preview proxy failed: ${err instanceof Error ? err.message : String(err)}`
|
|
32891
|
+
);
|
|
32892
|
+
sendWsMessage(deps.ws, { type: "proxy_result", id: pr.id, error: String(err) });
|
|
32893
|
+
});
|
|
32894
|
+
};
|
|
32895
|
+
|
|
32896
|
+
// src/firehose/routing/handlers/identified.ts
|
|
32897
|
+
var handleFirehoseIdentified = (_msg, _deps) => {
|
|
32898
|
+
};
|
|
32899
|
+
|
|
32900
|
+
// src/firehose/routing/dispatch-firehose-message.ts
|
|
32901
|
+
var router = createFirehoseMessageRouter();
|
|
32902
|
+
router.register("identified", handleFirehoseIdentified);
|
|
32903
|
+
router.register("log_viewer_open", handleDevServerLogsViewerOpen);
|
|
32904
|
+
router.register("log_viewer_close", handleDevServerLogsViewerClose);
|
|
32905
|
+
router.register("proxy", handleProxyMessage);
|
|
32906
|
+
function dispatchFirehoseJsonMessage(msg, deps) {
|
|
32907
|
+
router.dispatch(msg, deps);
|
|
32908
|
+
}
|
|
32909
|
+
|
|
32910
|
+
// src/firehose/routing/try-consume-binary-proxy-body.ts
|
|
32911
|
+
var PROXY_ID_BYTES = 36;
|
|
32912
|
+
function tryConsumeBinaryProxyBody(raw, deps) {
|
|
32913
|
+
if (raw.length < PROXY_ID_BYTES) return false;
|
|
32914
|
+
const id = raw.slice(0, PROXY_ID_BYTES).toString("utf8");
|
|
32915
|
+
const pending = deps.pendingProxyBody.get(id);
|
|
32916
|
+
if (!pending) return false;
|
|
32917
|
+
deps.pendingProxyBody.delete(id);
|
|
32918
|
+
const body = raw.slice(PROXY_ID_BYTES);
|
|
32919
|
+
deps.startStreamingProxy({
|
|
32920
|
+
...pending.pr,
|
|
32921
|
+
body: body.length > 0 ? new Uint8Array(body) : void 0
|
|
32922
|
+
});
|
|
32923
|
+
return true;
|
|
32924
|
+
}
|
|
32925
|
+
|
|
32926
|
+
// src/firehose/connect-firehose.ts
|
|
32927
|
+
function connectFirehose(options) {
|
|
32928
|
+
const { firehoseServerUrl, workspaceId, bridgeName, proxyPorts, log: log2, devServerManager, onOpen, onClose } = options;
|
|
32929
|
+
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
32930
|
+
const wsOptions = { perMessageDeflate: false };
|
|
32931
|
+
if (wsUrl.startsWith("wss://")) {
|
|
32932
|
+
wsOptions.agent = new https2.Agent({ rejectUnauthorized: false });
|
|
32933
|
+
}
|
|
32934
|
+
const ws = new wrapper_default(wsUrl, wsOptions);
|
|
32935
|
+
const firehoseSend = (payload) => {
|
|
32936
|
+
sendWsMessage(ws, payload);
|
|
32937
|
+
};
|
|
32938
|
+
const pendingProxyBody = /* @__PURE__ */ new Map();
|
|
32939
|
+
const deps = {
|
|
32940
|
+
ws,
|
|
32941
|
+
log: log2,
|
|
32942
|
+
devServerManager,
|
|
32943
|
+
pendingProxyBody,
|
|
32944
|
+
startStreamingProxy: (pr) => startStreamingProxy(ws, log2, pr)
|
|
32945
|
+
};
|
|
32946
|
+
ws.on("open", () => {
|
|
32947
|
+
onOpen?.();
|
|
32948
|
+
devServerManager.attachFirehose(firehoseSend);
|
|
32949
|
+
sendWsMessage(ws, { type: "identify", workspaceId, bridgeName, proxyPorts });
|
|
32950
|
+
});
|
|
32951
|
+
ws.on("message", (raw) => {
|
|
32952
|
+
setImmediate(() => {
|
|
32953
|
+
if (Buffer.isBuffer(raw) && tryConsumeBinaryProxyBody(raw, deps)) {
|
|
32954
|
+
return;
|
|
32955
|
+
}
|
|
32956
|
+
try {
|
|
32957
|
+
const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
|
|
32958
|
+
dispatchFirehoseJsonMessage(JSON.parse(text), deps);
|
|
32959
|
+
} catch {
|
|
32960
|
+
}
|
|
32961
|
+
});
|
|
32962
|
+
});
|
|
32963
|
+
ws.on("close", (code, reason) => {
|
|
32964
|
+
devServerManager.detachFirehose();
|
|
32965
|
+
log2(
|
|
32966
|
+
formatWebSocketClose(
|
|
32967
|
+
"[Proxy and log service]",
|
|
32968
|
+
code,
|
|
32969
|
+
typeof reason === "string" ? reason : reason.toString(),
|
|
32970
|
+
"reconnects automatically if the bridge service stays connected"
|
|
32971
|
+
)
|
|
32972
|
+
);
|
|
32973
|
+
onClose?.();
|
|
32974
|
+
});
|
|
32975
|
+
ws.on("error", (err) => {
|
|
32976
|
+
log2(`[Proxy and log service] WebSocket error: ${err.message}`);
|
|
32977
|
+
});
|
|
32978
|
+
return {
|
|
32979
|
+
close() {
|
|
32980
|
+
devServerManager.detachFirehose();
|
|
32981
|
+
try {
|
|
32982
|
+
ws.removeAllListeners();
|
|
32983
|
+
ws.close();
|
|
32984
|
+
} catch {
|
|
32985
|
+
}
|
|
32986
|
+
}
|
|
32987
|
+
};
|
|
32988
|
+
}
|
|
32989
|
+
|
|
32990
|
+
// src/bridge/connection/create-bridge-identified-handler.ts
|
|
32991
|
+
var FH_RECONNECT_BASE_MS = 2e3;
|
|
32992
|
+
var FH_RECONNECT_MAX_MS = 3e4;
|
|
32993
|
+
function createOnBridgeIdentified(opts) {
|
|
32994
|
+
const { sessionWorktreeManager, devServerManager, firehoseServerUrl, workspaceId, state, logFn } = opts;
|
|
32995
|
+
function clearFirehoseReconnectTimer() {
|
|
32996
|
+
if (state.firehoseReconnectTimeout != null) {
|
|
32997
|
+
clearTimeout(state.firehoseReconnectTimeout);
|
|
32998
|
+
state.firehoseReconnectTimeout = null;
|
|
32999
|
+
}
|
|
33000
|
+
}
|
|
33001
|
+
function attachFirehose(params) {
|
|
33002
|
+
state.lastFirehoseParams = params;
|
|
33003
|
+
clearFirehoseReconnectTimer();
|
|
33004
|
+
state.firehoseGeneration += 1;
|
|
33005
|
+
const myGen = state.firehoseGeneration;
|
|
33006
|
+
if (state.firehoseHandle) {
|
|
33007
|
+
state.firehoseHandle.close();
|
|
33008
|
+
state.firehoseHandle = null;
|
|
33009
|
+
}
|
|
33010
|
+
state.firehoseHandle = connectFirehose({
|
|
33011
|
+
firehoseServerUrl: params.firehoseServerUrl,
|
|
33012
|
+
workspaceId: params.workspaceId,
|
|
33013
|
+
bridgeName: params.bridgeName,
|
|
33014
|
+
proxyPorts: params.proxyPorts,
|
|
33015
|
+
log: logFn,
|
|
33016
|
+
devServerManager,
|
|
33017
|
+
onOpen: () => {
|
|
33018
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
33019
|
+
state.firehoseReconnectAttempt = 0;
|
|
33020
|
+
},
|
|
33021
|
+
onClose: () => {
|
|
33022
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
33023
|
+
state.firehoseHandle = null;
|
|
33024
|
+
if (state.closedByUser) return;
|
|
33025
|
+
const main = state.currentWs;
|
|
33026
|
+
if (!main || main.readyState !== wrapper_default.OPEN) {
|
|
33027
|
+
logFn("[Proxy and log service] not reconnecting: bridge service socket is not open");
|
|
33028
|
+
return;
|
|
33029
|
+
}
|
|
33030
|
+
clearFirehoseReconnectTimer();
|
|
33031
|
+
const delay2 = Math.min(
|
|
33032
|
+
FH_RECONNECT_BASE_MS * 2 ** state.firehoseReconnectAttempt,
|
|
33033
|
+
FH_RECONNECT_MAX_MS
|
|
33034
|
+
);
|
|
33035
|
+
state.firehoseReconnectAttempt += 1;
|
|
33036
|
+
logFn(
|
|
33037
|
+
`[Proxy and log service] reconnect attempt ${state.firehoseReconnectAttempt} in ${delay2 / 1e3}s\u2026`
|
|
33038
|
+
);
|
|
33039
|
+
state.firehoseReconnectTimeout = setTimeout(() => {
|
|
33040
|
+
state.firehoseReconnectTimeout = null;
|
|
33041
|
+
if (state.closedByUser) return;
|
|
33042
|
+
const w = state.currentWs;
|
|
33043
|
+
if (!w || w.readyState !== wrapper_default.OPEN) {
|
|
33044
|
+
logFn("[Proxy and log service] reconnect skipped: bridge service socket closed");
|
|
33045
|
+
return;
|
|
33046
|
+
}
|
|
33047
|
+
const p = state.lastFirehoseParams;
|
|
33048
|
+
if (!p) {
|
|
33049
|
+
logFn("[Proxy and log service] reconnect skipped: no stored connection params");
|
|
33050
|
+
return;
|
|
33051
|
+
}
|
|
33052
|
+
attachFirehose(p);
|
|
33053
|
+
}, delay2);
|
|
33054
|
+
}
|
|
33055
|
+
});
|
|
33056
|
+
}
|
|
33057
|
+
return (msg) => {
|
|
33058
|
+
sessionWorktreeManager.setBridgeSessionWorktrees(msg.sessionWorktreesEnabled === true);
|
|
33059
|
+
const bridgeName = msg.bridgeName;
|
|
33060
|
+
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts : [];
|
|
33061
|
+
const devServers = msg.devServers ?? [];
|
|
33062
|
+
setImmediate(() => {
|
|
33063
|
+
devServerManager.applyConfig(devServers);
|
|
33064
|
+
if (!firehoseServerUrl || typeof bridgeName !== "string" || !bridgeName) return;
|
|
33065
|
+
state.firehoseReconnectAttempt = 0;
|
|
33066
|
+
attachFirehose({
|
|
33067
|
+
firehoseServerUrl,
|
|
33068
|
+
workspaceId,
|
|
33069
|
+
bridgeName,
|
|
33070
|
+
proxyPorts
|
|
33071
|
+
});
|
|
33072
|
+
});
|
|
33073
|
+
};
|
|
33074
|
+
}
|
|
33075
|
+
|
|
33076
|
+
// src/dev-servers/detect-local-agent-types.ts
|
|
33077
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
33078
|
+
import { promisify as promisify4 } from "node:util";
|
|
33079
|
+
var execFileAsync4 = promisify4(execFile4);
|
|
33080
|
+
var CHECKS = {
|
|
33081
|
+
"cursor-cli": async () => {
|
|
33082
|
+
try {
|
|
33083
|
+
await execFileAsync4("which", ["agent"], { timeout: 4e3 });
|
|
33084
|
+
return true;
|
|
33085
|
+
} catch {
|
|
33086
|
+
return false;
|
|
33087
|
+
}
|
|
33088
|
+
},
|
|
33089
|
+
"codex-acp": async () => {
|
|
33090
|
+
try {
|
|
33091
|
+
await execFileAsync4("which", ["codex"], { timeout: 4e3 });
|
|
33092
|
+
return true;
|
|
33093
|
+
} catch {
|
|
33094
|
+
return false;
|
|
33095
|
+
}
|
|
33096
|
+
},
|
|
33097
|
+
"claude-code": async () => {
|
|
33098
|
+
try {
|
|
33099
|
+
await execFileAsync4("which", ["claude"], { timeout: 4e3 });
|
|
33100
|
+
return true;
|
|
33101
|
+
} catch {
|
|
33102
|
+
try {
|
|
33103
|
+
await execFileAsync4("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
|
|
33104
|
+
return true;
|
|
33105
|
+
} catch {
|
|
33106
|
+
return false;
|
|
33107
|
+
}
|
|
33108
|
+
}
|
|
33109
|
+
}
|
|
33110
|
+
};
|
|
33111
|
+
async function detectLocalAgentTypes() {
|
|
33112
|
+
try {
|
|
33113
|
+
const out = [];
|
|
33114
|
+
for (const [type, check2] of Object.entries(CHECKS)) {
|
|
33115
|
+
try {
|
|
33116
|
+
if (await check2()) out.push(type);
|
|
33117
|
+
} catch {
|
|
33118
|
+
}
|
|
33119
|
+
}
|
|
33120
|
+
return out;
|
|
33121
|
+
} catch {
|
|
33122
|
+
return [];
|
|
33123
|
+
}
|
|
33124
|
+
}
|
|
33125
|
+
|
|
33126
|
+
// src/bridge/connection/create-bridge-local-reports.ts
|
|
33127
|
+
function createSendLocalSkillsReport(getWs, logFn) {
|
|
33128
|
+
return () => {
|
|
33129
|
+
try {
|
|
33130
|
+
const socket = getWs();
|
|
33131
|
+
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
33132
|
+
const skills2 = discoverLocalSkills(process.cwd());
|
|
33133
|
+
socket.send(JSON.stringify({ type: "local_skills", skills: skills2 }));
|
|
33134
|
+
} catch (e) {
|
|
33135
|
+
logFn(`[Bridge service] local_skills report failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
33136
|
+
}
|
|
33137
|
+
};
|
|
33138
|
+
}
|
|
33139
|
+
function createReportAutoDetectedAgents(getWs, logFn) {
|
|
33140
|
+
return async () => {
|
|
33141
|
+
try {
|
|
33142
|
+
const types = await detectLocalAgentTypes();
|
|
33143
|
+
const socket = getWs();
|
|
33144
|
+
if (socket && socket.readyState === wrapper_default.OPEN) {
|
|
33145
|
+
sendWsMessage(socket, { type: "auto_detected_agents_report", agentTypes: types });
|
|
33146
|
+
}
|
|
33147
|
+
} catch (e) {
|
|
33148
|
+
logFn(`[Bridge service] auto_detected_agents report failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
33149
|
+
}
|
|
33150
|
+
};
|
|
33151
|
+
}
|
|
33152
|
+
|
|
32080
33153
|
// src/bridge/connection/create-bridge-connection.ts
|
|
32081
33154
|
async function createBridgeConnection(options) {
|
|
32082
|
-
const { apiUrl, workspaceId,
|
|
33155
|
+
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
33156
|
+
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
32083
33157
|
const logFn = options.log ?? log;
|
|
32084
33158
|
let accessToken = options.authToken;
|
|
32085
33159
|
let refreshTok = options.refreshToken;
|
|
@@ -32089,25 +33163,37 @@ async function createBridgeConnection(options) {
|
|
|
32089
33163
|
reconnectAttempt: 0,
|
|
32090
33164
|
reconnectTimeout: null,
|
|
32091
33165
|
currentWs: null,
|
|
32092
|
-
|
|
33166
|
+
firehoseHandle: null,
|
|
33167
|
+
lastFirehoseParams: null,
|
|
33168
|
+
firehoseReconnectTimeout: null,
|
|
33169
|
+
firehoseReconnectAttempt: 0,
|
|
33170
|
+
firehoseGeneration: 0
|
|
32093
33171
|
};
|
|
32094
33172
|
const worktreesRootAbs = options.worktreesRootAbs ?? defaultWorktreesRootAbs();
|
|
32095
33173
|
const sessionWorktreeManager = new SessionWorktreeManager({
|
|
32096
33174
|
worktreesRootAbs,
|
|
32097
33175
|
log: logFn
|
|
32098
33176
|
});
|
|
32099
|
-
const acpManager = await createAcpManager({
|
|
32100
|
-
|
|
32101
|
-
logFn(`Skills: ${skills2.map((s) => s.id).join(", ")}`);
|
|
32102
|
-
logFn("Connected to backend. Press Ctrl+C to exit.");
|
|
33177
|
+
const acpManager = await createAcpManager({ log: logFn });
|
|
33178
|
+
logFn("CLI running. Press Ctrl+C to exit.");
|
|
32103
33179
|
function getWs() {
|
|
32104
33180
|
return state.currentWs;
|
|
32105
33181
|
}
|
|
33182
|
+
const devServerManager = new DevServerManager({ getWs, log: logFn });
|
|
33183
|
+
const onBridgeIdentified = createOnBridgeIdentified({
|
|
33184
|
+
sessionWorktreeManager,
|
|
33185
|
+
devServerManager,
|
|
33186
|
+
firehoseServerUrl,
|
|
33187
|
+
workspaceId,
|
|
33188
|
+
state,
|
|
33189
|
+
logFn
|
|
33190
|
+
});
|
|
33191
|
+
const sendLocalSkillsReport = createSendLocalSkillsReport(getWs, logFn);
|
|
33192
|
+
const reportAutoDetectedAgents = createReportAutoDetectedAgents(getWs, logFn);
|
|
32106
33193
|
function handleOpen() {
|
|
32107
33194
|
state.reconnectAttempt = 0;
|
|
32108
33195
|
const socket = getWs();
|
|
32109
33196
|
if (socket) {
|
|
32110
|
-
logFn("WebSocket connected");
|
|
32111
33197
|
sendWsMessage(socket, { type: "identify", role: "cli" });
|
|
32112
33198
|
reportGitRepos(getWs, logFn);
|
|
32113
33199
|
}
|
|
@@ -32121,49 +33207,23 @@ async function createBridgeConnection(options) {
|
|
|
32121
33207
|
const was = state.currentWs;
|
|
32122
33208
|
state.currentWs = null;
|
|
32123
33209
|
if (was) was.removeAllListeners();
|
|
32124
|
-
|
|
32125
|
-
|
|
33210
|
+
const willReconnect = !state.closedByUser;
|
|
33211
|
+
logFn(
|
|
33212
|
+
formatWebSocketClose("[Bridge service]", code, reason, willReconnect ? "will schedule reconnect" : "not reconnecting (CLI shutting down)")
|
|
33213
|
+
);
|
|
33214
|
+
if (willReconnect) {
|
|
32126
33215
|
scheduleReconnect(state, connect, logFn);
|
|
32127
33216
|
}
|
|
32128
33217
|
}
|
|
32129
|
-
function onBridgeIdentified(msg) {
|
|
32130
|
-
sessionWorktreeManager.setBridgeSessionWorktrees(msg.sessionWorktreesEnabled === true);
|
|
32131
|
-
const bridgeName = msg.bridgeName;
|
|
32132
|
-
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts : [];
|
|
32133
|
-
if (proxyServerUrl && bridgeName) {
|
|
32134
|
-
logFn(`Proxy: setting up connection (server=${proxyServerUrl}, bridge=${bridgeName}, ports=[${proxyPorts.join(", ")}])`);
|
|
32135
|
-
if (state.proxyHandle) {
|
|
32136
|
-
state.proxyHandle.close();
|
|
32137
|
-
state.proxyHandle = null;
|
|
32138
|
-
}
|
|
32139
|
-
state.proxyHandle = connectProxy({
|
|
32140
|
-
proxyServerUrl,
|
|
32141
|
-
workspaceId,
|
|
32142
|
-
bridgeName,
|
|
32143
|
-
proxyPorts,
|
|
32144
|
-
log: logFn,
|
|
32145
|
-
onClose: () => {
|
|
32146
|
-
if (state.proxyHandle) state.proxyHandle = null;
|
|
32147
|
-
}
|
|
32148
|
-
});
|
|
32149
|
-
}
|
|
32150
|
-
}
|
|
32151
|
-
function sendLocalSkillsReport() {
|
|
32152
|
-
const socket = getWs();
|
|
32153
|
-
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
32154
|
-
const skills3 = discoverLocalSkills(process.cwd());
|
|
32155
|
-
socket.send(JSON.stringify({ type: "local_skills", skills: skills3 }));
|
|
32156
|
-
if (skills3.length > 0) {
|
|
32157
|
-
logFn(`Local agent skills (cwd): ${skills3.map((s) => s.path).join(", ")}`);
|
|
32158
|
-
}
|
|
32159
|
-
}
|
|
32160
33218
|
const messageDeps = {
|
|
32161
33219
|
getWs,
|
|
32162
33220
|
log: logFn,
|
|
32163
33221
|
acpManager,
|
|
32164
33222
|
sessionWorktreeManager,
|
|
32165
33223
|
onBridgeIdentified,
|
|
32166
|
-
sendLocalSkillsReport
|
|
33224
|
+
sendLocalSkillsReport,
|
|
33225
|
+
reportAutoDetectedAgents,
|
|
33226
|
+
devServerManager
|
|
32167
33227
|
};
|
|
32168
33228
|
function connect() {
|
|
32169
33229
|
if (state.closedByUser) return;
|
|
@@ -32177,7 +33237,6 @@ async function createBridgeConnection(options) {
|
|
|
32177
33237
|
state.currentWs = null;
|
|
32178
33238
|
}
|
|
32179
33239
|
const url2 = buildBridgeUrl(apiUrl, workspaceId, accessToken);
|
|
32180
|
-
logFn(`Connecting to backend at ${apiUrl}`);
|
|
32181
33240
|
state.currentWs = createWsBridge({
|
|
32182
33241
|
url: url2,
|
|
32183
33242
|
onAuthInvalid: () => {
|
|
@@ -32191,7 +33250,7 @@ async function createBridgeConnection(options) {
|
|
|
32191
33250
|
accessToken = next.token;
|
|
32192
33251
|
refreshTok = next.refreshToken;
|
|
32193
33252
|
persistTokens?.({ token: accessToken, refreshToken: refreshTok });
|
|
32194
|
-
logFn("Bridge access token refreshed; reconnecting\u2026");
|
|
33253
|
+
logFn("[Bridge service] access token refreshed; reconnecting\u2026");
|
|
32195
33254
|
state.reconnectAttempt = 0;
|
|
32196
33255
|
authRefreshInFlight = false;
|
|
32197
33256
|
connect();
|
|
@@ -32210,23 +33269,24 @@ async function createBridgeConnection(options) {
|
|
|
32210
33269
|
},
|
|
32211
33270
|
onOpen: handleOpen,
|
|
32212
33271
|
onClose: handleClose,
|
|
32213
|
-
onError: (err) => logFn(`WebSocket error: ${err.message}`),
|
|
33272
|
+
onError: (err) => logFn(`[Bridge service] WebSocket error: ${err.message}`),
|
|
32214
33273
|
onMessage: (data) => handleBridgeMessage(data, messageDeps)
|
|
32215
33274
|
});
|
|
32216
33275
|
}
|
|
32217
33276
|
connect();
|
|
32218
33277
|
const stopFileIndexWatcher = startFileIndexWatcher(process.cwd());
|
|
32219
33278
|
return {
|
|
32220
|
-
close: () => {
|
|
33279
|
+
close: async () => {
|
|
32221
33280
|
stopFileIndexWatcher();
|
|
32222
|
-
closeBridgeConnection(state, acpManager);
|
|
33281
|
+
await closeBridgeConnection(state, acpManager, devServerManager, logFn);
|
|
32223
33282
|
}
|
|
32224
33283
|
};
|
|
32225
33284
|
}
|
|
32226
33285
|
|
|
32227
33286
|
// src/run-bridge.ts
|
|
32228
33287
|
async function runBridge(options) {
|
|
32229
|
-
const { apiUrl, workspaceId, authToken, refreshToken,
|
|
33288
|
+
const { apiUrl, workspaceId, authToken, refreshToken, bridgeName, justAuthenticated, worktreesRootAbs } = options;
|
|
33289
|
+
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
32230
33290
|
const hasAuth = workspaceId && authToken;
|
|
32231
33291
|
if (!hasAuth) {
|
|
32232
33292
|
const handle2 = runPendingAuth({
|
|
@@ -32237,15 +33297,20 @@ async function runBridge(options) {
|
|
|
32237
33297
|
onAuth: (_auth) => {
|
|
32238
33298
|
}
|
|
32239
33299
|
});
|
|
32240
|
-
const onSignal2 = () => {
|
|
32241
|
-
|
|
32242
|
-
|
|
33300
|
+
const onSignal2 = (signal) => {
|
|
33301
|
+
logImmediate(`Received ${signal}; shutting down\u2026`);
|
|
33302
|
+
setImmediate(() => {
|
|
33303
|
+
handle2.close();
|
|
33304
|
+
process.exit(0);
|
|
33305
|
+
});
|
|
32243
33306
|
};
|
|
32244
|
-
|
|
32245
|
-
|
|
33307
|
+
const onSigInt2 = () => onSignal2("SIGINT");
|
|
33308
|
+
const onSigTerm2 = () => onSignal2("SIGTERM");
|
|
33309
|
+
process.on("SIGINT", onSigInt2);
|
|
33310
|
+
process.on("SIGTERM", onSigTerm2);
|
|
32246
33311
|
const auth = await handle2.authPromise;
|
|
32247
|
-
process.off("SIGINT",
|
|
32248
|
-
process.off("SIGTERM",
|
|
33312
|
+
process.off("SIGINT", onSigInt2);
|
|
33313
|
+
process.off("SIGTERM", onSigTerm2);
|
|
32249
33314
|
handle2.close();
|
|
32250
33315
|
if (!auth) return;
|
|
32251
33316
|
writeConfigForApi(apiUrl, {
|
|
@@ -32258,8 +33323,7 @@ async function runBridge(options) {
|
|
|
32258
33323
|
workspaceId: auth.workspaceId,
|
|
32259
33324
|
authToken: auth.token,
|
|
32260
33325
|
refreshToken: auth.refreshToken,
|
|
32261
|
-
|
|
32262
|
-
agentCommand,
|
|
33326
|
+
firehoseServerUrl,
|
|
32263
33327
|
bridgeName,
|
|
32264
33328
|
justAuthenticated: true,
|
|
32265
33329
|
worktreesRootAbs
|
|
@@ -32271,8 +33335,7 @@ async function runBridge(options) {
|
|
|
32271
33335
|
workspaceId,
|
|
32272
33336
|
authToken,
|
|
32273
33337
|
refreshToken,
|
|
32274
|
-
|
|
32275
|
-
agentCommand,
|
|
33338
|
+
firehoseServerUrl,
|
|
32276
33339
|
justAuthenticated,
|
|
32277
33340
|
worktreesRootAbs,
|
|
32278
33341
|
log,
|
|
@@ -32284,18 +33347,25 @@ async function runBridge(options) {
|
|
|
32284
33347
|
});
|
|
32285
33348
|
},
|
|
32286
33349
|
onAuthInvalid: () => {
|
|
32287
|
-
log("
|
|
33350
|
+
log("[Bridge service] token invalid or revoked; re-authenticating\u2026");
|
|
32288
33351
|
clearConfigForApi(apiUrl);
|
|
32289
|
-
handle.close()
|
|
32290
|
-
|
|
33352
|
+
void handle.close().then(() => {
|
|
33353
|
+
void runBridge({ apiUrl, firehoseServerUrl, worktreesRootAbs });
|
|
33354
|
+
});
|
|
32291
33355
|
}
|
|
32292
33356
|
});
|
|
32293
|
-
const onSignal = () => {
|
|
32294
|
-
|
|
32295
|
-
|
|
33357
|
+
const onSignal = (signal) => {
|
|
33358
|
+
logImmediate(`Received ${signal}; shutting down\u2026`);
|
|
33359
|
+
setImmediate(() => {
|
|
33360
|
+
void handle.close().then(() => {
|
|
33361
|
+
process.exit(0);
|
|
33362
|
+
});
|
|
33363
|
+
});
|
|
32296
33364
|
};
|
|
32297
|
-
|
|
32298
|
-
|
|
33365
|
+
const onSigInt = () => onSignal("SIGINT");
|
|
33366
|
+
const onSigTerm = () => onSignal("SIGTERM");
|
|
33367
|
+
process.on("SIGINT", onSigInt);
|
|
33368
|
+
process.on("SIGTERM", onSigTerm);
|
|
32299
33369
|
}
|
|
32300
33370
|
export {
|
|
32301
33371
|
callSkill,
|