@buildautomaton/cli 0.1.28 → 0.1.30
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 +1238 -651
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1203 -616
- package/dist/index.js.map +4 -4
- package/dist/migrations/000_bootstrap_migrations_table.sql +4 -0
- package/dist/migrations/001_cli_sqlite_checkpoint_v1.sql +20 -0
- package/dist/migrations/002_acp_capability_cache.sql +10 -0
- package/dist/migrations/002_agent_capabilities.sql +10 -0
- package/dist/migrations/002_agent_capability_cache.sql +10 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -2240,7 +2240,7 @@ var require_websocket = __commonJS({
|
|
|
2240
2240
|
var http = __require("http");
|
|
2241
2241
|
var net = __require("net");
|
|
2242
2242
|
var tls = __require("tls");
|
|
2243
|
-
var { randomBytes: randomBytes2, createHash } = __require("crypto");
|
|
2243
|
+
var { randomBytes: randomBytes2, createHash: createHash2 } = __require("crypto");
|
|
2244
2244
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
2245
2245
|
var { URL: URL2 } = __require("url");
|
|
2246
2246
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -2900,7 +2900,7 @@ var require_websocket = __commonJS({
|
|
|
2900
2900
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
2901
2901
|
return;
|
|
2902
2902
|
}
|
|
2903
|
-
const digest =
|
|
2903
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
2904
2904
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
2905
2905
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
2906
2906
|
return;
|
|
@@ -3267,7 +3267,7 @@ var require_websocket_server = __commonJS({
|
|
|
3267
3267
|
var EventEmitter2 = __require("events");
|
|
3268
3268
|
var http = __require("http");
|
|
3269
3269
|
var { Duplex } = __require("stream");
|
|
3270
|
-
var { createHash } = __require("crypto");
|
|
3270
|
+
var { createHash: createHash2 } = __require("crypto");
|
|
3271
3271
|
var extension = require_extension();
|
|
3272
3272
|
var PerMessageDeflate = require_permessage_deflate();
|
|
3273
3273
|
var subprotocol = require_subprotocol();
|
|
@@ -3568,7 +3568,7 @@ var require_websocket_server = __commonJS({
|
|
|
3568
3568
|
);
|
|
3569
3569
|
}
|
|
3570
3570
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3571
|
-
const digest =
|
|
3571
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
3572
3572
|
const headers = [
|
|
3573
3573
|
"HTTP/1.1 101 Switching Protocols",
|
|
3574
3574
|
"Upgrade: websocket",
|
|
@@ -4065,8 +4065,8 @@ var init_parseUtil = __esm({
|
|
|
4065
4065
|
init_errors();
|
|
4066
4066
|
init_en();
|
|
4067
4067
|
makeIssue = (params) => {
|
|
4068
|
-
const { data, path:
|
|
4069
|
-
const fullPath = [...
|
|
4068
|
+
const { data, path: path41, errorMaps, issueData } = params;
|
|
4069
|
+
const fullPath = [...path41, ...issueData.path || []];
|
|
4070
4070
|
const fullIssue = {
|
|
4071
4071
|
...issueData,
|
|
4072
4072
|
path: fullPath
|
|
@@ -4374,11 +4374,11 @@ var init_types = __esm({
|
|
|
4374
4374
|
init_parseUtil();
|
|
4375
4375
|
init_util();
|
|
4376
4376
|
ParseInputLazyPath = class {
|
|
4377
|
-
constructor(parent, value,
|
|
4377
|
+
constructor(parent, value, path41, key) {
|
|
4378
4378
|
this._cachedPath = [];
|
|
4379
4379
|
this.parent = parent;
|
|
4380
4380
|
this.data = value;
|
|
4381
|
-
this._path =
|
|
4381
|
+
this._path = path41;
|
|
4382
4382
|
this._key = key;
|
|
4383
4383
|
}
|
|
4384
4384
|
get path() {
|
|
@@ -7993,10 +7993,10 @@ function assignProp(target, prop, value) {
|
|
|
7993
7993
|
configurable: true
|
|
7994
7994
|
});
|
|
7995
7995
|
}
|
|
7996
|
-
function getElementAtPath(obj,
|
|
7997
|
-
if (!
|
|
7996
|
+
function getElementAtPath(obj, path41) {
|
|
7997
|
+
if (!path41)
|
|
7998
7998
|
return obj;
|
|
7999
|
-
return
|
|
7999
|
+
return path41.reduce((acc, key) => acc?.[key], obj);
|
|
8000
8000
|
}
|
|
8001
8001
|
function promiseAllObject(promisesObj) {
|
|
8002
8002
|
const keys = Object.keys(promisesObj);
|
|
@@ -8245,11 +8245,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8245
8245
|
}
|
|
8246
8246
|
return false;
|
|
8247
8247
|
}
|
|
8248
|
-
function prefixIssues(
|
|
8248
|
+
function prefixIssues(path41, issues) {
|
|
8249
8249
|
return issues.map((iss) => {
|
|
8250
8250
|
var _a2;
|
|
8251
8251
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8252
|
-
iss.path.unshift(
|
|
8252
|
+
iss.path.unshift(path41);
|
|
8253
8253
|
return iss;
|
|
8254
8254
|
});
|
|
8255
8255
|
}
|
|
@@ -8438,7 +8438,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8438
8438
|
return issue2.message;
|
|
8439
8439
|
};
|
|
8440
8440
|
const result = { errors: [] };
|
|
8441
|
-
const processError = (error41,
|
|
8441
|
+
const processError = (error41, path41 = []) => {
|
|
8442
8442
|
var _a2, _b;
|
|
8443
8443
|
for (const issue2 of error41.issues) {
|
|
8444
8444
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8448,7 +8448,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8448
8448
|
} else if (issue2.code === "invalid_element") {
|
|
8449
8449
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8450
8450
|
} else {
|
|
8451
|
-
const fullpath = [...
|
|
8451
|
+
const fullpath = [...path41, ...issue2.path];
|
|
8452
8452
|
if (fullpath.length === 0) {
|
|
8453
8453
|
result.errors.push(mapper(issue2));
|
|
8454
8454
|
continue;
|
|
@@ -8478,9 +8478,9 @@ function treeifyError(error40, _mapper) {
|
|
|
8478
8478
|
processError(error40);
|
|
8479
8479
|
return result;
|
|
8480
8480
|
}
|
|
8481
|
-
function toDotPath(
|
|
8481
|
+
function toDotPath(path41) {
|
|
8482
8482
|
const segs = [];
|
|
8483
|
-
for (const seg of
|
|
8483
|
+
for (const seg of path41) {
|
|
8484
8484
|
if (typeof seg === "number")
|
|
8485
8485
|
segs.push(`[${seg}]`);
|
|
8486
8486
|
else if (typeof seg === "symbol")
|
|
@@ -20943,8 +20943,8 @@ var init_acp = __esm({
|
|
|
20943
20943
|
this.#requestHandler = requestHandler;
|
|
20944
20944
|
this.#notificationHandler = notificationHandler;
|
|
20945
20945
|
this.#stream = stream;
|
|
20946
|
-
this.#closedPromise = new Promise((
|
|
20947
|
-
this.#abortController.signal.addEventListener("abort", () =>
|
|
20946
|
+
this.#closedPromise = new Promise((resolve18) => {
|
|
20947
|
+
this.#abortController.signal.addEventListener("abort", () => resolve18());
|
|
20948
20948
|
});
|
|
20949
20949
|
this.#receive();
|
|
20950
20950
|
}
|
|
@@ -21093,8 +21093,8 @@ var init_acp = __esm({
|
|
|
21093
21093
|
}
|
|
21094
21094
|
async sendRequest(method, params) {
|
|
21095
21095
|
const id = this.#nextRequestId++;
|
|
21096
|
-
const responsePromise = new Promise((
|
|
21097
|
-
this.#pendingResponses.set(id, { resolve:
|
|
21096
|
+
const responsePromise = new Promise((resolve18, reject) => {
|
|
21097
|
+
this.#pendingResponses.set(id, { resolve: resolve18, reject });
|
|
21098
21098
|
});
|
|
21099
21099
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
21100
21100
|
return responsePromise;
|
|
@@ -21669,7 +21669,7 @@ var require_has_flag = __commonJS({
|
|
|
21669
21669
|
var require_supports_color = __commonJS({
|
|
21670
21670
|
"../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
|
|
21671
21671
|
"use strict";
|
|
21672
|
-
var
|
|
21672
|
+
var os9 = __require("os");
|
|
21673
21673
|
var tty = __require("tty");
|
|
21674
21674
|
var hasFlag = require_has_flag();
|
|
21675
21675
|
var { env } = process;
|
|
@@ -21717,7 +21717,7 @@ var require_supports_color = __commonJS({
|
|
|
21717
21717
|
return min;
|
|
21718
21718
|
}
|
|
21719
21719
|
if (process.platform === "win32") {
|
|
21720
|
-
const osRelease =
|
|
21720
|
+
const osRelease = os9.release().split(".");
|
|
21721
21721
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
21722
21722
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
21723
21723
|
}
|
|
@@ -21963,10 +21963,10 @@ var require_src2 = __commonJS({
|
|
|
21963
21963
|
var fs_1 = __require("fs");
|
|
21964
21964
|
var debug_1 = __importDefault(require_src());
|
|
21965
21965
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
21966
|
-
function check2(
|
|
21967
|
-
log2(`checking %s`,
|
|
21966
|
+
function check2(path41, isFile, isDirectory) {
|
|
21967
|
+
log2(`checking %s`, path41);
|
|
21968
21968
|
try {
|
|
21969
|
-
const stat2 = fs_1.statSync(
|
|
21969
|
+
const stat2 = fs_1.statSync(path41);
|
|
21970
21970
|
if (stat2.isFile() && isFile) {
|
|
21971
21971
|
log2(`[OK] path represents a file`);
|
|
21972
21972
|
return true;
|
|
@@ -21986,8 +21986,8 @@ var require_src2 = __commonJS({
|
|
|
21986
21986
|
throw e;
|
|
21987
21987
|
}
|
|
21988
21988
|
}
|
|
21989
|
-
function exists2(
|
|
21990
|
-
return check2(
|
|
21989
|
+
function exists2(path41, type = exports.READABLE) {
|
|
21990
|
+
return check2(path41, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
21991
21991
|
}
|
|
21992
21992
|
exports.exists = exists2;
|
|
21993
21993
|
exports.FILE = 1;
|
|
@@ -22792,9 +22792,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
22792
22792
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
22793
22793
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
22794
22794
|
if (!rawPath || !summary) continue;
|
|
22795
|
-
const
|
|
22796
|
-
if (!
|
|
22797
|
-
rows.push({ path:
|
|
22795
|
+
const path41 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
22796
|
+
if (!path41) continue;
|
|
22797
|
+
rows.push({ path: path41, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
22798
22798
|
}
|
|
22799
22799
|
return rows;
|
|
22800
22800
|
}
|
|
@@ -23004,6 +23004,7 @@ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
|
|
|
23004
23004
|
// ../types/src/agent-config.ts
|
|
23005
23005
|
var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
|
|
23006
23006
|
var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
|
|
23007
|
+
var AGENT_CONFIG_AGENT_MODEL_KEY = "agent_model";
|
|
23007
23008
|
function getClaudePermissionModeFromAgentConfig(config2) {
|
|
23008
23009
|
if (!config2) return null;
|
|
23009
23010
|
const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
|
|
@@ -23015,6 +23016,13 @@ function getCliPermissionModeFromAgentConfig(config2) {
|
|
|
23015
23016
|
if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
|
|
23016
23017
|
return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
|
|
23017
23018
|
}
|
|
23019
|
+
function getAgentModelFromAgentConfig(config2) {
|
|
23020
|
+
if (!config2) return null;
|
|
23021
|
+
const cur = config2[AGENT_CONFIG_AGENT_MODEL_KEY];
|
|
23022
|
+
if (typeof cur !== "string") return null;
|
|
23023
|
+
const t = cur.trim();
|
|
23024
|
+
return t !== "" ? t : null;
|
|
23025
|
+
}
|
|
23018
23026
|
|
|
23019
23027
|
// src/agents/acp/claude-acp-permission-from-session.ts
|
|
23020
23028
|
function flattenSelectOptions(options) {
|
|
@@ -23070,6 +23078,48 @@ async function applyClaudePermissionFromAcpSession(params) {
|
|
|
23070
23078
|
}
|
|
23071
23079
|
}
|
|
23072
23080
|
|
|
23081
|
+
// src/agents/acp/apply-acp-model-from-agent-session.ts
|
|
23082
|
+
function flattenSelectOptions2(options) {
|
|
23083
|
+
if (options == null || options.length === 0) return [];
|
|
23084
|
+
const first2 = options[0];
|
|
23085
|
+
if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
|
|
23086
|
+
return options.flatMap((g) => Array.isArray(g.options) ? g.options : []);
|
|
23087
|
+
}
|
|
23088
|
+
return options;
|
|
23089
|
+
}
|
|
23090
|
+
function looksLikeModelOption(o) {
|
|
23091
|
+
if (o.category === "model" || o.category === "models") return true;
|
|
23092
|
+
const id = typeof o.id === "string" ? o.id.toLowerCase() : "";
|
|
23093
|
+
if (id === "model" || id.endsWith("_model") || id.includes("model")) return true;
|
|
23094
|
+
const name = typeof o.name === "string" ? o.name.toLowerCase() : "";
|
|
23095
|
+
return name.includes("model") && !name.includes("mode");
|
|
23096
|
+
}
|
|
23097
|
+
function pickModelConfigOption(configOptions) {
|
|
23098
|
+
if (configOptions == null || configOptions.length === 0) return null;
|
|
23099
|
+
return configOptions.find(looksLikeModelOption) ?? null;
|
|
23100
|
+
}
|
|
23101
|
+
async function applyAcpModelFromAcpSession(params) {
|
|
23102
|
+
const { sessionId, agentConfig, configOptions, setSessionConfigOption, logDebug: logDebug2 } = params;
|
|
23103
|
+
const desired = getAgentModelFromAgentConfig(agentConfig);
|
|
23104
|
+
if (desired == null) return;
|
|
23105
|
+
const modelOpt = pickModelConfigOption(configOptions ?? null);
|
|
23106
|
+
if (modelOpt == null) return;
|
|
23107
|
+
const flat = flattenSelectOptions2(modelOpt.options);
|
|
23108
|
+
const allowed = flat.some((o) => o.value === desired);
|
|
23109
|
+
if (!allowed) return;
|
|
23110
|
+
if (modelOpt.currentValue === desired) return;
|
|
23111
|
+
try {
|
|
23112
|
+
logDebug2(
|
|
23113
|
+
`[Agent] ACP session/set_config_option (model) configId=${JSON.stringify(modelOpt.id)} value=${JSON.stringify(desired)} was=${JSON.stringify(modelOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
|
|
23114
|
+
);
|
|
23115
|
+
await setSessionConfigOption({ sessionId, configId: modelOpt.id, value: desired });
|
|
23116
|
+
} catch (e) {
|
|
23117
|
+
logDebug2(
|
|
23118
|
+
`[Agent] ACP session/set_config_option (model) failed: ${e instanceof Error ? e.message : String(e)}`
|
|
23119
|
+
);
|
|
23120
|
+
}
|
|
23121
|
+
}
|
|
23122
|
+
|
|
23073
23123
|
// src/agents/acp/clients/shared/config-options-for-permission.ts
|
|
23074
23124
|
function configOptionsForPermission(getActive, established) {
|
|
23075
23125
|
const mem = getActive?.();
|
|
@@ -23162,6 +23212,17 @@ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
|
|
|
23162
23212
|
logDebug: ctx.logDebug
|
|
23163
23213
|
});
|
|
23164
23214
|
}
|
|
23215
|
+
const cfgAll = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
|
|
23216
|
+
const configOptionsForModel = established.configOptions;
|
|
23217
|
+
if (transport.setSessionConfigOption) {
|
|
23218
|
+
await applyAcpModelFromAcpSession({
|
|
23219
|
+
sessionId,
|
|
23220
|
+
agentConfig: cfgAll,
|
|
23221
|
+
configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsForModel),
|
|
23222
|
+
setSessionConfigOption: (p) => transport.setSessionConfigOption(p),
|
|
23223
|
+
logDebug: ctx.logDebug
|
|
23224
|
+
});
|
|
23225
|
+
}
|
|
23165
23226
|
return established;
|
|
23166
23227
|
}
|
|
23167
23228
|
|
|
@@ -23267,10 +23328,15 @@ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText,
|
|
|
23267
23328
|
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
23268
23329
|
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
23269
23330
|
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
23270
|
-
return new Promise((
|
|
23271
|
-
pending.set(requestId, { resolve:
|
|
23331
|
+
return new Promise((resolve18) => {
|
|
23332
|
+
pending.set(requestId, { resolve: resolve18, params: paramsRecord });
|
|
23333
|
+
if (onRequest == null) {
|
|
23334
|
+
pending.delete(requestId);
|
|
23335
|
+
resolve18({ outcome: { outcome: "denied" } });
|
|
23336
|
+
return;
|
|
23337
|
+
}
|
|
23272
23338
|
try {
|
|
23273
|
-
onRequest
|
|
23339
|
+
onRequest({
|
|
23274
23340
|
requestId,
|
|
23275
23341
|
method: "session/request_permission",
|
|
23276
23342
|
params: paramsRecord
|
|
@@ -23332,7 +23398,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
23332
23398
|
child.once("close", (code, signal) => {
|
|
23333
23399
|
onAgentSubprocessExit?.({ code, signal });
|
|
23334
23400
|
});
|
|
23335
|
-
return new Promise((
|
|
23401
|
+
return new Promise((resolve18, reject) => {
|
|
23336
23402
|
let initSettled = false;
|
|
23337
23403
|
const settleReject = (err) => {
|
|
23338
23404
|
if (initSettled) return;
|
|
@@ -23346,7 +23412,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
23346
23412
|
const settleResolve = (handle) => {
|
|
23347
23413
|
if (initSettled) return;
|
|
23348
23414
|
initSettled = true;
|
|
23349
|
-
|
|
23415
|
+
resolve18(handle);
|
|
23350
23416
|
};
|
|
23351
23417
|
child.on("error", (err) => {
|
|
23352
23418
|
settleReject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -23566,7 +23632,7 @@ async function proxyToLocal(request) {
|
|
|
23566
23632
|
};
|
|
23567
23633
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
23568
23634
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
23569
|
-
const once = await new Promise((
|
|
23635
|
+
const once = await new Promise((resolve18) => {
|
|
23570
23636
|
const req = mod.request(opts, (res) => {
|
|
23571
23637
|
const chunks = [];
|
|
23572
23638
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -23577,7 +23643,7 @@ async function proxyToLocal(request) {
|
|
|
23577
23643
|
if (typeof v === "string") headers[k] = v;
|
|
23578
23644
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
23579
23645
|
}
|
|
23580
|
-
|
|
23646
|
+
resolve18({
|
|
23581
23647
|
id: request.id,
|
|
23582
23648
|
statusCode: res.statusCode ?? 0,
|
|
23583
23649
|
headers,
|
|
@@ -23586,7 +23652,7 @@ async function proxyToLocal(request) {
|
|
|
23586
23652
|
});
|
|
23587
23653
|
});
|
|
23588
23654
|
req.on("error", (err) => {
|
|
23589
|
-
|
|
23655
|
+
resolve18({
|
|
23590
23656
|
id: request.id,
|
|
23591
23657
|
statusCode: 0,
|
|
23592
23658
|
headers: {},
|
|
@@ -23668,8 +23734,8 @@ function randomSecret() {
|
|
|
23668
23734
|
}
|
|
23669
23735
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
23670
23736
|
}
|
|
23671
|
-
async function requestPreviewApi(port, secret, method,
|
|
23672
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
23737
|
+
async function requestPreviewApi(port, secret, method, path41, body) {
|
|
23738
|
+
const url2 = `http://127.0.0.1:${port}${path41}`;
|
|
23673
23739
|
const headers = {
|
|
23674
23740
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
23675
23741
|
"Content-Type": "application/json"
|
|
@@ -23681,7 +23747,7 @@ async function requestPreviewApi(port, secret, method, path35, body) {
|
|
|
23681
23747
|
});
|
|
23682
23748
|
const data = await res.json().catch(() => ({}));
|
|
23683
23749
|
if (!res.ok) {
|
|
23684
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
23750
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path41}: ${res.status}`);
|
|
23685
23751
|
}
|
|
23686
23752
|
return data;
|
|
23687
23753
|
}
|
|
@@ -23896,7 +23962,7 @@ function installBridgeProcessResilience() {
|
|
|
23896
23962
|
}
|
|
23897
23963
|
|
|
23898
23964
|
// src/cli-version.ts
|
|
23899
|
-
var CLI_VERSION = "0.1.
|
|
23965
|
+
var CLI_VERSION = "0.1.30".length > 0 ? "0.1.30" : "0.0.0-dev";
|
|
23900
23966
|
|
|
23901
23967
|
// src/connection/heartbeat/constants.ts
|
|
23902
23968
|
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -24337,14 +24403,14 @@ var baseOpen = async (options) => {
|
|
|
24337
24403
|
}
|
|
24338
24404
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
24339
24405
|
if (options.wait) {
|
|
24340
|
-
return new Promise((
|
|
24406
|
+
return new Promise((resolve18, reject) => {
|
|
24341
24407
|
subprocess.once("error", reject);
|
|
24342
24408
|
subprocess.once("close", (exitCode) => {
|
|
24343
24409
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
24344
24410
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
24345
24411
|
return;
|
|
24346
24412
|
}
|
|
24347
|
-
|
|
24413
|
+
resolve18(subprocess);
|
|
24348
24414
|
});
|
|
24349
24415
|
});
|
|
24350
24416
|
}
|
|
@@ -24833,8 +24899,8 @@ function runPendingAuth(options) {
|
|
|
24833
24899
|
let hasOpenedBrowser = false;
|
|
24834
24900
|
let resolved = false;
|
|
24835
24901
|
let resolveAuth;
|
|
24836
|
-
const authPromise = new Promise((
|
|
24837
|
-
resolveAuth =
|
|
24902
|
+
const authPromise = new Promise((resolve18) => {
|
|
24903
|
+
resolveAuth = resolve18;
|
|
24838
24904
|
});
|
|
24839
24905
|
let reconnectAttempt = 0;
|
|
24840
24906
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -24956,11 +25022,353 @@ function runPendingAuth(options) {
|
|
|
24956
25022
|
};
|
|
24957
25023
|
}
|
|
24958
25024
|
|
|
25025
|
+
// src/sqlite/cli-database.ts
|
|
25026
|
+
import sqliteWasm from "node-sqlite3-wasm";
|
|
25027
|
+
|
|
25028
|
+
// src/sqlite/cli-sqlite-paths.ts
|
|
25029
|
+
import fs7 from "node:fs";
|
|
25030
|
+
import path5 from "node:path";
|
|
25031
|
+
import os3 from "node:os";
|
|
25032
|
+
function getCliSqlitePath() {
|
|
25033
|
+
const override = process.env.BUILDAMATON_CLI_SQLITE_PATH?.trim();
|
|
25034
|
+
if (override) return path5.resolve(override);
|
|
25035
|
+
return path5.join(os3.homedir(), ".buildautomaton", "cli.sqlite");
|
|
25036
|
+
}
|
|
25037
|
+
function ensureCliSqliteParentDir(sqlitePath) {
|
|
25038
|
+
const dir = path5.dirname(sqlitePath);
|
|
25039
|
+
if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
|
|
25040
|
+
}
|
|
25041
|
+
|
|
25042
|
+
// src/sqlite/legacy_migration/import-cli-legacy-disk-data.ts
|
|
25043
|
+
import fs12 from "node:fs";
|
|
25044
|
+
|
|
25045
|
+
// src/files/index/constants.ts
|
|
25046
|
+
import path6 from "node:path";
|
|
25047
|
+
import os4 from "node:os";
|
|
25048
|
+
var INDEX_WORK_YIELD_EVERY = 256;
|
|
25049
|
+
var INDEX_DIR = path6.join(os4.homedir(), ".buildautomaton");
|
|
25050
|
+
var INDEX_HASH_LEN = 16;
|
|
25051
|
+
|
|
25052
|
+
// src/prompt-turn-queue/paths.ts
|
|
25053
|
+
import path7 from "node:path";
|
|
25054
|
+
import os5 from "node:os";
|
|
25055
|
+
function getPromptQueuesDirectory() {
|
|
25056
|
+
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
25057
|
+
if (override) return path7.resolve(override);
|
|
25058
|
+
return path7.join(os5.homedir(), ".buildautomaton", "queues");
|
|
25059
|
+
}
|
|
25060
|
+
|
|
25061
|
+
// src/sqlite/legacy_migration/archive-file-index-json.ts
|
|
25062
|
+
import fs9 from "node:fs";
|
|
25063
|
+
import path9 from "node:path";
|
|
25064
|
+
|
|
25065
|
+
// src/sqlite/legacy_migration/archive-to-old-version.ts
|
|
25066
|
+
import fs8 from "node:fs";
|
|
25067
|
+
import path8 from "node:path";
|
|
25068
|
+
var OLD_VERSION_DIR = path8.join(INDEX_DIR, "old-version");
|
|
25069
|
+
function moveLegacyFileToOldVersionBackup(category, sourcePath) {
|
|
25070
|
+
const destDir = path8.join(OLD_VERSION_DIR, category);
|
|
25071
|
+
fs8.mkdirSync(destDir, { recursive: true });
|
|
25072
|
+
const base = path8.basename(sourcePath);
|
|
25073
|
+
let dest = path8.join(destDir, base);
|
|
25074
|
+
if (fs8.existsSync(dest)) {
|
|
25075
|
+
const ext = path8.extname(base);
|
|
25076
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
25077
|
+
dest = path8.join(destDir, `${stem}-${Date.now()}${ext}`);
|
|
25078
|
+
}
|
|
25079
|
+
fs8.renameSync(sourcePath, dest);
|
|
25080
|
+
}
|
|
25081
|
+
|
|
25082
|
+
// src/sqlite/legacy_migration/archive-file-index-json.ts
|
|
25083
|
+
function archiveLegacyFileIndexJsonFiles() {
|
|
25084
|
+
try {
|
|
25085
|
+
if (!fs9.existsSync(INDEX_DIR)) return;
|
|
25086
|
+
for (const name of fs9.readdirSync(INDEX_DIR)) {
|
|
25087
|
+
if (name.startsWith(".file-index-") && name.endsWith(".json")) {
|
|
25088
|
+
const full = path9.join(INDEX_DIR, name);
|
|
25089
|
+
try {
|
|
25090
|
+
moveLegacyFileToOldVersionBackup("file-index", full);
|
|
25091
|
+
} catch (err) {
|
|
25092
|
+
console.error(`[cli-sqlite] legacy import: could not archive ${name}`, err);
|
|
25093
|
+
}
|
|
25094
|
+
}
|
|
25095
|
+
}
|
|
25096
|
+
} catch (e) {
|
|
25097
|
+
console.error("[cli-sqlite] legacy import: archive file-index json failed", e);
|
|
25098
|
+
}
|
|
25099
|
+
}
|
|
25100
|
+
|
|
25101
|
+
// src/sqlite/legacy_migration/import-agent-sessions-from-disk.ts
|
|
25102
|
+
import fs10 from "node:fs";
|
|
25103
|
+
import path10 from "node:path";
|
|
25104
|
+
import os6 from "node:os";
|
|
25105
|
+
var LEGACY_AGENT_SESSION_DIR = path10.join(os6.homedir(), ".buildautomaton", "agent-sessions");
|
|
25106
|
+
function importLegacyAgentSessionsFromDisk(db) {
|
|
25107
|
+
try {
|
|
25108
|
+
if (!fs10.existsSync(LEGACY_AGENT_SESSION_DIR)) return;
|
|
25109
|
+
const names = fs10.readdirSync(LEGACY_AGENT_SESSION_DIR).filter((n) => n.endsWith(".json"));
|
|
25110
|
+
for (const name of names) {
|
|
25111
|
+
const sessionKey = name.slice(0, -".json".length);
|
|
25112
|
+
const full = path10.join(LEGACY_AGENT_SESSION_DIR, name);
|
|
25113
|
+
let raw;
|
|
25114
|
+
try {
|
|
25115
|
+
raw = fs10.readFileSync(full, "utf8");
|
|
25116
|
+
} catch {
|
|
25117
|
+
continue;
|
|
25118
|
+
}
|
|
25119
|
+
let parsed;
|
|
25120
|
+
try {
|
|
25121
|
+
parsed = JSON.parse(raw);
|
|
25122
|
+
} catch {
|
|
25123
|
+
continue;
|
|
25124
|
+
}
|
|
25125
|
+
if (parsed.v !== 1) continue;
|
|
25126
|
+
const acpSessionId = typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null;
|
|
25127
|
+
const backendAgentType = typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null;
|
|
25128
|
+
const configOptionsJson = Array.isArray(parsed.configOptions) ? JSON.stringify(parsed.configOptions) : null;
|
|
25129
|
+
const updatedAt = typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
25130
|
+
db.run(
|
|
25131
|
+
`INSERT OR REPLACE INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
|
|
25132
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
25133
|
+
[sessionKey, acpSessionId, backendAgentType, configOptionsJson, updatedAt]
|
|
25134
|
+
);
|
|
25135
|
+
try {
|
|
25136
|
+
moveLegacyFileToOldVersionBackup("agent-sessions", full);
|
|
25137
|
+
} catch {
|
|
25138
|
+
}
|
|
25139
|
+
}
|
|
25140
|
+
} catch (e) {
|
|
25141
|
+
console.error("[cli-sqlite] legacy import: agent_sessions from disk failed", e);
|
|
25142
|
+
}
|
|
25143
|
+
}
|
|
25144
|
+
|
|
25145
|
+
// src/sqlite/legacy_migration/import-prompt-queues-from-disk.ts
|
|
25146
|
+
import fs11 from "node:fs";
|
|
25147
|
+
import path11 from "node:path";
|
|
25148
|
+
|
|
25149
|
+
// src/sqlite/legacy_migration/parse-persisted-queue-json.ts
|
|
25150
|
+
function parsePersistedQueueFromJson(raw) {
|
|
25151
|
+
try {
|
|
25152
|
+
const o = JSON.parse(raw);
|
|
25153
|
+
const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
|
|
25154
|
+
if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
|
|
25155
|
+
return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
|
|
25156
|
+
} catch {
|
|
25157
|
+
return null;
|
|
25158
|
+
}
|
|
25159
|
+
}
|
|
25160
|
+
|
|
25161
|
+
// src/sqlite/legacy_migration/import-prompt-queues-from-disk.ts
|
|
25162
|
+
function importLegacyPromptQueuesFromDisk(db) {
|
|
25163
|
+
try {
|
|
25164
|
+
const dir = getPromptQueuesDirectory();
|
|
25165
|
+
if (!fs11.existsSync(dir)) return;
|
|
25166
|
+
for (const name of fs11.readdirSync(dir)) {
|
|
25167
|
+
if (!name.endsWith(".json")) continue;
|
|
25168
|
+
const full = path11.join(dir, name);
|
|
25169
|
+
let raw;
|
|
25170
|
+
try {
|
|
25171
|
+
raw = fs11.readFileSync(full, "utf8");
|
|
25172
|
+
} catch {
|
|
25173
|
+
continue;
|
|
25174
|
+
}
|
|
25175
|
+
const file2 = parsePersistedQueueFromJson(raw);
|
|
25176
|
+
if (!file2) continue;
|
|
25177
|
+
db.run(
|
|
25178
|
+
`INSERT OR REPLACE INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)`,
|
|
25179
|
+
[file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
|
|
25180
|
+
);
|
|
25181
|
+
try {
|
|
25182
|
+
moveLegacyFileToOldVersionBackup("queues", full);
|
|
25183
|
+
} catch {
|
|
25184
|
+
}
|
|
25185
|
+
}
|
|
25186
|
+
} catch (e) {
|
|
25187
|
+
console.error("[cli-sqlite] legacy import: prompt queues from disk failed", e);
|
|
25188
|
+
}
|
|
25189
|
+
}
|
|
25190
|
+
|
|
25191
|
+
// src/sqlite/legacy_migration/import-cli-legacy-disk-data.ts
|
|
25192
|
+
function legacyCliDiskMigrationIsPending() {
|
|
25193
|
+
try {
|
|
25194
|
+
if (fs12.existsSync(INDEX_DIR)) {
|
|
25195
|
+
for (const name of fs12.readdirSync(INDEX_DIR)) {
|
|
25196
|
+
if (name.startsWith(".file-index-") && name.endsWith(".json")) return true;
|
|
25197
|
+
}
|
|
25198
|
+
}
|
|
25199
|
+
} catch {
|
|
25200
|
+
}
|
|
25201
|
+
try {
|
|
25202
|
+
if (fs12.existsSync(LEGACY_AGENT_SESSION_DIR)) {
|
|
25203
|
+
if (fs12.readdirSync(LEGACY_AGENT_SESSION_DIR).some((n) => n.endsWith(".json"))) return true;
|
|
25204
|
+
}
|
|
25205
|
+
} catch {
|
|
25206
|
+
}
|
|
25207
|
+
try {
|
|
25208
|
+
const dir = getPromptQueuesDirectory();
|
|
25209
|
+
if (fs12.existsSync(dir) && fs12.readdirSync(dir).some((n) => n.endsWith(".json"))) return true;
|
|
25210
|
+
} catch {
|
|
25211
|
+
}
|
|
25212
|
+
return false;
|
|
25213
|
+
}
|
|
25214
|
+
function importCliSqliteLegacyDiskData(db, log2) {
|
|
25215
|
+
const pending = legacyCliDiskMigrationIsPending();
|
|
25216
|
+
if (pending && log2) {
|
|
25217
|
+
log2("Migrating legacy on-disk CLI data to SQLite\u2026");
|
|
25218
|
+
}
|
|
25219
|
+
archiveLegacyFileIndexJsonFiles();
|
|
25220
|
+
importLegacyAgentSessionsFromDisk(db);
|
|
25221
|
+
importLegacyPromptQueuesFromDisk(db);
|
|
25222
|
+
if (pending && log2) {
|
|
25223
|
+
log2("Legacy on-disk CLI data migration finished.");
|
|
25224
|
+
}
|
|
25225
|
+
}
|
|
25226
|
+
|
|
25227
|
+
// src/sqlite/load-cli-migration-sql.ts
|
|
25228
|
+
import { existsSync, readFileSync as readFileSync2 } from "node:fs";
|
|
25229
|
+
import { dirname as dirname2, join } from "node:path";
|
|
25230
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
25231
|
+
function readCliSqliteMigrationSql(filename) {
|
|
25232
|
+
const dir = dirname2(fileURLToPath2(import.meta.url));
|
|
25233
|
+
const resolved = join(dir, "migrations", filename);
|
|
25234
|
+
if (!existsSync(resolved)) {
|
|
25235
|
+
throw new Error(`Missing CLI SQLite migration SQL: ${resolved}`);
|
|
25236
|
+
}
|
|
25237
|
+
return readFileSync2(resolved, "utf8");
|
|
25238
|
+
}
|
|
25239
|
+
|
|
25240
|
+
// src/sqlite/migrate-cli-sqlite.ts
|
|
25241
|
+
function checkpointSatisfiedByLegacyChain(applied2, replacesLegacyMigrations) {
|
|
25242
|
+
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) => applied2.has(n));
|
|
25243
|
+
}
|
|
25244
|
+
function recordMigrationAndPruneCheckpointLegacy(db, migration, applied2) {
|
|
25245
|
+
db.run("INSERT INTO __migrations (name) VALUES (?)", [migration.name]);
|
|
25246
|
+
applied2.add(migration.name);
|
|
25247
|
+
if (migration.checkpoint !== true) return;
|
|
25248
|
+
const legacy = migration.replacesLegacyMigrations;
|
|
25249
|
+
if (!legacy?.length) return;
|
|
25250
|
+
for (const legacyName of legacy) {
|
|
25251
|
+
if (legacyName === migration.name) continue;
|
|
25252
|
+
db.run("DELETE FROM __migrations WHERE name = ?", [legacyName]);
|
|
25253
|
+
applied2.delete(legacyName);
|
|
25254
|
+
}
|
|
25255
|
+
}
|
|
25256
|
+
var CHECKPOINT_V1 = "001_cli_sqlite_checkpoint_v1";
|
|
25257
|
+
var CHECKPOINT_V1_SQL = readCliSqliteMigrationSql("001_cli_sqlite_checkpoint_v1.sql");
|
|
25258
|
+
var AGENT_CAPABILITIES_SQL = readCliSqliteMigrationSql("002_agent_capabilities.sql");
|
|
25259
|
+
function agentCapabilitiesTableState(db) {
|
|
25260
|
+
const rows = db.all(
|
|
25261
|
+
`SELECT name FROM sqlite_master WHERE type='table' AND name IN ('agent_capabilities', 'agent_capability_cache')`
|
|
25262
|
+
);
|
|
25263
|
+
const names = new Set(rows.map((r) => r.name));
|
|
25264
|
+
if (names.has("agent_capabilities")) return "current";
|
|
25265
|
+
if (names.has("agent_capability_cache")) return "legacy";
|
|
25266
|
+
return "new";
|
|
25267
|
+
}
|
|
25268
|
+
var CLI_SQLITE_MIGRATIONS = [
|
|
25269
|
+
{
|
|
25270
|
+
name: CHECKPOINT_V1,
|
|
25271
|
+
checkpoint: true,
|
|
25272
|
+
migrate: (db) => {
|
|
25273
|
+
db.exec(CHECKPOINT_V1_SQL);
|
|
25274
|
+
}
|
|
25275
|
+
},
|
|
25276
|
+
{
|
|
25277
|
+
name: "002_agent_capabilities",
|
|
25278
|
+
migrate: (db) => {
|
|
25279
|
+
const state = agentCapabilitiesTableState(db);
|
|
25280
|
+
if (state === "current") return;
|
|
25281
|
+
if (state === "legacy") {
|
|
25282
|
+
db.exec(`
|
|
25283
|
+
ALTER TABLE agent_capability_cache RENAME TO agent_capabilities;
|
|
25284
|
+
DROP INDEX IF EXISTS idx_agent_capability_cache_workspace;
|
|
25285
|
+
CREATE INDEX IF NOT EXISTS idx_agent_capabilities_workspace ON agent_capabilities(workspace_id);
|
|
25286
|
+
`);
|
|
25287
|
+
return;
|
|
25288
|
+
}
|
|
25289
|
+
db.exec(AGENT_CAPABILITIES_SQL);
|
|
25290
|
+
},
|
|
25291
|
+
alreadyApplied: (db) => agentCapabilitiesTableState(db) === "current"
|
|
25292
|
+
}
|
|
25293
|
+
];
|
|
25294
|
+
function migrateCliSqlite(db) {
|
|
25295
|
+
db.exec(readCliSqliteMigrationSql("000_bootstrap_migrations_table.sql"));
|
|
25296
|
+
const appliedRows = db.all("SELECT name FROM __migrations");
|
|
25297
|
+
const applied2 = new Set(appliedRows.map((r) => r.name));
|
|
25298
|
+
for (const migration of CLI_SQLITE_MIGRATIONS) {
|
|
25299
|
+
if (applied2.has(migration.name)) continue;
|
|
25300
|
+
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(applied2, migration.replacesLegacyMigrations)) {
|
|
25301
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
25302
|
+
continue;
|
|
25303
|
+
}
|
|
25304
|
+
if (migration.alreadyApplied?.(db)) {
|
|
25305
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
25306
|
+
continue;
|
|
25307
|
+
}
|
|
25308
|
+
try {
|
|
25309
|
+
migration.migrate(db);
|
|
25310
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
25311
|
+
} catch (e) {
|
|
25312
|
+
console.error(`[cli-sqlite] Migration failed: ${migration.name}`, e);
|
|
25313
|
+
throw e;
|
|
25314
|
+
}
|
|
25315
|
+
}
|
|
25316
|
+
}
|
|
25317
|
+
|
|
25318
|
+
// src/sqlite/cli-database.ts
|
|
25319
|
+
var { Database: SqliteDatabase } = sqliteWasm;
|
|
25320
|
+
var openDatabases = /* @__PURE__ */ new Map();
|
|
25321
|
+
var processExitCloseRegistered = false;
|
|
25322
|
+
function registerProcessExitSqliteClose() {
|
|
25323
|
+
if (processExitCloseRegistered) return;
|
|
25324
|
+
processExitCloseRegistered = true;
|
|
25325
|
+
process.once("exit", () => {
|
|
25326
|
+
for (const db of openDatabases.values()) {
|
|
25327
|
+
safeCloseCliSqliteDatabase(db);
|
|
25328
|
+
}
|
|
25329
|
+
openDatabases.clear();
|
|
25330
|
+
});
|
|
25331
|
+
}
|
|
25332
|
+
function safeCloseCliSqliteDatabase(db) {
|
|
25333
|
+
if (db == null) return;
|
|
25334
|
+
try {
|
|
25335
|
+
if (db.isOpen) db.close();
|
|
25336
|
+
} catch {
|
|
25337
|
+
}
|
|
25338
|
+
}
|
|
25339
|
+
function closeAllCliSqliteConnections() {
|
|
25340
|
+
for (const db of openDatabases.values()) {
|
|
25341
|
+
safeCloseCliSqliteDatabase(db);
|
|
25342
|
+
}
|
|
25343
|
+
openDatabases.clear();
|
|
25344
|
+
}
|
|
25345
|
+
function getCliDatabase(options) {
|
|
25346
|
+
const sqlitePath = getCliSqlitePath();
|
|
25347
|
+
const existing = openDatabases.get(sqlitePath);
|
|
25348
|
+
if (existing?.isOpen) return existing;
|
|
25349
|
+
if (existing && !existing.isOpen) {
|
|
25350
|
+
safeCloseCliSqliteDatabase(existing);
|
|
25351
|
+
openDatabases.delete(sqlitePath);
|
|
25352
|
+
}
|
|
25353
|
+
ensureCliSqliteParentDir(sqlitePath);
|
|
25354
|
+
const db = new SqliteDatabase(sqlitePath);
|
|
25355
|
+
try {
|
|
25356
|
+
migrateCliSqlite(db);
|
|
25357
|
+
importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
|
|
25358
|
+
} catch (e) {
|
|
25359
|
+
safeCloseCliSqliteDatabase(db);
|
|
25360
|
+
throw e;
|
|
25361
|
+
}
|
|
25362
|
+
openDatabases.set(sqlitePath, db);
|
|
25363
|
+
registerProcessExitSqliteClose();
|
|
25364
|
+
return db;
|
|
25365
|
+
}
|
|
25366
|
+
|
|
24959
25367
|
// src/connection/close-bridge-connection.ts
|
|
24960
25368
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
24961
25369
|
const say = log2 ?? logImmediate;
|
|
24962
25370
|
say("Cleaning up connections\u2026");
|
|
24963
|
-
await new Promise((
|
|
25371
|
+
await new Promise((resolve18) => setImmediate(resolve18));
|
|
24964
25372
|
state.closedByUser = true;
|
|
24965
25373
|
clearReconnectQuietTimer(state.mainQuiet);
|
|
24966
25374
|
clearReconnectQuietTimer(state.firehoseQuiet);
|
|
@@ -24999,20 +25407,24 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
|
|
|
24999
25407
|
say("Stopping local dev server processes\u2026");
|
|
25000
25408
|
await devServerManager.shutdownAllGraceful();
|
|
25001
25409
|
}
|
|
25410
|
+
try {
|
|
25411
|
+
closeAllCliSqliteConnections();
|
|
25412
|
+
} catch {
|
|
25413
|
+
}
|
|
25002
25414
|
say("Shutdown complete.");
|
|
25003
25415
|
}
|
|
25004
25416
|
|
|
25005
25417
|
// src/paths/session-layout-paths.ts
|
|
25006
|
-
import * as
|
|
25418
|
+
import * as path12 from "node:path";
|
|
25007
25419
|
function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
|
|
25008
|
-
const resolved = worktreePaths.map((p) =>
|
|
25420
|
+
const resolved = worktreePaths.map((p) => path12.resolve(p)).filter(Boolean);
|
|
25009
25421
|
if (resolved.length === 0) return null;
|
|
25010
25422
|
resolved.sort();
|
|
25011
25423
|
return resolved[0];
|
|
25012
25424
|
}
|
|
25013
25425
|
function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
|
|
25014
25426
|
if (resolvedSessionParentPath != null && String(resolvedSessionParentPath).trim() !== "") {
|
|
25015
|
-
return
|
|
25427
|
+
return path12.resolve(String(resolvedSessionParentPath).trim());
|
|
25016
25428
|
}
|
|
25017
25429
|
return getBridgeRoot();
|
|
25018
25430
|
}
|
|
@@ -25021,17 +25433,17 @@ function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
|
|
|
25021
25433
|
import { execFile as execFile7 } from "node:child_process";
|
|
25022
25434
|
import { readFile, stat } from "node:fs/promises";
|
|
25023
25435
|
import { promisify as promisify7 } from "node:util";
|
|
25024
|
-
import * as
|
|
25436
|
+
import * as path15 from "node:path";
|
|
25025
25437
|
|
|
25026
25438
|
// src/git/pre-turn-snapshot.ts
|
|
25027
|
-
import * as
|
|
25028
|
-
import * as
|
|
25439
|
+
import * as fs14 from "node:fs";
|
|
25440
|
+
import * as path14 from "node:path";
|
|
25029
25441
|
import { execFile as execFile6 } from "node:child_process";
|
|
25030
25442
|
import { promisify as promisify6 } from "node:util";
|
|
25031
25443
|
|
|
25032
25444
|
// src/git/discover-repos.ts
|
|
25033
|
-
import * as
|
|
25034
|
-
import * as
|
|
25445
|
+
import * as fs13 from "node:fs";
|
|
25446
|
+
import * as path13 from "node:path";
|
|
25035
25447
|
|
|
25036
25448
|
// ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
|
|
25037
25449
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -25070,8 +25482,8 @@ function pathspec(...paths) {
|
|
|
25070
25482
|
cache.set(key, paths);
|
|
25071
25483
|
return key;
|
|
25072
25484
|
}
|
|
25073
|
-
function isPathSpec(
|
|
25074
|
-
return
|
|
25485
|
+
function isPathSpec(path41) {
|
|
25486
|
+
return path41 instanceof String && cache.has(path41);
|
|
25075
25487
|
}
|
|
25076
25488
|
function toPaths(pathSpec) {
|
|
25077
25489
|
return cache.get(pathSpec) || [];
|
|
@@ -25160,8 +25572,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
25160
25572
|
function forEachLineWithContent(input, callback) {
|
|
25161
25573
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
25162
25574
|
}
|
|
25163
|
-
function folderExists(
|
|
25164
|
-
return (0, import_file_exists.exists)(
|
|
25575
|
+
function folderExists(path41) {
|
|
25576
|
+
return (0, import_file_exists.exists)(path41, import_file_exists.FOLDER);
|
|
25165
25577
|
}
|
|
25166
25578
|
function append(target, item) {
|
|
25167
25579
|
if (Array.isArray(target)) {
|
|
@@ -25565,8 +25977,8 @@ function checkIsRepoRootTask() {
|
|
|
25565
25977
|
commands,
|
|
25566
25978
|
format: "utf-8",
|
|
25567
25979
|
onError,
|
|
25568
|
-
parser(
|
|
25569
|
-
return /^\.(git)?$/.test(
|
|
25980
|
+
parser(path41) {
|
|
25981
|
+
return /^\.(git)?$/.test(path41.trim());
|
|
25570
25982
|
}
|
|
25571
25983
|
};
|
|
25572
25984
|
}
|
|
@@ -26000,11 +26412,11 @@ function parseGrep(grep) {
|
|
|
26000
26412
|
const paths = /* @__PURE__ */ new Set();
|
|
26001
26413
|
const results = {};
|
|
26002
26414
|
forEachLineWithContent(grep, (input) => {
|
|
26003
|
-
const [
|
|
26004
|
-
paths.add(
|
|
26005
|
-
(results[
|
|
26415
|
+
const [path41, line, preview] = input.split(NULL);
|
|
26416
|
+
paths.add(path41);
|
|
26417
|
+
(results[path41] = results[path41] || []).push({
|
|
26006
26418
|
line: asNumber(line),
|
|
26007
|
-
path:
|
|
26419
|
+
path: path41,
|
|
26008
26420
|
preview
|
|
26009
26421
|
});
|
|
26010
26422
|
});
|
|
@@ -26769,14 +27181,14 @@ var init_hash_object = __esm2({
|
|
|
26769
27181
|
init_task();
|
|
26770
27182
|
}
|
|
26771
27183
|
});
|
|
26772
|
-
function parseInit(bare,
|
|
27184
|
+
function parseInit(bare, path41, text) {
|
|
26773
27185
|
const response = String(text).trim();
|
|
26774
27186
|
let result;
|
|
26775
27187
|
if (result = initResponseRegex.exec(response)) {
|
|
26776
|
-
return new InitSummary(bare,
|
|
27188
|
+
return new InitSummary(bare, path41, false, result[1]);
|
|
26777
27189
|
}
|
|
26778
27190
|
if (result = reInitResponseRegex.exec(response)) {
|
|
26779
|
-
return new InitSummary(bare,
|
|
27191
|
+
return new InitSummary(bare, path41, true, result[1]);
|
|
26780
27192
|
}
|
|
26781
27193
|
let gitDir = "";
|
|
26782
27194
|
const tokens = response.split(" ");
|
|
@@ -26787,7 +27199,7 @@ function parseInit(bare, path35, text) {
|
|
|
26787
27199
|
break;
|
|
26788
27200
|
}
|
|
26789
27201
|
}
|
|
26790
|
-
return new InitSummary(bare,
|
|
27202
|
+
return new InitSummary(bare, path41, /^re/i.test(response), gitDir);
|
|
26791
27203
|
}
|
|
26792
27204
|
var InitSummary;
|
|
26793
27205
|
var initResponseRegex;
|
|
@@ -26796,9 +27208,9 @@ var init_InitSummary = __esm2({
|
|
|
26796
27208
|
"src/lib/responses/InitSummary.ts"() {
|
|
26797
27209
|
"use strict";
|
|
26798
27210
|
InitSummary = class {
|
|
26799
|
-
constructor(bare,
|
|
27211
|
+
constructor(bare, path41, existing, gitDir) {
|
|
26800
27212
|
this.bare = bare;
|
|
26801
|
-
this.path =
|
|
27213
|
+
this.path = path41;
|
|
26802
27214
|
this.existing = existing;
|
|
26803
27215
|
this.gitDir = gitDir;
|
|
26804
27216
|
}
|
|
@@ -26810,7 +27222,7 @@ var init_InitSummary = __esm2({
|
|
|
26810
27222
|
function hasBareCommand(command) {
|
|
26811
27223
|
return command.includes(bareCommand);
|
|
26812
27224
|
}
|
|
26813
|
-
function initTask(bare = false,
|
|
27225
|
+
function initTask(bare = false, path41, customArgs) {
|
|
26814
27226
|
const commands = ["init", ...customArgs];
|
|
26815
27227
|
if (bare && !hasBareCommand(commands)) {
|
|
26816
27228
|
commands.splice(1, 0, bareCommand);
|
|
@@ -26819,7 +27231,7 @@ function initTask(bare = false, path35, customArgs) {
|
|
|
26819
27231
|
commands,
|
|
26820
27232
|
format: "utf-8",
|
|
26821
27233
|
parser(text) {
|
|
26822
|
-
return parseInit(commands.includes("--bare"),
|
|
27234
|
+
return parseInit(commands.includes("--bare"), path41, text);
|
|
26823
27235
|
}
|
|
26824
27236
|
};
|
|
26825
27237
|
}
|
|
@@ -27635,12 +28047,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
27635
28047
|
"use strict";
|
|
27636
28048
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
27637
28049
|
FileStatusSummary = class {
|
|
27638
|
-
constructor(
|
|
27639
|
-
this.path =
|
|
28050
|
+
constructor(path41, index, working_dir) {
|
|
28051
|
+
this.path = path41;
|
|
27640
28052
|
this.index = index;
|
|
27641
28053
|
this.working_dir = working_dir;
|
|
27642
28054
|
if (index === "R" || working_dir === "R") {
|
|
27643
|
-
const detail = fromPathRegex.exec(
|
|
28055
|
+
const detail = fromPathRegex.exec(path41) || [null, path41, path41];
|
|
27644
28056
|
this.from = detail[2] || "";
|
|
27645
28057
|
this.path = detail[1] || "";
|
|
27646
28058
|
}
|
|
@@ -27671,14 +28083,14 @@ function splitLine(result, lineStr) {
|
|
|
27671
28083
|
default:
|
|
27672
28084
|
return;
|
|
27673
28085
|
}
|
|
27674
|
-
function data(index, workingDir,
|
|
28086
|
+
function data(index, workingDir, path41) {
|
|
27675
28087
|
const raw = `${index}${workingDir}`;
|
|
27676
28088
|
const handler = parsers6.get(raw);
|
|
27677
28089
|
if (handler) {
|
|
27678
|
-
handler(result,
|
|
28090
|
+
handler(result, path41);
|
|
27679
28091
|
}
|
|
27680
28092
|
if (raw !== "##" && raw !== "!!") {
|
|
27681
|
-
result.files.push(new FileStatusSummary(
|
|
28093
|
+
result.files.push(new FileStatusSummary(path41, index, workingDir));
|
|
27682
28094
|
}
|
|
27683
28095
|
}
|
|
27684
28096
|
}
|
|
@@ -27951,15 +28363,15 @@ var init_simple_git_api = __esm2({
|
|
|
27951
28363
|
this._executor = _executor;
|
|
27952
28364
|
}
|
|
27953
28365
|
_runTask(task, then) {
|
|
27954
|
-
const
|
|
27955
|
-
const promise2 =
|
|
28366
|
+
const chain2 = this._executor.chain();
|
|
28367
|
+
const promise2 = chain2.push(task);
|
|
27956
28368
|
if (then) {
|
|
27957
28369
|
taskCallback(task, promise2, then);
|
|
27958
28370
|
}
|
|
27959
28371
|
return Object.create(this, {
|
|
27960
28372
|
then: { value: promise2.then.bind(promise2) },
|
|
27961
28373
|
catch: { value: promise2.catch.bind(promise2) },
|
|
27962
|
-
_executor: { value:
|
|
28374
|
+
_executor: { value: chain2 }
|
|
27963
28375
|
});
|
|
27964
28376
|
}
|
|
27965
28377
|
add(files) {
|
|
@@ -27987,9 +28399,9 @@ var init_simple_git_api = __esm2({
|
|
|
27987
28399
|
next
|
|
27988
28400
|
);
|
|
27989
28401
|
}
|
|
27990
|
-
hashObject(
|
|
28402
|
+
hashObject(path41, write) {
|
|
27991
28403
|
return this._runTask(
|
|
27992
|
-
hashObjectTask(
|
|
28404
|
+
hashObjectTask(path41, write === true),
|
|
27993
28405
|
trailingFunctionArgument(arguments)
|
|
27994
28406
|
);
|
|
27995
28407
|
}
|
|
@@ -28342,8 +28754,8 @@ var init_branch = __esm2({
|
|
|
28342
28754
|
}
|
|
28343
28755
|
});
|
|
28344
28756
|
function toPath(input) {
|
|
28345
|
-
const
|
|
28346
|
-
return
|
|
28757
|
+
const path41 = input.trim().replace(/^["']|["']$/g, "");
|
|
28758
|
+
return path41 && normalize2(path41);
|
|
28347
28759
|
}
|
|
28348
28760
|
var parseCheckIgnore;
|
|
28349
28761
|
var init_CheckIgnore = __esm2({
|
|
@@ -28657,8 +29069,8 @@ __export2(sub_module_exports, {
|
|
|
28657
29069
|
subModuleTask: () => subModuleTask,
|
|
28658
29070
|
updateSubModuleTask: () => updateSubModuleTask
|
|
28659
29071
|
});
|
|
28660
|
-
function addSubModuleTask(repo,
|
|
28661
|
-
return subModuleTask(["add", repo,
|
|
29072
|
+
function addSubModuleTask(repo, path41) {
|
|
29073
|
+
return subModuleTask(["add", repo, path41]);
|
|
28662
29074
|
}
|
|
28663
29075
|
function initSubModuleTask(customArgs) {
|
|
28664
29076
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -28991,8 +29403,8 @@ var require_git = __commonJS2({
|
|
|
28991
29403
|
}
|
|
28992
29404
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
28993
29405
|
};
|
|
28994
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
28995
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
29406
|
+
Git2.prototype.submoduleAdd = function(repo, path41, then) {
|
|
29407
|
+
return this._runTask(addSubModuleTask2(repo, path41), trailingFunctionArgument2(arguments));
|
|
28996
29408
|
};
|
|
28997
29409
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
28998
29410
|
return this._runTask(
|
|
@@ -29636,20 +30048,20 @@ async function isGitRepoDirectory(dirPath) {
|
|
|
29636
30048
|
// src/git/discover-repos.ts
|
|
29637
30049
|
async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
29638
30050
|
const result = [];
|
|
29639
|
-
const cwdResolved =
|
|
30051
|
+
const cwdResolved = path13.resolve(cwd);
|
|
29640
30052
|
if (await isGitRepoDirectory(cwdResolved)) {
|
|
29641
30053
|
const remoteUrl = await getRemoteOriginUrl(cwdResolved);
|
|
29642
30054
|
result.push({ absolutePath: cwdResolved, remoteUrl });
|
|
29643
30055
|
}
|
|
29644
30056
|
let entries;
|
|
29645
30057
|
try {
|
|
29646
|
-
entries =
|
|
30058
|
+
entries = fs13.readdirSync(cwdResolved, { withFileTypes: true });
|
|
29647
30059
|
} catch {
|
|
29648
30060
|
return result;
|
|
29649
30061
|
}
|
|
29650
30062
|
for (const ent of entries) {
|
|
29651
30063
|
if (!ent.isDirectory()) continue;
|
|
29652
|
-
const childPath =
|
|
30064
|
+
const childPath = path13.join(cwdResolved, ent.name);
|
|
29653
30065
|
if (await isGitRepoDirectory(childPath)) {
|
|
29654
30066
|
const remoteUrl = await getRemoteOriginUrl(childPath);
|
|
29655
30067
|
result.push({ absolutePath: childPath, remoteUrl });
|
|
@@ -29658,22 +30070,22 @@ async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
|
29658
30070
|
return result;
|
|
29659
30071
|
}
|
|
29660
30072
|
async function discoverGitReposUnderRoot(rootPath) {
|
|
29661
|
-
const root =
|
|
30073
|
+
const root = path13.resolve(rootPath);
|
|
29662
30074
|
const roots = [];
|
|
29663
30075
|
async function walk(dir) {
|
|
29664
30076
|
if (await isGitRepoDirectory(dir)) {
|
|
29665
|
-
roots.push(
|
|
30077
|
+
roots.push(path13.resolve(dir));
|
|
29666
30078
|
return;
|
|
29667
30079
|
}
|
|
29668
30080
|
let entries;
|
|
29669
30081
|
try {
|
|
29670
|
-
entries =
|
|
30082
|
+
entries = fs13.readdirSync(dir, { withFileTypes: true });
|
|
29671
30083
|
} catch {
|
|
29672
30084
|
return;
|
|
29673
30085
|
}
|
|
29674
30086
|
for (const ent of entries) {
|
|
29675
30087
|
if (!ent.isDirectory() || ent.name === ".git") continue;
|
|
29676
|
-
await walk(
|
|
30088
|
+
await walk(path13.join(dir, ent.name));
|
|
29677
30089
|
}
|
|
29678
30090
|
}
|
|
29679
30091
|
await walk(root);
|
|
@@ -29689,7 +30101,7 @@ async function discoverGitReposUnderRoot(rootPath) {
|
|
|
29689
30101
|
// src/git/pre-turn-snapshot.ts
|
|
29690
30102
|
var execFileAsync5 = promisify6(execFile6);
|
|
29691
30103
|
function snapshotsDirForCwd(agentCwd) {
|
|
29692
|
-
return
|
|
30104
|
+
return path14.join(agentCwd, ".buildautomaton", "snapshots");
|
|
29693
30105
|
}
|
|
29694
30106
|
async function gitStashCreate(repoRoot, log2) {
|
|
29695
30107
|
try {
|
|
@@ -29718,7 +30130,7 @@ async function gitRun(repoRoot, args, log2, label) {
|
|
|
29718
30130
|
async function resolveSnapshotRepoRoots(options) {
|
|
29719
30131
|
const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
|
|
29720
30132
|
if (worktreePaths?.length) {
|
|
29721
|
-
const uniq = [...new Set(worktreePaths.map((p) =>
|
|
30133
|
+
const uniq = [...new Set(worktreePaths.map((p) => path14.resolve(p)))];
|
|
29722
30134
|
return uniq;
|
|
29723
30135
|
}
|
|
29724
30136
|
try {
|
|
@@ -29726,7 +30138,7 @@ async function resolveSnapshotRepoRoots(options) {
|
|
|
29726
30138
|
const mapped = repos.map((r) => r.absolutePath);
|
|
29727
30139
|
const sid = sessionId?.trim();
|
|
29728
30140
|
if (sid) {
|
|
29729
|
-
const filtered = mapped.filter((root) =>
|
|
30141
|
+
const filtered = mapped.filter((root) => path14.basename(root) === sid);
|
|
29730
30142
|
if (filtered.length > 0) return filtered;
|
|
29731
30143
|
}
|
|
29732
30144
|
return mapped;
|
|
@@ -29747,7 +30159,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
29747
30159
|
}
|
|
29748
30160
|
const dir = snapshotsDirForCwd(agentCwd);
|
|
29749
30161
|
try {
|
|
29750
|
-
|
|
30162
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
29751
30163
|
} catch (e) {
|
|
29752
30164
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
29753
30165
|
}
|
|
@@ -29756,9 +30168,9 @@ async function capturePreTurnSnapshot(options) {
|
|
|
29756
30168
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29757
30169
|
repos
|
|
29758
30170
|
};
|
|
29759
|
-
const filePath =
|
|
30171
|
+
const filePath = path14.join(dir, `${runId}.json`);
|
|
29760
30172
|
try {
|
|
29761
|
-
|
|
30173
|
+
fs14.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
29762
30174
|
} catch (e) {
|
|
29763
30175
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
29764
30176
|
}
|
|
@@ -29771,7 +30183,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
29771
30183
|
async function applyPreTurnSnapshot(filePath, log2) {
|
|
29772
30184
|
let data;
|
|
29773
30185
|
try {
|
|
29774
|
-
const raw =
|
|
30186
|
+
const raw = fs14.readFileSync(filePath, "utf8");
|
|
29775
30187
|
data = JSON.parse(raw);
|
|
29776
30188
|
} catch (e) {
|
|
29777
30189
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
@@ -29794,7 +30206,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
|
|
|
29794
30206
|
return { ok: true };
|
|
29795
30207
|
}
|
|
29796
30208
|
function snapshotFilePath(agentCwd, runId) {
|
|
29797
|
-
return
|
|
30209
|
+
return path14.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
|
|
29798
30210
|
}
|
|
29799
30211
|
|
|
29800
30212
|
// src/git/session-git-queue.ts
|
|
@@ -29843,7 +30255,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
29843
30255
|
continue;
|
|
29844
30256
|
}
|
|
29845
30257
|
const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
29846
|
-
const slug =
|
|
30258
|
+
const slug = path15.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
|
|
29847
30259
|
for (const rel of lines) {
|
|
29848
30260
|
if (rel.includes("..")) continue;
|
|
29849
30261
|
try {
|
|
@@ -29857,7 +30269,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
29857
30269
|
);
|
|
29858
30270
|
if (!patchContent.trim()) continue;
|
|
29859
30271
|
const displayPath = multiRepo ? `${slug}/${rel}` : rel;
|
|
29860
|
-
const workspaceFilePath =
|
|
30272
|
+
const workspaceFilePath = path15.join(repo.path, rel);
|
|
29861
30273
|
const newText = await readWorkspaceFileAsUtf8(workspaceFilePath);
|
|
29862
30274
|
sendSessionUpdate({
|
|
29863
30275
|
type: "session_file_change",
|
|
@@ -29879,9 +30291,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
29879
30291
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
29880
30292
|
async function putEncryptedChangeSummaryRows(params) {
|
|
29881
30293
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
29882
|
-
const entries = params.rows.map(({ path:
|
|
30294
|
+
const entries = params.rows.map(({ path: path41, summary }) => {
|
|
29883
30295
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
29884
|
-
return { path:
|
|
30296
|
+
return { path: path41, summary: JSON.stringify(enc) };
|
|
29885
30297
|
});
|
|
29886
30298
|
const res = await fetch(
|
|
29887
30299
|
`${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -30218,8 +30630,8 @@ async function sendPromptToAgent(options) {
|
|
|
30218
30630
|
}
|
|
30219
30631
|
|
|
30220
30632
|
// src/agents/acp/ensure-acp-client.ts
|
|
30221
|
-
import * as
|
|
30222
|
-
import * as
|
|
30633
|
+
import * as fs15 from "node:fs";
|
|
30634
|
+
import * as path18 from "node:path";
|
|
30223
30635
|
|
|
30224
30636
|
// src/error-message.ts
|
|
30225
30637
|
function errorMessage(err) {
|
|
@@ -30414,7 +30826,7 @@ async function createCursorAcpClient(options) {
|
|
|
30414
30826
|
logDebug,
|
|
30415
30827
|
getStderrText: () => stderrCapture.getText()
|
|
30416
30828
|
};
|
|
30417
|
-
return new Promise((
|
|
30829
|
+
return new Promise((resolve18, reject) => {
|
|
30418
30830
|
child.on("error", (err) => {
|
|
30419
30831
|
child.kill();
|
|
30420
30832
|
reject(new Error(formatSpawnError2(err, command[0])));
|
|
@@ -30493,12 +30905,16 @@ async function createCursorAcpClient(options) {
|
|
|
30493
30905
|
}
|
|
30494
30906
|
if (method === "session/request_permission" && typeof id === "number") {
|
|
30495
30907
|
const params = msg.params ?? {};
|
|
30496
|
-
|
|
30497
|
-
|
|
30498
|
-
|
|
30499
|
-
|
|
30500
|
-
|
|
30501
|
-
|
|
30908
|
+
if (onRequest) {
|
|
30909
|
+
pendingRequests.set(id, { method, params });
|
|
30910
|
+
onRequest({
|
|
30911
|
+
requestId: String(id),
|
|
30912
|
+
method,
|
|
30913
|
+
params
|
|
30914
|
+
});
|
|
30915
|
+
} else {
|
|
30916
|
+
respond(id, { outcome: { outcome: "denied" } });
|
|
30917
|
+
}
|
|
30502
30918
|
return;
|
|
30503
30919
|
}
|
|
30504
30920
|
if (typeof id === "number" && method) {
|
|
@@ -30586,7 +31002,7 @@ async function createCursorAcpClient(options) {
|
|
|
30586
31002
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
30587
31003
|
});
|
|
30588
31004
|
const sessionId = established.sessionId;
|
|
30589
|
-
|
|
31005
|
+
resolve18({
|
|
30590
31006
|
sessionId,
|
|
30591
31007
|
async sendPrompt(prompt, options2) {
|
|
30592
31008
|
const imgs = options2?.images?.map((im) => ({ type: "image", mimeType: im.mimeType, data: im.dataBase64 }));
|
|
@@ -30721,20 +31137,20 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
30721
31137
|
|
|
30722
31138
|
// src/agents/acp/session-file-change-path-kind.ts
|
|
30723
31139
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
30724
|
-
import { existsSync, statSync } from "node:fs";
|
|
31140
|
+
import { existsSync as existsSync2, statSync } from "node:fs";
|
|
30725
31141
|
|
|
30726
31142
|
// src/git/get-git-repo-root-sync.ts
|
|
30727
31143
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
30728
|
-
import * as
|
|
31144
|
+
import * as path16 from "node:path";
|
|
30729
31145
|
function getGitRepoRootSync(startDir) {
|
|
30730
31146
|
try {
|
|
30731
31147
|
const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
30732
|
-
cwd:
|
|
31148
|
+
cwd: path16.resolve(startDir),
|
|
30733
31149
|
encoding: "utf8",
|
|
30734
31150
|
stdio: ["ignore", "pipe", "ignore"],
|
|
30735
31151
|
maxBuffer: 1024 * 1024
|
|
30736
31152
|
}).trim();
|
|
30737
|
-
return out ?
|
|
31153
|
+
return out ? path16.resolve(out) : null;
|
|
30738
31154
|
} catch {
|
|
30739
31155
|
return null;
|
|
30740
31156
|
}
|
|
@@ -30742,26 +31158,26 @@ function getGitRepoRootSync(startDir) {
|
|
|
30742
31158
|
|
|
30743
31159
|
// src/agents/acp/workspace-files.ts
|
|
30744
31160
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
30745
|
-
import { readFileSync as
|
|
30746
|
-
import * as
|
|
31161
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
31162
|
+
import * as path17 from "node:path";
|
|
30747
31163
|
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
30748
31164
|
const trimmed2 = rawPath.trim();
|
|
30749
31165
|
if (!trimmed2) return null;
|
|
30750
|
-
const normalizedSessionParent =
|
|
31166
|
+
const normalizedSessionParent = path17.resolve(sessionParentPath);
|
|
30751
31167
|
let resolvedPath = resolveSafePathUnderCwd(sessionParentPath, trimmed2);
|
|
30752
31168
|
if (!resolvedPath) {
|
|
30753
|
-
const candidate =
|
|
31169
|
+
const candidate = path17.isAbsolute(trimmed2) ? path17.normalize(trimmed2) : path17.normalize(path17.resolve(normalizedSessionParent, trimmed2));
|
|
30754
31170
|
const gitRoot2 = getGitRepoRootSync(sessionParentPath);
|
|
30755
31171
|
if (!gitRoot2) return null;
|
|
30756
|
-
const rel =
|
|
30757
|
-
if (rel.startsWith("..") ||
|
|
31172
|
+
const rel = path17.relative(gitRoot2, candidate);
|
|
31173
|
+
if (rel.startsWith("..") || path17.isAbsolute(rel)) return null;
|
|
30758
31174
|
resolvedPath = candidate;
|
|
30759
31175
|
}
|
|
30760
31176
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30761
31177
|
if (gitRoot) {
|
|
30762
|
-
const relFromRoot =
|
|
30763
|
-
if (!relFromRoot.startsWith("..") && !
|
|
30764
|
-
return { resolvedPath, display: relFromRoot.split(
|
|
31178
|
+
const relFromRoot = path17.relative(gitRoot, resolvedPath);
|
|
31179
|
+
if (!relFromRoot.startsWith("..") && !path17.isAbsolute(relFromRoot)) {
|
|
31180
|
+
return { resolvedPath, display: relFromRoot.split(path17.sep).join("/") };
|
|
30765
31181
|
}
|
|
30766
31182
|
}
|
|
30767
31183
|
return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
|
|
@@ -30770,11 +31186,11 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
30770
31186
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
30771
31187
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30772
31188
|
if (gitRoot) {
|
|
30773
|
-
const resolvedPath2 =
|
|
30774
|
-
const rel =
|
|
30775
|
-
if (!rel.startsWith("..") && !
|
|
31189
|
+
const resolvedPath2 = path17.resolve(gitRoot, displayPath);
|
|
31190
|
+
const rel = path17.relative(gitRoot, resolvedPath2);
|
|
31191
|
+
if (!rel.startsWith("..") && !path17.isAbsolute(rel)) {
|
|
30776
31192
|
try {
|
|
30777
|
-
return
|
|
31193
|
+
return readFileSync4(resolvedPath2, "utf8");
|
|
30778
31194
|
} catch {
|
|
30779
31195
|
}
|
|
30780
31196
|
}
|
|
@@ -30782,7 +31198,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
30782
31198
|
const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
30783
31199
|
if (!resolvedPath) return "";
|
|
30784
31200
|
try {
|
|
30785
|
-
return
|
|
31201
|
+
return readFileSync4(resolvedPath, "utf8");
|
|
30786
31202
|
} catch {
|
|
30787
31203
|
return "";
|
|
30788
31204
|
}
|
|
@@ -30791,9 +31207,9 @@ function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
|
|
|
30791
31207
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
30792
31208
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
30793
31209
|
if (gitRoot) {
|
|
30794
|
-
const resolvedPath =
|
|
30795
|
-
const rel =
|
|
30796
|
-
if (!rel.startsWith("..") && !
|
|
31210
|
+
const resolvedPath = path17.resolve(gitRoot, displayPath);
|
|
31211
|
+
const rel = path17.relative(gitRoot, resolvedPath);
|
|
31212
|
+
if (!rel.startsWith("..") && !path17.isAbsolute(rel)) return resolvedPath;
|
|
30797
31213
|
}
|
|
30798
31214
|
return resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
30799
31215
|
}
|
|
@@ -30828,7 +31244,7 @@ function gitHeadPathObjectType(sessionParentPath, displayPath) {
|
|
|
30828
31244
|
}
|
|
30829
31245
|
function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
|
|
30830
31246
|
const resolvedPath = tryWorkspaceDisplayToPath(sessionParentPath, displayPath);
|
|
30831
|
-
if (resolvedPath &&
|
|
31247
|
+
if (resolvedPath && existsSync2(resolvedPath)) {
|
|
30832
31248
|
try {
|
|
30833
31249
|
if (statSync(resolvedPath).isDirectory()) {
|
|
30834
31250
|
return { isDirectory: true, directoryRemoved: false };
|
|
@@ -30928,7 +31344,7 @@ function createBridgeOnRequest(opts) {
|
|
|
30928
31344
|
}
|
|
30929
31345
|
|
|
30930
31346
|
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
|
|
30931
|
-
import { fileURLToPath as
|
|
31347
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
30932
31348
|
function readOptionalTextField(v) {
|
|
30933
31349
|
if (v === null || v === void 0) return "";
|
|
30934
31350
|
if (typeof v === "string") return v;
|
|
@@ -30938,7 +31354,7 @@ function normalizePathField(raw) {
|
|
|
30938
31354
|
const t = raw.trim();
|
|
30939
31355
|
if (t.startsWith("file://")) {
|
|
30940
31356
|
try {
|
|
30941
|
-
return
|
|
31357
|
+
return fileURLToPath3(t);
|
|
30942
31358
|
} catch {
|
|
30943
31359
|
return t;
|
|
30944
31360
|
}
|
|
@@ -31396,29 +31812,34 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
31396
31812
|
}
|
|
31397
31813
|
|
|
31398
31814
|
// src/agents/acp/local-agent-session-file.ts
|
|
31399
|
-
|
|
31400
|
-
import os3 from "node:os";
|
|
31401
|
-
import path11 from "node:path";
|
|
31402
|
-
var LOCAL_AGENT_SESSION_DIR = path11.join(os3.homedir(), ".buildautomaton", "agent-sessions");
|
|
31403
|
-
function safeFileSlug(cloudSessionId) {
|
|
31815
|
+
function sessionKeyForCloudSessionId(cloudSessionId) {
|
|
31404
31816
|
const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
|
|
31405
31817
|
return t.length > 0 ? t : "session";
|
|
31406
31818
|
}
|
|
31407
|
-
function localAgentSessionFilePath(cloudSessionId) {
|
|
31408
|
-
return path11.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
|
|
31409
|
-
}
|
|
31410
31819
|
function readLocalAgentSessionFile(cloudSessionId) {
|
|
31411
31820
|
try {
|
|
31412
|
-
const
|
|
31413
|
-
const
|
|
31414
|
-
const
|
|
31415
|
-
|
|
31821
|
+
const db = getCliDatabase();
|
|
31822
|
+
const key = sessionKeyForCloudSessionId(cloudSessionId);
|
|
31823
|
+
const row = db.get(
|
|
31824
|
+
"SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
|
|
31825
|
+
[key]
|
|
31826
|
+
);
|
|
31827
|
+
if (!row) return null;
|
|
31828
|
+
let configOptions = null;
|
|
31829
|
+
if (row.config_options_json != null && row.config_options_json !== "") {
|
|
31830
|
+
try {
|
|
31831
|
+
const parsed = JSON.parse(row.config_options_json);
|
|
31832
|
+
configOptions = Array.isArray(parsed) ? parsed : null;
|
|
31833
|
+
} catch {
|
|
31834
|
+
configOptions = null;
|
|
31835
|
+
}
|
|
31836
|
+
}
|
|
31416
31837
|
return {
|
|
31417
31838
|
v: 1,
|
|
31418
|
-
acpSessionId:
|
|
31419
|
-
backendAgentType:
|
|
31420
|
-
configOptions
|
|
31421
|
-
updatedAt:
|
|
31839
|
+
acpSessionId: row.acp_session_id,
|
|
31840
|
+
backendAgentType: row.backend_agent_type,
|
|
31841
|
+
configOptions,
|
|
31842
|
+
updatedAt: row.updated_at
|
|
31422
31843
|
};
|
|
31423
31844
|
} catch {
|
|
31424
31845
|
return null;
|
|
@@ -31426,9 +31847,8 @@ function readLocalAgentSessionFile(cloudSessionId) {
|
|
|
31426
31847
|
}
|
|
31427
31848
|
function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
31428
31849
|
try {
|
|
31429
|
-
const
|
|
31430
|
-
|
|
31431
|
-
const p = localAgentSessionFilePath(cloudSessionId);
|
|
31850
|
+
const db = getCliDatabase();
|
|
31851
|
+
const key = sessionKeyForCloudSessionId(cloudSessionId);
|
|
31432
31852
|
const prev = readLocalAgentSessionFile(cloudSessionId);
|
|
31433
31853
|
const next = {
|
|
31434
31854
|
v: 1,
|
|
@@ -31437,7 +31857,17 @@ function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
|
31437
31857
|
configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
|
|
31438
31858
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
31439
31859
|
};
|
|
31440
|
-
|
|
31860
|
+
const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
|
|
31861
|
+
db.run(
|
|
31862
|
+
`INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
|
|
31863
|
+
VALUES (?, ?, ?, ?, ?)
|
|
31864
|
+
ON CONFLICT(session_key) DO UPDATE SET
|
|
31865
|
+
acp_session_id = excluded.acp_session_id,
|
|
31866
|
+
backend_agent_type = excluded.backend_agent_type,
|
|
31867
|
+
config_options_json = excluded.config_options_json,
|
|
31868
|
+
updated_at = excluded.updated_at`,
|
|
31869
|
+
[key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
|
|
31870
|
+
);
|
|
31441
31871
|
} catch {
|
|
31442
31872
|
}
|
|
31443
31873
|
}
|
|
@@ -31452,6 +31882,7 @@ async function ensureAcpClient(options) {
|
|
|
31452
31882
|
sessionParentPath,
|
|
31453
31883
|
routing,
|
|
31454
31884
|
cloudSessionId,
|
|
31885
|
+
reportAgentCapabilities,
|
|
31455
31886
|
sendSessionUpdate,
|
|
31456
31887
|
sendRequest,
|
|
31457
31888
|
log: log2
|
|
@@ -31461,7 +31892,7 @@ async function ensureAcpClient(options) {
|
|
|
31461
31892
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
31462
31893
|
await state.acpStartPromise;
|
|
31463
31894
|
}
|
|
31464
|
-
if (state.acpHandle && state.lastAcpCwd != null &&
|
|
31895
|
+
if (state.acpHandle && state.lastAcpCwd != null && path18.resolve(state.lastAcpCwd) !== path18.resolve(targetSessionParentPath)) {
|
|
31465
31896
|
try {
|
|
31466
31897
|
state.acpHandle.disconnect();
|
|
31467
31898
|
} catch {
|
|
@@ -31496,7 +31927,7 @@ async function ensureAcpClient(options) {
|
|
|
31496
31927
|
if (!state.acpStartPromise) {
|
|
31497
31928
|
let statOk = false;
|
|
31498
31929
|
try {
|
|
31499
|
-
const st =
|
|
31930
|
+
const st = fs15.statSync(targetSessionParentPath);
|
|
31500
31931
|
statOk = st.isDirectory();
|
|
31501
31932
|
if (!statOk) {
|
|
31502
31933
|
state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
|
|
@@ -31539,6 +31970,12 @@ async function ensureAcpClient(options) {
|
|
|
31539
31970
|
backendAgentType: preferredAgentType
|
|
31540
31971
|
});
|
|
31541
31972
|
}
|
|
31973
|
+
if (reportAgentCapabilities && preferredAgentType && Array.isArray(info.configOptions) && info.configOptions.length > 0) {
|
|
31974
|
+
reportAgentCapabilities({
|
|
31975
|
+
agentType: preferredAgentType,
|
|
31976
|
+
configOptions: info.configOptions
|
|
31977
|
+
});
|
|
31978
|
+
}
|
|
31542
31979
|
},
|
|
31543
31980
|
onAcpConfigOptionsUpdated: (configOptions) => {
|
|
31544
31981
|
state.activeSessionConfigOptions = configOptions;
|
|
@@ -31548,6 +31985,12 @@ async function ensureAcpClient(options) {
|
|
|
31548
31985
|
backendAgentType: preferredAgentType
|
|
31549
31986
|
});
|
|
31550
31987
|
}
|
|
31988
|
+
if (reportAgentCapabilities && preferredAgentType && Array.isArray(configOptions) && configOptions.length > 0) {
|
|
31989
|
+
reportAgentCapabilities({
|
|
31990
|
+
agentType: preferredAgentType,
|
|
31991
|
+
configOptions
|
|
31992
|
+
});
|
|
31993
|
+
}
|
|
31551
31994
|
},
|
|
31552
31995
|
onAgentSubprocessExit: () => {
|
|
31553
31996
|
state.acpHandle = null;
|
|
@@ -31578,7 +32021,7 @@ async function ensureAcpClient(options) {
|
|
|
31578
32021
|
|
|
31579
32022
|
// src/agents/acp/create-acp-manager.ts
|
|
31580
32023
|
async function createAcpManager(options) {
|
|
31581
|
-
const { log: log2 } = options;
|
|
32024
|
+
const { log: log2, reportAgentCapabilities } = options;
|
|
31582
32025
|
const state = {
|
|
31583
32026
|
acpHandle: null,
|
|
31584
32027
|
acpStartPromise: null,
|
|
@@ -31622,7 +32065,8 @@ async function createAcpManager(options) {
|
|
|
31622
32065
|
cloudApiBaseUrl,
|
|
31623
32066
|
getCloudAccessToken,
|
|
31624
32067
|
e2ee,
|
|
31625
|
-
attachments
|
|
32068
|
+
attachments,
|
|
32069
|
+
agentId
|
|
31626
32070
|
} = opts;
|
|
31627
32071
|
const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
|
|
31628
32072
|
pendingCancelRunId = void 0;
|
|
@@ -31640,7 +32084,8 @@ async function createAcpManager(options) {
|
|
|
31640
32084
|
cloudSessionId: sessionId,
|
|
31641
32085
|
sendSessionUpdate,
|
|
31642
32086
|
sendRequest: sendSessionUpdate,
|
|
31643
|
-
log: log2
|
|
32087
|
+
log: log2,
|
|
32088
|
+
reportAgentCapabilities
|
|
31644
32089
|
});
|
|
31645
32090
|
if (!handle) {
|
|
31646
32091
|
const errMsg = state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
|
|
@@ -31743,12 +32188,12 @@ async function createAcpManager(options) {
|
|
|
31743
32188
|
}
|
|
31744
32189
|
|
|
31745
32190
|
// src/worktrees/session-worktree-manager.ts
|
|
31746
|
-
import * as
|
|
31747
|
-
import
|
|
32191
|
+
import * as path25 from "node:path";
|
|
32192
|
+
import os8 from "node:os";
|
|
31748
32193
|
|
|
31749
32194
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
31750
|
-
import * as
|
|
31751
|
-
import * as
|
|
32195
|
+
import * as fs17 from "node:fs";
|
|
32196
|
+
import * as path20 from "node:path";
|
|
31752
32197
|
|
|
31753
32198
|
// src/git/worktree-add.ts
|
|
31754
32199
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -31757,12 +32202,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
31757
32202
|
}
|
|
31758
32203
|
|
|
31759
32204
|
// src/worktrees/worktree-layout-file.ts
|
|
31760
|
-
import * as
|
|
31761
|
-
import * as
|
|
31762
|
-
import
|
|
32205
|
+
import * as fs16 from "node:fs";
|
|
32206
|
+
import * as path19 from "node:path";
|
|
32207
|
+
import os7 from "node:os";
|
|
31763
32208
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
31764
32209
|
function defaultWorktreeLayoutPath() {
|
|
31765
|
-
return
|
|
32210
|
+
return path19.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
31766
32211
|
}
|
|
31767
32212
|
function normalizeLoadedLayout(raw) {
|
|
31768
32213
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -31774,8 +32219,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
31774
32219
|
function loadWorktreeLayout() {
|
|
31775
32220
|
try {
|
|
31776
32221
|
const p = defaultWorktreeLayoutPath();
|
|
31777
|
-
if (!
|
|
31778
|
-
const raw = JSON.parse(
|
|
32222
|
+
if (!fs16.existsSync(p)) return { launcherCwds: [] };
|
|
32223
|
+
const raw = JSON.parse(fs16.readFileSync(p, "utf8"));
|
|
31779
32224
|
return normalizeLoadedLayout(raw);
|
|
31780
32225
|
} catch {
|
|
31781
32226
|
return { launcherCwds: [] };
|
|
@@ -31783,24 +32228,24 @@ function loadWorktreeLayout() {
|
|
|
31783
32228
|
}
|
|
31784
32229
|
function saveWorktreeLayout(layout) {
|
|
31785
32230
|
try {
|
|
31786
|
-
const dir =
|
|
31787
|
-
|
|
31788
|
-
|
|
32231
|
+
const dir = path19.dirname(defaultWorktreeLayoutPath());
|
|
32232
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
32233
|
+
fs16.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
31789
32234
|
} catch {
|
|
31790
32235
|
}
|
|
31791
32236
|
}
|
|
31792
32237
|
function baseNameSafe(pathString) {
|
|
31793
|
-
return
|
|
32238
|
+
return path19.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
31794
32239
|
}
|
|
31795
32240
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
31796
|
-
const norm =
|
|
31797
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
32241
|
+
const norm = path19.resolve(bridgeRootPath2);
|
|
32242
|
+
const existing = layout.launcherCwds.find((e) => path19.resolve(e.absolutePath) === norm);
|
|
31798
32243
|
return existing?.dirName;
|
|
31799
32244
|
}
|
|
31800
32245
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
31801
32246
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
31802
32247
|
if (existing) return existing;
|
|
31803
|
-
const norm =
|
|
32248
|
+
const norm = path19.resolve(bridgeRootPath2);
|
|
31804
32249
|
const base = baseNameSafe(norm);
|
|
31805
32250
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
31806
32251
|
let name = base;
|
|
@@ -31817,10 +32262,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
31817
32262
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
31818
32263
|
async function prepareNewSessionWorktrees(options) {
|
|
31819
32264
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
|
|
31820
|
-
const bridgeResolved =
|
|
32265
|
+
const bridgeResolved = path20.resolve(bridgeRoot);
|
|
31821
32266
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
31822
|
-
const bridgeKeyDir =
|
|
31823
|
-
const sessionDir =
|
|
32267
|
+
const bridgeKeyDir = path20.join(worktreesRootPath, cwdKey);
|
|
32268
|
+
const sessionDir = path20.join(bridgeKeyDir, sessionId);
|
|
31824
32269
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
31825
32270
|
if (repos.length === 0) {
|
|
31826
32271
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -31828,14 +32273,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
31828
32273
|
}
|
|
31829
32274
|
const branch = `session-${sessionId}`;
|
|
31830
32275
|
const worktreePaths = [];
|
|
31831
|
-
|
|
32276
|
+
fs17.mkdirSync(sessionDir, { recursive: true });
|
|
31832
32277
|
for (const repo of repos) {
|
|
31833
|
-
let rel =
|
|
31834
|
-
if (rel.startsWith("..") ||
|
|
32278
|
+
let rel = path20.relative(bridgeResolved, repo.absolutePath);
|
|
32279
|
+
if (rel.startsWith("..") || path20.isAbsolute(rel)) continue;
|
|
31835
32280
|
const relNorm = rel === "" ? "." : rel;
|
|
31836
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
32281
|
+
const wtPath = relNorm === "." ? sessionDir : path20.join(sessionDir, relNorm);
|
|
31837
32282
|
if (relNorm !== ".") {
|
|
31838
|
-
|
|
32283
|
+
fs17.mkdirSync(path20.dirname(wtPath), { recursive: true });
|
|
31839
32284
|
}
|
|
31840
32285
|
try {
|
|
31841
32286
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
@@ -31877,23 +32322,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
31877
32322
|
}
|
|
31878
32323
|
|
|
31879
32324
|
// src/worktrees/remove-session-worktrees.ts
|
|
31880
|
-
import * as
|
|
32325
|
+
import * as fs20 from "node:fs";
|
|
31881
32326
|
|
|
31882
32327
|
// src/git/worktree-remove.ts
|
|
31883
|
-
import * as
|
|
32328
|
+
import * as fs19 from "node:fs";
|
|
31884
32329
|
|
|
31885
32330
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
31886
|
-
import * as
|
|
31887
|
-
import * as
|
|
32331
|
+
import * as fs18 from "node:fs";
|
|
32332
|
+
import * as path21 from "node:path";
|
|
31888
32333
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
31889
|
-
const gitDirFile =
|
|
31890
|
-
if (!
|
|
31891
|
-
const first2 =
|
|
32334
|
+
const gitDirFile = path21.join(wt, ".git");
|
|
32335
|
+
if (!fs18.existsSync(gitDirFile) || !fs18.statSync(gitDirFile).isFile()) return "";
|
|
32336
|
+
const first2 = fs18.readFileSync(gitDirFile, "utf8").trim();
|
|
31892
32337
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
31893
32338
|
if (!m) return "";
|
|
31894
|
-
const gitWorktreePath =
|
|
31895
|
-
const gitDir =
|
|
31896
|
-
return
|
|
32339
|
+
const gitWorktreePath = path21.resolve(wt, m[1].trim());
|
|
32340
|
+
const gitDir = path21.dirname(path21.dirname(gitWorktreePath));
|
|
32341
|
+
return path21.dirname(gitDir);
|
|
31897
32342
|
}
|
|
31898
32343
|
|
|
31899
32344
|
// src/git/worktree-remove.ts
|
|
@@ -31902,7 +32347,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
31902
32347
|
if (mainRepo) {
|
|
31903
32348
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
31904
32349
|
} else {
|
|
31905
|
-
|
|
32350
|
+
fs19.rmSync(worktreePath, { recursive: true, force: true });
|
|
31906
32351
|
}
|
|
31907
32352
|
}
|
|
31908
32353
|
|
|
@@ -31915,7 +32360,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
31915
32360
|
} catch (e) {
|
|
31916
32361
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
31917
32362
|
try {
|
|
31918
|
-
|
|
32363
|
+
fs20.rmSync(wt, { recursive: true, force: true });
|
|
31919
32364
|
} catch {
|
|
31920
32365
|
}
|
|
31921
32366
|
}
|
|
@@ -32135,7 +32580,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
32135
32580
|
}
|
|
32136
32581
|
|
|
32137
32582
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
32138
|
-
import * as
|
|
32583
|
+
import * as path23 from "node:path";
|
|
32139
32584
|
|
|
32140
32585
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
32141
32586
|
function parseNameStatusLines(lines) {
|
|
@@ -32255,8 +32700,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
32255
32700
|
}
|
|
32256
32701
|
|
|
32257
32702
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
32258
|
-
import * as
|
|
32259
|
-
import * as
|
|
32703
|
+
import * as fs22 from "node:fs";
|
|
32704
|
+
import * as path22 from "node:path";
|
|
32260
32705
|
|
|
32261
32706
|
// src/git/working-directory/changes/count-lines.ts
|
|
32262
32707
|
import { createReadStream } from "node:fs";
|
|
@@ -32280,7 +32725,7 @@ async function countTextFileLines(filePath) {
|
|
|
32280
32725
|
}
|
|
32281
32726
|
|
|
32282
32727
|
// src/git/working-directory/changes/hydrate-patch.ts
|
|
32283
|
-
import * as
|
|
32728
|
+
import * as fs21 from "node:fs";
|
|
32284
32729
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
32285
32730
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
32286
32731
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -32295,7 +32740,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
32295
32740
|
}
|
|
32296
32741
|
async function readWorktreeFileLines(filePath) {
|
|
32297
32742
|
try {
|
|
32298
|
-
const raw = await
|
|
32743
|
+
const raw = await fs21.promises.readFile(filePath, "utf8");
|
|
32299
32744
|
return raw.split(/\r?\n/);
|
|
32300
32745
|
} catch {
|
|
32301
32746
|
return null;
|
|
@@ -32430,7 +32875,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
32430
32875
|
const rows = [];
|
|
32431
32876
|
for (const pathInRepo of paths) {
|
|
32432
32877
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
32433
|
-
const repoFilePath =
|
|
32878
|
+
const repoFilePath = path22.join(repoGitCwd, pathInRepo);
|
|
32434
32879
|
const nums = numByPath.get(pathInRepo);
|
|
32435
32880
|
let additions = nums?.additions ?? 0;
|
|
32436
32881
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -32443,7 +32888,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
32443
32888
|
deletions = fromGit.deletions;
|
|
32444
32889
|
} else {
|
|
32445
32890
|
try {
|
|
32446
|
-
const st = await
|
|
32891
|
+
const st = await fs22.promises.stat(repoFilePath);
|
|
32447
32892
|
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
32448
32893
|
else additions = 0;
|
|
32449
32894
|
} catch {
|
|
@@ -32469,7 +32914,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
32469
32914
|
} else {
|
|
32470
32915
|
pathInRepo = row.pathRelLauncher;
|
|
32471
32916
|
}
|
|
32472
|
-
const filePath =
|
|
32917
|
+
const filePath = path22.join(repoGitCwd, pathInRepo);
|
|
32473
32918
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
32474
32919
|
if (patch) {
|
|
32475
32920
|
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
@@ -32485,8 +32930,8 @@ function normRepoRel(p) {
|
|
|
32485
32930
|
return x === "" ? "." : x;
|
|
32486
32931
|
}
|
|
32487
32932
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
32488
|
-
const bridgeRoot =
|
|
32489
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
32933
|
+
const bridgeRoot = path23.resolve(getBridgeRoot());
|
|
32934
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path23.resolve(options.sessionWorktreeRootPath) : null;
|
|
32490
32935
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
32491
32936
|
const out = [];
|
|
32492
32937
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -32499,7 +32944,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
32499
32944
|
}
|
|
32500
32945
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
32501
32946
|
for (const target of options.commitTargetPaths) {
|
|
32502
|
-
const t =
|
|
32947
|
+
const t = path23.resolve(target);
|
|
32503
32948
|
if (!await isGitRepoDirectory(t)) continue;
|
|
32504
32949
|
const g = cliSimpleGit(t);
|
|
32505
32950
|
let branch = "HEAD";
|
|
@@ -32512,8 +32957,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
32512
32957
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
32513
32958
|
let repoRelPath;
|
|
32514
32959
|
if (sessionWtRoot) {
|
|
32515
|
-
const anchor = legacyNested ?
|
|
32516
|
-
const relNorm =
|
|
32960
|
+
const anchor = legacyNested ? path23.dirname(t) : t;
|
|
32961
|
+
const relNorm = path23.relative(sessionWtRoot, anchor);
|
|
32517
32962
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
32518
32963
|
} else {
|
|
32519
32964
|
let top = t;
|
|
@@ -32522,8 +32967,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
32522
32967
|
} catch {
|
|
32523
32968
|
top = t;
|
|
32524
32969
|
}
|
|
32525
|
-
const rel =
|
|
32526
|
-
repoRelPath = rel.startsWith("..") ?
|
|
32970
|
+
const rel = path23.relative(bridgeRoot, path23.resolve(top)).replace(/\\/g, "/") || ".";
|
|
32971
|
+
repoRelPath = rel.startsWith("..") ? path23.basename(path23.resolve(top)) : rel;
|
|
32527
32972
|
}
|
|
32528
32973
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
32529
32974
|
if (filter && norm !== filter) continue;
|
|
@@ -32588,11 +33033,11 @@ async function commitSessionWorktrees(options) {
|
|
|
32588
33033
|
}
|
|
32589
33034
|
|
|
32590
33035
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
32591
|
-
import * as
|
|
32592
|
-
import * as
|
|
33036
|
+
import * as fs23 from "node:fs";
|
|
33037
|
+
import * as path24 from "node:path";
|
|
32593
33038
|
function isGitDir(dirPath) {
|
|
32594
33039
|
try {
|
|
32595
|
-
return
|
|
33040
|
+
return fs23.existsSync(path24.join(dirPath, ".git"));
|
|
32596
33041
|
} catch {
|
|
32597
33042
|
return false;
|
|
32598
33043
|
}
|
|
@@ -32601,23 +33046,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
32601
33046
|
const out = [];
|
|
32602
33047
|
const walk = (dir) => {
|
|
32603
33048
|
if (isGitDir(dir)) {
|
|
32604
|
-
out.push(
|
|
33049
|
+
out.push(path24.resolve(dir));
|
|
32605
33050
|
return;
|
|
32606
33051
|
}
|
|
32607
33052
|
let entries;
|
|
32608
33053
|
try {
|
|
32609
|
-
entries =
|
|
33054
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
32610
33055
|
} catch {
|
|
32611
33056
|
return;
|
|
32612
33057
|
}
|
|
32613
33058
|
for (const e of entries) {
|
|
32614
33059
|
if (e.name.startsWith(".")) continue;
|
|
32615
|
-
const full =
|
|
33060
|
+
const full = path24.join(dir, e.name);
|
|
32616
33061
|
if (!e.isDirectory()) continue;
|
|
32617
33062
|
walk(full);
|
|
32618
33063
|
}
|
|
32619
33064
|
};
|
|
32620
|
-
walk(
|
|
33065
|
+
walk(path24.resolve(rootPath));
|
|
32621
33066
|
return [...new Set(out)];
|
|
32622
33067
|
}
|
|
32623
33068
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -32626,16 +33071,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
32626
33071
|
if (depth > maxDepth) return;
|
|
32627
33072
|
let entries;
|
|
32628
33073
|
try {
|
|
32629
|
-
entries =
|
|
33074
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
32630
33075
|
} catch {
|
|
32631
33076
|
return;
|
|
32632
33077
|
}
|
|
32633
33078
|
for (const e of entries) {
|
|
32634
33079
|
if (e.name.startsWith(".")) continue;
|
|
32635
|
-
const full =
|
|
33080
|
+
const full = path24.join(dir, e.name);
|
|
32636
33081
|
if (!e.isDirectory()) continue;
|
|
32637
33082
|
if (e.name === sessionId) {
|
|
32638
|
-
if (isGitDir(full)) out.push(
|
|
33083
|
+
if (isGitDir(full)) out.push(path24.resolve(full));
|
|
32639
33084
|
} else {
|
|
32640
33085
|
walk(full, depth + 1);
|
|
32641
33086
|
}
|
|
@@ -32647,14 +33092,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
32647
33092
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
32648
33093
|
let st;
|
|
32649
33094
|
try {
|
|
32650
|
-
st =
|
|
33095
|
+
st = fs23.statSync(sessionDir);
|
|
32651
33096
|
} catch {
|
|
32652
33097
|
return null;
|
|
32653
33098
|
}
|
|
32654
33099
|
if (!st.isDirectory()) return null;
|
|
32655
33100
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
32656
33101
|
if (worktreePaths.length === 0) return null;
|
|
32657
|
-
const abs =
|
|
33102
|
+
const abs = path24.resolve(sessionDir);
|
|
32658
33103
|
return {
|
|
32659
33104
|
sessionParentPath: abs,
|
|
32660
33105
|
workingTreeRelRoot: abs,
|
|
@@ -32664,20 +33109,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
32664
33109
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
32665
33110
|
const sid = sessionId.trim();
|
|
32666
33111
|
if (!sid) return null;
|
|
32667
|
-
const hintR =
|
|
33112
|
+
const hintR = path24.resolve(checkoutPath);
|
|
32668
33113
|
let best = null;
|
|
32669
|
-
let cur =
|
|
33114
|
+
let cur = path24.dirname(hintR);
|
|
32670
33115
|
for (let i = 0; i < 40; i++) {
|
|
32671
33116
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
32672
|
-
if (paths.some((p) =>
|
|
32673
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
33117
|
+
if (paths.some((p) => path24.resolve(p) === hintR)) {
|
|
33118
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path24.resolve(paths[0]);
|
|
32674
33119
|
best = {
|
|
32675
|
-
sessionParentPath:
|
|
32676
|
-
workingTreeRelRoot:
|
|
32677
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
33120
|
+
sessionParentPath: path24.resolve(isolated),
|
|
33121
|
+
workingTreeRelRoot: path24.resolve(cur),
|
|
33122
|
+
repoCheckoutPaths: paths.map((p) => path24.resolve(p))
|
|
32678
33123
|
};
|
|
32679
33124
|
}
|
|
32680
|
-
const next =
|
|
33125
|
+
const next = path24.dirname(cur);
|
|
32681
33126
|
if (next === cur) break;
|
|
32682
33127
|
cur = next;
|
|
32683
33128
|
}
|
|
@@ -32685,33 +33130,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
32685
33130
|
}
|
|
32686
33131
|
function discoverSessionWorktreeOnDisk(options) {
|
|
32687
33132
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
32688
|
-
if (!sessionId.trim() || !
|
|
33133
|
+
if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
|
|
32689
33134
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
32690
33135
|
const keys = [];
|
|
32691
33136
|
if (preferredKey) keys.push(preferredKey);
|
|
32692
33137
|
try {
|
|
32693
|
-
for (const name of
|
|
33138
|
+
for (const name of fs23.readdirSync(worktreesRootPath)) {
|
|
32694
33139
|
if (name.startsWith(".")) continue;
|
|
32695
|
-
const p =
|
|
32696
|
-
if (!
|
|
33140
|
+
const p = path24.join(worktreesRootPath, name);
|
|
33141
|
+
if (!fs23.statSync(p).isDirectory()) continue;
|
|
32697
33142
|
if (name !== preferredKey) keys.push(name);
|
|
32698
33143
|
}
|
|
32699
33144
|
} catch {
|
|
32700
33145
|
return null;
|
|
32701
33146
|
}
|
|
32702
33147
|
for (const key of keys) {
|
|
32703
|
-
const layoutRoot =
|
|
32704
|
-
if (!
|
|
32705
|
-
const sessionDir =
|
|
33148
|
+
const layoutRoot = path24.join(worktreesRootPath, key);
|
|
33149
|
+
if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
|
|
33150
|
+
const sessionDir = path24.join(layoutRoot, sessionId);
|
|
32706
33151
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
32707
33152
|
if (nested) return nested;
|
|
32708
33153
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
32709
33154
|
if (legacyPaths.length > 0) {
|
|
32710
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
33155
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
|
|
32711
33156
|
return {
|
|
32712
|
-
sessionParentPath:
|
|
32713
|
-
workingTreeRelRoot:
|
|
32714
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
33157
|
+
sessionParentPath: path24.resolve(isolated),
|
|
33158
|
+
workingTreeRelRoot: path24.resolve(layoutRoot),
|
|
33159
|
+
repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
|
|
32715
33160
|
};
|
|
32716
33161
|
}
|
|
32717
33162
|
}
|
|
@@ -32720,12 +33165,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
32720
33165
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
32721
33166
|
const sid = sessionId.trim();
|
|
32722
33167
|
if (!sid) return null;
|
|
32723
|
-
const hint =
|
|
32724
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
33168
|
+
const hint = path24.resolve(sessionWorktreeRootPathOrHint);
|
|
33169
|
+
const underHint = tryBindingFromSessionDirectory(path24.join(hint, sid));
|
|
32725
33170
|
if (underHint) return underHint;
|
|
32726
33171
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
32727
33172
|
if (direct) {
|
|
32728
|
-
if (
|
|
33173
|
+
if (path24.basename(hint) === sid && isGitDir(hint)) {
|
|
32729
33174
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
32730
33175
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
32731
33176
|
return legacyFromCheckout;
|
|
@@ -32733,24 +33178,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
32733
33178
|
}
|
|
32734
33179
|
return direct;
|
|
32735
33180
|
}
|
|
32736
|
-
if (
|
|
33181
|
+
if (path24.basename(hint) === sid && isGitDir(hint)) {
|
|
32737
33182
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
32738
33183
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
32739
33184
|
}
|
|
32740
33185
|
let st;
|
|
32741
33186
|
try {
|
|
32742
|
-
st =
|
|
33187
|
+
st = fs23.statSync(hint);
|
|
32743
33188
|
} catch {
|
|
32744
33189
|
return null;
|
|
32745
33190
|
}
|
|
32746
33191
|
if (!st.isDirectory()) return null;
|
|
32747
33192
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
32748
33193
|
if (legacyPaths.length === 0) return null;
|
|
32749
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
33194
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
|
|
32750
33195
|
return {
|
|
32751
|
-
sessionParentPath:
|
|
33196
|
+
sessionParentPath: path24.resolve(isolated),
|
|
32752
33197
|
workingTreeRelRoot: hint,
|
|
32753
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
33198
|
+
repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
|
|
32754
33199
|
};
|
|
32755
33200
|
}
|
|
32756
33201
|
|
|
@@ -32773,10 +33218,10 @@ var SessionWorktreeManager = class {
|
|
|
32773
33218
|
this.layout = loadWorktreeLayout();
|
|
32774
33219
|
}
|
|
32775
33220
|
rememberSessionWorktrees(sessionId, binding) {
|
|
32776
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
33221
|
+
const paths = binding.repoCheckoutPaths.map((p) => path25.resolve(p));
|
|
32777
33222
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
32778
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
32779
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
33223
|
+
this.sessionParentPathBySession.set(sessionId, path25.resolve(binding.sessionParentPath));
|
|
33224
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path25.resolve(binding.workingTreeRelRoot));
|
|
32780
33225
|
}
|
|
32781
33226
|
sessionParentPathAfterRemember(sessionId) {
|
|
32782
33227
|
return this.sessionParentPathBySession.get(sessionId);
|
|
@@ -32793,7 +33238,7 @@ var SessionWorktreeManager = class {
|
|
|
32793
33238
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
32794
33239
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
32795
33240
|
if (!parent || !relRoot) return false;
|
|
32796
|
-
return
|
|
33241
|
+
return path25.resolve(parent) !== path25.resolve(relRoot);
|
|
32797
33242
|
}
|
|
32798
33243
|
/**
|
|
32799
33244
|
* Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
|
|
@@ -32802,7 +33247,7 @@ var SessionWorktreeManager = class {
|
|
|
32802
33247
|
if (!sessionId) return null;
|
|
32803
33248
|
const sid = sessionId.trim();
|
|
32804
33249
|
const cached2 = this.sessionParentPathBySession.get(sid);
|
|
32805
|
-
if (cached2) return
|
|
33250
|
+
if (cached2) return path25.resolve(cached2);
|
|
32806
33251
|
const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
|
|
32807
33252
|
if (!paths?.length) return null;
|
|
32808
33253
|
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
@@ -32816,7 +33261,7 @@ var SessionWorktreeManager = class {
|
|
|
32816
33261
|
const sid = sessionId.trim();
|
|
32817
33262
|
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
32818
33263
|
if (parentPathRaw) {
|
|
32819
|
-
const resolved =
|
|
33264
|
+
const resolved = path25.resolve(parentPathRaw);
|
|
32820
33265
|
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
32821
33266
|
const diskFirst = this.tryDiscoverFromDisk(sid);
|
|
32822
33267
|
if (diskFirst) {
|
|
@@ -32835,7 +33280,7 @@ var SessionWorktreeManager = class {
|
|
|
32835
33280
|
this.rememberSessionWorktrees(sid, tryRoot);
|
|
32836
33281
|
return this.sessionParentPathAfterRemember(sid);
|
|
32837
33282
|
}
|
|
32838
|
-
const next =
|
|
33283
|
+
const next = path25.dirname(cur);
|
|
32839
33284
|
if (next === cur) break;
|
|
32840
33285
|
cur = next;
|
|
32841
33286
|
}
|
|
@@ -32988,63 +33433,35 @@ var SessionWorktreeManager = class {
|
|
|
32988
33433
|
}
|
|
32989
33434
|
};
|
|
32990
33435
|
function defaultWorktreesRootPath() {
|
|
32991
|
-
return
|
|
33436
|
+
return path25.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
32992
33437
|
}
|
|
32993
33438
|
|
|
32994
33439
|
// src/files/watch-file-index.ts
|
|
32995
33440
|
import { watch } from "node:fs";
|
|
33441
|
+
import path30 from "node:path";
|
|
33442
|
+
|
|
33443
|
+
// src/files/index/paths.ts
|
|
32996
33444
|
import path26 from "node:path";
|
|
33445
|
+
import crypto2 from "node:crypto";
|
|
33446
|
+
function getCwdHashForFileIndex(resolvedCwd) {
|
|
33447
|
+
return crypto2.createHash("sha256").update(path26.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
33448
|
+
}
|
|
32997
33449
|
|
|
32998
33450
|
// src/files/index/build-file-index.ts
|
|
32999
|
-
import
|
|
33451
|
+
import path28 from "node:path";
|
|
33000
33452
|
|
|
33001
33453
|
// src/runtime/yield-to-event-loop.ts
|
|
33002
33454
|
function yieldToEventLoop() {
|
|
33003
|
-
return new Promise((
|
|
33455
|
+
return new Promise((resolve18) => setImmediate(resolve18));
|
|
33004
33456
|
}
|
|
33005
33457
|
|
|
33006
33458
|
// src/files/index/walk-workspace-tree.ts
|
|
33007
|
-
import
|
|
33008
|
-
import
|
|
33009
|
-
|
|
33010
|
-
// src/files/index/constants.ts
|
|
33011
|
-
import path20 from "node:path";
|
|
33012
|
-
import os6 from "node:os";
|
|
33013
|
-
var INDEX_WORK_YIELD_EVERY = 256;
|
|
33014
|
-
var INDEX_DIR = path20.join(os6.homedir(), ".buildautomaton");
|
|
33015
|
-
var INDEX_HASH_LEN = 16;
|
|
33016
|
-
var INDEX_VERSION = 2;
|
|
33017
|
-
var INDEX_LOG_PREFIX = "[file-index]";
|
|
33018
|
-
|
|
33019
|
-
// src/files/index/walk-workspace-tree.ts
|
|
33020
|
-
function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
33021
|
-
let names;
|
|
33022
|
-
try {
|
|
33023
|
-
names = fs19.readdirSync(dir);
|
|
33024
|
-
} catch {
|
|
33025
|
-
return;
|
|
33026
|
-
}
|
|
33027
|
-
for (const name of names) {
|
|
33028
|
-
if (name.startsWith(".")) continue;
|
|
33029
|
-
const full = path21.join(dir, name);
|
|
33030
|
-
let stat2;
|
|
33031
|
-
try {
|
|
33032
|
-
stat2 = fs19.statSync(full);
|
|
33033
|
-
} catch {
|
|
33034
|
-
continue;
|
|
33035
|
-
}
|
|
33036
|
-
const relative5 = path21.relative(baseDir, full).replace(/\\/g, "/");
|
|
33037
|
-
if (stat2.isDirectory()) {
|
|
33038
|
-
walkWorkspaceTreeSync(full, baseDir, out);
|
|
33039
|
-
} else if (stat2.isFile()) {
|
|
33040
|
-
out.push(relative5);
|
|
33041
|
-
}
|
|
33042
|
-
}
|
|
33043
|
-
}
|
|
33459
|
+
import fs24 from "node:fs";
|
|
33460
|
+
import path27 from "node:path";
|
|
33044
33461
|
async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
33045
33462
|
let names;
|
|
33046
33463
|
try {
|
|
33047
|
-
names = await
|
|
33464
|
+
names = await fs24.promises.readdir(dir);
|
|
33048
33465
|
} catch {
|
|
33049
33466
|
return;
|
|
33050
33467
|
}
|
|
@@ -33054,14 +33471,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
33054
33471
|
await yieldToEventLoop();
|
|
33055
33472
|
}
|
|
33056
33473
|
state.n++;
|
|
33057
|
-
const full =
|
|
33474
|
+
const full = path27.join(dir, name);
|
|
33058
33475
|
let stat2;
|
|
33059
33476
|
try {
|
|
33060
|
-
stat2 = await
|
|
33477
|
+
stat2 = await fs24.promises.stat(full);
|
|
33061
33478
|
} catch {
|
|
33062
33479
|
continue;
|
|
33063
33480
|
}
|
|
33064
|
-
const relative5 =
|
|
33481
|
+
const relative5 = path27.relative(baseDir, full).replace(/\\/g, "/");
|
|
33065
33482
|
if (stat2.isDirectory()) {
|
|
33066
33483
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
33067
33484
|
} else if (stat2.isFile()) {
|
|
@@ -33073,205 +33490,124 @@ function createWalkYieldState() {
|
|
|
33073
33490
|
return { n: 0 };
|
|
33074
33491
|
}
|
|
33075
33492
|
|
|
33076
|
-
// src/files/index/
|
|
33077
|
-
|
|
33078
|
-
|
|
33079
|
-
const
|
|
33080
|
-
|
|
33081
|
-
out.push(lower.slice(i, i + 3));
|
|
33082
|
-
}
|
|
33083
|
-
return out;
|
|
33084
|
-
}
|
|
33085
|
-
function binarySearch(arr, x) {
|
|
33086
|
-
let lo = 0;
|
|
33087
|
-
let hi = arr.length - 1;
|
|
33088
|
-
while (lo <= hi) {
|
|
33089
|
-
const mid = lo + hi >>> 1;
|
|
33090
|
-
if (arr[mid] < x) lo = mid + 1;
|
|
33091
|
-
else if (arr[mid] > x) hi = mid - 1;
|
|
33092
|
-
else return mid;
|
|
33093
|
-
}
|
|
33094
|
-
return -1;
|
|
33095
|
-
}
|
|
33096
|
-
function intersectSortedTrigramSets(arrays) {
|
|
33097
|
-
if (arrays.length === 0) return [];
|
|
33098
|
-
if (arrays.length === 1) return arrays[0];
|
|
33099
|
-
const byLength = arrays.slice().sort((a, b) => a.length - b.length);
|
|
33100
|
-
const smallest = byLength[0];
|
|
33101
|
-
const rest = byLength.slice(1);
|
|
33102
|
-
const result = [];
|
|
33103
|
-
for (const idx of smallest) {
|
|
33104
|
-
if (rest.every((arr) => binarySearch(arr, idx) >= 0)) {
|
|
33105
|
-
result.push(idx);
|
|
33106
|
-
}
|
|
33107
|
-
}
|
|
33108
|
-
return result;
|
|
33109
|
-
}
|
|
33110
|
-
|
|
33111
|
-
// src/files/index/build-trigram-map.ts
|
|
33112
|
-
function buildTrigramMapForPaths(paths) {
|
|
33113
|
-
const trigramIndex = {};
|
|
33114
|
-
for (let i = 0; i < paths.length; i++) {
|
|
33115
|
-
const trigrams = getTrigrams(paths[i]);
|
|
33116
|
-
const seen = /* @__PURE__ */ new Set();
|
|
33117
|
-
for (const tri of trigrams) {
|
|
33118
|
-
if (seen.has(tri)) continue;
|
|
33119
|
-
seen.add(tri);
|
|
33120
|
-
if (!trigramIndex[tri]) trigramIndex[tri] = [];
|
|
33121
|
-
trigramIndex[tri].push(i);
|
|
33122
|
-
}
|
|
33123
|
-
}
|
|
33124
|
-
return trigramIndex;
|
|
33493
|
+
// src/files/index/file-index-sqlite-lock.ts
|
|
33494
|
+
import fs25 from "node:fs";
|
|
33495
|
+
function isSqliteCorruptError(e) {
|
|
33496
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
33497
|
+
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
33125
33498
|
}
|
|
33126
|
-
|
|
33127
|
-
|
|
33128
|
-
|
|
33129
|
-
|
|
33130
|
-
await
|
|
33131
|
-
}
|
|
33132
|
-
|
|
33133
|
-
|
|
33134
|
-
|
|
33135
|
-
|
|
33136
|
-
|
|
33137
|
-
|
|
33138
|
-
|
|
33499
|
+
var chain = Promise.resolve();
|
|
33500
|
+
function withFileIndexSqliteLock(fn) {
|
|
33501
|
+
const run = async () => {
|
|
33502
|
+
try {
|
|
33503
|
+
return await Promise.resolve(fn());
|
|
33504
|
+
} catch (e) {
|
|
33505
|
+
if (!isSqliteCorruptError(e)) throw e;
|
|
33506
|
+
closeAllCliSqliteConnections();
|
|
33507
|
+
try {
|
|
33508
|
+
fs25.unlinkSync(getCliSqlitePath());
|
|
33509
|
+
} catch {
|
|
33510
|
+
}
|
|
33511
|
+
chain = Promise.resolve();
|
|
33512
|
+
return await Promise.resolve(fn());
|
|
33139
33513
|
}
|
|
33140
|
-
}
|
|
33141
|
-
|
|
33142
|
-
|
|
33143
|
-
|
|
33144
|
-
|
|
33145
|
-
|
|
33146
|
-
|
|
33147
|
-
// src/files/index/paths.ts
|
|
33148
|
-
import path22 from "node:path";
|
|
33149
|
-
import crypto2 from "node:crypto";
|
|
33150
|
-
function getIndexPathForCwd(resolvedCwd) {
|
|
33151
|
-
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
33152
|
-
return path22.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
33153
|
-
}
|
|
33154
|
-
|
|
33155
|
-
// src/files/index/write-index-file.ts
|
|
33156
|
-
function writeIndexFileSync(resolvedCwd, data) {
|
|
33157
|
-
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
33158
|
-
try {
|
|
33159
|
-
if (!fs20.existsSync(INDEX_DIR)) fs20.mkdirSync(INDEX_DIR, { recursive: true });
|
|
33160
|
-
fs20.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
33161
|
-
} catch (e) {
|
|
33162
|
-
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
33163
|
-
}
|
|
33164
|
-
}
|
|
33165
|
-
async function writeIndexFileAsync(resolvedCwd, data) {
|
|
33166
|
-
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
33167
|
-
try {
|
|
33168
|
-
await fs20.promises.mkdir(INDEX_DIR, { recursive: true });
|
|
33169
|
-
await fs20.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
|
|
33170
|
-
} catch (e) {
|
|
33171
|
-
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
33172
|
-
}
|
|
33173
|
-
}
|
|
33174
|
-
function makeTrigramIndexData(paths, trigramIndex) {
|
|
33175
|
-
return { version: INDEX_VERSION, paths, trigramIndex };
|
|
33514
|
+
};
|
|
33515
|
+
const next = chain.then(run);
|
|
33516
|
+
chain = next.then(
|
|
33517
|
+
() => void 0,
|
|
33518
|
+
() => void 0
|
|
33519
|
+
);
|
|
33520
|
+
return next;
|
|
33176
33521
|
}
|
|
33177
33522
|
|
|
33178
33523
|
// src/files/index/build-file-index.ts
|
|
33179
33524
|
function sortPaths(paths) {
|
|
33180
33525
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
33181
33526
|
}
|
|
33182
|
-
function
|
|
33183
|
-
const
|
|
33184
|
-
const
|
|
33185
|
-
|
|
33186
|
-
sortPaths(paths);
|
|
33187
|
-
const trigramIndex = buildTrigramMapForPaths(paths);
|
|
33188
|
-
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
33189
|
-
writeIndexFileSync(resolved, data);
|
|
33190
|
-
return data;
|
|
33191
|
-
}
|
|
33192
|
-
async function buildFileIndexAsync(cwd) {
|
|
33193
|
-
const resolved = path23.resolve(cwd);
|
|
33194
|
-
const paths = [];
|
|
33195
|
-
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
33196
|
-
await yieldToEventLoop();
|
|
33197
|
-
sortPaths(paths);
|
|
33198
|
-
const trigramIndex = await buildTrigramMapForPathsAsync(paths);
|
|
33199
|
-
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
33200
|
-
await writeIndexFileAsync(resolved, data);
|
|
33201
|
-
return data;
|
|
33202
|
-
}
|
|
33203
|
-
|
|
33204
|
-
// src/files/index/load-file-index.ts
|
|
33205
|
-
import fs21 from "node:fs";
|
|
33206
|
-
import path24 from "node:path";
|
|
33207
|
-
function loadFileIndex(cwd) {
|
|
33208
|
-
const resolved = path24.resolve(cwd);
|
|
33209
|
-
const indexPath = getIndexPathForCwd(resolved);
|
|
33527
|
+
function persistPathsToSqlite(resolved, paths) {
|
|
33528
|
+
const db = getCliDatabase();
|
|
33529
|
+
const h = getCwdHashForFileIndex(resolved);
|
|
33530
|
+
db.run("BEGIN IMMEDIATE");
|
|
33210
33531
|
try {
|
|
33211
|
-
|
|
33212
|
-
const
|
|
33213
|
-
|
|
33214
|
-
const
|
|
33215
|
-
|
|
33216
|
-
return obj;
|
|
33532
|
+
db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
33533
|
+
const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
|
|
33534
|
+
try {
|
|
33535
|
+
for (const rel of paths) {
|
|
33536
|
+
ins.run([h, rel]);
|
|
33217
33537
|
}
|
|
33218
|
-
|
|
33538
|
+
} finally {
|
|
33539
|
+
ins.finalize();
|
|
33219
33540
|
}
|
|
33220
|
-
|
|
33221
|
-
|
|
33541
|
+
db.run("COMMIT");
|
|
33542
|
+
} catch (e) {
|
|
33543
|
+
try {
|
|
33544
|
+
db.run("ROLLBACK");
|
|
33545
|
+
} catch {
|
|
33222
33546
|
}
|
|
33223
|
-
|
|
33224
|
-
} catch {
|
|
33225
|
-
return null;
|
|
33547
|
+
throw e;
|
|
33226
33548
|
}
|
|
33227
33549
|
}
|
|
33550
|
+
async function buildFileIndexAsync(cwd) {
|
|
33551
|
+
return withFileIndexSqliteLock(async () => {
|
|
33552
|
+
const resolved = path28.resolve(cwd);
|
|
33553
|
+
const paths = [];
|
|
33554
|
+
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
33555
|
+
await yieldToEventLoop();
|
|
33556
|
+
sortPaths(paths);
|
|
33557
|
+
persistPathsToSqlite(resolved, paths);
|
|
33558
|
+
return { pathCount: paths.length };
|
|
33559
|
+
});
|
|
33560
|
+
}
|
|
33228
33561
|
|
|
33229
33562
|
// src/files/index/ensure-file-index.ts
|
|
33230
|
-
import
|
|
33231
|
-
async function ensureFileIndexAsync(cwd) {
|
|
33232
|
-
const resolved = path25.resolve(cwd);
|
|
33233
|
-
const cached2 = loadFileIndex(resolved);
|
|
33234
|
-
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
33235
|
-
const data = await buildFileIndexAsync(resolved);
|
|
33236
|
-
return { data, fromCache: false };
|
|
33237
|
-
}
|
|
33563
|
+
import path29 from "node:path";
|
|
33238
33564
|
|
|
33239
33565
|
// src/files/index/search-file-index.ts
|
|
33240
|
-
function
|
|
33241
|
-
|
|
33242
|
-
|
|
33243
|
-
|
|
33244
|
-
|
|
33245
|
-
const
|
|
33246
|
-
|
|
33247
|
-
|
|
33248
|
-
|
|
33249
|
-
|
|
33250
|
-
|
|
33251
|
-
|
|
33252
|
-
|
|
33253
|
-
|
|
33254
|
-
|
|
33566
|
+
function escapeLikePattern(fragment) {
|
|
33567
|
+
return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
33568
|
+
}
|
|
33569
|
+
function bridgeFileIndexIsPopulated(resolvedCwd) {
|
|
33570
|
+
const db = getCliDatabase();
|
|
33571
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
33572
|
+
const row = db.get("SELECT 1 as ok FROM file_index_path WHERE cwd_hash = ? LIMIT 1", [h]);
|
|
33573
|
+
return row != null;
|
|
33574
|
+
}
|
|
33575
|
+
function bridgeFileIndexPathCount(resolvedCwd) {
|
|
33576
|
+
const db = getCliDatabase();
|
|
33577
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
33578
|
+
const row = db.get("SELECT COUNT(*) as c FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
33579
|
+
const c = row?.c ?? 0;
|
|
33580
|
+
return Number(c);
|
|
33581
|
+
}
|
|
33582
|
+
function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
|
|
33255
33583
|
const q = query.trim().toLowerCase();
|
|
33256
33584
|
if (!q) return [];
|
|
33257
|
-
const
|
|
33258
|
-
const
|
|
33259
|
-
const
|
|
33260
|
-
|
|
33261
|
-
|
|
33262
|
-
|
|
33263
|
-
|
|
33264
|
-
|
|
33265
|
-
|
|
33266
|
-
|
|
33267
|
-
|
|
33268
|
-
|
|
33269
|
-
|
|
33270
|
-
|
|
33271
|
-
}
|
|
33585
|
+
const db = getCliDatabase();
|
|
33586
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
33587
|
+
const pattern = `%${escapeLikePattern(q)}%`;
|
|
33588
|
+
const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
|
|
33589
|
+
const rows = db.all(
|
|
33590
|
+
`SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' LIMIT ?`,
|
|
33591
|
+
[h, pattern, lim]
|
|
33592
|
+
);
|
|
33593
|
+
return rows.map((r) => String(r.path));
|
|
33594
|
+
}
|
|
33595
|
+
async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
33596
|
+
await yieldToEventLoop();
|
|
33597
|
+
const out = searchBridgeFilePaths(resolvedCwd, query, limit);
|
|
33598
|
+
if (out.length >= INDEX_WORK_YIELD_EVERY) await yieldToEventLoop();
|
|
33272
33599
|
return out;
|
|
33273
33600
|
}
|
|
33274
33601
|
|
|
33602
|
+
// src/files/index/ensure-file-index.ts
|
|
33603
|
+
async function ensureFileIndexAsync(cwd) {
|
|
33604
|
+
const resolved = path29.resolve(cwd);
|
|
33605
|
+
if (bridgeFileIndexIsPopulated(resolved)) {
|
|
33606
|
+
return { fromCache: true, pathCount: bridgeFileIndexPathCount(resolved) };
|
|
33607
|
+
}
|
|
33608
|
+
return { ...await buildFileIndexAsync(resolved), fromCache: false };
|
|
33609
|
+
}
|
|
33610
|
+
|
|
33275
33611
|
// src/files/watch-file-index.ts
|
|
33276
33612
|
var DEBOUNCE_MS = 900;
|
|
33277
33613
|
function shouldIgnoreRelative(rel) {
|
|
@@ -33312,7 +33648,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
33312
33648
|
}
|
|
33313
33649
|
}
|
|
33314
33650
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
33315
|
-
const resolved =
|
|
33651
|
+
const resolved = path30.resolve(cwd);
|
|
33316
33652
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
33317
33653
|
console.error("[file-index] Initial index build failed:", e);
|
|
33318
33654
|
});
|
|
@@ -33340,7 +33676,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
33340
33676
|
}
|
|
33341
33677
|
|
|
33342
33678
|
// src/connection/create-bridge-connection.ts
|
|
33343
|
-
import * as
|
|
33679
|
+
import * as path40 from "node:path";
|
|
33344
33680
|
|
|
33345
33681
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
33346
33682
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -33362,15 +33698,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
33362
33698
|
|
|
33363
33699
|
// src/dev-servers/process/terminate-child-process.ts
|
|
33364
33700
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
33365
|
-
const exited = new Promise((
|
|
33366
|
-
proc.once("exit", () =>
|
|
33701
|
+
const exited = new Promise((resolve18) => {
|
|
33702
|
+
proc.once("exit", () => resolve18());
|
|
33367
33703
|
});
|
|
33368
33704
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
33369
33705
|
try {
|
|
33370
33706
|
proc.kill("SIGTERM");
|
|
33371
33707
|
} catch {
|
|
33372
33708
|
}
|
|
33373
|
-
await Promise.race([exited, new Promise((
|
|
33709
|
+
await Promise.race([exited, new Promise((resolve18) => setTimeout(resolve18, graceMs))]);
|
|
33374
33710
|
}
|
|
33375
33711
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
33376
33712
|
log2(
|
|
@@ -33384,7 +33720,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
33384
33720
|
}
|
|
33385
33721
|
|
|
33386
33722
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
33387
|
-
import
|
|
33723
|
+
import fs26 from "node:fs";
|
|
33388
33724
|
|
|
33389
33725
|
// src/dev-servers/manager/forward-pipe.ts
|
|
33390
33726
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -33420,7 +33756,7 @@ function wireDevServerChildProcess(d) {
|
|
|
33420
33756
|
d.setPollInterval(void 0);
|
|
33421
33757
|
return;
|
|
33422
33758
|
}
|
|
33423
|
-
|
|
33759
|
+
fs26.readFile(d.mergedLogPath, (err, buf) => {
|
|
33424
33760
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
33425
33761
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
33426
33762
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -33458,7 +33794,7 @@ ${errTail}` : ""}`);
|
|
|
33458
33794
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
33459
33795
|
};
|
|
33460
33796
|
if (mergedPath) {
|
|
33461
|
-
|
|
33797
|
+
fs26.readFile(mergedPath, (err, buf) => {
|
|
33462
33798
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
33463
33799
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
33464
33800
|
if (chunk.length > 0) {
|
|
@@ -33560,13 +33896,13 @@ function parseDevServerDefs(servers) {
|
|
|
33560
33896
|
}
|
|
33561
33897
|
|
|
33562
33898
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
33563
|
-
import
|
|
33899
|
+
import fs27 from "node:fs";
|
|
33564
33900
|
function isSpawnEbadf(e) {
|
|
33565
33901
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
33566
33902
|
}
|
|
33567
33903
|
function rmDirQuiet(dir) {
|
|
33568
33904
|
try {
|
|
33569
|
-
|
|
33905
|
+
fs27.rmSync(dir, { recursive: true, force: true });
|
|
33570
33906
|
} catch {
|
|
33571
33907
|
}
|
|
33572
33908
|
}
|
|
@@ -33574,7 +33910,7 @@ var cachedDevNullReadFd;
|
|
|
33574
33910
|
function devNullReadFd() {
|
|
33575
33911
|
if (cachedDevNullReadFd === void 0) {
|
|
33576
33912
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
33577
|
-
cachedDevNullReadFd =
|
|
33913
|
+
cachedDevNullReadFd = fs27.openSync(devPath, "r");
|
|
33578
33914
|
}
|
|
33579
33915
|
return cachedDevNullReadFd;
|
|
33580
33916
|
}
|
|
@@ -33648,15 +33984,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
33648
33984
|
|
|
33649
33985
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
33650
33986
|
import { spawn as spawn7 } from "node:child_process";
|
|
33651
|
-
import
|
|
33987
|
+
import fs28 from "node:fs";
|
|
33652
33988
|
import { tmpdir } from "node:os";
|
|
33653
|
-
import
|
|
33989
|
+
import path31 from "node:path";
|
|
33654
33990
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
33655
|
-
const tmpRoot =
|
|
33656
|
-
const logPath =
|
|
33991
|
+
const tmpRoot = fs28.mkdtempSync(path31.join(tmpdir(), "ba-devsrv-log-"));
|
|
33992
|
+
const logPath = path31.join(tmpRoot, "combined.log");
|
|
33657
33993
|
let logFd;
|
|
33658
33994
|
try {
|
|
33659
|
-
logFd =
|
|
33995
|
+
logFd = fs28.openSync(logPath, "a");
|
|
33660
33996
|
} catch {
|
|
33661
33997
|
rmDirQuiet(tmpRoot);
|
|
33662
33998
|
return null;
|
|
@@ -33675,7 +34011,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
33675
34011
|
} else {
|
|
33676
34012
|
proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
33677
34013
|
}
|
|
33678
|
-
|
|
34014
|
+
fs28.closeSync(logFd);
|
|
33679
34015
|
return {
|
|
33680
34016
|
proc,
|
|
33681
34017
|
pipedStdoutStderr: true,
|
|
@@ -33684,7 +34020,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
33684
34020
|
};
|
|
33685
34021
|
} catch (e) {
|
|
33686
34022
|
try {
|
|
33687
|
-
|
|
34023
|
+
fs28.closeSync(logFd);
|
|
33688
34024
|
} catch {
|
|
33689
34025
|
}
|
|
33690
34026
|
rmDirQuiet(tmpRoot);
|
|
@@ -33695,22 +34031,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
33695
34031
|
|
|
33696
34032
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
33697
34033
|
import { spawn as spawn8 } from "node:child_process";
|
|
33698
|
-
import
|
|
34034
|
+
import fs29 from "node:fs";
|
|
33699
34035
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
33700
|
-
import
|
|
34036
|
+
import path32 from "node:path";
|
|
33701
34037
|
function shSingleQuote(s) {
|
|
33702
34038
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
33703
34039
|
}
|
|
33704
34040
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
33705
|
-
const tmpRoot =
|
|
33706
|
-
const logPath =
|
|
33707
|
-
const innerPath =
|
|
33708
|
-
const runnerPath =
|
|
34041
|
+
const tmpRoot = fs29.mkdtempSync(path32.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
34042
|
+
const logPath = path32.join(tmpRoot, "combined.log");
|
|
34043
|
+
const innerPath = path32.join(tmpRoot, "_cmd.sh");
|
|
34044
|
+
const runnerPath = path32.join(tmpRoot, "_run.sh");
|
|
33709
34045
|
try {
|
|
33710
|
-
|
|
34046
|
+
fs29.writeFileSync(innerPath, `#!/bin/sh
|
|
33711
34047
|
${command}
|
|
33712
34048
|
`);
|
|
33713
|
-
|
|
34049
|
+
fs29.writeFileSync(
|
|
33714
34050
|
runnerPath,
|
|
33715
34051
|
`#!/bin/sh
|
|
33716
34052
|
cd ${shSingleQuote(cwd)}
|
|
@@ -33736,13 +34072,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
33736
34072
|
}
|
|
33737
34073
|
}
|
|
33738
34074
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
33739
|
-
const tmpRoot =
|
|
33740
|
-
const logPath =
|
|
33741
|
-
const runnerPath =
|
|
34075
|
+
const tmpRoot = fs29.mkdtempSync(path32.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
34076
|
+
const logPath = path32.join(tmpRoot, "combined.log");
|
|
34077
|
+
const runnerPath = path32.join(tmpRoot, "_run.bat");
|
|
33742
34078
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
33743
34079
|
const com = process.env.ComSpec || "cmd.exe";
|
|
33744
34080
|
try {
|
|
33745
|
-
|
|
34081
|
+
fs29.writeFileSync(
|
|
33746
34082
|
runnerPath,
|
|
33747
34083
|
`@ECHO OFF\r
|
|
33748
34084
|
CD /D ${q(cwd)}\r
|
|
@@ -34511,30 +34847,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
34511
34847
|
}
|
|
34512
34848
|
|
|
34513
34849
|
// src/skills/discover-local-agent-skills.ts
|
|
34514
|
-
import
|
|
34515
|
-
import
|
|
34850
|
+
import fs30 from "node:fs";
|
|
34851
|
+
import path33 from "node:path";
|
|
34516
34852
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
34517
34853
|
function discoverLocalSkills(cwd) {
|
|
34518
34854
|
const out = [];
|
|
34519
34855
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
34520
34856
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
34521
|
-
const base =
|
|
34522
|
-
if (!
|
|
34857
|
+
const base = path33.join(cwd, rel);
|
|
34858
|
+
if (!fs30.existsSync(base) || !fs30.statSync(base).isDirectory()) continue;
|
|
34523
34859
|
let entries = [];
|
|
34524
34860
|
try {
|
|
34525
|
-
entries =
|
|
34861
|
+
entries = fs30.readdirSync(base);
|
|
34526
34862
|
} catch {
|
|
34527
34863
|
continue;
|
|
34528
34864
|
}
|
|
34529
34865
|
for (const name of entries) {
|
|
34530
|
-
const dir =
|
|
34866
|
+
const dir = path33.join(base, name);
|
|
34531
34867
|
try {
|
|
34532
|
-
if (!
|
|
34868
|
+
if (!fs30.statSync(dir).isDirectory()) continue;
|
|
34533
34869
|
} catch {
|
|
34534
34870
|
continue;
|
|
34535
34871
|
}
|
|
34536
|
-
const skillMd =
|
|
34537
|
-
if (!
|
|
34872
|
+
const skillMd = path33.join(dir, "SKILL.md");
|
|
34873
|
+
if (!fs30.existsSync(skillMd)) continue;
|
|
34538
34874
|
const key = `${rel}/${name}`;
|
|
34539
34875
|
if (seenKeys.has(key)) continue;
|
|
34540
34876
|
seenKeys.add(key);
|
|
@@ -34546,23 +34882,23 @@ function discoverLocalSkills(cwd) {
|
|
|
34546
34882
|
function discoverSkillLayoutRoots(cwd) {
|
|
34547
34883
|
const roots = [];
|
|
34548
34884
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
34549
|
-
const base =
|
|
34550
|
-
if (!
|
|
34885
|
+
const base = path33.join(cwd, rel);
|
|
34886
|
+
if (!fs30.existsSync(base) || !fs30.statSync(base).isDirectory()) continue;
|
|
34551
34887
|
let entries = [];
|
|
34552
34888
|
try {
|
|
34553
|
-
entries =
|
|
34889
|
+
entries = fs30.readdirSync(base);
|
|
34554
34890
|
} catch {
|
|
34555
34891
|
continue;
|
|
34556
34892
|
}
|
|
34557
34893
|
const skills2 = [];
|
|
34558
34894
|
for (const name of entries) {
|
|
34559
|
-
const dir =
|
|
34895
|
+
const dir = path33.join(base, name);
|
|
34560
34896
|
try {
|
|
34561
|
-
if (!
|
|
34897
|
+
if (!fs30.statSync(dir).isDirectory()) continue;
|
|
34562
34898
|
} catch {
|
|
34563
34899
|
continue;
|
|
34564
34900
|
}
|
|
34565
|
-
if (!
|
|
34901
|
+
if (!fs30.existsSync(path33.join(dir, "SKILL.md"))) continue;
|
|
34566
34902
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
34567
34903
|
skills2.push({ name, relPath });
|
|
34568
34904
|
}
|
|
@@ -34724,6 +35060,13 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
34724
35060
|
`[Bridge service] Auto-detect agents failed: ${e instanceof Error ? e.message : String(e)}`
|
|
34725
35061
|
);
|
|
34726
35062
|
}
|
|
35063
|
+
try {
|
|
35064
|
+
await deps.warmupAgentCapabilitiesOnConnect?.();
|
|
35065
|
+
} catch (e) {
|
|
35066
|
+
deps.log(
|
|
35067
|
+
`[Bridge service] Agent capability warmup failed: ${e instanceof Error ? e.message : String(e)}`
|
|
35068
|
+
);
|
|
35069
|
+
}
|
|
34727
35070
|
})();
|
|
34728
35071
|
});
|
|
34729
35072
|
setImmediate(() => {
|
|
@@ -34756,7 +35099,7 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
34756
35099
|
};
|
|
34757
35100
|
|
|
34758
35101
|
// src/prompt-turn-queue/runner.ts
|
|
34759
|
-
import
|
|
35102
|
+
import fs31 from "node:fs";
|
|
34760
35103
|
|
|
34761
35104
|
// src/prompt-turn-queue/client-report.ts
|
|
34762
35105
|
function sendPromptQueueClientReport(ws, queues) {
|
|
@@ -34765,32 +35108,6 @@ function sendPromptQueueClientReport(ws, queues) {
|
|
|
34765
35108
|
return true;
|
|
34766
35109
|
}
|
|
34767
35110
|
|
|
34768
|
-
// src/prompt-turn-queue/disk-store.ts
|
|
34769
|
-
import fs28 from "node:fs";
|
|
34770
|
-
|
|
34771
|
-
// src/prompt-turn-queue/paths.ts
|
|
34772
|
-
import crypto3 from "node:crypto";
|
|
34773
|
-
import fs27 from "node:fs";
|
|
34774
|
-
import path30 from "node:path";
|
|
34775
|
-
import os7 from "node:os";
|
|
34776
|
-
var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
|
|
34777
|
-
function queueStateFileSlug(queueKey) {
|
|
34778
|
-
if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
|
|
34779
|
-
return crypto3.createHash("sha256").update(queueKey, "utf8").digest("hex");
|
|
34780
|
-
}
|
|
34781
|
-
function getPromptQueuesDirectory() {
|
|
34782
|
-
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
34783
|
-
if (override) return path30.resolve(override);
|
|
34784
|
-
return path30.join(os7.homedir(), ".buildautomaton", "queues");
|
|
34785
|
-
}
|
|
34786
|
-
function ensurePromptQueuesDirectory() {
|
|
34787
|
-
const dir = getPromptQueuesDirectory();
|
|
34788
|
-
if (!fs27.existsSync(dir)) fs27.mkdirSync(dir, { recursive: true });
|
|
34789
|
-
}
|
|
34790
|
-
function queueStateFilePath(queueKey) {
|
|
34791
|
-
return path30.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
|
|
34792
|
-
}
|
|
34793
|
-
|
|
34794
35111
|
// src/prompt-turn-queue/disk-store.ts
|
|
34795
35112
|
var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
|
|
34796
35113
|
"queued",
|
|
@@ -34800,28 +35117,27 @@ var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
|
|
|
34800
35117
|
"stopping",
|
|
34801
35118
|
"discarded"
|
|
34802
35119
|
]);
|
|
34803
|
-
function parsePersistedQueueFile(raw) {
|
|
34804
|
-
try {
|
|
34805
|
-
const o = JSON.parse(raw);
|
|
34806
|
-
const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
|
|
34807
|
-
if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
|
|
34808
|
-
return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
|
|
34809
|
-
} catch {
|
|
34810
|
-
return null;
|
|
34811
|
-
}
|
|
34812
|
-
}
|
|
34813
35120
|
function readPersistedQueue(queueKey) {
|
|
34814
|
-
const
|
|
35121
|
+
const db = getCliDatabase();
|
|
35122
|
+
const row = db.get("SELECT queue_key, updated_at, turns_json FROM prompt_queue WHERE queue_key = ?", [
|
|
35123
|
+
queueKey
|
|
35124
|
+
]);
|
|
35125
|
+
if (!row) return null;
|
|
34815
35126
|
try {
|
|
34816
|
-
|
|
35127
|
+
const turns = JSON.parse(row.turns_json);
|
|
35128
|
+
if (!Array.isArray(turns)) return null;
|
|
35129
|
+
return { queueKey: row.queue_key, updatedAt: row.updated_at, turns };
|
|
34817
35130
|
} catch {
|
|
34818
35131
|
return null;
|
|
34819
35132
|
}
|
|
34820
35133
|
}
|
|
34821
35134
|
function writePersistedQueue(file2) {
|
|
34822
|
-
|
|
34823
|
-
|
|
34824
|
-
|
|
35135
|
+
const db = getCliDatabase();
|
|
35136
|
+
db.run(
|
|
35137
|
+
`INSERT INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)
|
|
35138
|
+
ON CONFLICT(queue_key) DO UPDATE SET updated_at = excluded.updated_at, turns_json = excluded.turns_json`,
|
|
35139
|
+
[file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
|
|
35140
|
+
);
|
|
34825
35141
|
}
|
|
34826
35142
|
function mergeServerQueueSnapshot(queueKey, serverTurns) {
|
|
34827
35143
|
const prev = readPersistedQueue(queueKey);
|
|
@@ -34879,7 +35195,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
34879
35195
|
const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
|
|
34880
35196
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
34881
35197
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
34882
|
-
if (!
|
|
35198
|
+
if (!fs31.existsSync(file2)) {
|
|
34883
35199
|
deps.log(
|
|
34884
35200
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
34885
35201
|
);
|
|
@@ -35103,9 +35419,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
35103
35419
|
for (const item of raw) {
|
|
35104
35420
|
if (!item || typeof item !== "object") continue;
|
|
35105
35421
|
const o = item;
|
|
35106
|
-
const
|
|
35107
|
-
if (!
|
|
35108
|
-
const row = { path:
|
|
35422
|
+
const path41 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
35423
|
+
if (!path41) continue;
|
|
35424
|
+
const row = { path: path41 };
|
|
35109
35425
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
35110
35426
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
35111
35427
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -35223,6 +35539,8 @@ function handleBridgePrompt(msg, deps) {
|
|
|
35223
35539
|
const sessionParent = rawParent === "bridge_root" || rawParent === "worktrees_root" ? rawParent : rawParent === "session_worktrees_root" ? "worktrees_root" : null;
|
|
35224
35540
|
const sessionParentPath = typeof msg.sessionParentPath === "string" && msg.sessionParentPath.trim() ? msg.sessionParentPath.trim() : null;
|
|
35225
35541
|
const agentType = typeof msg.agentType === "string" && msg.agentType.trim() ? msg.agentType.trim() : void 0;
|
|
35542
|
+
const rawAgentId = msg.agentId;
|
|
35543
|
+
const agentId = typeof rawAgentId === "string" && rawAgentId.trim() !== "" ? rawAgentId.trim() : null;
|
|
35226
35544
|
const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
|
|
35227
35545
|
const agentConfig = msg.agentConfig != null && typeof msg.agentConfig === "object" && !Array.isArray(msg.agentConfig) ? msg.agentConfig : void 0;
|
|
35228
35546
|
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
@@ -35260,6 +35578,7 @@ function handleBridgePrompt(msg, deps) {
|
|
|
35260
35578
|
runId,
|
|
35261
35579
|
mode,
|
|
35262
35580
|
agentType,
|
|
35581
|
+
agentId,
|
|
35263
35582
|
agentConfig,
|
|
35264
35583
|
sessionParentPath: effectiveCwd,
|
|
35265
35584
|
sendResult: sendResult2,
|
|
@@ -35326,15 +35645,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
35326
35645
|
};
|
|
35327
35646
|
|
|
35328
35647
|
// src/files/list-dir.ts
|
|
35329
|
-
import
|
|
35330
|
-
import
|
|
35648
|
+
import fs32 from "node:fs";
|
|
35649
|
+
import path35 from "node:path";
|
|
35331
35650
|
|
|
35332
35651
|
// src/files/ensure-under-cwd.ts
|
|
35333
|
-
import
|
|
35652
|
+
import path34 from "node:path";
|
|
35334
35653
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
35335
|
-
const normalized =
|
|
35336
|
-
const resolved =
|
|
35337
|
-
if (!resolved.startsWith(cwd +
|
|
35654
|
+
const normalized = path34.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
35655
|
+
const resolved = path34.resolve(cwd, normalized);
|
|
35656
|
+
if (!resolved.startsWith(cwd + path34.sep) && resolved !== cwd) {
|
|
35338
35657
|
return null;
|
|
35339
35658
|
}
|
|
35340
35659
|
return resolved;
|
|
@@ -35348,7 +35667,7 @@ async function listDirAsync(relativePath) {
|
|
|
35348
35667
|
return { error: "Path is outside working directory" };
|
|
35349
35668
|
}
|
|
35350
35669
|
try {
|
|
35351
|
-
const names = await
|
|
35670
|
+
const names = await fs32.promises.readdir(resolved, { withFileTypes: true });
|
|
35352
35671
|
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
35353
35672
|
const entries = [];
|
|
35354
35673
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -35356,12 +35675,12 @@ async function listDirAsync(relativePath) {
|
|
|
35356
35675
|
await yieldToEventLoop();
|
|
35357
35676
|
}
|
|
35358
35677
|
const d = visible[i];
|
|
35359
|
-
const entryPath =
|
|
35360
|
-
const fullPath =
|
|
35678
|
+
const entryPath = path35.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
35679
|
+
const fullPath = path35.join(resolved, d.name);
|
|
35361
35680
|
let isDir = d.isDirectory();
|
|
35362
35681
|
if (d.isSymbolicLink()) {
|
|
35363
35682
|
try {
|
|
35364
|
-
const targetStat = await
|
|
35683
|
+
const targetStat = await fs32.promises.stat(fullPath);
|
|
35365
35684
|
isDir = targetStat.isDirectory();
|
|
35366
35685
|
} catch {
|
|
35367
35686
|
isDir = false;
|
|
@@ -35386,25 +35705,25 @@ async function listDirAsync(relativePath) {
|
|
|
35386
35705
|
}
|
|
35387
35706
|
|
|
35388
35707
|
// src/files/read-file.ts
|
|
35389
|
-
import
|
|
35708
|
+
import fs33 from "node:fs";
|
|
35390
35709
|
import { StringDecoder } from "node:string_decoder";
|
|
35391
35710
|
function resolveFilePath(relativePath) {
|
|
35392
35711
|
const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
|
|
35393
35712
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
35394
35713
|
let real;
|
|
35395
35714
|
try {
|
|
35396
|
-
real =
|
|
35715
|
+
real = fs33.realpathSync(resolved);
|
|
35397
35716
|
} catch {
|
|
35398
35717
|
real = resolved;
|
|
35399
35718
|
}
|
|
35400
|
-
const stat2 =
|
|
35719
|
+
const stat2 = fs33.statSync(real);
|
|
35401
35720
|
if (!stat2.isFile()) return { error: "Not a file" };
|
|
35402
35721
|
return real;
|
|
35403
35722
|
}
|
|
35404
35723
|
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
35405
35724
|
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
35406
|
-
const fileSize =
|
|
35407
|
-
const fd =
|
|
35725
|
+
const fileSize = fs33.statSync(filePath).size;
|
|
35726
|
+
const fd = fs33.openSync(filePath, "r");
|
|
35408
35727
|
const bufSize = 64 * 1024;
|
|
35409
35728
|
const buf = Buffer.alloc(bufSize);
|
|
35410
35729
|
const decoder = new StringDecoder("utf8");
|
|
@@ -35417,7 +35736,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
35417
35736
|
let line0Accum = "";
|
|
35418
35737
|
try {
|
|
35419
35738
|
let bytesRead;
|
|
35420
|
-
while (!done && (bytesRead =
|
|
35739
|
+
while (!done && (bytesRead = fs33.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
35421
35740
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
35422
35741
|
partial2 = "";
|
|
35423
35742
|
let lineStart = 0;
|
|
@@ -35552,7 +35871,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
35552
35871
|
}
|
|
35553
35872
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
35554
35873
|
} finally {
|
|
35555
|
-
|
|
35874
|
+
fs33.closeSync(fd);
|
|
35556
35875
|
}
|
|
35557
35876
|
}
|
|
35558
35877
|
function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
@@ -35563,8 +35882,8 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
35563
35882
|
if (hasRange) {
|
|
35564
35883
|
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
35565
35884
|
}
|
|
35566
|
-
const stat2 =
|
|
35567
|
-
const raw =
|
|
35885
|
+
const stat2 = fs33.statSync(result);
|
|
35886
|
+
const raw = fs33.readFileSync(result, "utf8");
|
|
35568
35887
|
const lines = raw.split(/\r?\n/);
|
|
35569
35888
|
return { content: raw, totalLines: lines.length, size: stat2.size };
|
|
35570
35889
|
} catch (err) {
|
|
@@ -35577,14 +35896,14 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
35577
35896
|
}
|
|
35578
35897
|
|
|
35579
35898
|
// src/files/handle-file-browser-search.ts
|
|
35899
|
+
import path36 from "node:path";
|
|
35580
35900
|
var SEARCH_LIMIT = 100;
|
|
35581
35901
|
function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
35582
35902
|
void (async () => {
|
|
35583
35903
|
await yieldToEventLoop();
|
|
35584
35904
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
35585
|
-
const cwd = getBridgeRoot();
|
|
35586
|
-
|
|
35587
|
-
if (index === null) {
|
|
35905
|
+
const cwd = path36.resolve(getBridgeRoot());
|
|
35906
|
+
if (!bridgeFileIndexIsPopulated(cwd)) {
|
|
35588
35907
|
const payload2 = {
|
|
35589
35908
|
type: "file_browser_search_response",
|
|
35590
35909
|
id: msg.id,
|
|
@@ -35594,7 +35913,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
35594
35913
|
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
35595
35914
|
return;
|
|
35596
35915
|
}
|
|
35597
|
-
const results = await
|
|
35916
|
+
const results = await searchBridgeFilePathsAsync(cwd, q, SEARCH_LIMIT);
|
|
35598
35917
|
const payload = {
|
|
35599
35918
|
type: "file_browser_search_response",
|
|
35600
35919
|
id: msg.id,
|
|
@@ -35682,8 +36001,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
35682
36001
|
}
|
|
35683
36002
|
|
|
35684
36003
|
// src/skills/install-remote-skills.ts
|
|
35685
|
-
import
|
|
35686
|
-
import
|
|
36004
|
+
import fs34 from "node:fs";
|
|
36005
|
+
import path37 from "node:path";
|
|
35687
36006
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
35688
36007
|
const installed2 = [];
|
|
35689
36008
|
if (!Array.isArray(items)) {
|
|
@@ -35694,15 +36013,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
35694
36013
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
35695
36014
|
continue;
|
|
35696
36015
|
}
|
|
35697
|
-
const skillDir =
|
|
36016
|
+
const skillDir = path37.join(cwd, targetDir, item.skillName);
|
|
35698
36017
|
for (const f of item.files) {
|
|
35699
36018
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
35700
|
-
const dest =
|
|
35701
|
-
|
|
36019
|
+
const dest = path37.join(skillDir, f.path);
|
|
36020
|
+
fs34.mkdirSync(path37.dirname(dest), { recursive: true });
|
|
35702
36021
|
if (f.text !== void 0) {
|
|
35703
|
-
|
|
36022
|
+
fs34.writeFileSync(dest, f.text, "utf8");
|
|
35704
36023
|
} else if (f.base64) {
|
|
35705
|
-
|
|
36024
|
+
fs34.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
35706
36025
|
}
|
|
35707
36026
|
}
|
|
35708
36027
|
installed2.push({
|
|
@@ -35852,7 +36171,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
35852
36171
|
};
|
|
35853
36172
|
|
|
35854
36173
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
35855
|
-
import * as
|
|
36174
|
+
import * as fs35 from "node:fs";
|
|
35856
36175
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
35857
36176
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
35858
36177
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -35864,7 +36183,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
35864
36183
|
if (!s) return;
|
|
35865
36184
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
35866
36185
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
35867
|
-
if (!
|
|
36186
|
+
if (!fs35.existsSync(file2)) {
|
|
35868
36187
|
sendWsMessage(s, {
|
|
35869
36188
|
type: "revert_turn_snapshot_result",
|
|
35870
36189
|
id,
|
|
@@ -36354,11 +36673,248 @@ function createBridgeHeartbeatController(params) {
|
|
|
36354
36673
|
};
|
|
36355
36674
|
}
|
|
36356
36675
|
|
|
36676
|
+
// src/sqlite/hash-json-sha256.ts
|
|
36677
|
+
import { createHash } from "node:crypto";
|
|
36678
|
+
function hashJsonUtf8Sha256(value) {
|
|
36679
|
+
return createHash("sha256").update(JSON.stringify(value), "utf8").digest("hex");
|
|
36680
|
+
}
|
|
36681
|
+
|
|
36682
|
+
// src/sqlite/agent-capability-cache.ts
|
|
36683
|
+
function hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType) {
|
|
36684
|
+
const t = agentType.trim();
|
|
36685
|
+
if (!t) return false;
|
|
36686
|
+
try {
|
|
36687
|
+
const row = db.get(
|
|
36688
|
+
`SELECT config_options_json FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
|
|
36689
|
+
[workspaceId, t]
|
|
36690
|
+
);
|
|
36691
|
+
if (row?.config_options_json == null || row.config_options_json === "") return false;
|
|
36692
|
+
const parsed = JSON.parse(row.config_options_json);
|
|
36693
|
+
return Array.isArray(parsed) && parsed.length > 0;
|
|
36694
|
+
} catch {
|
|
36695
|
+
return false;
|
|
36696
|
+
}
|
|
36697
|
+
}
|
|
36698
|
+
function upsertCliAgentCapabilityCache(db, row) {
|
|
36699
|
+
const t = row.agentType.trim();
|
|
36700
|
+
if (!t) return false;
|
|
36701
|
+
const hash = hashJsonUtf8Sha256(row.configOptions);
|
|
36702
|
+
try {
|
|
36703
|
+
const prev = db.get(
|
|
36704
|
+
`SELECT content_hash FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
|
|
36705
|
+
[row.workspaceId, t]
|
|
36706
|
+
);
|
|
36707
|
+
if (prev?.content_hash === hash) return false;
|
|
36708
|
+
} catch {
|
|
36709
|
+
}
|
|
36710
|
+
const json2 = JSON.stringify(row.configOptions);
|
|
36711
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
36712
|
+
db.run(
|
|
36713
|
+
`INSERT INTO agent_capabilities (workspace_id, agent_type, config_options_json, content_hash, updated_at)
|
|
36714
|
+
VALUES (?, ?, ?, ?, ?)
|
|
36715
|
+
ON CONFLICT(workspace_id, agent_type) DO UPDATE SET
|
|
36716
|
+
config_options_json = excluded.config_options_json,
|
|
36717
|
+
content_hash = excluded.content_hash,
|
|
36718
|
+
updated_at = excluded.updated_at`,
|
|
36719
|
+
[row.workspaceId, t, json2, hash, now]
|
|
36720
|
+
);
|
|
36721
|
+
return true;
|
|
36722
|
+
}
|
|
36723
|
+
function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
36724
|
+
const rows = db.all(
|
|
36725
|
+
`SELECT agent_type, config_options_json FROM agent_capabilities WHERE workspace_id = ?`,
|
|
36726
|
+
[workspaceId]
|
|
36727
|
+
);
|
|
36728
|
+
const out = [];
|
|
36729
|
+
for (const r of rows) {
|
|
36730
|
+
try {
|
|
36731
|
+
const parsed = JSON.parse(r.config_options_json);
|
|
36732
|
+
if (!Array.isArray(parsed) || parsed.length === 0) continue;
|
|
36733
|
+
out.push({ agentType: r.agent_type, configOptions: parsed });
|
|
36734
|
+
} catch {
|
|
36735
|
+
}
|
|
36736
|
+
}
|
|
36737
|
+
return out;
|
|
36738
|
+
}
|
|
36739
|
+
|
|
36740
|
+
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
36741
|
+
import * as path39 from "node:path";
|
|
36742
|
+
|
|
36743
|
+
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
36744
|
+
import * as path38 from "node:path";
|
|
36745
|
+
async function probeOneAgentTypeForCapabilities(params) {
|
|
36746
|
+
const { agentType, cwd, workspaceId, log: log2, getDb, reportAgentCapabilities, bridgeReport = true } = params;
|
|
36747
|
+
const resolved = resolveAgentCommand(agentType);
|
|
36748
|
+
if (!resolved) return false;
|
|
36749
|
+
let sqliteChanged = false;
|
|
36750
|
+
const reportedRef = { done: false };
|
|
36751
|
+
const tryReport = (co) => {
|
|
36752
|
+
if (reportedRef.done) return;
|
|
36753
|
+
if (!Array.isArray(co) || co.length === 0) return;
|
|
36754
|
+
reportedRef.done = true;
|
|
36755
|
+
let changed = false;
|
|
36756
|
+
try {
|
|
36757
|
+
changed = upsertCliAgentCapabilityCache(getDb(), {
|
|
36758
|
+
workspaceId,
|
|
36759
|
+
agentType,
|
|
36760
|
+
configOptions: co
|
|
36761
|
+
});
|
|
36762
|
+
} catch {
|
|
36763
|
+
}
|
|
36764
|
+
sqliteChanged ||= changed;
|
|
36765
|
+
if (bridgeReport && changed) {
|
|
36766
|
+
reportAgentCapabilities?.({ agentType, configOptions: co });
|
|
36767
|
+
}
|
|
36768
|
+
};
|
|
36769
|
+
let handle = null;
|
|
36770
|
+
const killTimer = setTimeout(() => {
|
|
36771
|
+
try {
|
|
36772
|
+
handle?.disconnect();
|
|
36773
|
+
} catch {
|
|
36774
|
+
}
|
|
36775
|
+
}, 28e3);
|
|
36776
|
+
killTimer.unref?.();
|
|
36777
|
+
try {
|
|
36778
|
+
handle = await resolved.createClient({
|
|
36779
|
+
command: resolved.command,
|
|
36780
|
+
cwd: path38.resolve(cwd),
|
|
36781
|
+
backendAgentType: agentType,
|
|
36782
|
+
sessionMode: "agent",
|
|
36783
|
+
persistedAcpSessionId: null,
|
|
36784
|
+
agentConfig: null,
|
|
36785
|
+
getActiveConfigOptions: () => null,
|
|
36786
|
+
onAcpSessionEstablished: (info) => {
|
|
36787
|
+
tryReport(info.configOptions ?? null);
|
|
36788
|
+
},
|
|
36789
|
+
onAcpConfigOptionsUpdated: (co) => {
|
|
36790
|
+
tryReport(co);
|
|
36791
|
+
},
|
|
36792
|
+
onAgentSubprocessExit: () => {
|
|
36793
|
+
},
|
|
36794
|
+
onSessionUpdate: () => {
|
|
36795
|
+
}
|
|
36796
|
+
});
|
|
36797
|
+
await new Promise((r) => setTimeout(r, 1200));
|
|
36798
|
+
} catch (e) {
|
|
36799
|
+
log2(
|
|
36800
|
+
`[Bridge service] Agent capability probe (${agentType}): ${e instanceof Error ? e.message : String(e)}`
|
|
36801
|
+
);
|
|
36802
|
+
} finally {
|
|
36803
|
+
clearTimeout(killTimer);
|
|
36804
|
+
try {
|
|
36805
|
+
handle?.disconnect();
|
|
36806
|
+
} catch {
|
|
36807
|
+
}
|
|
36808
|
+
}
|
|
36809
|
+
return sqliteChanged;
|
|
36810
|
+
}
|
|
36811
|
+
|
|
36812
|
+
// src/agents/capabilities/probe-agent-capabilities-for-types.ts
|
|
36813
|
+
async function probeAgentCapabilitiesForDetectedTypes(params) {
|
|
36814
|
+
const {
|
|
36815
|
+
agentTypes,
|
|
36816
|
+
cwd,
|
|
36817
|
+
workspaceId,
|
|
36818
|
+
log: log2,
|
|
36819
|
+
getDb,
|
|
36820
|
+
reportAgentCapabilities,
|
|
36821
|
+
bridgeReport = true,
|
|
36822
|
+
forceAllTypes = false
|
|
36823
|
+
} = params;
|
|
36824
|
+
let changedCount = 0;
|
|
36825
|
+
for (let i = 0; i < agentTypes.length; i++) {
|
|
36826
|
+
if (i > 0) await yieldToEventLoop();
|
|
36827
|
+
const agentType = agentTypes[i];
|
|
36828
|
+
if (!agentType.trim()) continue;
|
|
36829
|
+
if (!forceAllTypes) {
|
|
36830
|
+
try {
|
|
36831
|
+
if (process.env.BUILDAUTOMATON_FORCE_PROBE_ACP_CAPABILITIES !== "1" && hasNonEmptyAgentCapabilityCache(getDb(), workspaceId, agentType)) {
|
|
36832
|
+
continue;
|
|
36833
|
+
}
|
|
36834
|
+
} catch {
|
|
36835
|
+
}
|
|
36836
|
+
}
|
|
36837
|
+
const changed = await probeOneAgentTypeForCapabilities({
|
|
36838
|
+
agentType,
|
|
36839
|
+
cwd,
|
|
36840
|
+
workspaceId,
|
|
36841
|
+
log: log2,
|
|
36842
|
+
getDb,
|
|
36843
|
+
reportAgentCapabilities,
|
|
36844
|
+
bridgeReport
|
|
36845
|
+
});
|
|
36846
|
+
if (changed) changedCount += 1;
|
|
36847
|
+
}
|
|
36848
|
+
return changedCount;
|
|
36849
|
+
}
|
|
36850
|
+
|
|
36851
|
+
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
36852
|
+
async function warmupAgentCapabilitiesOnConnect(params) {
|
|
36853
|
+
const { workspaceId, log: log2, getDb, getWs } = params;
|
|
36854
|
+
const cwd = path39.resolve(getBridgeRoot());
|
|
36855
|
+
const db = getDb();
|
|
36856
|
+
function sendBatchFromCache() {
|
|
36857
|
+
const socket = getWs();
|
|
36858
|
+
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
36859
|
+
try {
|
|
36860
|
+
const rows = listCliAgentCapabilityCacheForWorkspace(db, workspaceId);
|
|
36861
|
+
if (rows.length === 0) return;
|
|
36862
|
+
sendWsMessage(socket, {
|
|
36863
|
+
type: "agent_capabilities_batch",
|
|
36864
|
+
items: rows.map((r) => ({ agentType: r.agentType, configOptions: r.configOptions }))
|
|
36865
|
+
});
|
|
36866
|
+
} catch (e) {
|
|
36867
|
+
log2(
|
|
36868
|
+
`[Bridge service] Agent capability batch to bridge failed: ${e instanceof Error ? e.message : String(e)}`
|
|
36869
|
+
);
|
|
36870
|
+
}
|
|
36871
|
+
}
|
|
36872
|
+
sendBatchFromCache();
|
|
36873
|
+
let types = [];
|
|
36874
|
+
try {
|
|
36875
|
+
types = [...await detectLocalAgentTypes()];
|
|
36876
|
+
} catch (e) {
|
|
36877
|
+
log2(`[Bridge service] detectLocalAgentTypes failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
36878
|
+
}
|
|
36879
|
+
try {
|
|
36880
|
+
const n = await probeAgentCapabilitiesForDetectedTypes({
|
|
36881
|
+
agentTypes: types,
|
|
36882
|
+
cwd,
|
|
36883
|
+
workspaceId,
|
|
36884
|
+
log: log2,
|
|
36885
|
+
getDb,
|
|
36886
|
+
bridgeReport: false,
|
|
36887
|
+
forceAllTypes: false
|
|
36888
|
+
});
|
|
36889
|
+
if (n > 0) sendBatchFromCache();
|
|
36890
|
+
} catch (e) {
|
|
36891
|
+
log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
36892
|
+
}
|
|
36893
|
+
void (async () => {
|
|
36894
|
+
try {
|
|
36895
|
+
await yieldToEventLoop();
|
|
36896
|
+
const n = await probeAgentCapabilitiesForDetectedTypes({
|
|
36897
|
+
agentTypes: types,
|
|
36898
|
+
cwd,
|
|
36899
|
+
workspaceId,
|
|
36900
|
+
log: log2,
|
|
36901
|
+
getDb,
|
|
36902
|
+
bridgeReport: false,
|
|
36903
|
+
forceAllTypes: true
|
|
36904
|
+
});
|
|
36905
|
+
if (n > 0) sendBatchFromCache();
|
|
36906
|
+
} catch (e) {
|
|
36907
|
+
log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
36908
|
+
}
|
|
36909
|
+
})();
|
|
36910
|
+
}
|
|
36911
|
+
|
|
36357
36912
|
// src/connection/create-bridge-connection.ts
|
|
36358
36913
|
async function createBridgeConnection(options) {
|
|
36359
36914
|
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
36360
36915
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
36361
36916
|
const logFn = options.log ?? log;
|
|
36917
|
+
getCliDatabase({ logLegacyMigration: logFn });
|
|
36362
36918
|
const tokens = {
|
|
36363
36919
|
accessToken: options.authToken,
|
|
36364
36920
|
refreshToken: options.refreshToken
|
|
@@ -36381,16 +36937,39 @@ async function createBridgeConnection(options) {
|
|
|
36381
36937
|
firehoseOutage: createEmptyReconnectOutageTracker(),
|
|
36382
36938
|
lastFirehoseReconnectCloseMeta: null
|
|
36383
36939
|
};
|
|
36940
|
+
function getWs() {
|
|
36941
|
+
return state.currentWs;
|
|
36942
|
+
}
|
|
36943
|
+
function sendAgentCapabilitiesToBridge(info) {
|
|
36944
|
+
if (!Array.isArray(info.configOptions) || info.configOptions.length === 0) return;
|
|
36945
|
+
let changed = false;
|
|
36946
|
+
try {
|
|
36947
|
+
changed = upsertCliAgentCapabilityCache(getCliDatabase(), {
|
|
36948
|
+
workspaceId,
|
|
36949
|
+
agentType: info.agentType,
|
|
36950
|
+
configOptions: info.configOptions
|
|
36951
|
+
});
|
|
36952
|
+
} catch {
|
|
36953
|
+
}
|
|
36954
|
+
if (!changed) return;
|
|
36955
|
+
const socket = getWs();
|
|
36956
|
+
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
36957
|
+
sendWsMessage(socket, {
|
|
36958
|
+
type: "agent_capabilities",
|
|
36959
|
+
agentType: info.agentType,
|
|
36960
|
+
configOptions: info.configOptions
|
|
36961
|
+
});
|
|
36962
|
+
}
|
|
36384
36963
|
const worktreesRootPath = options.worktreesRootPath ?? defaultWorktreesRootPath();
|
|
36385
36964
|
const sessionWorktreeManager = new SessionWorktreeManager({
|
|
36386
36965
|
worktreesRootPath,
|
|
36387
36966
|
log: logFn
|
|
36388
36967
|
});
|
|
36389
|
-
const acpManager = await createAcpManager({
|
|
36968
|
+
const acpManager = await createAcpManager({
|
|
36969
|
+
log: logFn,
|
|
36970
|
+
reportAgentCapabilities: sendAgentCapabilitiesToBridge
|
|
36971
|
+
});
|
|
36390
36972
|
logFn("CLI running. Press Ctrl+C to exit.");
|
|
36391
|
-
function getWs() {
|
|
36392
|
-
return state.currentWs;
|
|
36393
|
-
}
|
|
36394
36973
|
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
36395
36974
|
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
|
|
36396
36975
|
const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
|
|
@@ -36418,14 +36997,22 @@ async function createBridgeConnection(options) {
|
|
|
36418
36997
|
},
|
|
36419
36998
|
sendLocalSkillsReport,
|
|
36420
36999
|
reportAutoDetectedAgents,
|
|
37000
|
+
warmupAgentCapabilitiesOnConnect: async () => {
|
|
37001
|
+
await warmupAgentCapabilitiesOnConnect({
|
|
37002
|
+
workspaceId,
|
|
37003
|
+
log: logFn,
|
|
37004
|
+
getDb: getCliDatabase,
|
|
37005
|
+
getWs
|
|
37006
|
+
});
|
|
37007
|
+
},
|
|
36421
37008
|
devServerManager,
|
|
36422
37009
|
e2ee,
|
|
36423
37010
|
cloudApiBaseUrl: apiUrl,
|
|
36424
37011
|
getCloudAccessToken: () => tokens.accessToken
|
|
36425
37012
|
};
|
|
36426
37013
|
const identifyReportedPaths = {
|
|
36427
|
-
bridgeRootPath:
|
|
36428
|
-
worktreesRootPath:
|
|
37014
|
+
bridgeRootPath: path40.resolve(getBridgeRoot()),
|
|
37015
|
+
worktreesRootPath: path40.resolve(worktreesRootPath)
|
|
36429
37016
|
};
|
|
36430
37017
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
36431
37018
|
state,
|