@buildautomaton/cli 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1408 -769
- package/dist/cli.js.map +4 -4
- package/dist/index.js +2155 -1515
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -973,8 +973,8 @@ var require_command = __commonJS({
|
|
|
973
973
|
"../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
|
|
974
974
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
975
975
|
var childProcess2 = __require("node:child_process");
|
|
976
|
-
var
|
|
977
|
-
var
|
|
976
|
+
var path37 = __require("node:path");
|
|
977
|
+
var fs36 = __require("node:fs");
|
|
978
978
|
var process8 = __require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
980
980
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1906,11 +1906,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1906
1906
|
let launchWithNode = false;
|
|
1907
1907
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1908
1908
|
function findFile(baseDir, baseName) {
|
|
1909
|
-
const localBin =
|
|
1910
|
-
if (
|
|
1911
|
-
if (sourceExt.includes(
|
|
1909
|
+
const localBin = path37.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs36.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path37.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs36.existsSync(`${localBin}${ext}`)
|
|
1914
1914
|
);
|
|
1915
1915
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1916
1916
|
return void 0;
|
|
@@ -1922,21 +1922,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1922
1922
|
if (this._scriptPath) {
|
|
1923
1923
|
let resolvedScriptPath;
|
|
1924
1924
|
try {
|
|
1925
|
-
resolvedScriptPath =
|
|
1925
|
+
resolvedScriptPath = fs36.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path37.resolve(
|
|
1930
|
+
path37.dirname(resolvedScriptPath),
|
|
1931
1931
|
executableDir
|
|
1932
1932
|
);
|
|
1933
1933
|
}
|
|
1934
1934
|
if (executableDir) {
|
|
1935
1935
|
let localFile = findFile(executableDir, executableFile);
|
|
1936
1936
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1937
|
-
const legacyName =
|
|
1937
|
+
const legacyName = path37.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path37.extname(this._scriptPath)
|
|
1940
1940
|
);
|
|
1941
1941
|
if (legacyName !== this._name) {
|
|
1942
1942
|
localFile = findFile(
|
|
@@ -1947,7 +1947,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1947
1947
|
}
|
|
1948
1948
|
executableFile = localFile || executableFile;
|
|
1949
1949
|
}
|
|
1950
|
-
launchWithNode = sourceExt.includes(
|
|
1950
|
+
launchWithNode = sourceExt.includes(path37.extname(executableFile));
|
|
1951
1951
|
let proc;
|
|
1952
1952
|
if (process8.platform !== "win32") {
|
|
1953
1953
|
if (launchWithNode) {
|
|
@@ -2787,7 +2787,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2787
2787
|
* @return {Command}
|
|
2788
2788
|
*/
|
|
2789
2789
|
nameFromFilename(filename) {
|
|
2790
|
-
this._name =
|
|
2790
|
+
this._name = path37.basename(filename, path37.extname(filename));
|
|
2791
2791
|
return this;
|
|
2792
2792
|
}
|
|
2793
2793
|
/**
|
|
@@ -2801,9 +2801,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2801
2801
|
* @param {string} [path]
|
|
2802
2802
|
* @return {(string|null|Command)}
|
|
2803
2803
|
*/
|
|
2804
|
-
executableDir(
|
|
2805
|
-
if (
|
|
2806
|
-
this._executableDir =
|
|
2804
|
+
executableDir(path38) {
|
|
2805
|
+
if (path38 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path38;
|
|
2807
2807
|
return this;
|
|
2808
2808
|
}
|
|
2809
2809
|
/**
|
|
@@ -7061,8 +7061,8 @@ var init_parseUtil = __esm({
|
|
|
7061
7061
|
init_errors();
|
|
7062
7062
|
init_en();
|
|
7063
7063
|
makeIssue = (params) => {
|
|
7064
|
-
const { data, path:
|
|
7065
|
-
const fullPath = [...
|
|
7064
|
+
const { data, path: path37, errorMaps, issueData } = params;
|
|
7065
|
+
const fullPath = [...path37, ...issueData.path || []];
|
|
7066
7066
|
const fullIssue = {
|
|
7067
7067
|
...issueData,
|
|
7068
7068
|
path: fullPath
|
|
@@ -7370,11 +7370,11 @@ var init_types = __esm({
|
|
|
7370
7370
|
init_parseUtil();
|
|
7371
7371
|
init_util();
|
|
7372
7372
|
ParseInputLazyPath = class {
|
|
7373
|
-
constructor(parent, value,
|
|
7373
|
+
constructor(parent, value, path37, key) {
|
|
7374
7374
|
this._cachedPath = [];
|
|
7375
7375
|
this.parent = parent;
|
|
7376
7376
|
this.data = value;
|
|
7377
|
-
this._path =
|
|
7377
|
+
this._path = path37;
|
|
7378
7378
|
this._key = key;
|
|
7379
7379
|
}
|
|
7380
7380
|
get path() {
|
|
@@ -11235,7 +11235,7 @@ var require_has_flag = __commonJS({
|
|
|
11235
11235
|
var require_supports_color = __commonJS({
|
|
11236
11236
|
"../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
|
|
11237
11237
|
"use strict";
|
|
11238
|
-
var
|
|
11238
|
+
var os8 = __require("os");
|
|
11239
11239
|
var tty = __require("tty");
|
|
11240
11240
|
var hasFlag = require_has_flag();
|
|
11241
11241
|
var { env } = process;
|
|
@@ -11283,7 +11283,7 @@ var require_supports_color = __commonJS({
|
|
|
11283
11283
|
return min;
|
|
11284
11284
|
}
|
|
11285
11285
|
if (process.platform === "win32") {
|
|
11286
|
-
const osRelease =
|
|
11286
|
+
const osRelease = os8.release().split(".");
|
|
11287
11287
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
11288
11288
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
11289
11289
|
}
|
|
@@ -11529,10 +11529,10 @@ var require_src2 = __commonJS({
|
|
|
11529
11529
|
var fs_1 = __require("fs");
|
|
11530
11530
|
var debug_1 = __importDefault(require_src());
|
|
11531
11531
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
11532
|
-
function check2(
|
|
11533
|
-
log2(`checking %s`,
|
|
11532
|
+
function check2(path37, isFile, isDirectory) {
|
|
11533
|
+
log2(`checking %s`, path37);
|
|
11534
11534
|
try {
|
|
11535
|
-
const stat3 = fs_1.statSync(
|
|
11535
|
+
const stat3 = fs_1.statSync(path37);
|
|
11536
11536
|
if (stat3.isFile() && isFile) {
|
|
11537
11537
|
log2(`[OK] path represents a file`);
|
|
11538
11538
|
return true;
|
|
@@ -11552,8 +11552,8 @@ var require_src2 = __commonJS({
|
|
|
11552
11552
|
throw e;
|
|
11553
11553
|
}
|
|
11554
11554
|
}
|
|
11555
|
-
function exists2(
|
|
11556
|
-
return check2(
|
|
11555
|
+
function exists2(path37, type = exports.READABLE) {
|
|
11556
|
+
return check2(path37, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
11557
11557
|
}
|
|
11558
11558
|
exports.exists = exists2;
|
|
11559
11559
|
exports.FILE = 1;
|
|
@@ -11850,10 +11850,10 @@ function assignProp(target, prop, value) {
|
|
|
11850
11850
|
configurable: true
|
|
11851
11851
|
});
|
|
11852
11852
|
}
|
|
11853
|
-
function getElementAtPath(obj,
|
|
11854
|
-
if (!
|
|
11853
|
+
function getElementAtPath(obj, path37) {
|
|
11854
|
+
if (!path37)
|
|
11855
11855
|
return obj;
|
|
11856
|
-
return
|
|
11856
|
+
return path37.reduce((acc, key) => acc?.[key], obj);
|
|
11857
11857
|
}
|
|
11858
11858
|
function promiseAllObject(promisesObj) {
|
|
11859
11859
|
const keys = Object.keys(promisesObj);
|
|
@@ -12102,11 +12102,11 @@ function aborted(x, startIndex = 0) {
|
|
|
12102
12102
|
}
|
|
12103
12103
|
return false;
|
|
12104
12104
|
}
|
|
12105
|
-
function prefixIssues(
|
|
12105
|
+
function prefixIssues(path37, issues) {
|
|
12106
12106
|
return issues.map((iss) => {
|
|
12107
12107
|
var _a2;
|
|
12108
12108
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
12109
|
-
iss.path.unshift(
|
|
12109
|
+
iss.path.unshift(path37);
|
|
12110
12110
|
return iss;
|
|
12111
12111
|
});
|
|
12112
12112
|
}
|
|
@@ -12295,7 +12295,7 @@ function treeifyError(error40, _mapper) {
|
|
|
12295
12295
|
return issue2.message;
|
|
12296
12296
|
};
|
|
12297
12297
|
const result = { errors: [] };
|
|
12298
|
-
const processError = (error41,
|
|
12298
|
+
const processError = (error41, path37 = []) => {
|
|
12299
12299
|
var _a2, _b;
|
|
12300
12300
|
for (const issue2 of error41.issues) {
|
|
12301
12301
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -12305,7 +12305,7 @@ function treeifyError(error40, _mapper) {
|
|
|
12305
12305
|
} else if (issue2.code === "invalid_element") {
|
|
12306
12306
|
processError({ issues: issue2.issues }, issue2.path);
|
|
12307
12307
|
} else {
|
|
12308
|
-
const fullpath = [...
|
|
12308
|
+
const fullpath = [...path37, ...issue2.path];
|
|
12309
12309
|
if (fullpath.length === 0) {
|
|
12310
12310
|
result.errors.push(mapper(issue2));
|
|
12311
12311
|
continue;
|
|
@@ -12335,9 +12335,9 @@ function treeifyError(error40, _mapper) {
|
|
|
12335
12335
|
processError(error40);
|
|
12336
12336
|
return result;
|
|
12337
12337
|
}
|
|
12338
|
-
function toDotPath(
|
|
12338
|
+
function toDotPath(path37) {
|
|
12339
12339
|
const segs = [];
|
|
12340
|
-
for (const seg of
|
|
12340
|
+
for (const seg of path37) {
|
|
12341
12341
|
if (typeof seg === "number")
|
|
12342
12342
|
segs.push(`[${seg}]`);
|
|
12343
12343
|
else if (typeof seg === "symbol")
|
|
@@ -25064,15 +25064,27 @@ var {
|
|
|
25064
25064
|
} = import_index.default;
|
|
25065
25065
|
|
|
25066
25066
|
// src/cli-version.ts
|
|
25067
|
-
var CLI_VERSION = "0.1.
|
|
25067
|
+
var CLI_VERSION = "0.1.25".length > 0 ? "0.1.25" : "0.0.0-dev";
|
|
25068
25068
|
|
|
25069
25069
|
// src/cli/defaults.ts
|
|
25070
25070
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
25071
25071
|
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
25072
25072
|
|
|
25073
25073
|
// src/cli/run-cli-action.ts
|
|
25074
|
-
import * as
|
|
25075
|
-
import * as
|
|
25074
|
+
import * as fs35 from "node:fs";
|
|
25075
|
+
import * as path36 from "node:path";
|
|
25076
|
+
|
|
25077
|
+
// src/cli-log-level.ts
|
|
25078
|
+
var verbosity = "info";
|
|
25079
|
+
function setCliLogVerbosity(level) {
|
|
25080
|
+
verbosity = level;
|
|
25081
|
+
}
|
|
25082
|
+
function getCliLogVerbosity() {
|
|
25083
|
+
return verbosity;
|
|
25084
|
+
}
|
|
25085
|
+
function isCliTrace() {
|
|
25086
|
+
return verbosity === "trace";
|
|
25087
|
+
}
|
|
25076
25088
|
|
|
25077
25089
|
// src/config.ts
|
|
25078
25090
|
import fs from "node:fs";
|
|
@@ -25442,15 +25454,26 @@ function getBridgeRoot() {
|
|
|
25442
25454
|
}
|
|
25443
25455
|
|
|
25444
25456
|
// src/log.ts
|
|
25445
|
-
function
|
|
25457
|
+
function timestampPrefix() {
|
|
25446
25458
|
const time3 = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
|
|
25447
|
-
|
|
25459
|
+
return `[${time3}]`;
|
|
25460
|
+
}
|
|
25461
|
+
function log(line) {
|
|
25462
|
+
console.log(`${timestampPrefix()} ${line}`);
|
|
25448
25463
|
}
|
|
25449
25464
|
function logImmediate(line) {
|
|
25450
|
-
|
|
25451
|
-
process.stdout.write(`[${time3}] ${line}
|
|
25465
|
+
process.stdout.write(`${timestampPrefix()} ${line}
|
|
25452
25466
|
`);
|
|
25453
25467
|
}
|
|
25468
|
+
function logDebug(line) {
|
|
25469
|
+
const v = getCliLogVerbosity();
|
|
25470
|
+
if (v !== "debug" && v !== "trace") return;
|
|
25471
|
+
console.log(`${timestampPrefix()} [debug] ${line}`);
|
|
25472
|
+
}
|
|
25473
|
+
function logTrace(line) {
|
|
25474
|
+
if (getCliLogVerbosity() !== "trace") return;
|
|
25475
|
+
console.log(`${timestampPrefix()} [trace] ${line}`);
|
|
25476
|
+
}
|
|
25454
25477
|
|
|
25455
25478
|
// src/process-bridge-resilience.ts
|
|
25456
25479
|
var installed = false;
|
|
@@ -25485,7 +25508,7 @@ function applyCliOutboundNetworkPreferences() {
|
|
|
25485
25508
|
}
|
|
25486
25509
|
}
|
|
25487
25510
|
|
|
25488
|
-
// src/
|
|
25511
|
+
// src/connection/cli-ws-client.ts
|
|
25489
25512
|
import https from "node:https";
|
|
25490
25513
|
var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
|
|
25491
25514
|
function attachWebSocketClientPing(ws, intervalMs) {
|
|
@@ -25545,7 +25568,7 @@ function safeSendWebSocketBinary(ws, data) {
|
|
|
25545
25568
|
}
|
|
25546
25569
|
}
|
|
25547
25570
|
|
|
25548
|
-
// src/
|
|
25571
|
+
// src/connection/create-ws-bridge.ts
|
|
25549
25572
|
var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
|
|
25550
25573
|
var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
|
|
25551
25574
|
function createWsBridge(options) {
|
|
@@ -26156,29 +26179,22 @@ async function openBrowser(connectionId, initialWorkspaceId, preferredBridgeName
|
|
|
26156
26179
|
}
|
|
26157
26180
|
}
|
|
26158
26181
|
|
|
26159
|
-
// src/
|
|
26160
|
-
var RECONNECT_FIRST_MS = 100;
|
|
26161
|
-
var RECONNECT_MAX_MS = 3e4;
|
|
26182
|
+
// src/connection/reconnect/constants.ts
|
|
26162
26183
|
var RECONNECT_QUIET_MS = 2e3;
|
|
26163
|
-
|
|
26164
|
-
|
|
26184
|
+
var PENDING_AUTH_RECONNECT_FIRST_MS = 100;
|
|
26185
|
+
var PENDING_AUTH_RECONNECT_MAX_MS = 3e4;
|
|
26186
|
+
function pendingAuthReconnectDelayMs(attemptBeforeIncrement) {
|
|
26187
|
+
return Math.min(PENDING_AUTH_RECONNECT_FIRST_MS * 2 ** attemptBeforeIncrement, PENDING_AUTH_RECONNECT_MAX_MS);
|
|
26165
26188
|
}
|
|
26166
26189
|
|
|
26167
|
-
// src/
|
|
26190
|
+
// src/connection/reconnect/format-reconnect-delay-for-log.ts
|
|
26168
26191
|
function formatReconnectDelayForLog(delayMs) {
|
|
26169
26192
|
if (delayMs < 1e3) return `${delayMs}ms`;
|
|
26170
26193
|
const s = delayMs / 1e3;
|
|
26171
26194
|
return Number.isInteger(s) ? `${s}s` : `${s.toFixed(1)}s`;
|
|
26172
26195
|
}
|
|
26173
26196
|
|
|
26174
|
-
// src/
|
|
26175
|
-
function logNextReconnectAttempt(log2, serviceLabel, quiet, delayMs, attempt) {
|
|
26176
|
-
if (!quiet.verboseLogs) return;
|
|
26177
|
-
const delayLabel = formatReconnectDelayForLog(delayMs);
|
|
26178
|
-
log2(`${serviceLabel} Next connection attempt in ${delayLabel} (attempt ${attempt}).`);
|
|
26179
|
-
}
|
|
26180
|
-
|
|
26181
|
-
// src/bridge/connection/ws-close-diagnostics.ts
|
|
26197
|
+
// src/connection/ws-close-diagnostics.ts
|
|
26182
26198
|
function describeWebSocketCloseCode(code) {
|
|
26183
26199
|
const known = {
|
|
26184
26200
|
1e3: "normal closure",
|
|
@@ -26209,7 +26225,7 @@ function formatWebSocketClose(label, code, reason, extra) {
|
|
|
26209
26225
|
return `${label} Disconnected: code=${code} (${describeWebSocketCloseCode(code)})${reasonPart}${extraPart}`;
|
|
26210
26226
|
}
|
|
26211
26227
|
|
|
26212
|
-
// src/
|
|
26228
|
+
// src/connection/reconnect/reconnect-quiet-slot.ts
|
|
26213
26229
|
function createEmptyReconnectQuietSlot() {
|
|
26214
26230
|
return { timer: null, verboseLogs: false, pendingCloseLog: null };
|
|
26215
26231
|
}
|
|
@@ -26219,6 +26235,11 @@ function clearReconnectQuietTimer(quiet) {
|
|
|
26219
26235
|
quiet.timer = null;
|
|
26220
26236
|
}
|
|
26221
26237
|
}
|
|
26238
|
+
function abandonReconnectQuietWindow(quiet) {
|
|
26239
|
+
clearReconnectQuietTimer(quiet);
|
|
26240
|
+
quiet.pendingCloseLog = null;
|
|
26241
|
+
quiet.verboseLogs = false;
|
|
26242
|
+
}
|
|
26222
26243
|
function clearReconnectQuietOnSuccessfulConnection(quiet, log2, reconnectedMessage) {
|
|
26223
26244
|
clearReconnectQuietTimer(quiet);
|
|
26224
26245
|
quiet.pendingCloseLog = null;
|
|
@@ -26239,12 +26260,16 @@ function beginDeferredDisconnectForReconnect(options) {
|
|
|
26239
26260
|
shutdownDetail,
|
|
26240
26261
|
reconnectingDetail,
|
|
26241
26262
|
quietMs = RECONNECT_QUIET_MS,
|
|
26242
|
-
shouldAbortQuietWindow
|
|
26263
|
+
shouldAbortQuietWindow,
|
|
26264
|
+
silentWhileReconnect = false
|
|
26243
26265
|
} = options;
|
|
26244
26266
|
if (!willReconnect) {
|
|
26245
26267
|
log2(formatWebSocketClose(serviceLabel, code, reason, shutdownDetail));
|
|
26246
26268
|
return;
|
|
26247
26269
|
}
|
|
26270
|
+
if (silentWhileReconnect) {
|
|
26271
|
+
return;
|
|
26272
|
+
}
|
|
26248
26273
|
quiet.pendingCloseLog = { code, reason };
|
|
26249
26274
|
if (quiet.timer == null) {
|
|
26250
26275
|
quiet.timer = setTimeout(() => {
|
|
@@ -26261,18 +26286,178 @@ function beginDeferredDisconnectForReconnect(options) {
|
|
|
26261
26286
|
}
|
|
26262
26287
|
}
|
|
26263
26288
|
|
|
26264
|
-
// src/
|
|
26265
|
-
function
|
|
26289
|
+
// src/connection/reconnect/reconnect-outage-plan.ts
|
|
26290
|
+
function createEmptyReconnectOutageTracker() {
|
|
26291
|
+
return {
|
|
26292
|
+
startedAt: null,
|
|
26293
|
+
totalFailures: 0,
|
|
26294
|
+
lastLoggedTierIndex: -1,
|
|
26295
|
+
originalCloseCode: null,
|
|
26296
|
+
originalCloseReason: null
|
|
26297
|
+
};
|
|
26298
|
+
}
|
|
26299
|
+
function resetReconnectOutageTracker(tracker) {
|
|
26300
|
+
tracker.startedAt = null;
|
|
26301
|
+
tracker.totalFailures = 0;
|
|
26302
|
+
tracker.lastLoggedTierIndex = -1;
|
|
26303
|
+
tracker.originalCloseCode = null;
|
|
26304
|
+
tracker.originalCloseReason = null;
|
|
26305
|
+
}
|
|
26306
|
+
function reconnectTierIndexForOutageElapsedMs(elapsedMs) {
|
|
26307
|
+
if (elapsedMs < 6e4) return 0;
|
|
26308
|
+
if (elapsedMs < 36e4) return 1;
|
|
26309
|
+
if (elapsedMs < 12e5) return 2;
|
|
26310
|
+
return 3;
|
|
26311
|
+
}
|
|
26312
|
+
function reconnectDelayMsForOutageElapsedMs(elapsedMs) {
|
|
26313
|
+
if (elapsedMs < 6e4) return 3e3;
|
|
26314
|
+
if (elapsedMs < 36e4) return 1e4;
|
|
26315
|
+
if (elapsedMs < 12e5) return 2e4;
|
|
26316
|
+
return 6e4;
|
|
26317
|
+
}
|
|
26318
|
+
function disconnectDetail(code, reason) {
|
|
26319
|
+
const r = reason.trim();
|
|
26320
|
+
const reasonPart = r ? ` reason="${r}"` : "";
|
|
26321
|
+
return `code=${code} (${describeWebSocketCloseCode(code)})${reasonPart}`;
|
|
26322
|
+
}
|
|
26323
|
+
function formatTierPromotionLogLine(parts) {
|
|
26324
|
+
const detail = disconnectDetail(parts.code, parts.reason);
|
|
26325
|
+
return `${parts.serviceLabel} ${parts.disconnectLeadIn}: ${detail}. Trying to re-establish a connection in the background (retry attempts so far: ${parts.totalFailures}).`;
|
|
26326
|
+
}
|
|
26327
|
+
function planReconnectAfterFailure(tracker, nowMs, serviceLabel, disconnectLeadIn, closeCode, closeReason) {
|
|
26328
|
+
if (tracker.startedAt == null) {
|
|
26329
|
+
tracker.startedAt = nowMs;
|
|
26330
|
+
}
|
|
26331
|
+
if (closeCode != null && tracker.originalCloseCode == null) {
|
|
26332
|
+
tracker.originalCloseCode = closeCode;
|
|
26333
|
+
tracker.originalCloseReason = closeReason ?? "";
|
|
26334
|
+
}
|
|
26335
|
+
tracker.totalFailures += 1;
|
|
26336
|
+
const elapsed = nowMs - tracker.startedAt;
|
|
26337
|
+
const tier = reconnectTierIndexForOutageElapsedMs(elapsed);
|
|
26338
|
+
const delayMs = reconnectDelayMsForOutageElapsedMs(elapsed);
|
|
26339
|
+
let logLine = null;
|
|
26340
|
+
if (tier > tracker.lastLoggedTierIndex) {
|
|
26341
|
+
tracker.lastLoggedTierIndex = tier;
|
|
26342
|
+
const code = tracker.originalCloseCode ?? closeCode ?? 0;
|
|
26343
|
+
const reason = tracker.originalCloseReason ?? closeReason ?? "";
|
|
26344
|
+
logLine = formatTierPromotionLogLine({
|
|
26345
|
+
serviceLabel,
|
|
26346
|
+
disconnectLeadIn,
|
|
26347
|
+
code,
|
|
26348
|
+
reason,
|
|
26349
|
+
totalFailures: tracker.totalFailures
|
|
26350
|
+
});
|
|
26351
|
+
}
|
|
26352
|
+
return { delayMs, logLine };
|
|
26353
|
+
}
|
|
26354
|
+
|
|
26355
|
+
// src/connection/reconnect/tiered-channel-reconnect.ts
|
|
26356
|
+
var BRIDGE_SERVICE_LABEL = "[Bridge service]";
|
|
26357
|
+
var BRIDGE_DISCONNECT_LEAD_IN = "Bridge connection was disconnected";
|
|
26358
|
+
var PREVIEW_TUNNEL_SERVICE_LABEL = "[Proxy and log service]";
|
|
26359
|
+
var PREVIEW_TUNNEL_DISCONNECT_LEAD_IN = "Preview tunnel connection was disconnected";
|
|
26360
|
+
var SHUTDOWN_DETAIL = "Not reconnecting (shutting down).";
|
|
26361
|
+
var RECONNECTING_DETAIL = "Reconnecting\u2026";
|
|
26362
|
+
function applyTieredReconnectPlanAndLog(tracker, log2, serviceLabel, disconnectLeadIn, closeCode, closeReason) {
|
|
26363
|
+
try {
|
|
26364
|
+
const { delayMs, logLine } = planReconnectAfterFailure(
|
|
26365
|
+
tracker,
|
|
26366
|
+
Date.now(),
|
|
26367
|
+
serviceLabel,
|
|
26368
|
+
disconnectLeadIn,
|
|
26369
|
+
closeCode,
|
|
26370
|
+
closeReason
|
|
26371
|
+
);
|
|
26372
|
+
if (logLine) {
|
|
26373
|
+
try {
|
|
26374
|
+
log2(logLine);
|
|
26375
|
+
} catch {
|
|
26376
|
+
}
|
|
26377
|
+
}
|
|
26378
|
+
return delayMs;
|
|
26379
|
+
} catch {
|
|
26380
|
+
return 3e3;
|
|
26381
|
+
}
|
|
26382
|
+
}
|
|
26383
|
+
function armReconnectDelayTimer(options) {
|
|
26384
|
+
const {
|
|
26385
|
+
delayMs,
|
|
26386
|
+
bumpAttempt,
|
|
26387
|
+
clearTimer,
|
|
26388
|
+
setTimer,
|
|
26389
|
+
shouldAbortBeforeRun,
|
|
26390
|
+
run,
|
|
26391
|
+
reschedule
|
|
26392
|
+
} = options;
|
|
26393
|
+
clearTimer();
|
|
26394
|
+
bumpAttempt();
|
|
26395
|
+
setTimer(
|
|
26396
|
+
setTimeout(() => {
|
|
26397
|
+
setTimer(null);
|
|
26398
|
+
if (shouldAbortBeforeRun()) return;
|
|
26399
|
+
try {
|
|
26400
|
+
run();
|
|
26401
|
+
} catch {
|
|
26402
|
+
try {
|
|
26403
|
+
if (!shouldAbortBeforeRun()) {
|
|
26404
|
+
reschedule();
|
|
26405
|
+
}
|
|
26406
|
+
} catch {
|
|
26407
|
+
}
|
|
26408
|
+
}
|
|
26409
|
+
}, delayMs)
|
|
26410
|
+
);
|
|
26411
|
+
}
|
|
26412
|
+
function beginTieredSilentReconnectDisconnect(options) {
|
|
26413
|
+
const {
|
|
26414
|
+
isClosedByUser,
|
|
26415
|
+
quiet,
|
|
26416
|
+
code,
|
|
26417
|
+
reason,
|
|
26418
|
+
willReconnect,
|
|
26419
|
+
log: log2,
|
|
26420
|
+
serviceLabel,
|
|
26421
|
+
shouldAbortQuietWindow
|
|
26422
|
+
} = options;
|
|
26266
26423
|
beginDeferredDisconnectForReconnect({
|
|
26424
|
+
isClosedByUser,
|
|
26425
|
+
quiet,
|
|
26426
|
+
code,
|
|
26427
|
+
reason,
|
|
26428
|
+
willReconnect,
|
|
26429
|
+
log: log2,
|
|
26430
|
+
serviceLabel,
|
|
26431
|
+
shutdownDetail: SHUTDOWN_DETAIL,
|
|
26432
|
+
reconnectingDetail: RECONNECTING_DETAIL,
|
|
26433
|
+
shouldAbortQuietWindow,
|
|
26434
|
+
silentWhileReconnect: willReconnect
|
|
26435
|
+
});
|
|
26436
|
+
}
|
|
26437
|
+
function clearTieredReconnectChannelOnOpen(options) {
|
|
26438
|
+
const { quiet, outage, clearLastCloseMeta, log: log2, restoredMessage } = options;
|
|
26439
|
+
const hadOutage = outage.startedAt != null || outage.totalFailures > 0;
|
|
26440
|
+
abandonReconnectQuietWindow(quiet);
|
|
26441
|
+
resetReconnectOutageTracker(outage);
|
|
26442
|
+
clearLastCloseMeta();
|
|
26443
|
+
if (hadOutage) {
|
|
26444
|
+
try {
|
|
26445
|
+
log2(restoredMessage);
|
|
26446
|
+
} catch {
|
|
26447
|
+
}
|
|
26448
|
+
}
|
|
26449
|
+
}
|
|
26450
|
+
|
|
26451
|
+
// src/connection/reconnect/bridge-main-reconnect.ts
|
|
26452
|
+
function beginMainBridgeDeferredDisconnect(state, code, reason, log2, willReconnect) {
|
|
26453
|
+
beginTieredSilentReconnectDisconnect({
|
|
26267
26454
|
isClosedByUser: () => state.closedByUser,
|
|
26268
26455
|
quiet: state.mainQuiet,
|
|
26269
26456
|
code,
|
|
26270
26457
|
reason,
|
|
26271
26458
|
willReconnect,
|
|
26272
26459
|
log: log2,
|
|
26273
|
-
serviceLabel:
|
|
26274
|
-
shutdownDetail: "Not reconnecting (shutting down).",
|
|
26275
|
-
reconnectingDetail: "Reconnecting\u2026",
|
|
26460
|
+
serviceLabel: BRIDGE_SERVICE_LABEL,
|
|
26276
26461
|
shouldAbortQuietWindow: () => {
|
|
26277
26462
|
const w = state.currentWs;
|
|
26278
26463
|
return w != null && w.readyState === wrapper_default.OPEN;
|
|
@@ -26280,32 +26465,59 @@ function beginMainBridgeDeferredDisconnect(state, code, reason, log2, willReconn
|
|
|
26280
26465
|
});
|
|
26281
26466
|
}
|
|
26282
26467
|
function clearMainBridgeReconnectQuietOnOpen(state, log2) {
|
|
26283
|
-
|
|
26468
|
+
clearTieredReconnectChannelOnOpen({
|
|
26469
|
+
quiet: state.mainQuiet,
|
|
26470
|
+
outage: state.mainOutage,
|
|
26471
|
+
clearLastCloseMeta: () => {
|
|
26472
|
+
state.lastReconnectCloseMeta = null;
|
|
26473
|
+
},
|
|
26474
|
+
log: log2,
|
|
26475
|
+
restoredMessage: "Bridge connection restored."
|
|
26476
|
+
});
|
|
26284
26477
|
}
|
|
26285
|
-
function scheduleMainBridgeReconnect(state, connect, log2) {
|
|
26478
|
+
function scheduleMainBridgeReconnect(state, connect, log2, closeMeta) {
|
|
26286
26479
|
if (state.closedByUser || state.currentWs != null) return;
|
|
26287
|
-
const
|
|
26288
|
-
|
|
26289
|
-
|
|
26290
|
-
|
|
26291
|
-
|
|
26292
|
-
|
|
26293
|
-
|
|
26480
|
+
const meta = closeMeta ?? state.lastReconnectCloseMeta ?? void 0;
|
|
26481
|
+
const delay2 = applyTieredReconnectPlanAndLog(
|
|
26482
|
+
state.mainOutage,
|
|
26483
|
+
log2,
|
|
26484
|
+
BRIDGE_SERVICE_LABEL,
|
|
26485
|
+
BRIDGE_DISCONNECT_LEAD_IN,
|
|
26486
|
+
meta?.code,
|
|
26487
|
+
meta?.reason
|
|
26488
|
+
);
|
|
26489
|
+
armReconnectDelayTimer({
|
|
26490
|
+
delayMs: delay2,
|
|
26491
|
+
bumpAttempt: () => {
|
|
26492
|
+
state.reconnectAttempt += 1;
|
|
26493
|
+
},
|
|
26494
|
+
clearTimer: () => {
|
|
26495
|
+
if (state.reconnectTimeout != null) {
|
|
26496
|
+
clearTimeout(state.reconnectTimeout);
|
|
26497
|
+
state.reconnectTimeout = null;
|
|
26498
|
+
}
|
|
26499
|
+
},
|
|
26500
|
+
setTimer: (id) => {
|
|
26501
|
+
state.reconnectTimeout = id;
|
|
26502
|
+
},
|
|
26503
|
+
shouldAbortBeforeRun: () => state.closedByUser || state.currentWs != null,
|
|
26504
|
+
run: connect,
|
|
26505
|
+
reschedule: () => {
|
|
26506
|
+
scheduleMainBridgeReconnect(state, connect, log2);
|
|
26507
|
+
}
|
|
26508
|
+
});
|
|
26294
26509
|
}
|
|
26295
26510
|
|
|
26296
|
-
// src/
|
|
26297
|
-
var PROXY_AND_LOG_SERVICE_LABEL = "[Proxy and log service]";
|
|
26511
|
+
// src/connection/reconnect/firehose-reconnect.ts
|
|
26298
26512
|
function beginFirehoseDeferredDisconnect(ctx, code, reason, log2) {
|
|
26299
|
-
|
|
26513
|
+
beginTieredSilentReconnectDisconnect({
|
|
26300
26514
|
isClosedByUser: () => ctx.closedByUser,
|
|
26301
26515
|
quiet: ctx.firehoseQuiet,
|
|
26302
26516
|
code,
|
|
26303
26517
|
reason,
|
|
26304
26518
|
willReconnect: true,
|
|
26305
26519
|
log: log2,
|
|
26306
|
-
serviceLabel:
|
|
26307
|
-
shutdownDetail: "Not reconnecting (shutting down).",
|
|
26308
|
-
reconnectingDetail: "Reconnecting\u2026",
|
|
26520
|
+
serviceLabel: PREVIEW_TUNNEL_SERVICE_LABEL,
|
|
26309
26521
|
shouldAbortQuietWindow: () => {
|
|
26310
26522
|
const w = ctx.currentWs;
|
|
26311
26523
|
if (!w || w.readyState !== wrapper_default.OPEN) return true;
|
|
@@ -26314,11 +26526,15 @@ function beginFirehoseDeferredDisconnect(ctx, code, reason, log2) {
|
|
|
26314
26526
|
});
|
|
26315
26527
|
}
|
|
26316
26528
|
function clearFirehoseReconnectQuietOnOpen(ctx, log2) {
|
|
26317
|
-
|
|
26318
|
-
ctx.firehoseQuiet,
|
|
26319
|
-
|
|
26320
|
-
|
|
26321
|
-
|
|
26529
|
+
clearTieredReconnectChannelOnOpen({
|
|
26530
|
+
quiet: ctx.firehoseQuiet,
|
|
26531
|
+
outage: ctx.firehoseOutage,
|
|
26532
|
+
clearLastCloseMeta: () => {
|
|
26533
|
+
ctx.lastFirehoseReconnectCloseMeta = null;
|
|
26534
|
+
},
|
|
26535
|
+
log: log2,
|
|
26536
|
+
restoredMessage: "Preview tunnel restored (local HTTP proxy and dev logs)."
|
|
26537
|
+
});
|
|
26322
26538
|
}
|
|
26323
26539
|
|
|
26324
26540
|
// src/auth/run-pending-auth.ts
|
|
@@ -26414,7 +26630,7 @@ function runPendingAuth(options) {
|
|
|
26414
26630
|
}
|
|
26415
26631
|
if (resolved) return;
|
|
26416
26632
|
beginDeferredPendingCloseLog(code, reason);
|
|
26417
|
-
const delay2 =
|
|
26633
|
+
const delay2 = pendingAuthReconnectDelayMs(reconnectAttempt);
|
|
26418
26634
|
reconnectAttempt += 1;
|
|
26419
26635
|
if (signInQuiet.verboseLogs) {
|
|
26420
26636
|
const delayLabel = formatReconnectDelayForLog(delay2);
|
|
@@ -26459,7 +26675,7 @@ function runPendingAuth(options) {
|
|
|
26459
26675
|
};
|
|
26460
26676
|
}
|
|
26461
26677
|
|
|
26462
|
-
// src/
|
|
26678
|
+
// src/connection/close-bridge-connection.ts
|
|
26463
26679
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
26464
26680
|
const say = log2 ?? logImmediate;
|
|
26465
26681
|
say("Cleaning up connections\u2026");
|
|
@@ -26847,9 +27063,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
26847
27063
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
26848
27064
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
26849
27065
|
if (!rawPath || !summary) continue;
|
|
26850
|
-
const
|
|
26851
|
-
if (!
|
|
26852
|
-
rows.push({ path:
|
|
27066
|
+
const path37 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
27067
|
+
if (!path37) continue;
|
|
27068
|
+
rows.push({ path: path37, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
26853
27069
|
}
|
|
26854
27070
|
return rows;
|
|
26855
27071
|
}
|
|
@@ -26974,6 +27190,30 @@ var GitRepoMetaSchema = external_exports.object({
|
|
|
26974
27190
|
updatedAt: external_exports.string()
|
|
26975
27191
|
});
|
|
26976
27192
|
|
|
27193
|
+
// ../types/src/claude-code-permission-mode.ts
|
|
27194
|
+
var CLAUDE_CODE_PERMISSION_MODES = [
|
|
27195
|
+
"default",
|
|
27196
|
+
"acceptEdits",
|
|
27197
|
+
"plan",
|
|
27198
|
+
"auto",
|
|
27199
|
+
"dontAsk",
|
|
27200
|
+
"bypassPermissions"
|
|
27201
|
+
];
|
|
27202
|
+
var MODE_SET = new Set(CLAUDE_CODE_PERMISSION_MODES);
|
|
27203
|
+
function isClaudeCodePermissionMode(value) {
|
|
27204
|
+
return MODE_SET.has(value);
|
|
27205
|
+
}
|
|
27206
|
+
|
|
27207
|
+
// ../types/src/agent-config.ts
|
|
27208
|
+
var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
|
|
27209
|
+
function getClaudePermissionModeFromAgentConfig(config2) {
|
|
27210
|
+
if (!config2) return null;
|
|
27211
|
+
const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
|
|
27212
|
+
if (typeof raw !== "string") return null;
|
|
27213
|
+
const t = raw.trim();
|
|
27214
|
+
return isClaudeCodePermissionMode(t) ? t : null;
|
|
27215
|
+
}
|
|
27216
|
+
|
|
26977
27217
|
// src/git/session-git-queue.ts
|
|
26978
27218
|
import { execFile as execFile7 } from "node:child_process";
|
|
26979
27219
|
import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
@@ -27027,8 +27267,8 @@ function pathspec(...paths) {
|
|
|
27027
27267
|
cache.set(key, paths);
|
|
27028
27268
|
return key;
|
|
27029
27269
|
}
|
|
27030
|
-
function isPathSpec(
|
|
27031
|
-
return
|
|
27270
|
+
function isPathSpec(path37) {
|
|
27271
|
+
return path37 instanceof String && cache.has(path37);
|
|
27032
27272
|
}
|
|
27033
27273
|
function toPaths(pathSpec) {
|
|
27034
27274
|
return cache.get(pathSpec) || [];
|
|
@@ -27117,8 +27357,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
27117
27357
|
function forEachLineWithContent(input, callback) {
|
|
27118
27358
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
27119
27359
|
}
|
|
27120
|
-
function folderExists(
|
|
27121
|
-
return (0, import_file_exists.exists)(
|
|
27360
|
+
function folderExists(path37) {
|
|
27361
|
+
return (0, import_file_exists.exists)(path37, import_file_exists.FOLDER);
|
|
27122
27362
|
}
|
|
27123
27363
|
function append(target, item) {
|
|
27124
27364
|
if (Array.isArray(target)) {
|
|
@@ -27522,8 +27762,8 @@ function checkIsRepoRootTask() {
|
|
|
27522
27762
|
commands,
|
|
27523
27763
|
format: "utf-8",
|
|
27524
27764
|
onError,
|
|
27525
|
-
parser(
|
|
27526
|
-
return /^\.(git)?$/.test(
|
|
27765
|
+
parser(path37) {
|
|
27766
|
+
return /^\.(git)?$/.test(path37.trim());
|
|
27527
27767
|
}
|
|
27528
27768
|
};
|
|
27529
27769
|
}
|
|
@@ -27957,11 +28197,11 @@ function parseGrep(grep) {
|
|
|
27957
28197
|
const paths = /* @__PURE__ */ new Set();
|
|
27958
28198
|
const results = {};
|
|
27959
28199
|
forEachLineWithContent(grep, (input) => {
|
|
27960
|
-
const [
|
|
27961
|
-
paths.add(
|
|
27962
|
-
(results[
|
|
28200
|
+
const [path37, line, preview] = input.split(NULL);
|
|
28201
|
+
paths.add(path37);
|
|
28202
|
+
(results[path37] = results[path37] || []).push({
|
|
27963
28203
|
line: asNumber(line),
|
|
27964
|
-
path:
|
|
28204
|
+
path: path37,
|
|
27965
28205
|
preview
|
|
27966
28206
|
});
|
|
27967
28207
|
});
|
|
@@ -28726,14 +28966,14 @@ var init_hash_object = __esm2({
|
|
|
28726
28966
|
init_task();
|
|
28727
28967
|
}
|
|
28728
28968
|
});
|
|
28729
|
-
function parseInit(bare,
|
|
28969
|
+
function parseInit(bare, path37, text) {
|
|
28730
28970
|
const response = String(text).trim();
|
|
28731
28971
|
let result;
|
|
28732
28972
|
if (result = initResponseRegex.exec(response)) {
|
|
28733
|
-
return new InitSummary(bare,
|
|
28973
|
+
return new InitSummary(bare, path37, false, result[1]);
|
|
28734
28974
|
}
|
|
28735
28975
|
if (result = reInitResponseRegex.exec(response)) {
|
|
28736
|
-
return new InitSummary(bare,
|
|
28976
|
+
return new InitSummary(bare, path37, true, result[1]);
|
|
28737
28977
|
}
|
|
28738
28978
|
let gitDir = "";
|
|
28739
28979
|
const tokens = response.split(" ");
|
|
@@ -28744,7 +28984,7 @@ function parseInit(bare, path36, text) {
|
|
|
28744
28984
|
break;
|
|
28745
28985
|
}
|
|
28746
28986
|
}
|
|
28747
|
-
return new InitSummary(bare,
|
|
28987
|
+
return new InitSummary(bare, path37, /^re/i.test(response), gitDir);
|
|
28748
28988
|
}
|
|
28749
28989
|
var InitSummary;
|
|
28750
28990
|
var initResponseRegex;
|
|
@@ -28753,9 +28993,9 @@ var init_InitSummary = __esm2({
|
|
|
28753
28993
|
"src/lib/responses/InitSummary.ts"() {
|
|
28754
28994
|
"use strict";
|
|
28755
28995
|
InitSummary = class {
|
|
28756
|
-
constructor(bare,
|
|
28996
|
+
constructor(bare, path37, existing, gitDir) {
|
|
28757
28997
|
this.bare = bare;
|
|
28758
|
-
this.path =
|
|
28998
|
+
this.path = path37;
|
|
28759
28999
|
this.existing = existing;
|
|
28760
29000
|
this.gitDir = gitDir;
|
|
28761
29001
|
}
|
|
@@ -28767,7 +29007,7 @@ var init_InitSummary = __esm2({
|
|
|
28767
29007
|
function hasBareCommand(command) {
|
|
28768
29008
|
return command.includes(bareCommand);
|
|
28769
29009
|
}
|
|
28770
|
-
function initTask(bare = false,
|
|
29010
|
+
function initTask(bare = false, path37, customArgs) {
|
|
28771
29011
|
const commands = ["init", ...customArgs];
|
|
28772
29012
|
if (bare && !hasBareCommand(commands)) {
|
|
28773
29013
|
commands.splice(1, 0, bareCommand);
|
|
@@ -28776,7 +29016,7 @@ function initTask(bare = false, path36, customArgs) {
|
|
|
28776
29016
|
commands,
|
|
28777
29017
|
format: "utf-8",
|
|
28778
29018
|
parser(text) {
|
|
28779
|
-
return parseInit(commands.includes("--bare"),
|
|
29019
|
+
return parseInit(commands.includes("--bare"), path37, text);
|
|
28780
29020
|
}
|
|
28781
29021
|
};
|
|
28782
29022
|
}
|
|
@@ -29592,12 +29832,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
29592
29832
|
"use strict";
|
|
29593
29833
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
29594
29834
|
FileStatusSummary = class {
|
|
29595
|
-
constructor(
|
|
29596
|
-
this.path =
|
|
29835
|
+
constructor(path37, index, working_dir) {
|
|
29836
|
+
this.path = path37;
|
|
29597
29837
|
this.index = index;
|
|
29598
29838
|
this.working_dir = working_dir;
|
|
29599
29839
|
if (index === "R" || working_dir === "R") {
|
|
29600
|
-
const detail = fromPathRegex.exec(
|
|
29840
|
+
const detail = fromPathRegex.exec(path37) || [null, path37, path37];
|
|
29601
29841
|
this.from = detail[2] || "";
|
|
29602
29842
|
this.path = detail[1] || "";
|
|
29603
29843
|
}
|
|
@@ -29628,14 +29868,14 @@ function splitLine(result, lineStr) {
|
|
|
29628
29868
|
default:
|
|
29629
29869
|
return;
|
|
29630
29870
|
}
|
|
29631
|
-
function data(index, workingDir,
|
|
29871
|
+
function data(index, workingDir, path37) {
|
|
29632
29872
|
const raw = `${index}${workingDir}`;
|
|
29633
29873
|
const handler = parsers6.get(raw);
|
|
29634
29874
|
if (handler) {
|
|
29635
|
-
handler(result,
|
|
29875
|
+
handler(result, path37);
|
|
29636
29876
|
}
|
|
29637
29877
|
if (raw !== "##" && raw !== "!!") {
|
|
29638
|
-
result.files.push(new FileStatusSummary(
|
|
29878
|
+
result.files.push(new FileStatusSummary(path37, index, workingDir));
|
|
29639
29879
|
}
|
|
29640
29880
|
}
|
|
29641
29881
|
}
|
|
@@ -29944,9 +30184,9 @@ var init_simple_git_api = __esm2({
|
|
|
29944
30184
|
next
|
|
29945
30185
|
);
|
|
29946
30186
|
}
|
|
29947
|
-
hashObject(
|
|
30187
|
+
hashObject(path37, write) {
|
|
29948
30188
|
return this._runTask(
|
|
29949
|
-
hashObjectTask(
|
|
30189
|
+
hashObjectTask(path37, write === true),
|
|
29950
30190
|
trailingFunctionArgument(arguments)
|
|
29951
30191
|
);
|
|
29952
30192
|
}
|
|
@@ -30299,8 +30539,8 @@ var init_branch = __esm2({
|
|
|
30299
30539
|
}
|
|
30300
30540
|
});
|
|
30301
30541
|
function toPath(input) {
|
|
30302
|
-
const
|
|
30303
|
-
return
|
|
30542
|
+
const path37 = input.trim().replace(/^["']|["']$/g, "");
|
|
30543
|
+
return path37 && normalize(path37);
|
|
30304
30544
|
}
|
|
30305
30545
|
var parseCheckIgnore;
|
|
30306
30546
|
var init_CheckIgnore = __esm2({
|
|
@@ -30614,8 +30854,8 @@ __export2(sub_module_exports, {
|
|
|
30614
30854
|
subModuleTask: () => subModuleTask,
|
|
30615
30855
|
updateSubModuleTask: () => updateSubModuleTask
|
|
30616
30856
|
});
|
|
30617
|
-
function addSubModuleTask(repo,
|
|
30618
|
-
return subModuleTask(["add", repo,
|
|
30857
|
+
function addSubModuleTask(repo, path37) {
|
|
30858
|
+
return subModuleTask(["add", repo, path37]);
|
|
30619
30859
|
}
|
|
30620
30860
|
function initSubModuleTask(customArgs) {
|
|
30621
30861
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -30948,8 +31188,8 @@ var require_git = __commonJS2({
|
|
|
30948
31188
|
}
|
|
30949
31189
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
30950
31190
|
};
|
|
30951
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
30952
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
31191
|
+
Git2.prototype.submoduleAdd = function(repo, path37, then) {
|
|
31192
|
+
return this._runTask(addSubModuleTask2(repo, path37), trailingFunctionArgument2(arguments));
|
|
30953
31193
|
};
|
|
30954
31194
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
30955
31195
|
return this._runTask(
|
|
@@ -31549,10 +31789,28 @@ function gitInstanceFactory(baseDir, options) {
|
|
|
31549
31789
|
init_git_response_error();
|
|
31550
31790
|
var simpleGit = gitInstanceFactory;
|
|
31551
31791
|
|
|
31792
|
+
// src/git/cli-simple-git.ts
|
|
31793
|
+
function cliSimpleGit(baseDir) {
|
|
31794
|
+
const git = simpleGit({ baseDir });
|
|
31795
|
+
git.outputHandler((command, stdout, stderr) => {
|
|
31796
|
+
const trace = isCliTrace();
|
|
31797
|
+
const onChunk = (label) => (chunk) => {
|
|
31798
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
31799
|
+
const line = text.replace(/\s+$/, "");
|
|
31800
|
+
if (trace && line) {
|
|
31801
|
+
logTrace(`[git ${command}] ${label}: ${line}`);
|
|
31802
|
+
}
|
|
31803
|
+
};
|
|
31804
|
+
stdout?.on("data", onChunk("stdout"));
|
|
31805
|
+
stderr?.on("data", onChunk("stderr"));
|
|
31806
|
+
});
|
|
31807
|
+
return git;
|
|
31808
|
+
}
|
|
31809
|
+
|
|
31552
31810
|
// src/git/remote-origin-url.ts
|
|
31553
31811
|
async function getRemoteOriginUrl(gitDir) {
|
|
31554
31812
|
try {
|
|
31555
|
-
const git =
|
|
31813
|
+
const git = cliSimpleGit(gitDir);
|
|
31556
31814
|
const remotes = await git.getRemotes(true);
|
|
31557
31815
|
const list = Array.isArray(remotes) ? remotes : [];
|
|
31558
31816
|
const origin = list.find((r) => r.name === "origin");
|
|
@@ -31566,7 +31824,7 @@ async function getRemoteOriginUrl(gitDir) {
|
|
|
31566
31824
|
// src/git/is-git-repo.ts
|
|
31567
31825
|
async function isGitRepoDirectory(dirPath) {
|
|
31568
31826
|
try {
|
|
31569
|
-
return await
|
|
31827
|
+
return await cliSimpleGit(dirPath).checkIsRepo();
|
|
31570
31828
|
} catch {
|
|
31571
31829
|
return false;
|
|
31572
31830
|
}
|
|
@@ -31818,9 +32076,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
31818
32076
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
31819
32077
|
async function putEncryptedChangeSummaryRows(params) {
|
|
31820
32078
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
31821
|
-
const entries = params.rows.map(({ path:
|
|
32079
|
+
const entries = params.rows.map(({ path: path37, summary }) => {
|
|
31822
32080
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
31823
|
-
return { path:
|
|
32081
|
+
return { path: path37, summary: JSON.stringify(enc) };
|
|
31824
32082
|
});
|
|
31825
32083
|
const res = await fetch(
|
|
31826
32084
|
`${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -32002,8 +32260,8 @@ async function sendPromptToAgent(options) {
|
|
|
32002
32260
|
}
|
|
32003
32261
|
|
|
32004
32262
|
// src/agents/acp/ensure-acp-client.ts
|
|
32005
|
-
import * as
|
|
32006
|
-
import * as
|
|
32263
|
+
import * as fs11 from "node:fs";
|
|
32264
|
+
import * as path13 from "node:path";
|
|
32007
32265
|
|
|
32008
32266
|
// src/error-message.ts
|
|
32009
32267
|
function errorMessage(err) {
|
|
@@ -32039,76 +32297,10 @@ async function isCommandOnPath(command, timeoutMs = 4e3) {
|
|
|
32039
32297
|
}
|
|
32040
32298
|
}
|
|
32041
32299
|
|
|
32042
|
-
// src/agents/acp/clients/sdk-stdio-acp-client.ts
|
|
32300
|
+
// src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
|
|
32043
32301
|
import { spawn as spawn2 } from "node:child_process";
|
|
32044
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
32045
|
-
import { dirname as dirname2 } from "node:path";
|
|
32046
32302
|
import { Readable, Writable } from "node:stream";
|
|
32047
32303
|
|
|
32048
|
-
// src/files/diff/unified-diff.ts
|
|
32049
|
-
function computeLineDiff(oldText, newText) {
|
|
32050
|
-
const oldLines = oldText.split("\n");
|
|
32051
|
-
const newLines = newText.split("\n");
|
|
32052
|
-
const m = oldLines.length;
|
|
32053
|
-
const n = newLines.length;
|
|
32054
|
-
const dp = Array(m + 1);
|
|
32055
|
-
for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
|
|
32056
|
-
for (let i2 = 1; i2 <= m; i2++) {
|
|
32057
|
-
for (let j2 = 1; j2 <= n; j2++) {
|
|
32058
|
-
if (oldLines[i2 - 1] === newLines[j2 - 1]) {
|
|
32059
|
-
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
32060
|
-
} else {
|
|
32061
|
-
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
32062
|
-
}
|
|
32063
|
-
}
|
|
32064
|
-
}
|
|
32065
|
-
const result = [];
|
|
32066
|
-
let i = m;
|
|
32067
|
-
let j = n;
|
|
32068
|
-
while (i > 0 || j > 0) {
|
|
32069
|
-
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
32070
|
-
result.unshift({ type: "context", line: oldLines[i - 1] });
|
|
32071
|
-
i--;
|
|
32072
|
-
j--;
|
|
32073
|
-
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
32074
|
-
result.unshift({ type: "add", line: newLines[j - 1] });
|
|
32075
|
-
j--;
|
|
32076
|
-
} else {
|
|
32077
|
-
result.unshift({ type: "remove", line: oldLines[i - 1] });
|
|
32078
|
-
i--;
|
|
32079
|
-
}
|
|
32080
|
-
}
|
|
32081
|
-
return result;
|
|
32082
|
-
}
|
|
32083
|
-
function editSnippetToUnifiedDiff(filePath, oldText, newText) {
|
|
32084
|
-
const lines = computeLineDiff(oldText, newText);
|
|
32085
|
-
const out = [`--- ${filePath}`, `+++ ${filePath}`];
|
|
32086
|
-
for (const d of lines) {
|
|
32087
|
-
if (d.type === "add") out.push(`+${d.line}`);
|
|
32088
|
-
else if (d.type === "remove") out.push(`-${d.line}`);
|
|
32089
|
-
else out.push(` ${d.line}`);
|
|
32090
|
-
}
|
|
32091
|
-
return out.join("\n");
|
|
32092
|
-
}
|
|
32093
|
-
|
|
32094
|
-
// src/agents/acp/safe-fs-path.ts
|
|
32095
|
-
import * as path9 from "node:path";
|
|
32096
|
-
function resolveSafePathUnderCwd(cwd, filePath) {
|
|
32097
|
-
const trimmed2 = filePath.trim();
|
|
32098
|
-
if (!trimmed2) return null;
|
|
32099
|
-
const normalizedCwd = path9.resolve(cwd);
|
|
32100
|
-
const resolved = path9.isAbsolute(trimmed2) ? path9.normalize(trimmed2) : path9.resolve(normalizedCwd, trimmed2);
|
|
32101
|
-
const rel = path9.relative(normalizedCwd, resolved);
|
|
32102
|
-
if (rel.startsWith("..") || path9.isAbsolute(rel)) return null;
|
|
32103
|
-
return resolved;
|
|
32104
|
-
}
|
|
32105
|
-
function toDisplayPathRelativeToCwd(cwd, absolutePath) {
|
|
32106
|
-
const normalizedCwd = path9.resolve(cwd);
|
|
32107
|
-
const rel = path9.relative(normalizedCwd, path9.resolve(absolutePath));
|
|
32108
|
-
if (!rel || rel === "") return path9.basename(absolutePath);
|
|
32109
|
-
return rel.split(path9.sep).join("/");
|
|
32110
|
-
}
|
|
32111
|
-
|
|
32112
32304
|
// src/agents/acp/clients/agent-stderr-capture.ts
|
|
32113
32305
|
var STDERR_CAPTURE_MAX = 48e3;
|
|
32114
32306
|
function createStderrCapture(child) {
|
|
@@ -32173,7 +32365,7 @@ function createKiroSdkExtNotificationHandler(options) {
|
|
|
32173
32365
|
};
|
|
32174
32366
|
}
|
|
32175
32367
|
|
|
32176
|
-
// src/agents/acp/clients/sdk-stdio-ext-notifications.ts
|
|
32368
|
+
// src/agents/acp/clients/sdk/sdk-stdio-ext-notifications.ts
|
|
32177
32369
|
var noopExtNotification = async () => {
|
|
32178
32370
|
};
|
|
32179
32371
|
function createSdkStdioExtNotificationHandler(options) {
|
|
@@ -32232,23 +32424,364 @@ function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
|
|
|
32232
32424
|
};
|
|
32233
32425
|
}
|
|
32234
32426
|
|
|
32235
|
-
// src/agents/acp/clients/
|
|
32236
|
-
|
|
32237
|
-
|
|
32238
|
-
|
|
32427
|
+
// src/agents/acp/clients/shared/acp-fs-read-write.ts
|
|
32428
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
32429
|
+
import { dirname as dirname2 } from "node:path";
|
|
32430
|
+
|
|
32431
|
+
// src/files/diff/unified-diff.ts
|
|
32432
|
+
function computeLineDiff(oldText, newText) {
|
|
32433
|
+
const oldLines = oldText.split("\n");
|
|
32434
|
+
const newLines = newText.split("\n");
|
|
32435
|
+
const m = oldLines.length;
|
|
32436
|
+
const n = newLines.length;
|
|
32437
|
+
const dp = Array(m + 1);
|
|
32438
|
+
for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
|
|
32439
|
+
for (let i2 = 1; i2 <= m; i2++) {
|
|
32440
|
+
for (let j2 = 1; j2 <= n; j2++) {
|
|
32441
|
+
if (oldLines[i2 - 1] === newLines[j2 - 1]) {
|
|
32442
|
+
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
32443
|
+
} else {
|
|
32444
|
+
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
32445
|
+
}
|
|
32446
|
+
}
|
|
32239
32447
|
}
|
|
32240
|
-
|
|
32448
|
+
const result = [];
|
|
32449
|
+
let i = m;
|
|
32450
|
+
let j = n;
|
|
32451
|
+
while (i > 0 || j > 0) {
|
|
32452
|
+
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
32453
|
+
result.unshift({ type: "context", line: oldLines[i - 1] });
|
|
32454
|
+
i--;
|
|
32455
|
+
j--;
|
|
32456
|
+
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
32457
|
+
result.unshift({ type: "add", line: newLines[j - 1] });
|
|
32458
|
+
j--;
|
|
32459
|
+
} else {
|
|
32460
|
+
result.unshift({ type: "remove", line: oldLines[i - 1] });
|
|
32461
|
+
i--;
|
|
32462
|
+
}
|
|
32463
|
+
}
|
|
32464
|
+
return result;
|
|
32465
|
+
}
|
|
32466
|
+
function editSnippetToUnifiedDiff(filePath, oldText, newText) {
|
|
32467
|
+
const lines = computeLineDiff(oldText, newText);
|
|
32468
|
+
const out = [`--- ${filePath}`, `+++ ${filePath}`];
|
|
32469
|
+
for (const d of lines) {
|
|
32470
|
+
if (d.type === "add") out.push(`+${d.line}`);
|
|
32471
|
+
else if (d.type === "remove") out.push(`-${d.line}`);
|
|
32472
|
+
else out.push(` ${d.line}`);
|
|
32473
|
+
}
|
|
32474
|
+
return out.join("\n");
|
|
32475
|
+
}
|
|
32476
|
+
|
|
32477
|
+
// src/agents/acp/safe-fs-path.ts
|
|
32478
|
+
import * as path9 from "node:path";
|
|
32479
|
+
function resolveSafePathUnderCwd(cwd, filePath) {
|
|
32480
|
+
const trimmed2 = filePath.trim();
|
|
32481
|
+
if (!trimmed2) return null;
|
|
32482
|
+
const normalizedCwd = path9.resolve(cwd);
|
|
32483
|
+
const resolved = path9.isAbsolute(trimmed2) ? path9.normalize(trimmed2) : path9.resolve(normalizedCwd, trimmed2);
|
|
32484
|
+
const rel = path9.relative(normalizedCwd, resolved);
|
|
32485
|
+
if (rel.startsWith("..") || path9.isAbsolute(rel)) return null;
|
|
32486
|
+
return resolved;
|
|
32241
32487
|
}
|
|
32242
|
-
function
|
|
32488
|
+
function toDisplayPathRelativeToCwd(cwd, absolutePath) {
|
|
32489
|
+
const normalizedCwd = path9.resolve(cwd);
|
|
32490
|
+
const rel = path9.relative(normalizedCwd, path9.resolve(absolutePath));
|
|
32491
|
+
if (!rel || rel === "") return path9.basename(absolutePath);
|
|
32492
|
+
return rel.split(path9.sep).join("/");
|
|
32493
|
+
}
|
|
32494
|
+
|
|
32495
|
+
// src/agents/acp/clients/shared/acp-fs-read-write.ts
|
|
32496
|
+
function sliceFileContentForAcp(content, line, limit) {
|
|
32243
32497
|
if (line == null && limit == null) return content;
|
|
32244
32498
|
const lines = content.split("\n");
|
|
32245
32499
|
const start = line != null && line > 0 ? line - 1 : 0;
|
|
32246
32500
|
const end = limit != null && limit > 0 ? start + limit : lines.length;
|
|
32247
32501
|
return lines.slice(start, end).join("\n");
|
|
32248
32502
|
}
|
|
32249
|
-
function
|
|
32503
|
+
function acpReadTextFileInProcess(ctx, filePath, line, limit) {
|
|
32504
|
+
const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
|
|
32505
|
+
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32506
|
+
try {
|
|
32507
|
+
let content = readFileSync2(resolvedPath, "utf8");
|
|
32508
|
+
content = sliceFileContentForAcp(content, line, limit);
|
|
32509
|
+
return { content };
|
|
32510
|
+
} catch (e) {
|
|
32511
|
+
if (e.code === "ENOENT") return { content: "" };
|
|
32512
|
+
throw e;
|
|
32513
|
+
}
|
|
32514
|
+
}
|
|
32515
|
+
function acpWriteTextFileInProcess(ctx, filePath, newText) {
|
|
32516
|
+
const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
|
|
32517
|
+
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32518
|
+
let oldText = "";
|
|
32519
|
+
try {
|
|
32520
|
+
oldText = readFileSync2(resolvedPath, "utf8");
|
|
32521
|
+
} catch (e) {
|
|
32522
|
+
if (e.code !== "ENOENT") throw e;
|
|
32523
|
+
}
|
|
32524
|
+
mkdirSync2(dirname2(resolvedPath), { recursive: true });
|
|
32525
|
+
writeFileSync2(resolvedPath, newText, "utf8");
|
|
32526
|
+
const displayPath = toDisplayPathRelativeToCwd(ctx.cwd, resolvedPath);
|
|
32527
|
+
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
32528
|
+
ctx.onFileChange?.({ path: displayPath, oldText, newText, patchContent });
|
|
32529
|
+
return {};
|
|
32530
|
+
}
|
|
32531
|
+
|
|
32532
|
+
// src/agents/acp/claude-acp-permission-from-session.ts
|
|
32533
|
+
function flattenSelectOptions(options) {
|
|
32534
|
+
if (options == null || options.length === 0) return [];
|
|
32535
|
+
const first2 = options[0];
|
|
32536
|
+
if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
|
|
32537
|
+
return options.flatMap(
|
|
32538
|
+
(g) => Array.isArray(g.options) ? g.options : []
|
|
32539
|
+
);
|
|
32540
|
+
}
|
|
32541
|
+
return options;
|
|
32542
|
+
}
|
|
32543
|
+
function pickModeConfigOption(configOptions) {
|
|
32544
|
+
if (configOptions == null || configOptions.length === 0) return null;
|
|
32545
|
+
const byCategory = configOptions.find((o) => o.category === "mode");
|
|
32546
|
+
if (byCategory) return byCategory;
|
|
32547
|
+
return configOptions.find((o) => o.id === "mode") ?? null;
|
|
32548
|
+
}
|
|
32549
|
+
async function applyClaudePermissionFromAcpSession(params) {
|
|
32550
|
+
const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
|
|
32551
|
+
const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
|
|
32552
|
+
if (desiredMode == null) return;
|
|
32553
|
+
const modeOpt = pickModeConfigOption(configOptions ?? null);
|
|
32554
|
+
if (modeOpt != null) {
|
|
32555
|
+
const flat = flattenSelectOptions(modeOpt.options);
|
|
32556
|
+
const allowed = flat.some((o) => o.value === desiredMode);
|
|
32557
|
+
if (allowed && modeOpt.currentValue !== desiredMode) {
|
|
32558
|
+
try {
|
|
32559
|
+
logDebug2(
|
|
32560
|
+
`[Agent] Claude Code: sending ACP session/set_config_option (permission mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
|
|
32561
|
+
);
|
|
32562
|
+
await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
|
|
32563
|
+
} catch (e) {
|
|
32564
|
+
logDebug2(
|
|
32565
|
+
`[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
|
|
32566
|
+
);
|
|
32567
|
+
}
|
|
32568
|
+
}
|
|
32569
|
+
return;
|
|
32570
|
+
}
|
|
32571
|
+
if (modes?.availableModes?.length) {
|
|
32572
|
+
const allowed = modes.availableModes.some((m) => m.id === desiredMode);
|
|
32573
|
+
if (allowed && desiredMode !== modes.currentModeId) {
|
|
32574
|
+
try {
|
|
32575
|
+
logDebug2(
|
|
32576
|
+
`[Agent] Claude Code: sending ACP session/set_mode (permission mode) modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
|
|
32577
|
+
);
|
|
32578
|
+
await setSessionMode({ sessionId, modeId: desiredMode });
|
|
32579
|
+
} catch (e) {
|
|
32580
|
+
logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
32581
|
+
}
|
|
32582
|
+
}
|
|
32583
|
+
}
|
|
32584
|
+
}
|
|
32585
|
+
|
|
32586
|
+
// src/agents/acp/clients/shared/config-options-for-permission.ts
|
|
32587
|
+
function configOptionsForPermission(getActive, established) {
|
|
32588
|
+
const mem = getActive?.();
|
|
32589
|
+
if (Array.isArray(mem) && mem.length > 0) return mem;
|
|
32590
|
+
return established ?? void 0;
|
|
32591
|
+
}
|
|
32592
|
+
|
|
32593
|
+
// src/agents/acp/clients/shared/establish-acp-session.ts
|
|
32594
|
+
function establishedFromResult(raw, sessionId) {
|
|
32595
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
32596
|
+
return {
|
|
32597
|
+
sessionId,
|
|
32598
|
+
configOptions: Array.isArray(r.configOptions) ? r.configOptions : null,
|
|
32599
|
+
modes: r.modes ?? null
|
|
32600
|
+
};
|
|
32601
|
+
}
|
|
32602
|
+
function sessionIdFromNewSessionResult(raw) {
|
|
32603
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
32604
|
+
return typeof r.sessionId === "string" ? r.sessionId : "";
|
|
32605
|
+
}
|
|
32606
|
+
async function establishAcpSessionWithTransport(transport, ctx, canResume, canLoad) {
|
|
32607
|
+
const { cwd, mcpServers, persistedAcpSessionId, agentLabel, suppressLoadReplay } = ctx;
|
|
32608
|
+
const prev = typeof persistedAcpSessionId === "string" && persistedAcpSessionId.trim() !== "" ? persistedAcpSessionId.trim() : "";
|
|
32609
|
+
if (prev) {
|
|
32610
|
+
if (canResume) {
|
|
32611
|
+
try {
|
|
32612
|
+
logDebug(`[Agent] ${agentLabel} ACP session/resume for stored session ${prev.slice(0, 8)}\u2026`);
|
|
32613
|
+
const result2 = await transport.resumeSession({ sessionId: prev, cwd, mcpServers });
|
|
32614
|
+
return establishedFromResult(result2, prev);
|
|
32615
|
+
} catch (e) {
|
|
32616
|
+
logDebug(`[Agent] ${agentLabel} ACP session/resume failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
32617
|
+
}
|
|
32618
|
+
}
|
|
32619
|
+
if (canLoad) {
|
|
32620
|
+
suppressLoadReplay.value = true;
|
|
32621
|
+
try {
|
|
32622
|
+
logDebug(`[Agent] ${agentLabel} ACP session/load for stored session ${prev.slice(0, 8)}\u2026`);
|
|
32623
|
+
const result2 = await transport.loadSession({ sessionId: prev, cwd, mcpServers });
|
|
32624
|
+
return establishedFromResult(result2, prev);
|
|
32625
|
+
} catch (e) {
|
|
32626
|
+
logDebug(`[Agent] ${agentLabel} ACP session/load failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
32627
|
+
} finally {
|
|
32628
|
+
suppressLoadReplay.value = false;
|
|
32629
|
+
}
|
|
32630
|
+
}
|
|
32631
|
+
}
|
|
32632
|
+
const result = await transport.newSession({ cwd, mcpServers });
|
|
32633
|
+
const sid = sessionIdFromNewSessionResult(result);
|
|
32634
|
+
if (!sid) throw new Error(`${agentLabel} ACP session/new did not return sessionId`);
|
|
32635
|
+
return establishedFromResult(result, sid);
|
|
32636
|
+
}
|
|
32637
|
+
|
|
32638
|
+
// src/agents/acp/clients/shared/parse-acp-init-capabilities.ts
|
|
32639
|
+
function parseAcpInitAgentCapabilities(initResult) {
|
|
32640
|
+
const agentCapabilities = initResult?.agentCapabilities;
|
|
32641
|
+
const canLoad = agentCapabilities?.loadSession === true;
|
|
32642
|
+
const sessionCaps = agentCapabilities?.sessionCapabilities;
|
|
32643
|
+
const canResume = Boolean(sessionCaps?.resume);
|
|
32644
|
+
return { canResume, canLoad };
|
|
32645
|
+
}
|
|
32646
|
+
|
|
32647
|
+
// src/agents/acp/clients/shared/bootstrap-acp-wire-session.ts
|
|
32648
|
+
async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
|
|
32649
|
+
const initResult = await transport.initialize(initializeRequest);
|
|
32650
|
+
const { canResume, canLoad } = parseAcpInitAgentCapabilities(initResult);
|
|
32651
|
+
await transport.afterInitialize?.();
|
|
32652
|
+
const established = await establishAcpSessionWithTransport(transport, ctx, canResume, canLoad);
|
|
32653
|
+
const sessionId = established.sessionId;
|
|
32654
|
+
ctx.onAcpSessionEstablished?.({
|
|
32655
|
+
acpSessionId: sessionId,
|
|
32656
|
+
configOptions: established.configOptions,
|
|
32657
|
+
modes: established.modes
|
|
32658
|
+
});
|
|
32659
|
+
if (ctx.backendAgentType === "claude-code") {
|
|
32660
|
+
const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
|
|
32661
|
+
const configOptionsTyped = established.configOptions;
|
|
32662
|
+
const modesTyped = established.modes;
|
|
32663
|
+
await applyClaudePermissionFromAcpSession({
|
|
32664
|
+
sessionId,
|
|
32665
|
+
agentConfig: cfg,
|
|
32666
|
+
configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
|
|
32667
|
+
modes: modesTyped,
|
|
32668
|
+
setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
|
|
32669
|
+
},
|
|
32670
|
+
setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
|
|
32671
|
+
},
|
|
32672
|
+
logDebug: ctx.logDebug
|
|
32673
|
+
});
|
|
32674
|
+
}
|
|
32675
|
+
return established;
|
|
32676
|
+
}
|
|
32677
|
+
|
|
32678
|
+
// src/agents/acp/clients/shared/dispatch-session-update.ts
|
|
32679
|
+
function dispatchAcpSessionUpdate(opts) {
|
|
32680
|
+
const { flatPayload, onAcpConfigOptionsUpdated, onSessionUpdate, suppressLoadReplay } = opts;
|
|
32681
|
+
const su = flatPayload.sessionUpdate ?? flatPayload.session_update;
|
|
32682
|
+
if (su === "config_option_update") {
|
|
32683
|
+
const co = flatPayload.configOptions;
|
|
32684
|
+
if (Array.isArray(co)) onAcpConfigOptionsUpdated?.(co);
|
|
32685
|
+
return;
|
|
32686
|
+
}
|
|
32687
|
+
if (suppressLoadReplay()) return;
|
|
32688
|
+
onSessionUpdate?.(flatPayload);
|
|
32689
|
+
}
|
|
32690
|
+
|
|
32691
|
+
// src/agents/acp/clients/shared/flatten-sdk-session-notification.ts
|
|
32692
|
+
function flattenSdkSessionNotificationParams(params) {
|
|
32250
32693
|
return { sessionId: params.sessionId, ...params.update };
|
|
32251
32694
|
}
|
|
32695
|
+
|
|
32696
|
+
// src/agents/acp/clients/shared/normalize-acp-prompt-result.ts
|
|
32697
|
+
function normalizeAcpPromptTurnSuccess(opts) {
|
|
32698
|
+
const { stopReason, output, stderrCaptureText, backendAgentType } = opts;
|
|
32699
|
+
const mergedOutput = output || void 0;
|
|
32700
|
+
const stop = (stopReason ?? "").toLowerCase();
|
|
32701
|
+
const cancelled = stop === "cancelled";
|
|
32702
|
+
const refusal = stop === "refusal";
|
|
32703
|
+
const stderrEvaluated = Boolean(stderrCaptureText && backendAgentType);
|
|
32704
|
+
const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(backendAgentType, stderrCaptureText) : false;
|
|
32705
|
+
if (cancelled) {
|
|
32706
|
+
return {
|
|
32707
|
+
success: false,
|
|
32708
|
+
stopReason,
|
|
32709
|
+
output: mergedOutput,
|
|
32710
|
+
error: mergeErrorWithStderr("Stopped by user", stderrCaptureText)
|
|
32711
|
+
};
|
|
32712
|
+
}
|
|
32713
|
+
if (refusal) {
|
|
32714
|
+
return {
|
|
32715
|
+
success: false,
|
|
32716
|
+
stopReason,
|
|
32717
|
+
output: mergedOutput,
|
|
32718
|
+
error: mergeErrorWithStderr("The agent refused the request.", stderrCaptureText)
|
|
32719
|
+
};
|
|
32720
|
+
}
|
|
32721
|
+
if (stderrSuggestsAuth) {
|
|
32722
|
+
return {
|
|
32723
|
+
success: false,
|
|
32724
|
+
stopReason,
|
|
32725
|
+
output: mergedOutput,
|
|
32726
|
+
error: stderrCaptureText
|
|
32727
|
+
};
|
|
32728
|
+
}
|
|
32729
|
+
return {
|
|
32730
|
+
success: true,
|
|
32731
|
+
stopReason,
|
|
32732
|
+
output: mergedOutput
|
|
32733
|
+
};
|
|
32734
|
+
}
|
|
32735
|
+
function normalizeAcpPromptTurnFailure(err, stderrCaptureText) {
|
|
32736
|
+
const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCaptureText);
|
|
32737
|
+
return { success: false, error: merged };
|
|
32738
|
+
}
|
|
32739
|
+
|
|
32740
|
+
// src/agents/acp/clients/shared/send-acp-prompt-via-transport.ts
|
|
32741
|
+
async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText) {
|
|
32742
|
+
try {
|
|
32743
|
+
const response = await transport.prompt({
|
|
32744
|
+
sessionId,
|
|
32745
|
+
prompt: [{ type: "text", text: promptText }]
|
|
32746
|
+
});
|
|
32747
|
+
await new Promise((r2) => setImmediate(r2));
|
|
32748
|
+
const r = response;
|
|
32749
|
+
return normalizeAcpPromptTurnSuccess({
|
|
32750
|
+
stopReason: r?.stopReason,
|
|
32751
|
+
output: r?.output,
|
|
32752
|
+
stderrCaptureText: ctx.getStderrText(),
|
|
32753
|
+
backendAgentType: ctx.backendAgentType
|
|
32754
|
+
});
|
|
32755
|
+
} catch (err) {
|
|
32756
|
+
await new Promise((r) => setImmediate(r));
|
|
32757
|
+
return normalizeAcpPromptTurnFailure(err, ctx.getStderrText());
|
|
32758
|
+
}
|
|
32759
|
+
}
|
|
32760
|
+
|
|
32761
|
+
// src/agents/acp/clients/sdk/sdk-acp-session-transport.ts
|
|
32762
|
+
function createSdkAcpSessionTransport(connection) {
|
|
32763
|
+
const c = connection;
|
|
32764
|
+
return {
|
|
32765
|
+
initialize: (request) => c.initialize(request),
|
|
32766
|
+
resumeSession: (p) => c.unstable_resumeSession(p),
|
|
32767
|
+
loadSession: (p) => c.loadSession(p),
|
|
32768
|
+
newSession: (p) => c.newSession(p),
|
|
32769
|
+
prompt: (p) => c.prompt(p),
|
|
32770
|
+
cancelSession: async (sessionId) => {
|
|
32771
|
+
await c.cancel({ sessionId });
|
|
32772
|
+
},
|
|
32773
|
+
setSessionConfigOption: c.setSessionConfigOption ? (p) => c.setSessionConfigOption(p) : void 0,
|
|
32774
|
+
setSessionMode: c.setSessionMode ? (p) => c.setSessionMode(p) : void 0
|
|
32775
|
+
};
|
|
32776
|
+
}
|
|
32777
|
+
|
|
32778
|
+
// src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
|
|
32779
|
+
function formatSpawnError(err, command) {
|
|
32780
|
+
if (err.code === "ENOENT") {
|
|
32781
|
+
return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
|
|
32782
|
+
}
|
|
32783
|
+
return err.message || String(err);
|
|
32784
|
+
}
|
|
32252
32785
|
async function createSdkStdioAcpClient(options) {
|
|
32253
32786
|
const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
|
|
32254
32787
|
const {
|
|
@@ -32259,7 +32792,12 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32259
32792
|
onRequest,
|
|
32260
32793
|
onFileChange,
|
|
32261
32794
|
killSubprocessAfterCancelMs,
|
|
32262
|
-
onAgentSubprocessExit
|
|
32795
|
+
onAgentSubprocessExit,
|
|
32796
|
+
agentConfig,
|
|
32797
|
+
persistedAcpSessionId,
|
|
32798
|
+
onAcpSessionEstablished,
|
|
32799
|
+
onAcpConfigOptionsUpdated,
|
|
32800
|
+
getActiveConfigOptions
|
|
32263
32801
|
} = options;
|
|
32264
32802
|
const isWindows = process.platform === "win32";
|
|
32265
32803
|
const child = spawn2(command[0], command.slice(1), {
|
|
@@ -32308,6 +32846,22 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32308
32846
|
backendAgentType,
|
|
32309
32847
|
onSessionUpdate
|
|
32310
32848
|
});
|
|
32849
|
+
const suppressLoadReplayRef = { value: false };
|
|
32850
|
+
const sessionCtx = {
|
|
32851
|
+
cwd,
|
|
32852
|
+
onFileChange,
|
|
32853
|
+
mcpServers: [],
|
|
32854
|
+
persistedAcpSessionId,
|
|
32855
|
+
agentLabel: "ACP",
|
|
32856
|
+
suppressLoadReplay: suppressLoadReplayRef,
|
|
32857
|
+
backendAgentType: backendAgentType ?? null,
|
|
32858
|
+
agentConfig,
|
|
32859
|
+
getActiveConfigOptions,
|
|
32860
|
+
onAcpSessionEstablished,
|
|
32861
|
+
onAcpConfigOptionsUpdated,
|
|
32862
|
+
logDebug,
|
|
32863
|
+
getStderrText: () => stderrCapture.getText()
|
|
32864
|
+
};
|
|
32311
32865
|
let permissionSeq = 0;
|
|
32312
32866
|
const pendingPermissionReplies = /* @__PURE__ */ new Map();
|
|
32313
32867
|
const client = (_agent) => ({
|
|
@@ -32327,35 +32881,19 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32327
32881
|
});
|
|
32328
32882
|
},
|
|
32329
32883
|
async readTextFile(params) {
|
|
32330
|
-
|
|
32331
|
-
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32332
|
-
try {
|
|
32333
|
-
let content = readFileSync2(resolvedPath, "utf8");
|
|
32334
|
-
content = sliceFileContentRange(content, params.line, params.limit);
|
|
32335
|
-
return { content };
|
|
32336
|
-
} catch (e) {
|
|
32337
|
-
if (e.code === "ENOENT") return { content: "" };
|
|
32338
|
-
throw e;
|
|
32339
|
-
}
|
|
32884
|
+
return acpReadTextFileInProcess(sessionCtx, params.path, params.line, params.limit);
|
|
32340
32885
|
},
|
|
32341
32886
|
async writeTextFile(params) {
|
|
32342
|
-
|
|
32343
|
-
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32344
|
-
let oldText = "";
|
|
32345
|
-
try {
|
|
32346
|
-
oldText = readFileSync2(resolvedPath, "utf8");
|
|
32347
|
-
} catch (e) {
|
|
32348
|
-
if (e.code !== "ENOENT") throw e;
|
|
32349
|
-
}
|
|
32350
|
-
mkdirSync2(dirname2(resolvedPath), { recursive: true });
|
|
32351
|
-
writeFileSync2(resolvedPath, params.content, "utf8");
|
|
32352
|
-
const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
|
|
32353
|
-
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, params.content);
|
|
32354
|
-
onFileChange?.({ path: displayPath, oldText, newText: params.content, patchContent });
|
|
32355
|
-
return {};
|
|
32887
|
+
return acpWriteTextFileInProcess(sessionCtx, params.path, params.content);
|
|
32356
32888
|
},
|
|
32357
32889
|
async sessionUpdate(params) {
|
|
32358
|
-
|
|
32890
|
+
const bridged = flattenSdkSessionNotificationParams(params);
|
|
32891
|
+
dispatchAcpSessionUpdate({
|
|
32892
|
+
flatPayload: bridged,
|
|
32893
|
+
onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
|
|
32894
|
+
onSessionUpdate,
|
|
32895
|
+
suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
|
|
32896
|
+
});
|
|
32359
32897
|
},
|
|
32360
32898
|
async extNotification(method, params) {
|
|
32361
32899
|
await extNotification(method, params);
|
|
@@ -32365,70 +32903,19 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32365
32903
|
connection.signal.addEventListener("abort", () => {
|
|
32366
32904
|
child.kill();
|
|
32367
32905
|
});
|
|
32368
|
-
|
|
32906
|
+
const transport = createSdkAcpSessionTransport(connection);
|
|
32907
|
+
const established = await bootstrapAcpWireSession(transport, sessionCtx, {
|
|
32369
32908
|
protocolVersion: PROTOCOL_VERSION2,
|
|
32370
32909
|
clientCapabilities: {
|
|
32371
32910
|
fs: { readTextFile: true, writeTextFile: true }
|
|
32372
32911
|
},
|
|
32373
32912
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
32374
32913
|
});
|
|
32375
|
-
const
|
|
32376
|
-
const sessionId = newSessionRes.sessionId;
|
|
32914
|
+
const sessionId = established.sessionId;
|
|
32377
32915
|
settleResolve({
|
|
32378
32916
|
sessionId,
|
|
32379
32917
|
async sendPrompt(prompt, _options) {
|
|
32380
|
-
|
|
32381
|
-
const response = await connection.prompt({
|
|
32382
|
-
sessionId,
|
|
32383
|
-
prompt: [{ type: "text", text: prompt }]
|
|
32384
|
-
});
|
|
32385
|
-
await new Promise((r2) => setImmediate(r2));
|
|
32386
|
-
const r = response;
|
|
32387
|
-
const stopReason = (r?.stopReason ?? "").toLowerCase();
|
|
32388
|
-
const cancelled = stopReason === "cancelled";
|
|
32389
|
-
const refusal = stopReason === "refusal";
|
|
32390
|
-
const stderrAfter = stderrCapture.getText();
|
|
32391
|
-
const agentType = backendAgentType ?? null;
|
|
32392
|
-
const stderrEvaluated = Boolean(stderrAfter && agentType);
|
|
32393
|
-
const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
|
|
32394
|
-
if (cancelled) {
|
|
32395
|
-
return {
|
|
32396
|
-
success: false,
|
|
32397
|
-
stopReason: r?.stopReason,
|
|
32398
|
-
output: r?.output,
|
|
32399
|
-
error: mergeErrorWithStderr("Stopped by user", stderrAfter)
|
|
32400
|
-
};
|
|
32401
|
-
}
|
|
32402
|
-
if (refusal) {
|
|
32403
|
-
return {
|
|
32404
|
-
success: false,
|
|
32405
|
-
stopReason: r?.stopReason,
|
|
32406
|
-
output: r?.output,
|
|
32407
|
-
error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
|
|
32408
|
-
};
|
|
32409
|
-
}
|
|
32410
|
-
if (stderrSuggestsAuth) {
|
|
32411
|
-
return {
|
|
32412
|
-
success: false,
|
|
32413
|
-
stopReason: r?.stopReason,
|
|
32414
|
-
output: r?.output,
|
|
32415
|
-
error: stderrAfter
|
|
32416
|
-
};
|
|
32417
|
-
}
|
|
32418
|
-
return {
|
|
32419
|
-
success: true,
|
|
32420
|
-
stopReason: r?.stopReason,
|
|
32421
|
-
output: r?.output
|
|
32422
|
-
};
|
|
32423
|
-
} catch (err) {
|
|
32424
|
-
await new Promise((r) => setImmediate(r));
|
|
32425
|
-
const stderrAfter = stderrCapture.getText();
|
|
32426
|
-
const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
|
|
32427
|
-
return {
|
|
32428
|
-
success: false,
|
|
32429
|
-
error: merged
|
|
32430
|
-
};
|
|
32431
|
-
}
|
|
32918
|
+
return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
|
|
32432
32919
|
},
|
|
32433
32920
|
async cancel() {
|
|
32434
32921
|
for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
|
|
@@ -32436,7 +32923,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32436
32923
|
entry.resolve({ outcome: { outcome: "cancelled" } });
|
|
32437
32924
|
}
|
|
32438
32925
|
try {
|
|
32439
|
-
await
|
|
32926
|
+
await transport.cancelSession(sessionId);
|
|
32440
32927
|
} catch {
|
|
32441
32928
|
}
|
|
32442
32929
|
if (killSubprocessAfterCancelMs != null && killSubprocessAfterCancelMs >= 0) {
|
|
@@ -32485,10 +32972,7 @@ async function detectLocalAgentPresence() {
|
|
|
32485
32972
|
return false;
|
|
32486
32973
|
}
|
|
32487
32974
|
}
|
|
32488
|
-
function buildClaudeCodeAcpSpawnCommand(base,
|
|
32489
|
-
if (!sessionMode) return [...base];
|
|
32490
|
-
const m = sessionMode.trim();
|
|
32491
|
-
if (m === "plan") return [...base, "--permission-mode", "plan"];
|
|
32975
|
+
function buildClaudeCodeAcpSpawnCommand(base, _sessionMode) {
|
|
32492
32976
|
return [...base];
|
|
32493
32977
|
}
|
|
32494
32978
|
async function createClaudeCodeAcpClient(options) {
|
|
@@ -32530,7 +33014,7 @@ async function createCodexAcpClient(options) {
|
|
|
32530
33014
|
return createSdkStdioAcpClient({ ...options, command });
|
|
32531
33015
|
}
|
|
32532
33016
|
|
|
32533
|
-
// src/agents/acp/clients/cursor-acp-client.ts
|
|
33017
|
+
// src/agents/acp/clients/cursor/cursor-acp-client.ts
|
|
32534
33018
|
var cursor_acp_client_exports = {};
|
|
32535
33019
|
__export(cursor_acp_client_exports, {
|
|
32536
33020
|
BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
|
|
@@ -32538,8 +33022,6 @@ __export(cursor_acp_client_exports, {
|
|
|
32538
33022
|
createCursorAcpClient: () => createCursorAcpClient,
|
|
32539
33023
|
detectLocalAgentPresence: () => detectLocalAgentPresence3
|
|
32540
33024
|
});
|
|
32541
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
|
|
32542
|
-
import { dirname as dirname3 } from "node:path";
|
|
32543
33025
|
import { spawn as spawn3 } from "node:child_process";
|
|
32544
33026
|
import * as readline from "node:readline";
|
|
32545
33027
|
|
|
@@ -32556,7 +33038,23 @@ function formatSessionUpdateKindForLog(kind) {
|
|
|
32556
33038
|
return kind.split("_").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
|
|
32557
33039
|
}
|
|
32558
33040
|
|
|
32559
|
-
// src/agents/acp/clients/cursor-acp-
|
|
33041
|
+
// src/agents/acp/clients/cursor/cursor-json-rpc-acp-transport.ts
|
|
33042
|
+
function createCursorJsonRpcAcpTransport(deps) {
|
|
33043
|
+
const { send, cancelSessionNotification } = deps;
|
|
33044
|
+
return {
|
|
33045
|
+
initialize: (request) => send("initialize", request),
|
|
33046
|
+
afterInitialize: async () => {
|
|
33047
|
+
await send("authenticate", { methodId: "cursor_login" });
|
|
33048
|
+
},
|
|
33049
|
+
resumeSession: (p) => send("session/resume", p),
|
|
33050
|
+
loadSession: (p) => send("session/load", p),
|
|
33051
|
+
newSession: (p) => send("session/new", p),
|
|
33052
|
+
prompt: (p) => send("session/prompt", p),
|
|
33053
|
+
cancelSession: (sessionId) => cancelSessionNotification(sessionId)
|
|
33054
|
+
};
|
|
33055
|
+
}
|
|
33056
|
+
|
|
33057
|
+
// src/agents/acp/clients/cursor/cursor-acp-client.ts
|
|
32560
33058
|
var FS_READ_METHODS = /* @__PURE__ */ new Set(["fs/read_text_file", "fs/readTextFile"]);
|
|
32561
33059
|
var FS_WRITE_METHODS = /* @__PURE__ */ new Set(["fs/write_text_file", "fs/writeTextFile"]);
|
|
32562
33060
|
function formatSpawnError2(err, command) {
|
|
@@ -32573,13 +33071,6 @@ function safeJsonParse(value) {
|
|
|
32573
33071
|
return null;
|
|
32574
33072
|
}
|
|
32575
33073
|
}
|
|
32576
|
-
function sliceLinesByRange(content, line, limit) {
|
|
32577
|
-
if (line == null && limit == null) return content;
|
|
32578
|
-
const lines = content.split("\n");
|
|
32579
|
-
const start = line != null && line > 0 ? line - 1 : 0;
|
|
32580
|
-
const end = limit != null && limit > 0 ? start + limit : lines.length;
|
|
32581
|
-
return lines.slice(start, end).join("\n");
|
|
32582
|
-
}
|
|
32583
33074
|
function buildCursorAcpSpawnCommand(base, sessionMode) {
|
|
32584
33075
|
if (!sessionMode) return [...base];
|
|
32585
33076
|
const m = sessionMode.trim();
|
|
@@ -32593,7 +33084,11 @@ async function createCursorAcpClient(options) {
|
|
|
32593
33084
|
backendAgentType,
|
|
32594
33085
|
onSessionUpdate,
|
|
32595
33086
|
onRequest,
|
|
32596
|
-
onFileChange
|
|
33087
|
+
onFileChange,
|
|
33088
|
+
persistedAcpSessionId,
|
|
33089
|
+
onAcpSessionEstablished,
|
|
33090
|
+
onAcpConfigOptionsUpdated,
|
|
33091
|
+
onAgentSubprocessExit
|
|
32597
33092
|
} = options;
|
|
32598
33093
|
const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
|
|
32599
33094
|
const isWindows = process.platform === "win32";
|
|
@@ -32605,6 +33100,25 @@ async function createCursorAcpClient(options) {
|
|
|
32605
33100
|
});
|
|
32606
33101
|
const stderrCapture = createStderrCapture(child);
|
|
32607
33102
|
child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
|
|
33103
|
+
child.once("close", (code, signal) => {
|
|
33104
|
+
onAgentSubprocessExit?.({ code, signal });
|
|
33105
|
+
});
|
|
33106
|
+
const suppressLoadReplayRef = { value: false };
|
|
33107
|
+
const sessionCtx = {
|
|
33108
|
+
cwd,
|
|
33109
|
+
onFileChange,
|
|
33110
|
+
mcpServers: [],
|
|
33111
|
+
persistedAcpSessionId,
|
|
33112
|
+
agentLabel: "Cursor",
|
|
33113
|
+
suppressLoadReplay: suppressLoadReplayRef,
|
|
33114
|
+
backendAgentType: backendAgentType ?? null,
|
|
33115
|
+
agentConfig: options.agentConfig,
|
|
33116
|
+
getActiveConfigOptions: options.getActiveConfigOptions,
|
|
33117
|
+
onAcpSessionEstablished,
|
|
33118
|
+
onAcpConfigOptionsUpdated,
|
|
33119
|
+
logDebug,
|
|
33120
|
+
getStderrText: () => stderrCapture.getText()
|
|
33121
|
+
};
|
|
32608
33122
|
return new Promise((resolve18, reject) => {
|
|
32609
33123
|
child.on("error", (err) => {
|
|
32610
33124
|
child.kill();
|
|
@@ -32613,6 +33127,16 @@ async function createCursorAcpClient(options) {
|
|
|
32613
33127
|
let nextId = 1;
|
|
32614
33128
|
const pending = /* @__PURE__ */ new Map();
|
|
32615
33129
|
const pendingRequests = /* @__PURE__ */ new Map();
|
|
33130
|
+
function cancelSessionNotification(sessionId) {
|
|
33131
|
+
const line = JSON.stringify({
|
|
33132
|
+
jsonrpc: "2.0",
|
|
33133
|
+
method: "session/cancel",
|
|
33134
|
+
params: { sessionId }
|
|
33135
|
+
}) + "\n";
|
|
33136
|
+
return new Promise((res, rej) => {
|
|
33137
|
+
child.stdin.write(line, (err) => err ? rej(err) : res());
|
|
33138
|
+
});
|
|
33139
|
+
}
|
|
32616
33140
|
function send(method, params) {
|
|
32617
33141
|
const id = nextId++;
|
|
32618
33142
|
const line = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
|
|
@@ -32636,7 +33160,6 @@ async function createCursorAcpClient(options) {
|
|
|
32636
33160
|
respond(requestId, payload);
|
|
32637
33161
|
pendingRequests.delete(requestId);
|
|
32638
33162
|
}
|
|
32639
|
-
let promptOutputBuffer = "";
|
|
32640
33163
|
const rl = readline.createInterface({ input: child.stdout });
|
|
32641
33164
|
rl.on("line", (line) => {
|
|
32642
33165
|
const msg = safeJsonParse(line);
|
|
@@ -32665,11 +33188,12 @@ async function createCursorAcpClient(options) {
|
|
|
32665
33188
|
`[acp] Received session update (${kindLabel}) tool=${toolName || "(none)"}`
|
|
32666
33189
|
);
|
|
32667
33190
|
}
|
|
32668
|
-
|
|
32669
|
-
|
|
32670
|
-
|
|
32671
|
-
|
|
32672
|
-
|
|
33191
|
+
dispatchAcpSessionUpdate({
|
|
33192
|
+
flatPayload: update,
|
|
33193
|
+
onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
|
|
33194
|
+
onSessionUpdate,
|
|
33195
|
+
suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
|
|
33196
|
+
});
|
|
32673
33197
|
return;
|
|
32674
33198
|
}
|
|
32675
33199
|
if (method === "session/request_permission" && typeof id === "number") {
|
|
@@ -32689,21 +33213,13 @@ async function createCursorAcpClient(options) {
|
|
|
32689
33213
|
if (dbgFs) {
|
|
32690
33214
|
console.error(`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""}`);
|
|
32691
33215
|
}
|
|
32692
|
-
const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
|
|
32693
|
-
if (!resolvedPath) {
|
|
32694
|
-
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty)`);
|
|
32695
|
-
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
32696
|
-
return;
|
|
32697
|
-
}
|
|
32698
33216
|
try {
|
|
32699
|
-
|
|
32700
|
-
const
|
|
32701
|
-
const
|
|
32702
|
-
|
|
32703
|
-
respond(id, { content });
|
|
33217
|
+
const lineNum = typeof params.line === "number" ? params.line : void 0;
|
|
33218
|
+
const limitNum = typeof params.limit === "number" ? params.limit : void 0;
|
|
33219
|
+
const out = acpReadTextFileInProcess(sessionCtx, filePath, lineNum, limitNum);
|
|
33220
|
+
respond(id, out);
|
|
32704
33221
|
} catch (e) {
|
|
32705
|
-
|
|
32706
|
-
if (code === "ENOENT") {
|
|
33222
|
+
if (e?.code === "ENOENT") {
|
|
32707
33223
|
respond(id, { content: "" });
|
|
32708
33224
|
} else {
|
|
32709
33225
|
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
@@ -32720,32 +33236,17 @@ async function createCursorAcpClient(options) {
|
|
|
32720
33236
|
`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""} newBytes=${newText.length}`
|
|
32721
33237
|
);
|
|
32722
33238
|
}
|
|
32723
|
-
const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
|
|
32724
|
-
if (!resolvedPath) {
|
|
32725
|
-
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
|
|
32726
|
-
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
32727
|
-
return;
|
|
32728
|
-
}
|
|
32729
|
-
let oldText = "";
|
|
32730
33239
|
try {
|
|
32731
|
-
|
|
33240
|
+
acpWriteTextFileInProcess(sessionCtx, filePath, newText);
|
|
33241
|
+
respond(id, null);
|
|
32732
33242
|
} catch (e) {
|
|
32733
|
-
if (e.
|
|
33243
|
+
if (e.message === "Invalid or disallowed path") {
|
|
33244
|
+
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
|
|
33245
|
+
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
33246
|
+
} else {
|
|
32734
33247
|
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
32735
|
-
return;
|
|
32736
33248
|
}
|
|
32737
33249
|
}
|
|
32738
|
-
try {
|
|
32739
|
-
mkdirSync3(dirname3(resolvedPath), { recursive: true });
|
|
32740
|
-
writeFileSync3(resolvedPath, newText, "utf8");
|
|
32741
|
-
} catch (e) {
|
|
32742
|
-
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
32743
|
-
return;
|
|
32744
|
-
}
|
|
32745
|
-
const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
|
|
32746
|
-
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
32747
|
-
onFileChange?.({ path: displayPath, oldText, newText, patchContent });
|
|
32748
|
-
respond(id, null);
|
|
32749
33250
|
return;
|
|
32750
33251
|
}
|
|
32751
33252
|
if (method === "cursor/create_plan" || method === "cursor/ask_question") {
|
|
@@ -32767,16 +33268,7 @@ async function createCursorAcpClient(options) {
|
|
|
32767
33268
|
});
|
|
32768
33269
|
(async () => {
|
|
32769
33270
|
try {
|
|
32770
|
-
let
|
|
32771
|
-
const line = JSON.stringify({
|
|
32772
|
-
jsonrpc: "2.0",
|
|
32773
|
-
method: "session/cancel",
|
|
32774
|
-
params: { sessionId }
|
|
32775
|
-
}) + "\n";
|
|
32776
|
-
return new Promise((res, rej) => {
|
|
32777
|
-
child.stdin.write(line, (err) => err ? rej(err) : res());
|
|
32778
|
-
});
|
|
32779
|
-
}, cancelPendingPermissionRequests2 = function() {
|
|
33271
|
+
let cancelPendingPermissionRequests2 = function() {
|
|
32780
33272
|
for (const [reqId, pending2] of [...pendingRequests.entries()]) {
|
|
32781
33273
|
if (pending2.method === "session/request_permission") {
|
|
32782
33274
|
respond(reqId, { outcome: { outcome: "cancelled" } });
|
|
@@ -32784,76 +33276,25 @@ async function createCursorAcpClient(options) {
|
|
|
32784
33276
|
}
|
|
32785
33277
|
}
|
|
32786
33278
|
};
|
|
32787
|
-
var
|
|
32788
|
-
|
|
33279
|
+
var cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
|
|
33280
|
+
const transport = createCursorJsonRpcAcpTransport({
|
|
33281
|
+
send,
|
|
33282
|
+
cancelSessionNotification
|
|
33283
|
+
});
|
|
33284
|
+
const established = await bootstrapAcpWireSession(transport, sessionCtx, {
|
|
32789
33285
|
protocolVersion: 1,
|
|
32790
33286
|
clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: false },
|
|
32791
33287
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
32792
33288
|
});
|
|
32793
|
-
|
|
32794
|
-
const newResult = await send("session/new", { cwd, mcpServers: [] });
|
|
32795
|
-
const sessionId = newResult?.sessionId ?? "";
|
|
32796
|
-
if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
|
|
33289
|
+
const sessionId = established.sessionId;
|
|
32797
33290
|
resolve18({
|
|
32798
33291
|
sessionId,
|
|
32799
33292
|
async sendPrompt(prompt, _options) {
|
|
32800
|
-
|
|
32801
|
-
try {
|
|
32802
|
-
const result = await send("session/prompt", {
|
|
32803
|
-
sessionId,
|
|
32804
|
-
prompt: [{ type: "text", text: prompt }]
|
|
32805
|
-
});
|
|
32806
|
-
await new Promise((r) => setImmediate(r));
|
|
32807
|
-
const output = (result?.output ?? promptOutputBuffer) || void 0;
|
|
32808
|
-
const stopReason = (result?.stopReason ?? "").toLowerCase();
|
|
32809
|
-
const cancelled = stopReason === "cancelled";
|
|
32810
|
-
const refusal = stopReason === "refusal";
|
|
32811
|
-
const stderrAfter = stderrCapture.getText();
|
|
32812
|
-
const agentType = backendAgentType ?? null;
|
|
32813
|
-
const stderrEvaluated = Boolean(stderrAfter && agentType);
|
|
32814
|
-
const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
|
|
32815
|
-
if (cancelled) {
|
|
32816
|
-
return {
|
|
32817
|
-
success: false,
|
|
32818
|
-
stopReason: result?.stopReason,
|
|
32819
|
-
output: output || void 0,
|
|
32820
|
-
error: mergeErrorWithStderr("Stopped by user", stderrAfter)
|
|
32821
|
-
};
|
|
32822
|
-
}
|
|
32823
|
-
if (refusal) {
|
|
32824
|
-
return {
|
|
32825
|
-
success: false,
|
|
32826
|
-
stopReason: result?.stopReason,
|
|
32827
|
-
output: output || void 0,
|
|
32828
|
-
error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
|
|
32829
|
-
};
|
|
32830
|
-
}
|
|
32831
|
-
if (stderrSuggestsAuth) {
|
|
32832
|
-
return {
|
|
32833
|
-
success: false,
|
|
32834
|
-
stopReason: result?.stopReason,
|
|
32835
|
-
output: output || void 0,
|
|
32836
|
-
error: stderrAfter
|
|
32837
|
-
};
|
|
32838
|
-
}
|
|
32839
|
-
return {
|
|
32840
|
-
success: true,
|
|
32841
|
-
stopReason: result?.stopReason,
|
|
32842
|
-
output: output || void 0
|
|
32843
|
-
};
|
|
32844
|
-
} catch (err) {
|
|
32845
|
-
await new Promise((r) => setImmediate(r));
|
|
32846
|
-
const stderrAfter = stderrCapture.getText();
|
|
32847
|
-
const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
|
|
32848
|
-
return {
|
|
32849
|
-
success: false,
|
|
32850
|
-
error: merged
|
|
32851
|
-
};
|
|
32852
|
-
}
|
|
33293
|
+
return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
|
|
32853
33294
|
},
|
|
32854
33295
|
async cancel() {
|
|
32855
33296
|
cancelPendingPermissionRequests2();
|
|
32856
|
-
await
|
|
33297
|
+
await transport.cancelSession(sessionId);
|
|
32857
33298
|
},
|
|
32858
33299
|
resolveRequest(requestId, result) {
|
|
32859
33300
|
const numericId = Number(requestId);
|
|
@@ -32951,7 +33392,7 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
32951
33392
|
command,
|
|
32952
33393
|
label: preferredAgentType,
|
|
32953
33394
|
createClient: createCursorAcpClient,
|
|
32954
|
-
spawnCommandForSession: (sessionMode) => buildCursorAcpSpawnCommand(command, sessionMode)
|
|
33395
|
+
spawnCommandForSession: (sessionMode, _agentConfig) => buildCursorAcpSpawnCommand(command, sessionMode)
|
|
32955
33396
|
};
|
|
32956
33397
|
}
|
|
32957
33398
|
if (useCodexAcp(preferredAgentType, command)) {
|
|
@@ -32959,7 +33400,7 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
32959
33400
|
command,
|
|
32960
33401
|
label: preferredAgentType,
|
|
32961
33402
|
createClient: createCodexAcpClient,
|
|
32962
|
-
spawnCommandForSession: (sessionMode) => buildCodexAcpSpawnCommand(command, sessionMode)
|
|
33403
|
+
spawnCommandForSession: (sessionMode, _agentConfig) => buildCodexAcpSpawnCommand(command, sessionMode)
|
|
32963
33404
|
};
|
|
32964
33405
|
}
|
|
32965
33406
|
if (useKiroAcp(preferredAgentType, command)) {
|
|
@@ -32967,7 +33408,7 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
32967
33408
|
command,
|
|
32968
33409
|
label: preferredAgentType,
|
|
32969
33410
|
createClient: createKiroAcpClient,
|
|
32970
|
-
spawnCommandForSession: (sessionMode) => buildKiroAcpSpawnCommand(command, sessionMode)
|
|
33411
|
+
spawnCommandForSession: (sessionMode, _agentConfig) => buildKiroAcpSpawnCommand(command, sessionMode)
|
|
32971
33412
|
};
|
|
32972
33413
|
}
|
|
32973
33414
|
return {
|
|
@@ -33001,7 +33442,7 @@ function getGitRepoRootSync(startDir) {
|
|
|
33001
33442
|
|
|
33002
33443
|
// src/agents/acp/workspace-files.ts
|
|
33003
33444
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
33004
|
-
import { readFileSync as
|
|
33445
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
33005
33446
|
import * as path11 from "node:path";
|
|
33006
33447
|
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
33007
33448
|
const trimmed2 = rawPath.trim();
|
|
@@ -33033,7 +33474,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
33033
33474
|
const rel = path11.relative(gitRoot, resolvedPath2);
|
|
33034
33475
|
if (!rel.startsWith("..") && !path11.isAbsolute(rel)) {
|
|
33035
33476
|
try {
|
|
33036
|
-
return
|
|
33477
|
+
return readFileSync3(resolvedPath2, "utf8");
|
|
33037
33478
|
} catch {
|
|
33038
33479
|
}
|
|
33039
33480
|
}
|
|
@@ -33041,7 +33482,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
33041
33482
|
const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
33042
33483
|
if (!resolvedPath) return "";
|
|
33043
33484
|
try {
|
|
33044
|
-
return
|
|
33485
|
+
return readFileSync3(resolvedPath, "utf8");
|
|
33045
33486
|
} catch {
|
|
33046
33487
|
return "";
|
|
33047
33488
|
}
|
|
@@ -33545,6 +33986,9 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
33545
33986
|
const sentFileChangePaths = /* @__PURE__ */ new Set();
|
|
33546
33987
|
const p = params;
|
|
33547
33988
|
const updateKind = p.sessionUpdate ?? p.session_update ?? p.type ?? "update";
|
|
33989
|
+
if (updateKind === "config_option_update") {
|
|
33990
|
+
return;
|
|
33991
|
+
}
|
|
33548
33992
|
const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
|
|
33549
33993
|
const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
|
|
33550
33994
|
const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
|
|
@@ -33631,14 +34075,72 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
33631
34075
|
};
|
|
33632
34076
|
}
|
|
33633
34077
|
|
|
34078
|
+
// src/agents/acp/local-agent-session-file.ts
|
|
34079
|
+
import fs10 from "node:fs";
|
|
34080
|
+
import os3 from "node:os";
|
|
34081
|
+
import path12 from "node:path";
|
|
34082
|
+
var LOCAL_AGENT_SESSION_DIR = path12.join(os3.homedir(), ".buildautomaton", "agent-sessions");
|
|
34083
|
+
function safeFileSlug(cloudSessionId) {
|
|
34084
|
+
const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
|
|
34085
|
+
return t.length > 0 ? t : "session";
|
|
34086
|
+
}
|
|
34087
|
+
function localAgentSessionFilePath(cloudSessionId) {
|
|
34088
|
+
return path12.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
|
|
34089
|
+
}
|
|
34090
|
+
function readLocalAgentSessionFile(cloudSessionId) {
|
|
34091
|
+
try {
|
|
34092
|
+
const p = localAgentSessionFilePath(cloudSessionId);
|
|
34093
|
+
const raw = fs10.readFileSync(p, "utf8");
|
|
34094
|
+
const parsed = JSON.parse(raw);
|
|
34095
|
+
if (parsed.v !== 1) return null;
|
|
34096
|
+
return {
|
|
34097
|
+
v: 1,
|
|
34098
|
+
acpSessionId: typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null,
|
|
34099
|
+
backendAgentType: typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null,
|
|
34100
|
+
configOptions: Array.isArray(parsed.configOptions) ? parsed.configOptions : null,
|
|
34101
|
+
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
34102
|
+
};
|
|
34103
|
+
} catch {
|
|
34104
|
+
return null;
|
|
34105
|
+
}
|
|
34106
|
+
}
|
|
34107
|
+
function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
34108
|
+
try {
|
|
34109
|
+
const dir = LOCAL_AGENT_SESSION_DIR;
|
|
34110
|
+
if (!fs10.existsSync(dir)) fs10.mkdirSync(dir, { recursive: true });
|
|
34111
|
+
const p = localAgentSessionFilePath(cloudSessionId);
|
|
34112
|
+
const prev = readLocalAgentSessionFile(cloudSessionId);
|
|
34113
|
+
const next = {
|
|
34114
|
+
v: 1,
|
|
34115
|
+
acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
|
|
34116
|
+
backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
|
|
34117
|
+
configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
|
|
34118
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
34119
|
+
};
|
|
34120
|
+
fs10.writeFileSync(p, JSON.stringify(next, null, 2), "utf8");
|
|
34121
|
+
} catch {
|
|
34122
|
+
}
|
|
34123
|
+
}
|
|
34124
|
+
|
|
33634
34125
|
// src/agents/acp/ensure-acp-client.ts
|
|
33635
34126
|
async function ensureAcpClient(options) {
|
|
33636
|
-
const {
|
|
34127
|
+
const {
|
|
34128
|
+
state,
|
|
34129
|
+
preferredAgentType,
|
|
34130
|
+
mode,
|
|
34131
|
+
agentConfig,
|
|
34132
|
+
sessionParentPath,
|
|
34133
|
+
routing,
|
|
34134
|
+
cloudSessionId,
|
|
34135
|
+
sendSessionUpdate,
|
|
34136
|
+
sendRequest,
|
|
34137
|
+
log: log2
|
|
34138
|
+
} = options;
|
|
33637
34139
|
const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
|
|
33638
34140
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
33639
34141
|
await state.acpStartPromise;
|
|
33640
34142
|
}
|
|
33641
|
-
if (state.acpHandle && state.lastAcpCwd != null &&
|
|
34143
|
+
if (state.acpHandle && state.lastAcpCwd != null && path13.resolve(state.lastAcpCwd) !== path13.resolve(targetSessionParentPath)) {
|
|
33642
34144
|
try {
|
|
33643
34145
|
state.acpHandle.disconnect();
|
|
33644
34146
|
} catch {
|
|
@@ -33646,6 +34148,7 @@ async function ensureAcpClient(options) {
|
|
|
33646
34148
|
state.acpHandle = null;
|
|
33647
34149
|
state.acpStartPromise = null;
|
|
33648
34150
|
state.acpAgentKey = null;
|
|
34151
|
+
state.activeSessionConfigOptions = null;
|
|
33649
34152
|
}
|
|
33650
34153
|
const resolved = resolveAgentCommand(preferredAgentType);
|
|
33651
34154
|
if (!resolved) {
|
|
@@ -33655,8 +34158,9 @@ async function ensureAcpClient(options) {
|
|
|
33655
34158
|
state.lastAcpStartError = "No agent type: ensure the app sends agentType on prompts or agent_config for this bridge.";
|
|
33656
34159
|
return null;
|
|
33657
34160
|
}
|
|
33658
|
-
const fullCmd = resolved.spawnCommandForSession(mode);
|
|
33659
|
-
const
|
|
34161
|
+
const fullCmd = resolved.spawnCommandForSession(mode, agentConfig ?? null);
|
|
34162
|
+
const cacheConfig = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) && Object.keys(agentConfig).length > 0 ? `\0${JSON.stringify(agentConfig, Object.keys(agentConfig).sort())}` : "";
|
|
34163
|
+
const agentKey = `${resolved.label}::${fullCmd.join("\0")}${cacheConfig}`;
|
|
33660
34164
|
if (state.acpHandle && state.acpAgentKey !== agentKey) {
|
|
33661
34165
|
try {
|
|
33662
34166
|
state.acpHandle.disconnect();
|
|
@@ -33665,12 +34169,13 @@ async function ensureAcpClient(options) {
|
|
|
33665
34169
|
state.acpHandle = null;
|
|
33666
34170
|
state.acpStartPromise = null;
|
|
33667
34171
|
state.acpAgentKey = null;
|
|
34172
|
+
state.activeSessionConfigOptions = null;
|
|
33668
34173
|
}
|
|
33669
34174
|
if (state.acpHandle) return state.acpHandle;
|
|
33670
34175
|
if (!state.acpStartPromise) {
|
|
33671
34176
|
let statOk = false;
|
|
33672
34177
|
try {
|
|
33673
|
-
const st =
|
|
34178
|
+
const st = fs11.statSync(targetSessionParentPath);
|
|
33674
34179
|
statOk = st.isDirectory();
|
|
33675
34180
|
if (!statOk) {
|
|
33676
34181
|
state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
|
|
@@ -33690,14 +34195,40 @@ async function ensureAcpClient(options) {
|
|
|
33690
34195
|
getSendRequest: () => sendRequest,
|
|
33691
34196
|
log: log2
|
|
33692
34197
|
});
|
|
34198
|
+
const persisted = cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "" ? readLocalAgentSessionFile(cloudSessionId) : null;
|
|
34199
|
+
const persistedAcpSessionId = persisted && persisted.backendAgentType === preferredAgentType && typeof persisted.acpSessionId === "string" && persisted.acpSessionId.trim() !== "" ? persisted.acpSessionId.trim() : null;
|
|
34200
|
+
state.activeSessionConfigOptions = Array.isArray(persisted?.configOptions) ? persisted.configOptions : null;
|
|
33693
34201
|
state.acpStartPromise = resolved.createClient({
|
|
33694
34202
|
command: resolved.command,
|
|
33695
34203
|
sessionMode: mode,
|
|
34204
|
+
agentConfig: agentConfig ?? null,
|
|
33696
34205
|
backendAgentType: preferredAgentType,
|
|
34206
|
+
persistedAcpSessionId,
|
|
34207
|
+
getActiveConfigOptions: () => state.activeSessionConfigOptions,
|
|
34208
|
+
onAcpSessionEstablished: (info) => {
|
|
34209
|
+
state.activeSessionConfigOptions = info.configOptions ?? state.activeSessionConfigOptions;
|
|
34210
|
+
if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
|
|
34211
|
+
writeLocalAgentSessionFile(cloudSessionId, {
|
|
34212
|
+
acpSessionId: info.acpSessionId,
|
|
34213
|
+
configOptions: info.configOptions,
|
|
34214
|
+
backendAgentType: preferredAgentType
|
|
34215
|
+
});
|
|
34216
|
+
}
|
|
34217
|
+
},
|
|
34218
|
+
onAcpConfigOptionsUpdated: (configOptions) => {
|
|
34219
|
+
state.activeSessionConfigOptions = configOptions;
|
|
34220
|
+
if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
|
|
34221
|
+
writeLocalAgentSessionFile(cloudSessionId, {
|
|
34222
|
+
configOptions,
|
|
34223
|
+
backendAgentType: preferredAgentType
|
|
34224
|
+
});
|
|
34225
|
+
}
|
|
34226
|
+
},
|
|
33697
34227
|
onAgentSubprocessExit: () => {
|
|
33698
34228
|
state.acpHandle = null;
|
|
33699
34229
|
state.acpStartPromise = null;
|
|
33700
34230
|
state.acpAgentKey = null;
|
|
34231
|
+
state.activeSessionConfigOptions = null;
|
|
33701
34232
|
state.lastAcpStartError = "Agent subprocess exited";
|
|
33702
34233
|
},
|
|
33703
34234
|
...hooks,
|
|
@@ -33727,7 +34258,8 @@ async function createAcpManager(options) {
|
|
|
33727
34258
|
acpStartPromise: null,
|
|
33728
34259
|
lastAcpStartError: null,
|
|
33729
34260
|
lastAcpCwd: null,
|
|
33730
|
-
acpAgentKey: null
|
|
34261
|
+
acpAgentKey: null,
|
|
34262
|
+
activeSessionConfigOptions: null
|
|
33731
34263
|
};
|
|
33732
34264
|
let backendFallbackAgentType = null;
|
|
33733
34265
|
const promptRouting = {};
|
|
@@ -33754,6 +34286,7 @@ async function createAcpManager(options) {
|
|
|
33754
34286
|
runId,
|
|
33755
34287
|
mode,
|
|
33756
34288
|
agentType,
|
|
34289
|
+
agentConfig,
|
|
33757
34290
|
sessionParentPath,
|
|
33758
34291
|
sendResult: sendResult2,
|
|
33759
34292
|
sendSessionUpdate,
|
|
@@ -33773,8 +34306,10 @@ async function createAcpManager(options) {
|
|
|
33773
34306
|
state,
|
|
33774
34307
|
preferredAgentType: preferredForPrompt,
|
|
33775
34308
|
mode,
|
|
34309
|
+
agentConfig: agentConfig ?? null,
|
|
33776
34310
|
sessionParentPath,
|
|
33777
34311
|
routing: promptRouting,
|
|
34312
|
+
cloudSessionId: sessionId,
|
|
33778
34313
|
sendSessionUpdate,
|
|
33779
34314
|
sendRequest: sendSessionUpdate,
|
|
33780
34315
|
log: log2
|
|
@@ -33865,6 +34400,7 @@ async function createAcpManager(options) {
|
|
|
33865
34400
|
state.acpHandle = null;
|
|
33866
34401
|
state.acpStartPromise = null;
|
|
33867
34402
|
state.acpAgentKey = null;
|
|
34403
|
+
state.activeSessionConfigOptions = null;
|
|
33868
34404
|
}
|
|
33869
34405
|
return {
|
|
33870
34406
|
setPreferredAgentType,
|
|
@@ -33877,26 +34413,26 @@ async function createAcpManager(options) {
|
|
|
33877
34413
|
}
|
|
33878
34414
|
|
|
33879
34415
|
// src/worktrees/session-worktree-manager.ts
|
|
33880
|
-
import * as
|
|
33881
|
-
import
|
|
34416
|
+
import * as path20 from "node:path";
|
|
34417
|
+
import os5 from "node:os";
|
|
33882
34418
|
|
|
33883
34419
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
33884
|
-
import * as
|
|
33885
|
-
import * as
|
|
34420
|
+
import * as fs13 from "node:fs";
|
|
34421
|
+
import * as path15 from "node:path";
|
|
33886
34422
|
|
|
33887
34423
|
// src/git/worktree-add.ts
|
|
33888
34424
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
33889
|
-
const mainGit =
|
|
34425
|
+
const mainGit = cliSimpleGit(mainRepoPath);
|
|
33890
34426
|
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
|
|
33891
34427
|
}
|
|
33892
34428
|
|
|
33893
34429
|
// src/worktrees/worktree-layout-file.ts
|
|
33894
|
-
import * as
|
|
33895
|
-
import * as
|
|
33896
|
-
import
|
|
34430
|
+
import * as fs12 from "node:fs";
|
|
34431
|
+
import * as path14 from "node:path";
|
|
34432
|
+
import os4 from "node:os";
|
|
33897
34433
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
33898
34434
|
function defaultWorktreeLayoutPath() {
|
|
33899
|
-
return
|
|
34435
|
+
return path14.join(os4.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
33900
34436
|
}
|
|
33901
34437
|
function normalizeLoadedLayout(raw) {
|
|
33902
34438
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -33908,8 +34444,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
33908
34444
|
function loadWorktreeLayout() {
|
|
33909
34445
|
try {
|
|
33910
34446
|
const p = defaultWorktreeLayoutPath();
|
|
33911
|
-
if (!
|
|
33912
|
-
const raw = JSON.parse(
|
|
34447
|
+
if (!fs12.existsSync(p)) return { launcherCwds: [] };
|
|
34448
|
+
const raw = JSON.parse(fs12.readFileSync(p, "utf8"));
|
|
33913
34449
|
return normalizeLoadedLayout(raw);
|
|
33914
34450
|
} catch {
|
|
33915
34451
|
return { launcherCwds: [] };
|
|
@@ -33917,24 +34453,24 @@ function loadWorktreeLayout() {
|
|
|
33917
34453
|
}
|
|
33918
34454
|
function saveWorktreeLayout(layout) {
|
|
33919
34455
|
try {
|
|
33920
|
-
const dir =
|
|
33921
|
-
|
|
33922
|
-
|
|
34456
|
+
const dir = path14.dirname(defaultWorktreeLayoutPath());
|
|
34457
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
34458
|
+
fs12.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
33923
34459
|
} catch {
|
|
33924
34460
|
}
|
|
33925
34461
|
}
|
|
33926
34462
|
function baseNameSafe(pathString) {
|
|
33927
|
-
return
|
|
34463
|
+
return path14.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
33928
34464
|
}
|
|
33929
34465
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
33930
|
-
const norm =
|
|
33931
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
34466
|
+
const norm = path14.resolve(bridgeRootPath2);
|
|
34467
|
+
const existing = layout.launcherCwds.find((e) => path14.resolve(e.absolutePath) === norm);
|
|
33932
34468
|
return existing?.dirName;
|
|
33933
34469
|
}
|
|
33934
34470
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
33935
34471
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
33936
34472
|
if (existing) return existing;
|
|
33937
|
-
const norm =
|
|
34473
|
+
const norm = path14.resolve(bridgeRootPath2);
|
|
33938
34474
|
const base = baseNameSafe(norm);
|
|
33939
34475
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
33940
34476
|
let name = base;
|
|
@@ -33951,10 +34487,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
33951
34487
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
33952
34488
|
async function prepareNewSessionWorktrees(options) {
|
|
33953
34489
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
|
|
33954
|
-
const bridgeResolved =
|
|
34490
|
+
const bridgeResolved = path15.resolve(bridgeRoot);
|
|
33955
34491
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
33956
|
-
const bridgeKeyDir =
|
|
33957
|
-
const sessionDir =
|
|
34492
|
+
const bridgeKeyDir = path15.join(worktreesRootPath, cwdKey);
|
|
34493
|
+
const sessionDir = path15.join(bridgeKeyDir, sessionId);
|
|
33958
34494
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
33959
34495
|
if (repos.length === 0) {
|
|
33960
34496
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -33962,14 +34498,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
33962
34498
|
}
|
|
33963
34499
|
const branch = `session-${sessionId}`;
|
|
33964
34500
|
const worktreePaths = [];
|
|
33965
|
-
|
|
34501
|
+
fs13.mkdirSync(sessionDir, { recursive: true });
|
|
33966
34502
|
for (const repo of repos) {
|
|
33967
|
-
let rel =
|
|
33968
|
-
if (rel.startsWith("..") ||
|
|
34503
|
+
let rel = path15.relative(bridgeResolved, repo.absolutePath);
|
|
34504
|
+
if (rel.startsWith("..") || path15.isAbsolute(rel)) continue;
|
|
33969
34505
|
const relNorm = rel === "" ? "." : rel;
|
|
33970
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
34506
|
+
const wtPath = relNorm === "." ? sessionDir : path15.join(sessionDir, relNorm);
|
|
33971
34507
|
if (relNorm !== ".") {
|
|
33972
|
-
|
|
34508
|
+
fs13.mkdirSync(path15.dirname(wtPath), { recursive: true });
|
|
33973
34509
|
}
|
|
33974
34510
|
try {
|
|
33975
34511
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
@@ -33991,7 +34527,7 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
33991
34527
|
|
|
33992
34528
|
// src/git/rename-branch.ts
|
|
33993
34529
|
async function gitRenameCurrentBranch(repoDir, newName) {
|
|
33994
|
-
const g =
|
|
34530
|
+
const g = cliSimpleGit(repoDir);
|
|
33995
34531
|
await g.raw(["branch", "-m", newName]);
|
|
33996
34532
|
}
|
|
33997
34533
|
|
|
@@ -34011,32 +34547,32 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
34011
34547
|
}
|
|
34012
34548
|
|
|
34013
34549
|
// src/worktrees/remove-session-worktrees.ts
|
|
34014
|
-
import * as
|
|
34550
|
+
import * as fs16 from "node:fs";
|
|
34015
34551
|
|
|
34016
34552
|
// src/git/worktree-remove.ts
|
|
34017
|
-
import * as
|
|
34553
|
+
import * as fs15 from "node:fs";
|
|
34018
34554
|
|
|
34019
34555
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
34020
|
-
import * as
|
|
34021
|
-
import * as
|
|
34556
|
+
import * as fs14 from "node:fs";
|
|
34557
|
+
import * as path16 from "node:path";
|
|
34022
34558
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
34023
|
-
const gitDirFile =
|
|
34024
|
-
if (!
|
|
34025
|
-
const first2 =
|
|
34559
|
+
const gitDirFile = path16.join(wt, ".git");
|
|
34560
|
+
if (!fs14.existsSync(gitDirFile) || !fs14.statSync(gitDirFile).isFile()) return "";
|
|
34561
|
+
const first2 = fs14.readFileSync(gitDirFile, "utf8").trim();
|
|
34026
34562
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
34027
34563
|
if (!m) return "";
|
|
34028
|
-
const gitWorktreePath =
|
|
34029
|
-
const gitDir =
|
|
34030
|
-
return
|
|
34564
|
+
const gitWorktreePath = path16.resolve(wt, m[1].trim());
|
|
34565
|
+
const gitDir = path16.dirname(path16.dirname(gitWorktreePath));
|
|
34566
|
+
return path16.dirname(gitDir);
|
|
34031
34567
|
}
|
|
34032
34568
|
|
|
34033
34569
|
// src/git/worktree-remove.ts
|
|
34034
34570
|
async function gitWorktreeRemoveForce(worktreePath) {
|
|
34035
34571
|
const mainRepo = resolveMainRepoFromWorktreeGitFile(worktreePath);
|
|
34036
34572
|
if (mainRepo) {
|
|
34037
|
-
await
|
|
34573
|
+
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
34038
34574
|
} else {
|
|
34039
|
-
|
|
34575
|
+
fs15.rmSync(worktreePath, { recursive: true, force: true });
|
|
34040
34576
|
}
|
|
34041
34577
|
}
|
|
34042
34578
|
|
|
@@ -34049,7 +34585,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
34049
34585
|
} catch (e) {
|
|
34050
34586
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
34051
34587
|
try {
|
|
34052
|
-
|
|
34588
|
+
fs16.rmSync(wt, { recursive: true, force: true });
|
|
34053
34589
|
} catch {
|
|
34054
34590
|
}
|
|
34055
34591
|
}
|
|
@@ -34164,7 +34700,7 @@ async function gitLogNotReachableFromBase(g, baseSha, headSha) {
|
|
|
34164
34700
|
}
|
|
34165
34701
|
}
|
|
34166
34702
|
async function commitsAheadOfRemoteTracking(repoDir) {
|
|
34167
|
-
const g =
|
|
34703
|
+
const g = cliSimpleGit(repoDir);
|
|
34168
34704
|
const headSha = await revParseSafe(g, "HEAD");
|
|
34169
34705
|
if (!headSha) return 0;
|
|
34170
34706
|
const baseSha = await resolveBaseShaForUnpushedCommits(g);
|
|
@@ -34178,14 +34714,14 @@ async function commitsAheadOfRemoteTracking(repoDir) {
|
|
|
34178
34714
|
}
|
|
34179
34715
|
}
|
|
34180
34716
|
async function getRepoWorkingTreeStatus(repoDir) {
|
|
34181
|
-
const g =
|
|
34717
|
+
const g = cliSimpleGit(repoDir);
|
|
34182
34718
|
const st = await g.status();
|
|
34183
34719
|
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
34184
34720
|
const ahead = await commitsAheadOfRemoteTracking(repoDir);
|
|
34185
34721
|
return { hasUncommittedChanges, hasUnpushedCommits: ahead > 0 };
|
|
34186
34722
|
}
|
|
34187
34723
|
async function listUnpushedCommits(repoDir) {
|
|
34188
|
-
const g =
|
|
34724
|
+
const g = cliSimpleGit(repoDir);
|
|
34189
34725
|
const headSha = await revParseSafe(g, "HEAD");
|
|
34190
34726
|
if (!headSha) return [];
|
|
34191
34727
|
const baseSha = await resolveBaseShaForUnpushedCommits(g);
|
|
@@ -34204,7 +34740,7 @@ async function aggregateSessionPathsWorkingTreeStatus(paths) {
|
|
|
34204
34740
|
}
|
|
34205
34741
|
async function pushAheadOfUpstreamForPaths(paths) {
|
|
34206
34742
|
for (const p of paths) {
|
|
34207
|
-
const g =
|
|
34743
|
+
const g = cliSimpleGit(p);
|
|
34208
34744
|
const ahead = await commitsAheadOfRemoteTracking(p);
|
|
34209
34745
|
if (ahead <= 0) continue;
|
|
34210
34746
|
await g.push();
|
|
@@ -34269,7 +34805,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
34269
34805
|
}
|
|
34270
34806
|
|
|
34271
34807
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
34272
|
-
import * as
|
|
34808
|
+
import * as path18 from "node:path";
|
|
34273
34809
|
|
|
34274
34810
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
34275
34811
|
function parseNameStatusLines(lines) {
|
|
@@ -34346,7 +34882,7 @@ async function parentForCommitDiff(g, sha) {
|
|
|
34346
34882
|
}
|
|
34347
34883
|
}
|
|
34348
34884
|
async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
34349
|
-
const g =
|
|
34885
|
+
const g = cliSimpleGit(repoGitCwd);
|
|
34350
34886
|
const parent = await parentForCommitDiff(g, commitSha);
|
|
34351
34887
|
const range = `${parent}..${commitSha}`;
|
|
34352
34888
|
const [nameStatusRaw, numstatRaw] = await Promise.all([
|
|
@@ -34389,8 +34925,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
34389
34925
|
}
|
|
34390
34926
|
|
|
34391
34927
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
34392
|
-
import * as
|
|
34393
|
-
import * as
|
|
34928
|
+
import * as fs18 from "node:fs";
|
|
34929
|
+
import * as path17 from "node:path";
|
|
34394
34930
|
|
|
34395
34931
|
// src/git/working-directory/changes/count-lines.ts
|
|
34396
34932
|
import { createReadStream } from "node:fs";
|
|
@@ -34414,14 +34950,14 @@ async function countTextFileLines(filePath) {
|
|
|
34414
34950
|
}
|
|
34415
34951
|
|
|
34416
34952
|
// src/git/working-directory/changes/hydrate-patch.ts
|
|
34417
|
-
import * as
|
|
34953
|
+
import * as fs17 from "node:fs";
|
|
34418
34954
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
34419
34955
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
34420
34956
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
34421
34957
|
async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
34422
34958
|
try {
|
|
34423
34959
|
const rel = pathInRepo.replace(/\\/g, "/");
|
|
34424
|
-
const raw = await
|
|
34960
|
+
const raw = await cliSimpleGit(repoCwd).show([`HEAD:${rel}`]);
|
|
34425
34961
|
return String(raw).split(/\r?\n/);
|
|
34426
34962
|
} catch {
|
|
34427
34963
|
return null;
|
|
@@ -34429,7 +34965,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
34429
34965
|
}
|
|
34430
34966
|
async function readWorktreeFileLines(filePath) {
|
|
34431
34967
|
try {
|
|
34432
|
-
const raw = await
|
|
34968
|
+
const raw = await fs17.promises.readFile(filePath, "utf8");
|
|
34433
34969
|
return raw.split(/\r?\n/);
|
|
34434
34970
|
} catch {
|
|
34435
34971
|
return null;
|
|
@@ -34531,7 +35067,7 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
34531
35067
|
|
|
34532
35068
|
// src/git/working-directory/changes/unified-diff-for-file.ts
|
|
34533
35069
|
async function unifiedDiffForFile(repoCwd, pathInRepo, change) {
|
|
34534
|
-
const g =
|
|
35070
|
+
const g = cliSimpleGit(repoCwd);
|
|
34535
35071
|
try {
|
|
34536
35072
|
let raw;
|
|
34537
35073
|
if (change === "added") {
|
|
@@ -34550,7 +35086,7 @@ async function unifiedDiffForFile(repoCwd, pathInRepo, change) {
|
|
|
34550
35086
|
|
|
34551
35087
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
34552
35088
|
async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
34553
|
-
const g =
|
|
35089
|
+
const g = cliSimpleGit(repoGitCwd);
|
|
34554
35090
|
const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
|
|
34555
35091
|
g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
|
|
34556
35092
|
g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
|
|
@@ -34564,7 +35100,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
34564
35100
|
const rows = [];
|
|
34565
35101
|
for (const pathInRepo of paths) {
|
|
34566
35102
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
34567
|
-
const repoFilePath =
|
|
35103
|
+
const repoFilePath = path17.join(repoGitCwd, pathInRepo);
|
|
34568
35104
|
const nums = numByPath.get(pathInRepo);
|
|
34569
35105
|
let additions = nums?.additions ?? 0;
|
|
34570
35106
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -34577,7 +35113,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
34577
35113
|
deletions = fromGit.deletions;
|
|
34578
35114
|
} else {
|
|
34579
35115
|
try {
|
|
34580
|
-
const st = await
|
|
35116
|
+
const st = await fs18.promises.stat(repoFilePath);
|
|
34581
35117
|
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
34582
35118
|
else additions = 0;
|
|
34583
35119
|
} catch {
|
|
@@ -34603,7 +35139,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
34603
35139
|
} else {
|
|
34604
35140
|
pathInRepo = row.pathRelLauncher;
|
|
34605
35141
|
}
|
|
34606
|
-
const filePath =
|
|
35142
|
+
const filePath = path17.join(repoGitCwd, pathInRepo);
|
|
34607
35143
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
34608
35144
|
if (patch) {
|
|
34609
35145
|
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
@@ -34619,8 +35155,8 @@ function normRepoRel(p) {
|
|
|
34619
35155
|
return x === "" ? "." : x;
|
|
34620
35156
|
}
|
|
34621
35157
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
34622
|
-
const bridgeRoot =
|
|
34623
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
35158
|
+
const bridgeRoot = path18.resolve(getBridgeRoot());
|
|
35159
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path18.resolve(options.sessionWorktreeRootPath) : null;
|
|
34624
35160
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
34625
35161
|
const out = [];
|
|
34626
35162
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -34633,9 +35169,9 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34633
35169
|
}
|
|
34634
35170
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
34635
35171
|
for (const target of options.commitTargetPaths) {
|
|
34636
|
-
const t =
|
|
35172
|
+
const t = path18.resolve(target);
|
|
34637
35173
|
if (!await isGitRepoDirectory(t)) continue;
|
|
34638
|
-
const g =
|
|
35174
|
+
const g = cliSimpleGit(t);
|
|
34639
35175
|
let branch = "HEAD";
|
|
34640
35176
|
try {
|
|
34641
35177
|
branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim() || "HEAD";
|
|
@@ -34646,8 +35182,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34646
35182
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
34647
35183
|
let repoRelPath;
|
|
34648
35184
|
if (sessionWtRoot) {
|
|
34649
|
-
const anchor = legacyNested ?
|
|
34650
|
-
const relNorm =
|
|
35185
|
+
const anchor = legacyNested ? path18.dirname(t) : t;
|
|
35186
|
+
const relNorm = path18.relative(sessionWtRoot, anchor);
|
|
34651
35187
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
34652
35188
|
} else {
|
|
34653
35189
|
let top = t;
|
|
@@ -34656,8 +35192,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34656
35192
|
} catch {
|
|
34657
35193
|
top = t;
|
|
34658
35194
|
}
|
|
34659
|
-
const rel =
|
|
34660
|
-
repoRelPath = rel.startsWith("..") ?
|
|
35195
|
+
const rel = path18.relative(bridgeRoot, path18.resolve(top)).replace(/\\/g, "/") || ".";
|
|
35196
|
+
repoRelPath = rel.startsWith("..") ? path18.basename(path18.resolve(top)) : rel;
|
|
34661
35197
|
}
|
|
34662
35198
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
34663
35199
|
if (filter && norm !== filter) continue;
|
|
@@ -34686,7 +35222,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34686
35222
|
|
|
34687
35223
|
// src/git/commit-and-push.ts
|
|
34688
35224
|
async function gitCommitAllIfDirty(repoDir, message, options) {
|
|
34689
|
-
const g =
|
|
35225
|
+
const g = cliSimpleGit(repoDir);
|
|
34690
35226
|
const st = await g.status();
|
|
34691
35227
|
if (!st.files?.length) return;
|
|
34692
35228
|
const branch = options.branch.trim();
|
|
@@ -34722,11 +35258,11 @@ async function commitSessionWorktrees(options) {
|
|
|
34722
35258
|
}
|
|
34723
35259
|
|
|
34724
35260
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
34725
|
-
import * as
|
|
34726
|
-
import * as
|
|
35261
|
+
import * as fs19 from "node:fs";
|
|
35262
|
+
import * as path19 from "node:path";
|
|
34727
35263
|
function isGitDir(dirPath) {
|
|
34728
35264
|
try {
|
|
34729
|
-
return
|
|
35265
|
+
return fs19.existsSync(path19.join(dirPath, ".git"));
|
|
34730
35266
|
} catch {
|
|
34731
35267
|
return false;
|
|
34732
35268
|
}
|
|
@@ -34735,23 +35271,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
34735
35271
|
const out = [];
|
|
34736
35272
|
const walk = (dir) => {
|
|
34737
35273
|
if (isGitDir(dir)) {
|
|
34738
|
-
out.push(
|
|
35274
|
+
out.push(path19.resolve(dir));
|
|
34739
35275
|
return;
|
|
34740
35276
|
}
|
|
34741
35277
|
let entries;
|
|
34742
35278
|
try {
|
|
34743
|
-
entries =
|
|
35279
|
+
entries = fs19.readdirSync(dir, { withFileTypes: true });
|
|
34744
35280
|
} catch {
|
|
34745
35281
|
return;
|
|
34746
35282
|
}
|
|
34747
35283
|
for (const e of entries) {
|
|
34748
35284
|
if (e.name.startsWith(".")) continue;
|
|
34749
|
-
const full =
|
|
35285
|
+
const full = path19.join(dir, e.name);
|
|
34750
35286
|
if (!e.isDirectory()) continue;
|
|
34751
35287
|
walk(full);
|
|
34752
35288
|
}
|
|
34753
35289
|
};
|
|
34754
|
-
walk(
|
|
35290
|
+
walk(path19.resolve(rootPath));
|
|
34755
35291
|
return [...new Set(out)];
|
|
34756
35292
|
}
|
|
34757
35293
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -34760,16 +35296,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
34760
35296
|
if (depth > maxDepth) return;
|
|
34761
35297
|
let entries;
|
|
34762
35298
|
try {
|
|
34763
|
-
entries =
|
|
35299
|
+
entries = fs19.readdirSync(dir, { withFileTypes: true });
|
|
34764
35300
|
} catch {
|
|
34765
35301
|
return;
|
|
34766
35302
|
}
|
|
34767
35303
|
for (const e of entries) {
|
|
34768
35304
|
if (e.name.startsWith(".")) continue;
|
|
34769
|
-
const full =
|
|
35305
|
+
const full = path19.join(dir, e.name);
|
|
34770
35306
|
if (!e.isDirectory()) continue;
|
|
34771
35307
|
if (e.name === sessionId) {
|
|
34772
|
-
if (isGitDir(full)) out.push(
|
|
35308
|
+
if (isGitDir(full)) out.push(path19.resolve(full));
|
|
34773
35309
|
} else {
|
|
34774
35310
|
walk(full, depth + 1);
|
|
34775
35311
|
}
|
|
@@ -34781,14 +35317,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
34781
35317
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
34782
35318
|
let st;
|
|
34783
35319
|
try {
|
|
34784
|
-
st =
|
|
35320
|
+
st = fs19.statSync(sessionDir);
|
|
34785
35321
|
} catch {
|
|
34786
35322
|
return null;
|
|
34787
35323
|
}
|
|
34788
35324
|
if (!st.isDirectory()) return null;
|
|
34789
35325
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
34790
35326
|
if (worktreePaths.length === 0) return null;
|
|
34791
|
-
const abs =
|
|
35327
|
+
const abs = path19.resolve(sessionDir);
|
|
34792
35328
|
return {
|
|
34793
35329
|
sessionParentPath: abs,
|
|
34794
35330
|
workingTreeRelRoot: abs,
|
|
@@ -34798,20 +35334,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
34798
35334
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
34799
35335
|
const sid = sessionId.trim();
|
|
34800
35336
|
if (!sid) return null;
|
|
34801
|
-
const hintR =
|
|
35337
|
+
const hintR = path19.resolve(checkoutPath);
|
|
34802
35338
|
let best = null;
|
|
34803
|
-
let cur =
|
|
35339
|
+
let cur = path19.dirname(hintR);
|
|
34804
35340
|
for (let i = 0; i < 40; i++) {
|
|
34805
35341
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
34806
|
-
if (paths.some((p) =>
|
|
34807
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
35342
|
+
if (paths.some((p) => path19.resolve(p) === hintR)) {
|
|
35343
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path19.resolve(paths[0]);
|
|
34808
35344
|
best = {
|
|
34809
|
-
sessionParentPath:
|
|
34810
|
-
workingTreeRelRoot:
|
|
34811
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
35345
|
+
sessionParentPath: path19.resolve(isolated),
|
|
35346
|
+
workingTreeRelRoot: path19.resolve(cur),
|
|
35347
|
+
repoCheckoutPaths: paths.map((p) => path19.resolve(p))
|
|
34812
35348
|
};
|
|
34813
35349
|
}
|
|
34814
|
-
const next =
|
|
35350
|
+
const next = path19.dirname(cur);
|
|
34815
35351
|
if (next === cur) break;
|
|
34816
35352
|
cur = next;
|
|
34817
35353
|
}
|
|
@@ -34819,33 +35355,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
34819
35355
|
}
|
|
34820
35356
|
function discoverSessionWorktreeOnDisk(options) {
|
|
34821
35357
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
34822
|
-
if (!sessionId.trim() || !
|
|
35358
|
+
if (!sessionId.trim() || !fs19.existsSync(worktreesRootPath)) return null;
|
|
34823
35359
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
34824
35360
|
const keys = [];
|
|
34825
35361
|
if (preferredKey) keys.push(preferredKey);
|
|
34826
35362
|
try {
|
|
34827
|
-
for (const name of
|
|
35363
|
+
for (const name of fs19.readdirSync(worktreesRootPath)) {
|
|
34828
35364
|
if (name.startsWith(".")) continue;
|
|
34829
|
-
const p =
|
|
34830
|
-
if (!
|
|
35365
|
+
const p = path19.join(worktreesRootPath, name);
|
|
35366
|
+
if (!fs19.statSync(p).isDirectory()) continue;
|
|
34831
35367
|
if (name !== preferredKey) keys.push(name);
|
|
34832
35368
|
}
|
|
34833
35369
|
} catch {
|
|
34834
35370
|
return null;
|
|
34835
35371
|
}
|
|
34836
35372
|
for (const key of keys) {
|
|
34837
|
-
const layoutRoot =
|
|
34838
|
-
if (!
|
|
34839
|
-
const sessionDir =
|
|
35373
|
+
const layoutRoot = path19.join(worktreesRootPath, key);
|
|
35374
|
+
if (!fs19.existsSync(layoutRoot) || !fs19.statSync(layoutRoot).isDirectory()) continue;
|
|
35375
|
+
const sessionDir = path19.join(layoutRoot, sessionId);
|
|
34840
35376
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
34841
35377
|
if (nested) return nested;
|
|
34842
35378
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
34843
35379
|
if (legacyPaths.length > 0) {
|
|
34844
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
35380
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path19.resolve(legacyPaths[0]);
|
|
34845
35381
|
return {
|
|
34846
|
-
sessionParentPath:
|
|
34847
|
-
workingTreeRelRoot:
|
|
34848
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
35382
|
+
sessionParentPath: path19.resolve(isolated),
|
|
35383
|
+
workingTreeRelRoot: path19.resolve(layoutRoot),
|
|
35384
|
+
repoCheckoutPaths: legacyPaths.map((p) => path19.resolve(p))
|
|
34849
35385
|
};
|
|
34850
35386
|
}
|
|
34851
35387
|
}
|
|
@@ -34854,12 +35390,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
34854
35390
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
34855
35391
|
const sid = sessionId.trim();
|
|
34856
35392
|
if (!sid) return null;
|
|
34857
|
-
const hint =
|
|
34858
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
35393
|
+
const hint = path19.resolve(sessionWorktreeRootPathOrHint);
|
|
35394
|
+
const underHint = tryBindingFromSessionDirectory(path19.join(hint, sid));
|
|
34859
35395
|
if (underHint) return underHint;
|
|
34860
35396
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
34861
35397
|
if (direct) {
|
|
34862
|
-
if (
|
|
35398
|
+
if (path19.basename(hint) === sid && isGitDir(hint)) {
|
|
34863
35399
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34864
35400
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
34865
35401
|
return legacyFromCheckout;
|
|
@@ -34867,24 +35403,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
34867
35403
|
}
|
|
34868
35404
|
return direct;
|
|
34869
35405
|
}
|
|
34870
|
-
if (
|
|
35406
|
+
if (path19.basename(hint) === sid && isGitDir(hint)) {
|
|
34871
35407
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34872
35408
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
34873
35409
|
}
|
|
34874
35410
|
let st;
|
|
34875
35411
|
try {
|
|
34876
|
-
st =
|
|
35412
|
+
st = fs19.statSync(hint);
|
|
34877
35413
|
} catch {
|
|
34878
35414
|
return null;
|
|
34879
35415
|
}
|
|
34880
35416
|
if (!st.isDirectory()) return null;
|
|
34881
35417
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
34882
35418
|
if (legacyPaths.length === 0) return null;
|
|
34883
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
35419
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path19.resolve(legacyPaths[0]);
|
|
34884
35420
|
return {
|
|
34885
|
-
sessionParentPath:
|
|
35421
|
+
sessionParentPath: path19.resolve(isolated),
|
|
34886
35422
|
workingTreeRelRoot: hint,
|
|
34887
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
35423
|
+
repoCheckoutPaths: legacyPaths.map((p) => path19.resolve(p))
|
|
34888
35424
|
};
|
|
34889
35425
|
}
|
|
34890
35426
|
|
|
@@ -34907,10 +35443,10 @@ var SessionWorktreeManager = class {
|
|
|
34907
35443
|
this.layout = loadWorktreeLayout();
|
|
34908
35444
|
}
|
|
34909
35445
|
rememberSessionWorktrees(sessionId, binding) {
|
|
34910
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
35446
|
+
const paths = binding.repoCheckoutPaths.map((p) => path20.resolve(p));
|
|
34911
35447
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
34912
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
34913
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
35448
|
+
this.sessionParentPathBySession.set(sessionId, path20.resolve(binding.sessionParentPath));
|
|
35449
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path20.resolve(binding.workingTreeRelRoot));
|
|
34914
35450
|
}
|
|
34915
35451
|
sessionParentPathAfterRemember(sessionId) {
|
|
34916
35452
|
return this.sessionParentPathBySession.get(sessionId);
|
|
@@ -34927,7 +35463,7 @@ var SessionWorktreeManager = class {
|
|
|
34927
35463
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
34928
35464
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
34929
35465
|
if (!parent || !relRoot) return false;
|
|
34930
|
-
return
|
|
35466
|
+
return path20.resolve(parent) !== path20.resolve(relRoot);
|
|
34931
35467
|
}
|
|
34932
35468
|
/**
|
|
34933
35469
|
* Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
|
|
@@ -34936,7 +35472,7 @@ var SessionWorktreeManager = class {
|
|
|
34936
35472
|
if (!sessionId) return null;
|
|
34937
35473
|
const sid = sessionId.trim();
|
|
34938
35474
|
const cached2 = this.sessionParentPathBySession.get(sid);
|
|
34939
|
-
if (cached2) return
|
|
35475
|
+
if (cached2) return path20.resolve(cached2);
|
|
34940
35476
|
const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
|
|
34941
35477
|
if (!paths?.length) return null;
|
|
34942
35478
|
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
@@ -34950,7 +35486,7 @@ var SessionWorktreeManager = class {
|
|
|
34950
35486
|
const sid = sessionId.trim();
|
|
34951
35487
|
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
34952
35488
|
if (parentPathRaw) {
|
|
34953
|
-
const resolved =
|
|
35489
|
+
const resolved = path20.resolve(parentPathRaw);
|
|
34954
35490
|
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
34955
35491
|
const diskFirst = this.tryDiscoverFromDisk(sid);
|
|
34956
35492
|
if (diskFirst) {
|
|
@@ -34969,7 +35505,7 @@ var SessionWorktreeManager = class {
|
|
|
34969
35505
|
this.rememberSessionWorktrees(sid, tryRoot);
|
|
34970
35506
|
return this.sessionParentPathAfterRemember(sid);
|
|
34971
35507
|
}
|
|
34972
|
-
const next =
|
|
35508
|
+
const next = path20.dirname(cur);
|
|
34973
35509
|
if (next === cur) break;
|
|
34974
35510
|
cur = next;
|
|
34975
35511
|
}
|
|
@@ -35122,15 +35658,15 @@ var SessionWorktreeManager = class {
|
|
|
35122
35658
|
}
|
|
35123
35659
|
};
|
|
35124
35660
|
function defaultWorktreesRootPath() {
|
|
35125
|
-
return
|
|
35661
|
+
return path20.join(os5.homedir(), ".buildautomaton", "worktrees");
|
|
35126
35662
|
}
|
|
35127
35663
|
|
|
35128
35664
|
// src/files/watch-file-index.ts
|
|
35129
35665
|
import { watch } from "node:fs";
|
|
35130
|
-
import
|
|
35666
|
+
import path27 from "node:path";
|
|
35131
35667
|
|
|
35132
35668
|
// src/files/index/build-file-index.ts
|
|
35133
|
-
import
|
|
35669
|
+
import path24 from "node:path";
|
|
35134
35670
|
|
|
35135
35671
|
// src/runtime/yield-to-event-loop.ts
|
|
35136
35672
|
function yieldToEventLoop() {
|
|
@@ -35138,14 +35674,14 @@ function yieldToEventLoop() {
|
|
|
35138
35674
|
}
|
|
35139
35675
|
|
|
35140
35676
|
// src/files/index/walk-workspace-tree.ts
|
|
35141
|
-
import
|
|
35142
|
-
import
|
|
35677
|
+
import fs20 from "node:fs";
|
|
35678
|
+
import path22 from "node:path";
|
|
35143
35679
|
|
|
35144
35680
|
// src/files/index/constants.ts
|
|
35145
|
-
import
|
|
35146
|
-
import
|
|
35681
|
+
import path21 from "node:path";
|
|
35682
|
+
import os6 from "node:os";
|
|
35147
35683
|
var INDEX_WORK_YIELD_EVERY = 256;
|
|
35148
|
-
var INDEX_DIR =
|
|
35684
|
+
var INDEX_DIR = path21.join(os6.homedir(), ".buildautomaton");
|
|
35149
35685
|
var INDEX_HASH_LEN = 16;
|
|
35150
35686
|
var INDEX_VERSION = 2;
|
|
35151
35687
|
var INDEX_LOG_PREFIX = "[file-index]";
|
|
@@ -35154,20 +35690,20 @@ var INDEX_LOG_PREFIX = "[file-index]";
|
|
|
35154
35690
|
function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
35155
35691
|
let names;
|
|
35156
35692
|
try {
|
|
35157
|
-
names =
|
|
35693
|
+
names = fs20.readdirSync(dir);
|
|
35158
35694
|
} catch {
|
|
35159
35695
|
return;
|
|
35160
35696
|
}
|
|
35161
35697
|
for (const name of names) {
|
|
35162
35698
|
if (name.startsWith(".")) continue;
|
|
35163
|
-
const full =
|
|
35699
|
+
const full = path22.join(dir, name);
|
|
35164
35700
|
let stat3;
|
|
35165
35701
|
try {
|
|
35166
|
-
stat3 =
|
|
35702
|
+
stat3 = fs20.statSync(full);
|
|
35167
35703
|
} catch {
|
|
35168
35704
|
continue;
|
|
35169
35705
|
}
|
|
35170
|
-
const relative5 =
|
|
35706
|
+
const relative5 = path22.relative(baseDir, full).replace(/\\/g, "/");
|
|
35171
35707
|
if (stat3.isDirectory()) {
|
|
35172
35708
|
walkWorkspaceTreeSync(full, baseDir, out);
|
|
35173
35709
|
} else if (stat3.isFile()) {
|
|
@@ -35178,7 +35714,7 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
|
35178
35714
|
async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
35179
35715
|
let names;
|
|
35180
35716
|
try {
|
|
35181
|
-
names = await
|
|
35717
|
+
names = await fs20.promises.readdir(dir);
|
|
35182
35718
|
} catch {
|
|
35183
35719
|
return;
|
|
35184
35720
|
}
|
|
@@ -35188,14 +35724,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
35188
35724
|
await yieldToEventLoop();
|
|
35189
35725
|
}
|
|
35190
35726
|
state.n++;
|
|
35191
|
-
const full =
|
|
35727
|
+
const full = path22.join(dir, name);
|
|
35192
35728
|
let stat3;
|
|
35193
35729
|
try {
|
|
35194
|
-
stat3 = await
|
|
35730
|
+
stat3 = await fs20.promises.stat(full);
|
|
35195
35731
|
} catch {
|
|
35196
35732
|
continue;
|
|
35197
35733
|
}
|
|
35198
|
-
const relative5 =
|
|
35734
|
+
const relative5 = path22.relative(baseDir, full).replace(/\\/g, "/");
|
|
35199
35735
|
if (stat3.isDirectory()) {
|
|
35200
35736
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
35201
35737
|
} else if (stat3.isFile()) {
|
|
@@ -35276,22 +35812,22 @@ async function buildTrigramMapForPathsAsync(paths) {
|
|
|
35276
35812
|
}
|
|
35277
35813
|
|
|
35278
35814
|
// src/files/index/write-index-file.ts
|
|
35279
|
-
import
|
|
35815
|
+
import fs21 from "node:fs";
|
|
35280
35816
|
|
|
35281
35817
|
// src/files/index/paths.ts
|
|
35282
|
-
import
|
|
35818
|
+
import path23 from "node:path";
|
|
35283
35819
|
import crypto2 from "node:crypto";
|
|
35284
35820
|
function getIndexPathForCwd(resolvedCwd) {
|
|
35285
35821
|
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
35286
|
-
return
|
|
35822
|
+
return path23.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
35287
35823
|
}
|
|
35288
35824
|
|
|
35289
35825
|
// src/files/index/write-index-file.ts
|
|
35290
35826
|
function writeIndexFileSync(resolvedCwd, data) {
|
|
35291
35827
|
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
35292
35828
|
try {
|
|
35293
|
-
if (!
|
|
35294
|
-
|
|
35829
|
+
if (!fs21.existsSync(INDEX_DIR)) fs21.mkdirSync(INDEX_DIR, { recursive: true });
|
|
35830
|
+
fs21.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
35295
35831
|
} catch (e) {
|
|
35296
35832
|
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
35297
35833
|
}
|
|
@@ -35299,8 +35835,8 @@ function writeIndexFileSync(resolvedCwd, data) {
|
|
|
35299
35835
|
async function writeIndexFileAsync(resolvedCwd, data) {
|
|
35300
35836
|
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
35301
35837
|
try {
|
|
35302
|
-
await
|
|
35303
|
-
await
|
|
35838
|
+
await fs21.promises.mkdir(INDEX_DIR, { recursive: true });
|
|
35839
|
+
await fs21.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
|
|
35304
35840
|
} catch (e) {
|
|
35305
35841
|
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
35306
35842
|
}
|
|
@@ -35314,7 +35850,7 @@ function sortPaths(paths) {
|
|
|
35314
35850
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
35315
35851
|
}
|
|
35316
35852
|
function buildFileIndex(cwd) {
|
|
35317
|
-
const resolved =
|
|
35853
|
+
const resolved = path24.resolve(cwd);
|
|
35318
35854
|
const paths = [];
|
|
35319
35855
|
walkWorkspaceTreeSync(resolved, resolved, paths);
|
|
35320
35856
|
sortPaths(paths);
|
|
@@ -35324,7 +35860,7 @@ function buildFileIndex(cwd) {
|
|
|
35324
35860
|
return data;
|
|
35325
35861
|
}
|
|
35326
35862
|
async function buildFileIndexAsync(cwd) {
|
|
35327
|
-
const resolved =
|
|
35863
|
+
const resolved = path24.resolve(cwd);
|
|
35328
35864
|
const paths = [];
|
|
35329
35865
|
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
35330
35866
|
await yieldToEventLoop();
|
|
@@ -35336,13 +35872,13 @@ async function buildFileIndexAsync(cwd) {
|
|
|
35336
35872
|
}
|
|
35337
35873
|
|
|
35338
35874
|
// src/files/index/load-file-index.ts
|
|
35339
|
-
import
|
|
35340
|
-
import
|
|
35875
|
+
import fs22 from "node:fs";
|
|
35876
|
+
import path25 from "node:path";
|
|
35341
35877
|
function loadFileIndex(cwd) {
|
|
35342
|
-
const resolved =
|
|
35878
|
+
const resolved = path25.resolve(cwd);
|
|
35343
35879
|
const indexPath = getIndexPathForCwd(resolved);
|
|
35344
35880
|
try {
|
|
35345
|
-
const raw =
|
|
35881
|
+
const raw = fs22.readFileSync(indexPath, "utf8");
|
|
35346
35882
|
const parsed = JSON.parse(raw);
|
|
35347
35883
|
if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
|
|
35348
35884
|
const obj = parsed;
|
|
@@ -35361,9 +35897,9 @@ function loadFileIndex(cwd) {
|
|
|
35361
35897
|
}
|
|
35362
35898
|
|
|
35363
35899
|
// src/files/index/ensure-file-index.ts
|
|
35364
|
-
import
|
|
35900
|
+
import path26 from "node:path";
|
|
35365
35901
|
async function ensureFileIndexAsync(cwd) {
|
|
35366
|
-
const resolved =
|
|
35902
|
+
const resolved = path26.resolve(cwd);
|
|
35367
35903
|
const cached2 = loadFileIndex(resolved);
|
|
35368
35904
|
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
35369
35905
|
const data = await buildFileIndexAsync(resolved);
|
|
@@ -35446,7 +35982,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
35446
35982
|
}
|
|
35447
35983
|
}
|
|
35448
35984
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
35449
|
-
const resolved =
|
|
35985
|
+
const resolved = path27.resolve(cwd);
|
|
35450
35986
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
35451
35987
|
console.error("[file-index] Initial index build failed:", e);
|
|
35452
35988
|
});
|
|
@@ -35473,8 +36009,8 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
35473
36009
|
};
|
|
35474
36010
|
}
|
|
35475
36011
|
|
|
35476
|
-
// src/
|
|
35477
|
-
import * as
|
|
36012
|
+
// src/connection/create-bridge-connection.ts
|
|
36013
|
+
import * as path35 from "node:path";
|
|
35478
36014
|
|
|
35479
36015
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
35480
36016
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -35518,7 +36054,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
35518
36054
|
}
|
|
35519
36055
|
|
|
35520
36056
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
35521
|
-
import
|
|
36057
|
+
import fs23 from "node:fs";
|
|
35522
36058
|
|
|
35523
36059
|
// src/dev-servers/manager/forward-pipe.ts
|
|
35524
36060
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -35554,7 +36090,7 @@ function wireDevServerChildProcess(d) {
|
|
|
35554
36090
|
d.setPollInterval(void 0);
|
|
35555
36091
|
return;
|
|
35556
36092
|
}
|
|
35557
|
-
|
|
36093
|
+
fs23.readFile(d.mergedLogPath, (err, buf) => {
|
|
35558
36094
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
35559
36095
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
35560
36096
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -35592,7 +36128,7 @@ ${errTail}` : ""}`);
|
|
|
35592
36128
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
35593
36129
|
};
|
|
35594
36130
|
if (mergedPath) {
|
|
35595
|
-
|
|
36131
|
+
fs23.readFile(mergedPath, (err, buf) => {
|
|
35596
36132
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
35597
36133
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
35598
36134
|
if (chunk.length > 0) {
|
|
@@ -35694,13 +36230,13 @@ function parseDevServerDefs(servers) {
|
|
|
35694
36230
|
}
|
|
35695
36231
|
|
|
35696
36232
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
35697
|
-
import
|
|
36233
|
+
import fs24 from "node:fs";
|
|
35698
36234
|
function isSpawnEbadf(e) {
|
|
35699
36235
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
35700
36236
|
}
|
|
35701
36237
|
function rmDirQuiet(dir) {
|
|
35702
36238
|
try {
|
|
35703
|
-
|
|
36239
|
+
fs24.rmSync(dir, { recursive: true, force: true });
|
|
35704
36240
|
} catch {
|
|
35705
36241
|
}
|
|
35706
36242
|
}
|
|
@@ -35708,7 +36244,7 @@ var cachedDevNullReadFd;
|
|
|
35708
36244
|
function devNullReadFd() {
|
|
35709
36245
|
if (cachedDevNullReadFd === void 0) {
|
|
35710
36246
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
35711
|
-
cachedDevNullReadFd =
|
|
36247
|
+
cachedDevNullReadFd = fs24.openSync(devPath, "r");
|
|
35712
36248
|
}
|
|
35713
36249
|
return cachedDevNullReadFd;
|
|
35714
36250
|
}
|
|
@@ -35782,15 +36318,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
35782
36318
|
|
|
35783
36319
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
35784
36320
|
import { spawn as spawn6 } from "node:child_process";
|
|
35785
|
-
import
|
|
36321
|
+
import fs25 from "node:fs";
|
|
35786
36322
|
import { tmpdir } from "node:os";
|
|
35787
|
-
import
|
|
36323
|
+
import path28 from "node:path";
|
|
35788
36324
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
35789
|
-
const tmpRoot =
|
|
35790
|
-
const logPath =
|
|
36325
|
+
const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir(), "ba-devsrv-log-"));
|
|
36326
|
+
const logPath = path28.join(tmpRoot, "combined.log");
|
|
35791
36327
|
let logFd;
|
|
35792
36328
|
try {
|
|
35793
|
-
logFd =
|
|
36329
|
+
logFd = fs25.openSync(logPath, "a");
|
|
35794
36330
|
} catch {
|
|
35795
36331
|
rmDirQuiet(tmpRoot);
|
|
35796
36332
|
return null;
|
|
@@ -35809,7 +36345,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35809
36345
|
} else {
|
|
35810
36346
|
proc = spawn6("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
35811
36347
|
}
|
|
35812
|
-
|
|
36348
|
+
fs25.closeSync(logFd);
|
|
35813
36349
|
return {
|
|
35814
36350
|
proc,
|
|
35815
36351
|
pipedStdoutStderr: true,
|
|
@@ -35818,7 +36354,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35818
36354
|
};
|
|
35819
36355
|
} catch (e) {
|
|
35820
36356
|
try {
|
|
35821
|
-
|
|
36357
|
+
fs25.closeSync(logFd);
|
|
35822
36358
|
} catch {
|
|
35823
36359
|
}
|
|
35824
36360
|
rmDirQuiet(tmpRoot);
|
|
@@ -35829,22 +36365,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35829
36365
|
|
|
35830
36366
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
35831
36367
|
import { spawn as spawn7 } from "node:child_process";
|
|
35832
|
-
import
|
|
36368
|
+
import fs26 from "node:fs";
|
|
35833
36369
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
35834
|
-
import
|
|
36370
|
+
import path29 from "node:path";
|
|
35835
36371
|
function shSingleQuote(s) {
|
|
35836
36372
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
35837
36373
|
}
|
|
35838
36374
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
35839
|
-
const tmpRoot =
|
|
35840
|
-
const logPath =
|
|
35841
|
-
const innerPath =
|
|
35842
|
-
const runnerPath =
|
|
36375
|
+
const tmpRoot = fs26.mkdtempSync(path29.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36376
|
+
const logPath = path29.join(tmpRoot, "combined.log");
|
|
36377
|
+
const innerPath = path29.join(tmpRoot, "_cmd.sh");
|
|
36378
|
+
const runnerPath = path29.join(tmpRoot, "_run.sh");
|
|
35843
36379
|
try {
|
|
35844
|
-
|
|
36380
|
+
fs26.writeFileSync(innerPath, `#!/bin/sh
|
|
35845
36381
|
${command}
|
|
35846
36382
|
`);
|
|
35847
|
-
|
|
36383
|
+
fs26.writeFileSync(
|
|
35848
36384
|
runnerPath,
|
|
35849
36385
|
`#!/bin/sh
|
|
35850
36386
|
cd ${shSingleQuote(cwd)}
|
|
@@ -35870,13 +36406,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
35870
36406
|
}
|
|
35871
36407
|
}
|
|
35872
36408
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
35873
|
-
const tmpRoot =
|
|
35874
|
-
const logPath =
|
|
35875
|
-
const runnerPath =
|
|
36409
|
+
const tmpRoot = fs26.mkdtempSync(path29.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36410
|
+
const logPath = path29.join(tmpRoot, "combined.log");
|
|
36411
|
+
const runnerPath = path29.join(tmpRoot, "_run.bat");
|
|
35876
36412
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
35877
36413
|
const com = process.env.ComSpec || "cmd.exe";
|
|
35878
36414
|
try {
|
|
35879
|
-
|
|
36415
|
+
fs26.writeFileSync(
|
|
35880
36416
|
runnerPath,
|
|
35881
36417
|
`@ECHO OFF\r
|
|
35882
36418
|
CD /D ${q(cwd)}\r
|
|
@@ -36609,7 +37145,17 @@ function tryConsumeBinaryProxyBody(raw, deps) {
|
|
|
36609
37145
|
|
|
36610
37146
|
// src/firehose/connect-firehose.ts
|
|
36611
37147
|
function connectFirehose(options) {
|
|
36612
|
-
const {
|
|
37148
|
+
const {
|
|
37149
|
+
firehoseServerUrl,
|
|
37150
|
+
workspaceId,
|
|
37151
|
+
bridgeName,
|
|
37152
|
+
proxyPorts,
|
|
37153
|
+
log: log2,
|
|
37154
|
+
devServerManager,
|
|
37155
|
+
onOpen,
|
|
37156
|
+
onClose,
|
|
37157
|
+
suppressWebSocketErrors
|
|
37158
|
+
} = options;
|
|
36613
37159
|
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
36614
37160
|
applyCliOutboundNetworkPreferences();
|
|
36615
37161
|
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
@@ -36654,7 +37200,9 @@ function connectFirehose(options) {
|
|
|
36654
37200
|
});
|
|
36655
37201
|
ws.on("error", (err) => {
|
|
36656
37202
|
disposeClientPing();
|
|
36657
|
-
|
|
37203
|
+
if (!suppressWebSocketErrors?.()) {
|
|
37204
|
+
logCliWebSocketError(log2, "[Proxy and log service]", err);
|
|
37205
|
+
}
|
|
36658
37206
|
if (ws.readyState === wrapper_default.CONNECTING || ws.readyState === wrapper_default.OPEN) {
|
|
36659
37207
|
safeCloseWebSocket(ws);
|
|
36660
37208
|
}
|
|
@@ -36669,7 +37217,7 @@ function connectFirehose(options) {
|
|
|
36669
37217
|
};
|
|
36670
37218
|
}
|
|
36671
37219
|
|
|
36672
|
-
// src/
|
|
37220
|
+
// src/connection/attach-firehose-after-identified.ts
|
|
36673
37221
|
function attachFirehoseAfterIdentified(ctx, params) {
|
|
36674
37222
|
const { state, devServerManager, logFn } = ctx;
|
|
36675
37223
|
function clearFirehoseReconnectTimer() {
|
|
@@ -36686,10 +37234,44 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
36686
37234
|
firehoseQuiet: state.firehoseQuiet
|
|
36687
37235
|
};
|
|
36688
37236
|
}
|
|
37237
|
+
function scheduleFirehoseRetryAfterDrop(closeMeta) {
|
|
37238
|
+
if (state.closedByUser) return;
|
|
37239
|
+
const meta = closeMeta ?? state.lastFirehoseReconnectCloseMeta ?? void 0;
|
|
37240
|
+
const delay2 = applyTieredReconnectPlanAndLog(
|
|
37241
|
+
state.firehoseOutage,
|
|
37242
|
+
logFn,
|
|
37243
|
+
PREVIEW_TUNNEL_SERVICE_LABEL,
|
|
37244
|
+
PREVIEW_TUNNEL_DISCONNECT_LEAD_IN,
|
|
37245
|
+
meta?.code,
|
|
37246
|
+
meta?.reason
|
|
37247
|
+
);
|
|
37248
|
+
armReconnectDelayTimer({
|
|
37249
|
+
delayMs: delay2,
|
|
37250
|
+
bumpAttempt: () => {
|
|
37251
|
+
state.firehoseReconnectAttempt += 1;
|
|
37252
|
+
},
|
|
37253
|
+
clearTimer: clearFirehoseReconnectTimer,
|
|
37254
|
+
setTimer: (id) => {
|
|
37255
|
+
state.firehoseReconnectTimeout = id;
|
|
37256
|
+
},
|
|
37257
|
+
shouldAbortBeforeRun: () => state.closedByUser,
|
|
37258
|
+
run: () => {
|
|
37259
|
+
const p = state.lastFirehoseParams;
|
|
37260
|
+
if (!p) return;
|
|
37261
|
+
attachFirehoseAfterIdentified(ctx, p);
|
|
37262
|
+
},
|
|
37263
|
+
reschedule: () => {
|
|
37264
|
+
scheduleFirehoseRetryAfterDrop();
|
|
37265
|
+
}
|
|
37266
|
+
});
|
|
37267
|
+
}
|
|
36689
37268
|
state.lastFirehoseParams = params;
|
|
36690
37269
|
clearFirehoseReconnectTimer();
|
|
36691
37270
|
if (state.firehoseReconnectAttempt === 0) {
|
|
36692
|
-
|
|
37271
|
+
try {
|
|
37272
|
+
logFn("Connecting to preview tunnel (local HTTP proxy and dev logs)\u2026");
|
|
37273
|
+
} catch {
|
|
37274
|
+
}
|
|
36693
37275
|
}
|
|
36694
37276
|
state.firehoseGeneration += 1;
|
|
36695
37277
|
const myGen = state.firehoseGeneration;
|
|
@@ -36704,47 +37286,47 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
36704
37286
|
proxyPorts: params.proxyPorts,
|
|
36705
37287
|
log: logFn,
|
|
36706
37288
|
devServerManager,
|
|
37289
|
+
suppressWebSocketErrors: () => !state.closedByUser && state.firehoseOutage.startedAt != null,
|
|
36707
37290
|
onOpen: () => {
|
|
36708
37291
|
if (myGen !== state.firehoseGeneration) return;
|
|
36709
|
-
|
|
37292
|
+
try {
|
|
37293
|
+
clearFirehoseReconnectQuietOnOpen(
|
|
37294
|
+
{
|
|
37295
|
+
firehoseQuiet: state.firehoseQuiet,
|
|
37296
|
+
firehoseOutage: state.firehoseOutage,
|
|
37297
|
+
lastFirehoseReconnectCloseMeta: state.lastFirehoseReconnectCloseMeta
|
|
37298
|
+
},
|
|
37299
|
+
logFn
|
|
37300
|
+
);
|
|
37301
|
+
} catch {
|
|
37302
|
+
}
|
|
36710
37303
|
const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
|
|
36711
37304
|
state.firehoseReconnectAttempt = 0;
|
|
36712
37305
|
if (!logOpenAsFirehoseReconnect) {
|
|
36713
|
-
|
|
37306
|
+
try {
|
|
37307
|
+
logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
|
|
37308
|
+
} catch {
|
|
37309
|
+
}
|
|
36714
37310
|
}
|
|
36715
37311
|
},
|
|
36716
37312
|
onClose: (code, reason) => {
|
|
36717
37313
|
if (myGen !== state.firehoseGeneration) return;
|
|
36718
37314
|
state.firehoseHandle = null;
|
|
36719
37315
|
if (state.closedByUser) return;
|
|
36720
|
-
|
|
36721
|
-
|
|
36722
|
-
|
|
36723
|
-
|
|
36724
|
-
|
|
36725
|
-
|
|
36726
|
-
|
|
36727
|
-
|
|
36728
|
-
|
|
36729
|
-
state.firehoseReconnectAttempt
|
|
36730
|
-
);
|
|
36731
|
-
state.firehoseReconnectTimeout = setTimeout(() => {
|
|
36732
|
-
state.firehoseReconnectTimeout = null;
|
|
36733
|
-
if (state.closedByUser) return;
|
|
36734
|
-
const p = state.lastFirehoseParams;
|
|
36735
|
-
if (!p) {
|
|
36736
|
-
if (state.firehoseQuiet.verboseLogs) {
|
|
36737
|
-
logFn(`${PROXY_AND_LOG_SERVICE_LABEL} Reconnect skipped: no stored connection parameters.`);
|
|
36738
|
-
}
|
|
36739
|
-
return;
|
|
36740
|
-
}
|
|
36741
|
-
attachFirehoseAfterIdentified(ctx, p);
|
|
36742
|
-
}, delay2);
|
|
37316
|
+
state.lastFirehoseReconnectCloseMeta = { code, reason };
|
|
37317
|
+
try {
|
|
37318
|
+
beginFirehoseDeferredDisconnect(firehoseCtx(), code, reason, logFn);
|
|
37319
|
+
} catch {
|
|
37320
|
+
}
|
|
37321
|
+
try {
|
|
37322
|
+
scheduleFirehoseRetryAfterDrop({ code, reason });
|
|
37323
|
+
} catch {
|
|
37324
|
+
}
|
|
36743
37325
|
}
|
|
36744
37326
|
});
|
|
36745
37327
|
}
|
|
36746
37328
|
|
|
36747
|
-
// src/
|
|
37329
|
+
// src/connection/create-bridge-identified-handler.ts
|
|
36748
37330
|
function createOnBridgeIdentified(opts) {
|
|
36749
37331
|
const { devServerManager, firehoseServerUrl, workspaceId, state, logFn } = opts;
|
|
36750
37332
|
const firehoseCtx = { state, devServerManager, logFn };
|
|
@@ -36767,30 +37349,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
36767
37349
|
}
|
|
36768
37350
|
|
|
36769
37351
|
// src/skills/discover-local-agent-skills.ts
|
|
36770
|
-
import
|
|
36771
|
-
import
|
|
37352
|
+
import fs27 from "node:fs";
|
|
37353
|
+
import path30 from "node:path";
|
|
36772
37354
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
36773
37355
|
function discoverLocalSkills(cwd) {
|
|
36774
37356
|
const out = [];
|
|
36775
37357
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
36776
37358
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
36777
|
-
const base =
|
|
36778
|
-
if (!
|
|
37359
|
+
const base = path30.join(cwd, rel);
|
|
37360
|
+
if (!fs27.existsSync(base) || !fs27.statSync(base).isDirectory()) continue;
|
|
36779
37361
|
let entries = [];
|
|
36780
37362
|
try {
|
|
36781
|
-
entries =
|
|
37363
|
+
entries = fs27.readdirSync(base);
|
|
36782
37364
|
} catch {
|
|
36783
37365
|
continue;
|
|
36784
37366
|
}
|
|
36785
37367
|
for (const name of entries) {
|
|
36786
|
-
const dir =
|
|
37368
|
+
const dir = path30.join(base, name);
|
|
36787
37369
|
try {
|
|
36788
|
-
if (!
|
|
37370
|
+
if (!fs27.statSync(dir).isDirectory()) continue;
|
|
36789
37371
|
} catch {
|
|
36790
37372
|
continue;
|
|
36791
37373
|
}
|
|
36792
|
-
const skillMd =
|
|
36793
|
-
if (!
|
|
37374
|
+
const skillMd = path30.join(dir, "SKILL.md");
|
|
37375
|
+
if (!fs27.existsSync(skillMd)) continue;
|
|
36794
37376
|
const key = `${rel}/${name}`;
|
|
36795
37377
|
if (seenKeys.has(key)) continue;
|
|
36796
37378
|
seenKeys.add(key);
|
|
@@ -36802,23 +37384,23 @@ function discoverLocalSkills(cwd) {
|
|
|
36802
37384
|
function discoverSkillLayoutRoots(cwd) {
|
|
36803
37385
|
const roots = [];
|
|
36804
37386
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
36805
|
-
const base =
|
|
36806
|
-
if (!
|
|
37387
|
+
const base = path30.join(cwd, rel);
|
|
37388
|
+
if (!fs27.existsSync(base) || !fs27.statSync(base).isDirectory()) continue;
|
|
36807
37389
|
let entries = [];
|
|
36808
37390
|
try {
|
|
36809
|
-
entries =
|
|
37391
|
+
entries = fs27.readdirSync(base);
|
|
36810
37392
|
} catch {
|
|
36811
37393
|
continue;
|
|
36812
37394
|
}
|
|
36813
37395
|
const skills2 = [];
|
|
36814
37396
|
for (const name of entries) {
|
|
36815
|
-
const dir =
|
|
37397
|
+
const dir = path30.join(base, name);
|
|
36816
37398
|
try {
|
|
36817
|
-
if (!
|
|
37399
|
+
if (!fs27.statSync(dir).isDirectory()) continue;
|
|
36818
37400
|
} catch {
|
|
36819
37401
|
continue;
|
|
36820
37402
|
}
|
|
36821
|
-
if (!
|
|
37403
|
+
if (!fs27.existsSync(path30.join(dir, "SKILL.md"))) continue;
|
|
36822
37404
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
36823
37405
|
skills2.push({ name, relPath });
|
|
36824
37406
|
}
|
|
@@ -36855,7 +37437,7 @@ async function detectLocalAgentTypes() {
|
|
|
36855
37437
|
}
|
|
36856
37438
|
}
|
|
36857
37439
|
|
|
36858
|
-
// src/
|
|
37440
|
+
// src/connection/create-bridge-local-reports.ts
|
|
36859
37441
|
function createSendLocalSkillsReport(getWs, logFn) {
|
|
36860
37442
|
return () => {
|
|
36861
37443
|
setImmediate(() => {
|
|
@@ -36888,14 +37470,14 @@ function createReportAutoDetectedAgents(getWs, logFn) {
|
|
|
36888
37470
|
};
|
|
36889
37471
|
}
|
|
36890
37472
|
|
|
36891
|
-
// src/
|
|
37473
|
+
// src/connection/build-bridge-url.ts
|
|
36892
37474
|
function buildBridgeUrl(apiUrl, workspaceId, authToken) {
|
|
36893
37475
|
const base = apiUrl.startsWith("https") ? apiUrl.replace(/^https/, "wss") : apiUrl.replace(/^http/, "ws");
|
|
36894
37476
|
const params = new URLSearchParams({ workspaceId, token: authToken });
|
|
36895
37477
|
return `${base}/ws/bridge?${params.toString()}`;
|
|
36896
37478
|
}
|
|
36897
37479
|
|
|
36898
|
-
// src/
|
|
37480
|
+
// src/connection/report-git-repos.ts
|
|
36899
37481
|
function reportGitRepos(getWs, log2) {
|
|
36900
37482
|
setImmediate(() => {
|
|
36901
37483
|
discoverGitRepos().then((repos) => {
|
|
@@ -36951,14 +37533,14 @@ function parseApiToBridgeMessage(data, log2) {
|
|
|
36951
37533
|
return data;
|
|
36952
37534
|
}
|
|
36953
37535
|
|
|
36954
|
-
// src/
|
|
37536
|
+
// src/routing/handlers/auth-token.ts
|
|
36955
37537
|
var handleAuthToken = (msg, { log: log2 }) => {
|
|
36956
37538
|
if (typeof msg.token !== "string") return;
|
|
36957
37539
|
log2("Received auth token. Save it for future runs:");
|
|
36958
37540
|
log2(` export BUILDAUTOMATON_AUTH_TOKEN="${msg.token}"`);
|
|
36959
37541
|
};
|
|
36960
37542
|
|
|
36961
|
-
// src/
|
|
37543
|
+
// src/routing/handlers/bridge-identified.ts
|
|
36962
37544
|
var handleBridgeIdentified = (msg, deps) => {
|
|
36963
37545
|
if (typeof msg.bridgeName !== "string") return;
|
|
36964
37546
|
deps.onBridgeIdentified({
|
|
@@ -36994,13 +37576,13 @@ function handleBridgeAgentConfig(msg, { acpManager }) {
|
|
|
36994
37576
|
acpManager.setPreferredAgentType(msg.agents[0].type);
|
|
36995
37577
|
}
|
|
36996
37578
|
|
|
36997
|
-
// src/
|
|
37579
|
+
// src/routing/handlers/agent-config.ts
|
|
36998
37580
|
var handleAgentConfigMessage = (msg, deps) => {
|
|
36999
37581
|
handleBridgeAgentConfig(msg, deps);
|
|
37000
37582
|
};
|
|
37001
37583
|
|
|
37002
37584
|
// src/prompt-turn-queue/runner.ts
|
|
37003
|
-
import
|
|
37585
|
+
import fs30 from "node:fs";
|
|
37004
37586
|
|
|
37005
37587
|
// src/prompt-turn-queue/client-report.ts
|
|
37006
37588
|
function sendPromptQueueClientReport(ws, queues) {
|
|
@@ -37010,13 +37592,13 @@ function sendPromptQueueClientReport(ws, queues) {
|
|
|
37010
37592
|
}
|
|
37011
37593
|
|
|
37012
37594
|
// src/prompt-turn-queue/disk-store.ts
|
|
37013
|
-
import
|
|
37595
|
+
import fs29 from "node:fs";
|
|
37014
37596
|
|
|
37015
37597
|
// src/prompt-turn-queue/paths.ts
|
|
37016
37598
|
import crypto3 from "node:crypto";
|
|
37017
|
-
import
|
|
37018
|
-
import
|
|
37019
|
-
import
|
|
37599
|
+
import fs28 from "node:fs";
|
|
37600
|
+
import path31 from "node:path";
|
|
37601
|
+
import os7 from "node:os";
|
|
37020
37602
|
var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
|
|
37021
37603
|
function queueStateFileSlug(queueKey) {
|
|
37022
37604
|
if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
|
|
@@ -37024,15 +37606,15 @@ function queueStateFileSlug(queueKey) {
|
|
|
37024
37606
|
}
|
|
37025
37607
|
function getPromptQueuesDirectory() {
|
|
37026
37608
|
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
37027
|
-
if (override) return
|
|
37028
|
-
return
|
|
37609
|
+
if (override) return path31.resolve(override);
|
|
37610
|
+
return path31.join(os7.homedir(), ".buildautomaton", "queues");
|
|
37029
37611
|
}
|
|
37030
37612
|
function ensurePromptQueuesDirectory() {
|
|
37031
37613
|
const dir = getPromptQueuesDirectory();
|
|
37032
|
-
if (!
|
|
37614
|
+
if (!fs28.existsSync(dir)) fs28.mkdirSync(dir, { recursive: true });
|
|
37033
37615
|
}
|
|
37034
37616
|
function queueStateFilePath(queueKey) {
|
|
37035
|
-
return
|
|
37617
|
+
return path31.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
|
|
37036
37618
|
}
|
|
37037
37619
|
|
|
37038
37620
|
// src/prompt-turn-queue/disk-store.ts
|
|
@@ -37057,7 +37639,7 @@ function parsePersistedQueueFile(raw) {
|
|
|
37057
37639
|
function readPersistedQueue(queueKey) {
|
|
37058
37640
|
const p = queueStateFilePath(queueKey);
|
|
37059
37641
|
try {
|
|
37060
|
-
return parsePersistedQueueFile(
|
|
37642
|
+
return parsePersistedQueueFile(fs29.readFileSync(p, "utf8"));
|
|
37061
37643
|
} catch {
|
|
37062
37644
|
return null;
|
|
37063
37645
|
}
|
|
@@ -37065,7 +37647,7 @@ function readPersistedQueue(queueKey) {
|
|
|
37065
37647
|
function writePersistedQueue(file2) {
|
|
37066
37648
|
ensurePromptQueuesDirectory();
|
|
37067
37649
|
const p = queueStateFilePath(file2.queueKey);
|
|
37068
|
-
|
|
37650
|
+
fs29.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
|
|
37069
37651
|
}
|
|
37070
37652
|
function mergeServerQueueSnapshot(queueKey, serverTurns) {
|
|
37071
37653
|
const prev = readPersistedQueue(queueKey);
|
|
@@ -37123,7 +37705,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
37123
37705
|
const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
|
|
37124
37706
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
37125
37707
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
37126
|
-
if (!
|
|
37708
|
+
if (!fs30.existsSync(file2)) {
|
|
37127
37709
|
deps.log(
|
|
37128
37710
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
37129
37711
|
);
|
|
@@ -37153,7 +37735,8 @@ function dispatchLocalPrompt(next, deps) {
|
|
|
37153
37735
|
...typeof pl.followUpCatalogPromptId === "string" ? { followUpCatalogPromptId: pl.followUpCatalogPromptId } : {},
|
|
37154
37736
|
...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
|
|
37155
37737
|
...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
|
|
37156
|
-
...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {}
|
|
37738
|
+
...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {},
|
|
37739
|
+
...pl.agentConfig != null && typeof pl.agentConfig === "object" && !Array.isArray(pl.agentConfig) && Object.keys(pl.agentConfig).length > 0 ? { agentConfig: pl.agentConfig } : {}
|
|
37157
37740
|
};
|
|
37158
37741
|
handleBridgePrompt(msg, deps);
|
|
37159
37742
|
}
|
|
@@ -37345,9 +37928,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
37345
37928
|
for (const item of raw) {
|
|
37346
37929
|
if (!item || typeof item !== "object") continue;
|
|
37347
37930
|
const o = item;
|
|
37348
|
-
const
|
|
37349
|
-
if (!
|
|
37350
|
-
const row = { path:
|
|
37931
|
+
const path37 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
37932
|
+
if (!path37) continue;
|
|
37933
|
+
const row = { path: path37 };
|
|
37351
37934
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
37352
37935
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
37353
37936
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -37451,6 +38034,7 @@ function handleBridgePrompt(msg, deps) {
|
|
|
37451
38034
|
const sessionParentPath = typeof msg.sessionParentPath === "string" && msg.sessionParentPath.trim() ? msg.sessionParentPath.trim() : null;
|
|
37452
38035
|
const agentType = typeof msg.agentType === "string" && msg.agentType.trim() ? msg.agentType.trim() : void 0;
|
|
37453
38036
|
const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
|
|
38037
|
+
const agentConfig = msg.agentConfig != null && typeof msg.agentConfig === "object" && !Array.isArray(msg.agentConfig) ? msg.agentConfig : void 0;
|
|
37454
38038
|
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
37455
38039
|
async function preambleAndPrompt(resolvedCwd) {
|
|
37456
38040
|
const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
|
|
@@ -37486,6 +38070,7 @@ function handleBridgePrompt(msg, deps) {
|
|
|
37486
38070
|
runId,
|
|
37487
38071
|
mode,
|
|
37488
38072
|
agentType,
|
|
38073
|
+
agentConfig,
|
|
37489
38074
|
sessionParentPath: effectiveCwd,
|
|
37490
38075
|
sendResult: sendResult2,
|
|
37491
38076
|
sendSessionUpdate,
|
|
@@ -37502,27 +38087,27 @@ function handleBridgePrompt(msg, deps) {
|
|
|
37502
38087
|
});
|
|
37503
38088
|
}
|
|
37504
38089
|
|
|
37505
|
-
// src/
|
|
38090
|
+
// src/routing/handlers/prompt.ts
|
|
37506
38091
|
var handlePromptMessage = (msg, deps) => {
|
|
37507
38092
|
handleBridgePrompt(msg, deps);
|
|
37508
38093
|
};
|
|
37509
38094
|
|
|
37510
|
-
// src/
|
|
38095
|
+
// src/routing/handlers/prompt-queue-state.ts
|
|
37511
38096
|
var handlePromptQueueStateMessage = (msg, deps) => {
|
|
37512
38097
|
void applyPromptQueueStateFromServer(msg, deps).catch((err) => {
|
|
37513
38098
|
deps.log(`[Queue] applyPromptQueueStateFromServer failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
37514
38099
|
});
|
|
37515
38100
|
};
|
|
37516
38101
|
|
|
37517
|
-
// src/agents/acp/from-bridge/handle-bridge-
|
|
37518
|
-
function
|
|
38102
|
+
// src/agents/acp/from-bridge/handle-bridge-session-request-response.ts
|
|
38103
|
+
function handleBridgeSessionRequestResponse(msg, { acpManager }) {
|
|
37519
38104
|
if (typeof msg.requestId !== "string") return;
|
|
37520
38105
|
acpManager.resolveRequest(msg.requestId, msg.result ?? {});
|
|
37521
38106
|
}
|
|
37522
38107
|
|
|
37523
|
-
// src/
|
|
37524
|
-
var
|
|
37525
|
-
|
|
38108
|
+
// src/routing/handlers/session-request-response.ts
|
|
38109
|
+
var handleSessionRequestResponseMessage = (msg, deps) => {
|
|
38110
|
+
handleBridgeSessionRequestResponse(msg, deps);
|
|
37526
38111
|
};
|
|
37527
38112
|
|
|
37528
38113
|
// src/skills/preview.ts
|
|
@@ -37546,8 +38131,8 @@ function randomSecret() {
|
|
|
37546
38131
|
}
|
|
37547
38132
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
37548
38133
|
}
|
|
37549
|
-
async function requestPreviewApi(port, secret, method,
|
|
37550
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
38134
|
+
async function requestPreviewApi(port, secret, method, path37, body) {
|
|
38135
|
+
const url2 = `http://127.0.0.1:${port}${path37}`;
|
|
37551
38136
|
const headers = {
|
|
37552
38137
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
37553
38138
|
"Content-Type": "application/json"
|
|
@@ -37559,7 +38144,7 @@ async function requestPreviewApi(port, secret, method, path36, body) {
|
|
|
37559
38144
|
});
|
|
37560
38145
|
const data = await res.json().catch(() => ({}));
|
|
37561
38146
|
if (!res.ok) {
|
|
37562
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
38147
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path37}: ${res.status}`);
|
|
37563
38148
|
}
|
|
37564
38149
|
return data;
|
|
37565
38150
|
}
|
|
@@ -37709,7 +38294,7 @@ function handleSkillCall(msg, socket, log2) {
|
|
|
37709
38294
|
});
|
|
37710
38295
|
}
|
|
37711
38296
|
|
|
37712
|
-
// src/
|
|
38297
|
+
// src/routing/handlers/skill-call.ts
|
|
37713
38298
|
var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
37714
38299
|
const skillId = typeof msg.skillId === "string" ? msg.skillId : "";
|
|
37715
38300
|
const operationId = typeof msg.operationId === "string" ? msg.operationId : "";
|
|
@@ -37724,15 +38309,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
37724
38309
|
};
|
|
37725
38310
|
|
|
37726
38311
|
// src/files/list-dir.ts
|
|
37727
|
-
import
|
|
37728
|
-
import
|
|
38312
|
+
import fs31 from "node:fs";
|
|
38313
|
+
import path33 from "node:path";
|
|
37729
38314
|
|
|
37730
38315
|
// src/files/ensure-under-cwd.ts
|
|
37731
|
-
import
|
|
38316
|
+
import path32 from "node:path";
|
|
37732
38317
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
37733
|
-
const normalized =
|
|
37734
|
-
const resolved =
|
|
37735
|
-
if (!resolved.startsWith(cwd +
|
|
38318
|
+
const normalized = path32.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
38319
|
+
const resolved = path32.resolve(cwd, normalized);
|
|
38320
|
+
if (!resolved.startsWith(cwd + path32.sep) && resolved !== cwd) {
|
|
37736
38321
|
return null;
|
|
37737
38322
|
}
|
|
37738
38323
|
return resolved;
|
|
@@ -37746,7 +38331,7 @@ async function listDirAsync(relativePath) {
|
|
|
37746
38331
|
return { error: "Path is outside working directory" };
|
|
37747
38332
|
}
|
|
37748
38333
|
try {
|
|
37749
|
-
const names = await
|
|
38334
|
+
const names = await fs31.promises.readdir(resolved, { withFileTypes: true });
|
|
37750
38335
|
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
37751
38336
|
const entries = [];
|
|
37752
38337
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -37754,12 +38339,12 @@ async function listDirAsync(relativePath) {
|
|
|
37754
38339
|
await yieldToEventLoop();
|
|
37755
38340
|
}
|
|
37756
38341
|
const d = visible[i];
|
|
37757
|
-
const entryPath =
|
|
37758
|
-
const fullPath =
|
|
38342
|
+
const entryPath = path33.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
38343
|
+
const fullPath = path33.join(resolved, d.name);
|
|
37759
38344
|
let isDir = d.isDirectory();
|
|
37760
38345
|
if (d.isSymbolicLink()) {
|
|
37761
38346
|
try {
|
|
37762
|
-
const targetStat = await
|
|
38347
|
+
const targetStat = await fs31.promises.stat(fullPath);
|
|
37763
38348
|
isDir = targetStat.isDirectory();
|
|
37764
38349
|
} catch {
|
|
37765
38350
|
isDir = false;
|
|
@@ -37784,25 +38369,25 @@ async function listDirAsync(relativePath) {
|
|
|
37784
38369
|
}
|
|
37785
38370
|
|
|
37786
38371
|
// src/files/read-file.ts
|
|
37787
|
-
import
|
|
38372
|
+
import fs32 from "node:fs";
|
|
37788
38373
|
import { StringDecoder } from "node:string_decoder";
|
|
37789
38374
|
function resolveFilePath(relativePath) {
|
|
37790
38375
|
const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
|
|
37791
38376
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
37792
38377
|
let real;
|
|
37793
38378
|
try {
|
|
37794
|
-
real =
|
|
38379
|
+
real = fs32.realpathSync(resolved);
|
|
37795
38380
|
} catch {
|
|
37796
38381
|
real = resolved;
|
|
37797
38382
|
}
|
|
37798
|
-
const stat3 =
|
|
38383
|
+
const stat3 = fs32.statSync(real);
|
|
37799
38384
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
37800
38385
|
return real;
|
|
37801
38386
|
}
|
|
37802
38387
|
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
37803
38388
|
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
37804
|
-
const fileSize =
|
|
37805
|
-
const fd =
|
|
38389
|
+
const fileSize = fs32.statSync(filePath).size;
|
|
38390
|
+
const fd = fs32.openSync(filePath, "r");
|
|
37806
38391
|
const bufSize = 64 * 1024;
|
|
37807
38392
|
const buf = Buffer.alloc(bufSize);
|
|
37808
38393
|
const decoder = new StringDecoder("utf8");
|
|
@@ -37815,7 +38400,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
37815
38400
|
let line0Accum = "";
|
|
37816
38401
|
try {
|
|
37817
38402
|
let bytesRead;
|
|
37818
|
-
while (!done && (bytesRead =
|
|
38403
|
+
while (!done && (bytesRead = fs32.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
37819
38404
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
37820
38405
|
partial2 = "";
|
|
37821
38406
|
let lineStart = 0;
|
|
@@ -37950,7 +38535,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
37950
38535
|
}
|
|
37951
38536
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
37952
38537
|
} finally {
|
|
37953
|
-
|
|
38538
|
+
fs32.closeSync(fd);
|
|
37954
38539
|
}
|
|
37955
38540
|
}
|
|
37956
38541
|
function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
@@ -37961,8 +38546,8 @@ function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
37961
38546
|
if (hasRange) {
|
|
37962
38547
|
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
37963
38548
|
}
|
|
37964
|
-
const stat3 =
|
|
37965
|
-
const raw =
|
|
38549
|
+
const stat3 = fs32.statSync(result);
|
|
38550
|
+
const raw = fs32.readFileSync(result, "utf8");
|
|
37966
38551
|
const lines = raw.split(/\r?\n/);
|
|
37967
38552
|
return { content: raw, totalLines: lines.length, size: stat3.size };
|
|
37968
38553
|
} catch (err) {
|
|
@@ -38051,7 +38636,7 @@ function handleFileBrowserRequest(msg, socket, e2ee) {
|
|
|
38051
38636
|
})();
|
|
38052
38637
|
}
|
|
38053
38638
|
|
|
38054
|
-
// src/
|
|
38639
|
+
// src/routing/handlers/file-browser-messages.ts
|
|
38055
38640
|
function handleFileBrowserRequestMessage(msg, { getWs, e2ee }) {
|
|
38056
38641
|
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
38057
38642
|
const socket = getWs();
|
|
@@ -38069,7 +38654,7 @@ function handleFileBrowserSearchMessage(msg, { getWs, e2ee }) {
|
|
|
38069
38654
|
handleFileBrowserSearch(msg, socket, e2ee);
|
|
38070
38655
|
}
|
|
38071
38656
|
|
|
38072
|
-
// src/
|
|
38657
|
+
// src/routing/handlers/skill-layout-request.ts
|
|
38073
38658
|
function handleSkillLayoutRequest(msg, deps) {
|
|
38074
38659
|
const socket = deps.getWs();
|
|
38075
38660
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
@@ -38080,8 +38665,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
38080
38665
|
}
|
|
38081
38666
|
|
|
38082
38667
|
// src/skills/install-remote-skills.ts
|
|
38083
|
-
import
|
|
38084
|
-
import
|
|
38668
|
+
import fs33 from "node:fs";
|
|
38669
|
+
import path34 from "node:path";
|
|
38085
38670
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
38086
38671
|
const installed2 = [];
|
|
38087
38672
|
if (!Array.isArray(items)) {
|
|
@@ -38092,15 +38677,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
38092
38677
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
38093
38678
|
continue;
|
|
38094
38679
|
}
|
|
38095
|
-
const skillDir =
|
|
38680
|
+
const skillDir = path34.join(cwd, targetDir, item.skillName);
|
|
38096
38681
|
for (const f of item.files) {
|
|
38097
38682
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
38098
|
-
const dest =
|
|
38099
|
-
|
|
38683
|
+
const dest = path34.join(skillDir, f.path);
|
|
38684
|
+
fs33.mkdirSync(path34.dirname(dest), { recursive: true });
|
|
38100
38685
|
if (f.text !== void 0) {
|
|
38101
|
-
|
|
38686
|
+
fs33.writeFileSync(dest, f.text, "utf8");
|
|
38102
38687
|
} else if (f.base64) {
|
|
38103
|
-
|
|
38688
|
+
fs33.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
38104
38689
|
}
|
|
38105
38690
|
}
|
|
38106
38691
|
installed2.push({
|
|
@@ -38115,7 +38700,7 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
38115
38700
|
}
|
|
38116
38701
|
}
|
|
38117
38702
|
|
|
38118
|
-
// src/
|
|
38703
|
+
// src/routing/handlers/install-skills.ts
|
|
38119
38704
|
var handleInstallSkillsMessage = (msg, deps) => {
|
|
38120
38705
|
const socket = deps.getWs();
|
|
38121
38706
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
@@ -38136,12 +38721,12 @@ var handleInstallSkillsMessage = (msg, deps) => {
|
|
|
38136
38721
|
}
|
|
38137
38722
|
};
|
|
38138
38723
|
|
|
38139
|
-
// src/
|
|
38724
|
+
// src/routing/handlers/refresh-local-skills.ts
|
|
38140
38725
|
var handleRefreshLocalSkills = (_msg, deps) => {
|
|
38141
38726
|
deps.sendLocalSkillsReport?.();
|
|
38142
38727
|
};
|
|
38143
38728
|
|
|
38144
|
-
// src/
|
|
38729
|
+
// src/routing/handlers/session-git-request.ts
|
|
38145
38730
|
function sendResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
38146
38731
|
if (!ws) return;
|
|
38147
38732
|
const message = { type: "session_git_result", id, ...payload };
|
|
@@ -38227,7 +38812,7 @@ var handleSessionGitRequestMessage = (msg, deps) => {
|
|
|
38227
38812
|
})();
|
|
38228
38813
|
};
|
|
38229
38814
|
|
|
38230
|
-
// src/
|
|
38815
|
+
// src/routing/handlers/rename-session-branch.ts
|
|
38231
38816
|
var handleRenameSessionBranchMessage = (msg, deps) => {
|
|
38232
38817
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
38233
38818
|
const newBranch = typeof msg.newBranch === "string" ? msg.newBranch : "";
|
|
@@ -38235,22 +38820,22 @@ var handleRenameSessionBranchMessage = (msg, deps) => {
|
|
|
38235
38820
|
void deps.sessionWorktreeManager.renameSessionBranch(sessionId, newBranch);
|
|
38236
38821
|
};
|
|
38237
38822
|
|
|
38238
|
-
// src/
|
|
38823
|
+
// src/routing/handlers/session-archived.ts
|
|
38239
38824
|
var handleSessionArchivedMessage = (msg, deps) => {
|
|
38240
38825
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
38241
38826
|
if (!sessionId) return;
|
|
38242
38827
|
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
38243
38828
|
};
|
|
38244
38829
|
|
|
38245
|
-
// src/
|
|
38830
|
+
// src/routing/handlers/session-discarded.ts
|
|
38246
38831
|
var handleSessionDiscardedMessage = (msg, deps) => {
|
|
38247
38832
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
38248
38833
|
if (!sessionId) return;
|
|
38249
38834
|
void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
|
|
38250
38835
|
};
|
|
38251
38836
|
|
|
38252
|
-
// src/
|
|
38253
|
-
import * as
|
|
38837
|
+
// src/routing/handlers/revert-turn-snapshot.ts
|
|
38838
|
+
import * as fs34 from "node:fs";
|
|
38254
38839
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
38255
38840
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
38256
38841
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -38262,7 +38847,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
38262
38847
|
if (!s) return;
|
|
38263
38848
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
38264
38849
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
38265
|
-
if (!
|
|
38850
|
+
if (!fs34.existsSync(file2)) {
|
|
38266
38851
|
sendWsMessage(s, {
|
|
38267
38852
|
type: "revert_turn_snapshot_result",
|
|
38268
38853
|
id,
|
|
@@ -38281,7 +38866,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
38281
38866
|
})();
|
|
38282
38867
|
};
|
|
38283
38868
|
|
|
38284
|
-
// src/
|
|
38869
|
+
// src/routing/handlers/dev-server-control.ts
|
|
38285
38870
|
var handleDevServerControl = (msg, deps) => {
|
|
38286
38871
|
let wire;
|
|
38287
38872
|
try {
|
|
@@ -38296,13 +38881,13 @@ var handleDevServerControl = (msg, deps) => {
|
|
|
38296
38881
|
deps.devServerManager?.handleControl(serverId, action);
|
|
38297
38882
|
};
|
|
38298
38883
|
|
|
38299
|
-
// src/
|
|
38884
|
+
// src/routing/handlers/dev-servers-config.ts
|
|
38300
38885
|
var handleDevServersConfig = (msg, deps) => {
|
|
38301
38886
|
const devServers = msg.devServers;
|
|
38302
38887
|
deps.devServerManager?.applyConfig(devServers ?? []);
|
|
38303
38888
|
};
|
|
38304
38889
|
|
|
38305
|
-
// src/
|
|
38890
|
+
// src/routing/dispatch-bridge-message.ts
|
|
38306
38891
|
function dispatchBridgeMessage(msg, deps) {
|
|
38307
38892
|
switch (msg.type) {
|
|
38308
38893
|
case "auth_token":
|
|
@@ -38342,7 +38927,7 @@ function dispatchBridgeMessage(msg, deps) {
|
|
|
38342
38927
|
handleRevertTurnSnapshotMessage(msg, deps);
|
|
38343
38928
|
break;
|
|
38344
38929
|
case "cursor_request_response":
|
|
38345
|
-
|
|
38930
|
+
handleSessionRequestResponseMessage(msg, deps);
|
|
38346
38931
|
break;
|
|
38347
38932
|
case "skill_call":
|
|
38348
38933
|
handleSkillCallMessage(msg, deps);
|
|
@@ -38365,7 +38950,7 @@ function dispatchBridgeMessage(msg, deps) {
|
|
|
38365
38950
|
}
|
|
38366
38951
|
}
|
|
38367
38952
|
|
|
38368
|
-
// src/
|
|
38953
|
+
// src/routing/handle-bridge-message.ts
|
|
38369
38954
|
function handleBridgeMessage(data, deps) {
|
|
38370
38955
|
if (!deps.getWs()) return;
|
|
38371
38956
|
const msg = parseApiToBridgeMessage(data, deps.log);
|
|
@@ -38402,7 +38987,7 @@ async function refreshBridgeTokens(params) {
|
|
|
38402
38987
|
}
|
|
38403
38988
|
}
|
|
38404
38989
|
|
|
38405
|
-
// src/
|
|
38990
|
+
// src/connection/main-bridge-ws-lifecycle.ts
|
|
38406
38991
|
function createMainBridgeWebSocketLifecycle(params) {
|
|
38407
38992
|
const {
|
|
38408
38993
|
state,
|
|
@@ -38448,13 +39033,26 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
38448
39033
|
}
|
|
38449
39034
|
}
|
|
38450
39035
|
function handleClose(code, reason) {
|
|
38451
|
-
|
|
38452
|
-
|
|
38453
|
-
|
|
38454
|
-
|
|
38455
|
-
|
|
38456
|
-
|
|
38457
|
-
|
|
39036
|
+
try {
|
|
39037
|
+
const was = state.currentWs;
|
|
39038
|
+
state.currentWs = null;
|
|
39039
|
+
if (was) was.removeAllListeners();
|
|
39040
|
+
const willReconnect = !state.closedByUser;
|
|
39041
|
+
beginMainBridgeDeferredDisconnect(state, code, reason, logFn, willReconnect);
|
|
39042
|
+
if (willReconnect) {
|
|
39043
|
+
state.lastReconnectCloseMeta = { code, reason };
|
|
39044
|
+
try {
|
|
39045
|
+
scheduleMainBridgeReconnect(state, connect, logFn, { code, reason });
|
|
39046
|
+
} catch {
|
|
39047
|
+
}
|
|
39048
|
+
}
|
|
39049
|
+
} catch {
|
|
39050
|
+
if (!state.closedByUser) {
|
|
39051
|
+
try {
|
|
39052
|
+
scheduleMainBridgeReconnect(state, connect, logFn);
|
|
39053
|
+
} catch {
|
|
39054
|
+
}
|
|
39055
|
+
}
|
|
38458
39056
|
}
|
|
38459
39057
|
}
|
|
38460
39058
|
function connect() {
|
|
@@ -38464,7 +39062,10 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
38464
39062
|
state.reconnectTimeout = null;
|
|
38465
39063
|
}
|
|
38466
39064
|
if (state.reconnectAttempt === 0) {
|
|
38467
|
-
|
|
39065
|
+
try {
|
|
39066
|
+
logFn("Connecting to bridge service\u2026");
|
|
39067
|
+
} catch {
|
|
39068
|
+
}
|
|
38468
39069
|
}
|
|
38469
39070
|
const prev = state.currentWs;
|
|
38470
39071
|
if (prev) {
|
|
@@ -38480,53 +39081,84 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
38480
39081
|
}
|
|
38481
39082
|
state.currentWs = null;
|
|
38482
39083
|
}
|
|
38483
|
-
|
|
38484
|
-
|
|
38485
|
-
|
|
38486
|
-
|
|
38487
|
-
|
|
38488
|
-
|
|
38489
|
-
|
|
38490
|
-
|
|
38491
|
-
|
|
38492
|
-
|
|
38493
|
-
|
|
38494
|
-
|
|
38495
|
-
|
|
38496
|
-
|
|
38497
|
-
|
|
38498
|
-
|
|
38499
|
-
|
|
38500
|
-
|
|
38501
|
-
|
|
38502
|
-
|
|
38503
|
-
|
|
38504
|
-
|
|
38505
|
-
|
|
38506
|
-
|
|
38507
|
-
|
|
39084
|
+
try {
|
|
39085
|
+
const url2 = buildBridgeUrl(apiUrl, workspaceId, tokens.accessToken);
|
|
39086
|
+
state.currentWs = createWsBridge({
|
|
39087
|
+
url: url2,
|
|
39088
|
+
clientPingIntervalMs: CLI_WEBSOCKET_CLIENT_PING_MS,
|
|
39089
|
+
onAuthInvalid: () => {
|
|
39090
|
+
if (authRefreshInFlight) return;
|
|
39091
|
+
void (async () => {
|
|
39092
|
+
authRefreshInFlight = true;
|
|
39093
|
+
try {
|
|
39094
|
+
if (tokens.refreshToken) {
|
|
39095
|
+
const next = await refreshBridgeTokens({
|
|
39096
|
+
apiUrl,
|
|
39097
|
+
workspaceId,
|
|
39098
|
+
refreshToken: tokens.refreshToken
|
|
39099
|
+
});
|
|
39100
|
+
if (next?.token && next.refreshToken) {
|
|
39101
|
+
tokens.accessToken = next.token;
|
|
39102
|
+
tokens.refreshToken = next.refreshToken;
|
|
39103
|
+
persistTokens?.({ token: tokens.accessToken, refreshToken: tokens.refreshToken });
|
|
39104
|
+
try {
|
|
39105
|
+
logFn("[Bridge service] Access token refreshed; reconnecting\u2026");
|
|
39106
|
+
} catch {
|
|
39107
|
+
}
|
|
39108
|
+
state.reconnectAttempt = 0;
|
|
39109
|
+
resetReconnectOutageTracker(state.mainOutage);
|
|
39110
|
+
state.lastReconnectCloseMeta = null;
|
|
39111
|
+
state.logBridgeOpenAsReconnect = true;
|
|
39112
|
+
authRefreshInFlight = false;
|
|
39113
|
+
connect();
|
|
39114
|
+
return;
|
|
39115
|
+
}
|
|
38508
39116
|
}
|
|
39117
|
+
authRefreshInFlight = false;
|
|
39118
|
+
state.reconnectAttempt = 0;
|
|
39119
|
+
resetReconnectOutageTracker(state.mainOutage);
|
|
39120
|
+
state.lastReconnectCloseMeta = null;
|
|
39121
|
+
onAuthInvalid();
|
|
39122
|
+
} catch {
|
|
39123
|
+
authRefreshInFlight = false;
|
|
39124
|
+
state.reconnectAttempt = 0;
|
|
39125
|
+
resetReconnectOutageTracker(state.mainOutage);
|
|
39126
|
+
state.lastReconnectCloseMeta = null;
|
|
39127
|
+
onAuthInvalid();
|
|
38509
39128
|
}
|
|
38510
|
-
|
|
38511
|
-
|
|
38512
|
-
|
|
39129
|
+
})();
|
|
39130
|
+
},
|
|
39131
|
+
onOpen: handleOpen,
|
|
39132
|
+
onClose: handleClose,
|
|
39133
|
+
onError: (err) => {
|
|
39134
|
+
if (state.mainOutage.startedAt != null) {
|
|
39135
|
+
return;
|
|
39136
|
+
}
|
|
39137
|
+
try {
|
|
39138
|
+
logCliWebSocketError(logFn, "[Bridge service]", err);
|
|
38513
39139
|
} catch {
|
|
38514
|
-
authRefreshInFlight = false;
|
|
38515
|
-
state.reconnectAttempt = 0;
|
|
38516
|
-
onAuthInvalid();
|
|
38517
39140
|
}
|
|
38518
|
-
}
|
|
38519
|
-
|
|
38520
|
-
|
|
38521
|
-
|
|
38522
|
-
|
|
38523
|
-
|
|
38524
|
-
|
|
39141
|
+
},
|
|
39142
|
+
onMessage: (data) => {
|
|
39143
|
+
try {
|
|
39144
|
+
handleBridgeMessage(data, messageDeps);
|
|
39145
|
+
} catch {
|
|
39146
|
+
}
|
|
39147
|
+
}
|
|
39148
|
+
});
|
|
39149
|
+
} catch {
|
|
39150
|
+
if (!state.closedByUser && state.currentWs == null) {
|
|
39151
|
+
try {
|
|
39152
|
+
scheduleMainBridgeReconnect(state, connect, logFn);
|
|
39153
|
+
} catch {
|
|
39154
|
+
}
|
|
39155
|
+
}
|
|
39156
|
+
}
|
|
38525
39157
|
}
|
|
38526
39158
|
return { connect };
|
|
38527
39159
|
}
|
|
38528
39160
|
|
|
38529
|
-
// src/
|
|
39161
|
+
// src/connection/create-bridge-connection.ts
|
|
38530
39162
|
async function createBridgeConnection(options) {
|
|
38531
39163
|
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
38532
39164
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
@@ -38538,16 +39170,20 @@ async function createBridgeConnection(options) {
|
|
|
38538
39170
|
const state = {
|
|
38539
39171
|
closedByUser: false,
|
|
38540
39172
|
reconnectAttempt: 0,
|
|
39173
|
+
lastReconnectCloseMeta: null,
|
|
38541
39174
|
logBridgeOpenAsReconnect: false,
|
|
38542
39175
|
reconnectTimeout: null,
|
|
38543
39176
|
currentWs: null,
|
|
38544
39177
|
mainQuiet: createEmptyReconnectQuietSlot(),
|
|
39178
|
+
mainOutage: createEmptyReconnectOutageTracker(),
|
|
38545
39179
|
firehoseHandle: null,
|
|
38546
39180
|
lastFirehoseParams: null,
|
|
38547
39181
|
firehoseReconnectTimeout: null,
|
|
38548
39182
|
firehoseReconnectAttempt: 0,
|
|
38549
39183
|
firehoseGeneration: 0,
|
|
38550
|
-
firehoseQuiet: createEmptyReconnectQuietSlot()
|
|
39184
|
+
firehoseQuiet: createEmptyReconnectQuietSlot(),
|
|
39185
|
+
firehoseOutage: createEmptyReconnectOutageTracker(),
|
|
39186
|
+
lastFirehoseReconnectCloseMeta: null
|
|
38551
39187
|
};
|
|
38552
39188
|
const worktreesRootPath = options.worktreesRootPath ?? defaultWorktreesRootPath();
|
|
38553
39189
|
const sessionWorktreeManager = new SessionWorktreeManager({
|
|
@@ -38584,8 +39220,8 @@ async function createBridgeConnection(options) {
|
|
|
38584
39220
|
getCloudAccessToken: () => tokens.accessToken
|
|
38585
39221
|
};
|
|
38586
39222
|
const identifyReportedPaths = {
|
|
38587
|
-
bridgeRootPath:
|
|
38588
|
-
worktreesRootPath:
|
|
39223
|
+
bridgeRootPath: path35.resolve(getBridgeRoot()),
|
|
39224
|
+
worktreesRootPath: path35.resolve(worktreesRootPath)
|
|
38589
39225
|
};
|
|
38590
39226
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
38591
39227
|
state,
|
|
@@ -38809,6 +39445,9 @@ function colorize(color, message) {
|
|
|
38809
39445
|
return `${color}${message}${RESET}`;
|
|
38810
39446
|
}
|
|
38811
39447
|
async function runCliAction(program2, opts) {
|
|
39448
|
+
const trace = opts.trace === true;
|
|
39449
|
+
const debug2 = opts.debug === true || trace;
|
|
39450
|
+
setCliLogVerbosity(trace ? "trace" : debug2 ? "debug" : "info");
|
|
38812
39451
|
const positionalUrl = program2.args?.[0];
|
|
38813
39452
|
const urlFromPositional = typeof positionalUrl === "string" && /^https?:\/\//i.test(positionalUrl) ? positionalUrl : void 0;
|
|
38814
39453
|
const apiUrlFromCli = opts.apiUrl ?? urlFromPositional;
|
|
@@ -38818,9 +39457,9 @@ async function runCliAction(program2, opts) {
|
|
|
38818
39457
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
38819
39458
|
const bridgeRootOpt = (opts.bridgeRoot && typeof opts.bridgeRoot === "string" && opts.bridgeRoot.trim() ? opts.bridgeRoot.trim() : null) ?? (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim() ? opts.cwd.trim() : null);
|
|
38820
39459
|
if (bridgeRootOpt) {
|
|
38821
|
-
const resolvedBridgeRoot =
|
|
39460
|
+
const resolvedBridgeRoot = path36.resolve(process.cwd(), bridgeRootOpt);
|
|
38822
39461
|
try {
|
|
38823
|
-
const st =
|
|
39462
|
+
const st = fs35.statSync(resolvedBridgeRoot);
|
|
38824
39463
|
if (!st.isDirectory()) {
|
|
38825
39464
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
38826
39465
|
process.exit(1);
|
|
@@ -38840,7 +39479,7 @@ async function runCliAction(program2, opts) {
|
|
|
38840
39479
|
);
|
|
38841
39480
|
let worktreesRootPath;
|
|
38842
39481
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
38843
|
-
worktreesRootPath =
|
|
39482
|
+
worktreesRootPath = path36.resolve(opts.worktreesRoot.trim());
|
|
38844
39483
|
}
|
|
38845
39484
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
38846
39485
|
if (e2eCertificates) {
|
|
@@ -38900,7 +39539,7 @@ async function main() {
|
|
|
38900
39539
|
"--e2ee-certificates-dir <path>",
|
|
38901
39540
|
"Directory to load or generate E2EE keys for sessions, files, and logs",
|
|
38902
39541
|
process.env.BUILDAUTOMATON_E2EE_CERTIFICATES_DIR
|
|
38903
|
-
).option("--no-config", "Ignore saved config at ~/.buildautomaton/config.json").action(async (opts) => runCliAction(program2, opts));
|
|
39542
|
+
).option("--no-config", "Ignore saved config at ~/.buildautomaton/config.json").option("--debug", "Print debug-level messages from the CLI").option("--trace", "Print trace-level messages (e.g. git subprocess output); implies --debug").action(async (opts) => runCliAction(program2, opts));
|
|
38904
39543
|
await program2.parseAsync(process.argv);
|
|
38905
39544
|
}
|
|
38906
39545
|
main().catch((err) => {
|