@buildautomaton/cli 0.1.24 → 0.1.26
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 +991 -612
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1137 -763
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -973,8 +973,8 @@ var require_command = __commonJS({
|
|
|
973
973
|
"../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
|
|
974
974
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
975
975
|
var childProcess2 = __require("node:child_process");
|
|
976
|
-
var
|
|
977
|
-
var
|
|
976
|
+
var path37 = __require("node:path");
|
|
977
|
+
var fs36 = __require("node:fs");
|
|
978
978
|
var process8 = __require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
980
980
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1906,11 +1906,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1906
1906
|
let launchWithNode = false;
|
|
1907
1907
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1908
1908
|
function findFile(baseDir, baseName) {
|
|
1909
|
-
const localBin =
|
|
1910
|
-
if (
|
|
1911
|
-
if (sourceExt.includes(
|
|
1909
|
+
const localBin = path37.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs36.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path37.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs36.existsSync(`${localBin}${ext}`)
|
|
1914
1914
|
);
|
|
1915
1915
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1916
1916
|
return void 0;
|
|
@@ -1922,21 +1922,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1922
1922
|
if (this._scriptPath) {
|
|
1923
1923
|
let resolvedScriptPath;
|
|
1924
1924
|
try {
|
|
1925
|
-
resolvedScriptPath =
|
|
1925
|
+
resolvedScriptPath = fs36.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path37.resolve(
|
|
1930
|
+
path37.dirname(resolvedScriptPath),
|
|
1931
1931
|
executableDir
|
|
1932
1932
|
);
|
|
1933
1933
|
}
|
|
1934
1934
|
if (executableDir) {
|
|
1935
1935
|
let localFile = findFile(executableDir, executableFile);
|
|
1936
1936
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1937
|
-
const legacyName =
|
|
1937
|
+
const legacyName = path37.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path37.extname(this._scriptPath)
|
|
1940
1940
|
);
|
|
1941
1941
|
if (legacyName !== this._name) {
|
|
1942
1942
|
localFile = findFile(
|
|
@@ -1947,7 +1947,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1947
1947
|
}
|
|
1948
1948
|
executableFile = localFile || executableFile;
|
|
1949
1949
|
}
|
|
1950
|
-
launchWithNode = sourceExt.includes(
|
|
1950
|
+
launchWithNode = sourceExt.includes(path37.extname(executableFile));
|
|
1951
1951
|
let proc;
|
|
1952
1952
|
if (process8.platform !== "win32") {
|
|
1953
1953
|
if (launchWithNode) {
|
|
@@ -2787,7 +2787,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2787
2787
|
* @return {Command}
|
|
2788
2788
|
*/
|
|
2789
2789
|
nameFromFilename(filename) {
|
|
2790
|
-
this._name =
|
|
2790
|
+
this._name = path37.basename(filename, path37.extname(filename));
|
|
2791
2791
|
return this;
|
|
2792
2792
|
}
|
|
2793
2793
|
/**
|
|
@@ -2801,9 +2801,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2801
2801
|
* @param {string} [path]
|
|
2802
2802
|
* @return {(string|null|Command)}
|
|
2803
2803
|
*/
|
|
2804
|
-
executableDir(
|
|
2805
|
-
if (
|
|
2806
|
-
this._executableDir =
|
|
2804
|
+
executableDir(path38) {
|
|
2805
|
+
if (path38 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path38;
|
|
2807
2807
|
return this;
|
|
2808
2808
|
}
|
|
2809
2809
|
/**
|
|
@@ -7061,8 +7061,8 @@ var init_parseUtil = __esm({
|
|
|
7061
7061
|
init_errors();
|
|
7062
7062
|
init_en();
|
|
7063
7063
|
makeIssue = (params) => {
|
|
7064
|
-
const { data, path:
|
|
7065
|
-
const fullPath = [...
|
|
7064
|
+
const { data, path: path37, errorMaps, issueData } = params;
|
|
7065
|
+
const fullPath = [...path37, ...issueData.path || []];
|
|
7066
7066
|
const fullIssue = {
|
|
7067
7067
|
...issueData,
|
|
7068
7068
|
path: fullPath
|
|
@@ -7370,11 +7370,11 @@ var init_types = __esm({
|
|
|
7370
7370
|
init_parseUtil();
|
|
7371
7371
|
init_util();
|
|
7372
7372
|
ParseInputLazyPath = class {
|
|
7373
|
-
constructor(parent, value,
|
|
7373
|
+
constructor(parent, value, path37, key) {
|
|
7374
7374
|
this._cachedPath = [];
|
|
7375
7375
|
this.parent = parent;
|
|
7376
7376
|
this.data = value;
|
|
7377
|
-
this._path =
|
|
7377
|
+
this._path = path37;
|
|
7378
7378
|
this._key = key;
|
|
7379
7379
|
}
|
|
7380
7380
|
get path() {
|
|
@@ -11235,7 +11235,7 @@ var require_has_flag = __commonJS({
|
|
|
11235
11235
|
var require_supports_color = __commonJS({
|
|
11236
11236
|
"../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
|
|
11237
11237
|
"use strict";
|
|
11238
|
-
var
|
|
11238
|
+
var os8 = __require("os");
|
|
11239
11239
|
var tty = __require("tty");
|
|
11240
11240
|
var hasFlag = require_has_flag();
|
|
11241
11241
|
var { env } = process;
|
|
@@ -11283,7 +11283,7 @@ var require_supports_color = __commonJS({
|
|
|
11283
11283
|
return min;
|
|
11284
11284
|
}
|
|
11285
11285
|
if (process.platform === "win32") {
|
|
11286
|
-
const osRelease =
|
|
11286
|
+
const osRelease = os8.release().split(".");
|
|
11287
11287
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
11288
11288
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
11289
11289
|
}
|
|
@@ -11529,10 +11529,10 @@ var require_src2 = __commonJS({
|
|
|
11529
11529
|
var fs_1 = __require("fs");
|
|
11530
11530
|
var debug_1 = __importDefault(require_src());
|
|
11531
11531
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
11532
|
-
function check2(
|
|
11533
|
-
log2(`checking %s`,
|
|
11532
|
+
function check2(path37, isFile, isDirectory) {
|
|
11533
|
+
log2(`checking %s`, path37);
|
|
11534
11534
|
try {
|
|
11535
|
-
const stat3 = fs_1.statSync(
|
|
11535
|
+
const stat3 = fs_1.statSync(path37);
|
|
11536
11536
|
if (stat3.isFile() && isFile) {
|
|
11537
11537
|
log2(`[OK] path represents a file`);
|
|
11538
11538
|
return true;
|
|
@@ -11552,8 +11552,8 @@ var require_src2 = __commonJS({
|
|
|
11552
11552
|
throw e;
|
|
11553
11553
|
}
|
|
11554
11554
|
}
|
|
11555
|
-
function exists2(
|
|
11556
|
-
return check2(
|
|
11555
|
+
function exists2(path37, type = exports.READABLE) {
|
|
11556
|
+
return check2(path37, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
11557
11557
|
}
|
|
11558
11558
|
exports.exists = exists2;
|
|
11559
11559
|
exports.FILE = 1;
|
|
@@ -11850,10 +11850,10 @@ function assignProp(target, prop, value) {
|
|
|
11850
11850
|
configurable: true
|
|
11851
11851
|
});
|
|
11852
11852
|
}
|
|
11853
|
-
function getElementAtPath(obj,
|
|
11854
|
-
if (!
|
|
11853
|
+
function getElementAtPath(obj, path37) {
|
|
11854
|
+
if (!path37)
|
|
11855
11855
|
return obj;
|
|
11856
|
-
return
|
|
11856
|
+
return path37.reduce((acc, key) => acc?.[key], obj);
|
|
11857
11857
|
}
|
|
11858
11858
|
function promiseAllObject(promisesObj) {
|
|
11859
11859
|
const keys = Object.keys(promisesObj);
|
|
@@ -12102,11 +12102,11 @@ function aborted(x, startIndex = 0) {
|
|
|
12102
12102
|
}
|
|
12103
12103
|
return false;
|
|
12104
12104
|
}
|
|
12105
|
-
function prefixIssues(
|
|
12105
|
+
function prefixIssues(path37, issues) {
|
|
12106
12106
|
return issues.map((iss) => {
|
|
12107
12107
|
var _a2;
|
|
12108
12108
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
12109
|
-
iss.path.unshift(
|
|
12109
|
+
iss.path.unshift(path37);
|
|
12110
12110
|
return iss;
|
|
12111
12111
|
});
|
|
12112
12112
|
}
|
|
@@ -12295,7 +12295,7 @@ function treeifyError(error40, _mapper) {
|
|
|
12295
12295
|
return issue2.message;
|
|
12296
12296
|
};
|
|
12297
12297
|
const result = { errors: [] };
|
|
12298
|
-
const processError = (error41,
|
|
12298
|
+
const processError = (error41, path37 = []) => {
|
|
12299
12299
|
var _a2, _b;
|
|
12300
12300
|
for (const issue2 of error41.issues) {
|
|
12301
12301
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -12305,7 +12305,7 @@ function treeifyError(error40, _mapper) {
|
|
|
12305
12305
|
} else if (issue2.code === "invalid_element") {
|
|
12306
12306
|
processError({ issues: issue2.issues }, issue2.path);
|
|
12307
12307
|
} else {
|
|
12308
|
-
const fullpath = [...
|
|
12308
|
+
const fullpath = [...path37, ...issue2.path];
|
|
12309
12309
|
if (fullpath.length === 0) {
|
|
12310
12310
|
result.errors.push(mapper(issue2));
|
|
12311
12311
|
continue;
|
|
@@ -12335,9 +12335,9 @@ function treeifyError(error40, _mapper) {
|
|
|
12335
12335
|
processError(error40);
|
|
12336
12336
|
return result;
|
|
12337
12337
|
}
|
|
12338
|
-
function toDotPath(
|
|
12338
|
+
function toDotPath(path37) {
|
|
12339
12339
|
const segs = [];
|
|
12340
|
-
for (const seg of
|
|
12340
|
+
for (const seg of path37) {
|
|
12341
12341
|
if (typeof seg === "number")
|
|
12342
12342
|
segs.push(`[${seg}]`);
|
|
12343
12343
|
else if (typeof seg === "symbol")
|
|
@@ -25064,15 +25064,15 @@ var {
|
|
|
25064
25064
|
} = import_index.default;
|
|
25065
25065
|
|
|
25066
25066
|
// src/cli-version.ts
|
|
25067
|
-
var CLI_VERSION = "0.1.
|
|
25067
|
+
var CLI_VERSION = "0.1.26".length > 0 ? "0.1.26" : "0.0.0-dev";
|
|
25068
25068
|
|
|
25069
25069
|
// src/cli/defaults.ts
|
|
25070
25070
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
25071
25071
|
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
25072
25072
|
|
|
25073
25073
|
// src/cli/run-cli-action.ts
|
|
25074
|
-
import * as
|
|
25075
|
-
import * as
|
|
25074
|
+
import * as fs35 from "node:fs";
|
|
25075
|
+
import * as path36 from "node:path";
|
|
25076
25076
|
|
|
25077
25077
|
// src/cli-log-level.ts
|
|
25078
25078
|
var verbosity = "info";
|
|
@@ -25465,6 +25465,11 @@ function logImmediate(line) {
|
|
|
25465
25465
|
process.stdout.write(`${timestampPrefix()} ${line}
|
|
25466
25466
|
`);
|
|
25467
25467
|
}
|
|
25468
|
+
function logDebug(line) {
|
|
25469
|
+
const v = getCliLogVerbosity();
|
|
25470
|
+
if (v !== "debug" && v !== "trace") return;
|
|
25471
|
+
console.log(`${timestampPrefix()} [debug] ${line}`);
|
|
25472
|
+
}
|
|
25468
25473
|
function logTrace(line) {
|
|
25469
25474
|
if (getCliLogVerbosity() !== "trace") return;
|
|
25470
25475
|
console.log(`${timestampPrefix()} [trace] ${line}`);
|
|
@@ -27058,9 +27063,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
27058
27063
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
27059
27064
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
27060
27065
|
if (!rawPath || !summary) continue;
|
|
27061
|
-
const
|
|
27062
|
-
if (!
|
|
27063
|
-
rows.push({ path:
|
|
27066
|
+
const path37 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
27067
|
+
if (!path37) continue;
|
|
27068
|
+
rows.push({ path: path37, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
27064
27069
|
}
|
|
27065
27070
|
return rows;
|
|
27066
27071
|
}
|
|
@@ -27199,8 +27204,77 @@ function isClaudeCodePermissionMode(value) {
|
|
|
27199
27204
|
return MODE_SET.has(value);
|
|
27200
27205
|
}
|
|
27201
27206
|
|
|
27207
|
+
// ../types/src/cli-permission-mode.ts
|
|
27208
|
+
var CLI_PERMISSION_MODE_DEFAULT = "default";
|
|
27209
|
+
var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
|
|
27210
|
+
function normalizeCliPermissionModeInput(raw) {
|
|
27211
|
+
if (typeof raw !== "string") return CLI_PERMISSION_MODE_DEFAULT;
|
|
27212
|
+
const t = raw.trim();
|
|
27213
|
+
if (t === CLI_PERMISSION_MODE_DANGEROUS) return CLI_PERMISSION_MODE_DANGEROUS;
|
|
27214
|
+
if (t === "standard") return CLI_PERMISSION_MODE_DEFAULT;
|
|
27215
|
+
return CLI_PERMISSION_MODE_DEFAULT;
|
|
27216
|
+
}
|
|
27217
|
+
|
|
27218
|
+
// ../types/src/acp-permission-auto-approve.ts
|
|
27219
|
+
function isRejectKind(kind) {
|
|
27220
|
+
return kind === "reject_once" || kind === "reject_always";
|
|
27221
|
+
}
|
|
27222
|
+
function normalizeOptions(raw) {
|
|
27223
|
+
if (!Array.isArray(raw)) return [];
|
|
27224
|
+
const out = [];
|
|
27225
|
+
for (const item of raw) {
|
|
27226
|
+
if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
|
|
27227
|
+
const o = item;
|
|
27228
|
+
const rawId = o.optionId ?? o.id;
|
|
27229
|
+
const optionId = typeof rawId === "string" && rawId.trim() !== "" ? rawId.trim() : typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : "";
|
|
27230
|
+
if (!optionId) continue;
|
|
27231
|
+
const kind = typeof o.kind === "string" ? o.kind : void 0;
|
|
27232
|
+
out.push({ optionId, ...kind ? { kind } : {} });
|
|
27233
|
+
}
|
|
27234
|
+
return out;
|
|
27235
|
+
}
|
|
27236
|
+
function pickAllowOption(options) {
|
|
27237
|
+
const nonReject = options.filter((o) => !isRejectKind(o.kind));
|
|
27238
|
+
if (nonReject.length === 0) return null;
|
|
27239
|
+
const allowOnce = nonReject.find((o) => o.kind === "allow_once");
|
|
27240
|
+
if (allowOnce) return allowOnce;
|
|
27241
|
+
const notAlways = nonReject.filter((o) => o.kind !== "allow_always");
|
|
27242
|
+
if (notAlways.length > 0) return notAlways[0] ?? null;
|
|
27243
|
+
return nonReject.find((o) => o.kind === "allow_always") ?? nonReject[0] ?? null;
|
|
27244
|
+
}
|
|
27245
|
+
function firstNonEmptyOptionsArray(...candidates) {
|
|
27246
|
+
for (const c of candidates) {
|
|
27247
|
+
if (Array.isArray(c) && c.length > 0) return c;
|
|
27248
|
+
}
|
|
27249
|
+
const fallback = candidates[0];
|
|
27250
|
+
return Array.isArray(fallback) ? fallback : [];
|
|
27251
|
+
}
|
|
27252
|
+
function extractAcpPermissionRequestOptionArray(params) {
|
|
27253
|
+
const toolCall = params.toolCall;
|
|
27254
|
+
const fromToolCall = toolCall != null && typeof toolCall === "object" && !Array.isArray(toolCall) ? toolCall : null;
|
|
27255
|
+
return firstNonEmptyOptionsArray(
|
|
27256
|
+
params.options,
|
|
27257
|
+
params.permissionOptions,
|
|
27258
|
+
fromToolCall?.options,
|
|
27259
|
+
fromToolCall?.permissionOptions
|
|
27260
|
+
);
|
|
27261
|
+
}
|
|
27262
|
+
function buildCliAutoApprovedPermissionRpcResult(requestParams) {
|
|
27263
|
+
const opt = pickAllowOption(normalizeOptions(extractAcpPermissionRequestOptionArray(requestParams)));
|
|
27264
|
+
if (!opt) return null;
|
|
27265
|
+
const kind = opt.kind?.trim();
|
|
27266
|
+
return {
|
|
27267
|
+
outcome: {
|
|
27268
|
+
outcome: "selected",
|
|
27269
|
+
optionId: opt.optionId,
|
|
27270
|
+
...kind ? { _meta: { permissionOptionKind: kind } } : {}
|
|
27271
|
+
}
|
|
27272
|
+
};
|
|
27273
|
+
}
|
|
27274
|
+
|
|
27202
27275
|
// ../types/src/agent-config.ts
|
|
27203
27276
|
var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
|
|
27277
|
+
var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
|
|
27204
27278
|
function getClaudePermissionModeFromAgentConfig(config2) {
|
|
27205
27279
|
if (!config2) return null;
|
|
27206
27280
|
const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
|
|
@@ -27208,6 +27282,10 @@ function getClaudePermissionModeFromAgentConfig(config2) {
|
|
|
27208
27282
|
const t = raw.trim();
|
|
27209
27283
|
return isClaudeCodePermissionMode(t) ? t : null;
|
|
27210
27284
|
}
|
|
27285
|
+
function getCliPermissionModeFromAgentConfig(config2) {
|
|
27286
|
+
if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
|
|
27287
|
+
return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
|
|
27288
|
+
}
|
|
27211
27289
|
|
|
27212
27290
|
// src/git/session-git-queue.ts
|
|
27213
27291
|
import { execFile as execFile7 } from "node:child_process";
|
|
@@ -27262,8 +27340,8 @@ function pathspec(...paths) {
|
|
|
27262
27340
|
cache.set(key, paths);
|
|
27263
27341
|
return key;
|
|
27264
27342
|
}
|
|
27265
|
-
function isPathSpec(
|
|
27266
|
-
return
|
|
27343
|
+
function isPathSpec(path37) {
|
|
27344
|
+
return path37 instanceof String && cache.has(path37);
|
|
27267
27345
|
}
|
|
27268
27346
|
function toPaths(pathSpec) {
|
|
27269
27347
|
return cache.get(pathSpec) || [];
|
|
@@ -27352,8 +27430,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
27352
27430
|
function forEachLineWithContent(input, callback) {
|
|
27353
27431
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
27354
27432
|
}
|
|
27355
|
-
function folderExists(
|
|
27356
|
-
return (0, import_file_exists.exists)(
|
|
27433
|
+
function folderExists(path37) {
|
|
27434
|
+
return (0, import_file_exists.exists)(path37, import_file_exists.FOLDER);
|
|
27357
27435
|
}
|
|
27358
27436
|
function append(target, item) {
|
|
27359
27437
|
if (Array.isArray(target)) {
|
|
@@ -27757,8 +27835,8 @@ function checkIsRepoRootTask() {
|
|
|
27757
27835
|
commands,
|
|
27758
27836
|
format: "utf-8",
|
|
27759
27837
|
onError,
|
|
27760
|
-
parser(
|
|
27761
|
-
return /^\.(git)?$/.test(
|
|
27838
|
+
parser(path37) {
|
|
27839
|
+
return /^\.(git)?$/.test(path37.trim());
|
|
27762
27840
|
}
|
|
27763
27841
|
};
|
|
27764
27842
|
}
|
|
@@ -28192,11 +28270,11 @@ function parseGrep(grep) {
|
|
|
28192
28270
|
const paths = /* @__PURE__ */ new Set();
|
|
28193
28271
|
const results = {};
|
|
28194
28272
|
forEachLineWithContent(grep, (input) => {
|
|
28195
|
-
const [
|
|
28196
|
-
paths.add(
|
|
28197
|
-
(results[
|
|
28273
|
+
const [path37, line, preview] = input.split(NULL);
|
|
28274
|
+
paths.add(path37);
|
|
28275
|
+
(results[path37] = results[path37] || []).push({
|
|
28198
28276
|
line: asNumber(line),
|
|
28199
|
-
path:
|
|
28277
|
+
path: path37,
|
|
28200
28278
|
preview
|
|
28201
28279
|
});
|
|
28202
28280
|
});
|
|
@@ -28961,14 +29039,14 @@ var init_hash_object = __esm2({
|
|
|
28961
29039
|
init_task();
|
|
28962
29040
|
}
|
|
28963
29041
|
});
|
|
28964
|
-
function parseInit(bare,
|
|
29042
|
+
function parseInit(bare, path37, text) {
|
|
28965
29043
|
const response = String(text).trim();
|
|
28966
29044
|
let result;
|
|
28967
29045
|
if (result = initResponseRegex.exec(response)) {
|
|
28968
|
-
return new InitSummary(bare,
|
|
29046
|
+
return new InitSummary(bare, path37, false, result[1]);
|
|
28969
29047
|
}
|
|
28970
29048
|
if (result = reInitResponseRegex.exec(response)) {
|
|
28971
|
-
return new InitSummary(bare,
|
|
29049
|
+
return new InitSummary(bare, path37, true, result[1]);
|
|
28972
29050
|
}
|
|
28973
29051
|
let gitDir = "";
|
|
28974
29052
|
const tokens = response.split(" ");
|
|
@@ -28979,7 +29057,7 @@ function parseInit(bare, path36, text) {
|
|
|
28979
29057
|
break;
|
|
28980
29058
|
}
|
|
28981
29059
|
}
|
|
28982
|
-
return new InitSummary(bare,
|
|
29060
|
+
return new InitSummary(bare, path37, /^re/i.test(response), gitDir);
|
|
28983
29061
|
}
|
|
28984
29062
|
var InitSummary;
|
|
28985
29063
|
var initResponseRegex;
|
|
@@ -28988,9 +29066,9 @@ var init_InitSummary = __esm2({
|
|
|
28988
29066
|
"src/lib/responses/InitSummary.ts"() {
|
|
28989
29067
|
"use strict";
|
|
28990
29068
|
InitSummary = class {
|
|
28991
|
-
constructor(bare,
|
|
29069
|
+
constructor(bare, path37, existing, gitDir) {
|
|
28992
29070
|
this.bare = bare;
|
|
28993
|
-
this.path =
|
|
29071
|
+
this.path = path37;
|
|
28994
29072
|
this.existing = existing;
|
|
28995
29073
|
this.gitDir = gitDir;
|
|
28996
29074
|
}
|
|
@@ -29002,7 +29080,7 @@ var init_InitSummary = __esm2({
|
|
|
29002
29080
|
function hasBareCommand(command) {
|
|
29003
29081
|
return command.includes(bareCommand);
|
|
29004
29082
|
}
|
|
29005
|
-
function initTask(bare = false,
|
|
29083
|
+
function initTask(bare = false, path37, customArgs) {
|
|
29006
29084
|
const commands = ["init", ...customArgs];
|
|
29007
29085
|
if (bare && !hasBareCommand(commands)) {
|
|
29008
29086
|
commands.splice(1, 0, bareCommand);
|
|
@@ -29011,7 +29089,7 @@ function initTask(bare = false, path36, customArgs) {
|
|
|
29011
29089
|
commands,
|
|
29012
29090
|
format: "utf-8",
|
|
29013
29091
|
parser(text) {
|
|
29014
|
-
return parseInit(commands.includes("--bare"),
|
|
29092
|
+
return parseInit(commands.includes("--bare"), path37, text);
|
|
29015
29093
|
}
|
|
29016
29094
|
};
|
|
29017
29095
|
}
|
|
@@ -29827,12 +29905,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
29827
29905
|
"use strict";
|
|
29828
29906
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
29829
29907
|
FileStatusSummary = class {
|
|
29830
|
-
constructor(
|
|
29831
|
-
this.path =
|
|
29908
|
+
constructor(path37, index, working_dir) {
|
|
29909
|
+
this.path = path37;
|
|
29832
29910
|
this.index = index;
|
|
29833
29911
|
this.working_dir = working_dir;
|
|
29834
29912
|
if (index === "R" || working_dir === "R") {
|
|
29835
|
-
const detail = fromPathRegex.exec(
|
|
29913
|
+
const detail = fromPathRegex.exec(path37) || [null, path37, path37];
|
|
29836
29914
|
this.from = detail[2] || "";
|
|
29837
29915
|
this.path = detail[1] || "";
|
|
29838
29916
|
}
|
|
@@ -29863,14 +29941,14 @@ function splitLine(result, lineStr) {
|
|
|
29863
29941
|
default:
|
|
29864
29942
|
return;
|
|
29865
29943
|
}
|
|
29866
|
-
function data(index, workingDir,
|
|
29944
|
+
function data(index, workingDir, path37) {
|
|
29867
29945
|
const raw = `${index}${workingDir}`;
|
|
29868
29946
|
const handler = parsers6.get(raw);
|
|
29869
29947
|
if (handler) {
|
|
29870
|
-
handler(result,
|
|
29948
|
+
handler(result, path37);
|
|
29871
29949
|
}
|
|
29872
29950
|
if (raw !== "##" && raw !== "!!") {
|
|
29873
|
-
result.files.push(new FileStatusSummary(
|
|
29951
|
+
result.files.push(new FileStatusSummary(path37, index, workingDir));
|
|
29874
29952
|
}
|
|
29875
29953
|
}
|
|
29876
29954
|
}
|
|
@@ -30179,9 +30257,9 @@ var init_simple_git_api = __esm2({
|
|
|
30179
30257
|
next
|
|
30180
30258
|
);
|
|
30181
30259
|
}
|
|
30182
|
-
hashObject(
|
|
30260
|
+
hashObject(path37, write) {
|
|
30183
30261
|
return this._runTask(
|
|
30184
|
-
hashObjectTask(
|
|
30262
|
+
hashObjectTask(path37, write === true),
|
|
30185
30263
|
trailingFunctionArgument(arguments)
|
|
30186
30264
|
);
|
|
30187
30265
|
}
|
|
@@ -30534,8 +30612,8 @@ var init_branch = __esm2({
|
|
|
30534
30612
|
}
|
|
30535
30613
|
});
|
|
30536
30614
|
function toPath(input) {
|
|
30537
|
-
const
|
|
30538
|
-
return
|
|
30615
|
+
const path37 = input.trim().replace(/^["']|["']$/g, "");
|
|
30616
|
+
return path37 && normalize(path37);
|
|
30539
30617
|
}
|
|
30540
30618
|
var parseCheckIgnore;
|
|
30541
30619
|
var init_CheckIgnore = __esm2({
|
|
@@ -30849,8 +30927,8 @@ __export2(sub_module_exports, {
|
|
|
30849
30927
|
subModuleTask: () => subModuleTask,
|
|
30850
30928
|
updateSubModuleTask: () => updateSubModuleTask
|
|
30851
30929
|
});
|
|
30852
|
-
function addSubModuleTask(repo,
|
|
30853
|
-
return subModuleTask(["add", repo,
|
|
30930
|
+
function addSubModuleTask(repo, path37) {
|
|
30931
|
+
return subModuleTask(["add", repo, path37]);
|
|
30854
30932
|
}
|
|
30855
30933
|
function initSubModuleTask(customArgs) {
|
|
30856
30934
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -31183,8 +31261,8 @@ var require_git = __commonJS2({
|
|
|
31183
31261
|
}
|
|
31184
31262
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
31185
31263
|
};
|
|
31186
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
31187
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
31264
|
+
Git2.prototype.submoduleAdd = function(repo, path37, then) {
|
|
31265
|
+
return this._runTask(addSubModuleTask2(repo, path37), trailingFunctionArgument2(arguments));
|
|
31188
31266
|
};
|
|
31189
31267
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
31190
31268
|
return this._runTask(
|
|
@@ -32071,9 +32149,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32071
32149
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
32072
32150
|
async function putEncryptedChangeSummaryRows(params) {
|
|
32073
32151
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
32074
|
-
const entries = params.rows.map(({ path:
|
|
32152
|
+
const entries = params.rows.map(({ path: path37, summary }) => {
|
|
32075
32153
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
32076
|
-
return { path:
|
|
32154
|
+
return { path: path37, summary: JSON.stringify(enc) };
|
|
32077
32155
|
});
|
|
32078
32156
|
const res = await fetch(
|
|
32079
32157
|
`${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -32255,8 +32333,8 @@ async function sendPromptToAgent(options) {
|
|
|
32255
32333
|
}
|
|
32256
32334
|
|
|
32257
32335
|
// src/agents/acp/ensure-acp-client.ts
|
|
32258
|
-
import * as
|
|
32259
|
-
import * as
|
|
32336
|
+
import * as fs11 from "node:fs";
|
|
32337
|
+
import * as path13 from "node:path";
|
|
32260
32338
|
|
|
32261
32339
|
// src/error-message.ts
|
|
32262
32340
|
function errorMessage(err) {
|
|
@@ -32292,76 +32370,10 @@ async function isCommandOnPath(command, timeoutMs = 4e3) {
|
|
|
32292
32370
|
}
|
|
32293
32371
|
}
|
|
32294
32372
|
|
|
32295
|
-
// src/agents/acp/clients/sdk-stdio-acp-client.ts
|
|
32373
|
+
// src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
|
|
32296
32374
|
import { spawn as spawn2 } from "node:child_process";
|
|
32297
|
-
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
32298
|
-
import { dirname as dirname2 } from "node:path";
|
|
32299
32375
|
import { Readable, Writable } from "node:stream";
|
|
32300
32376
|
|
|
32301
|
-
// src/files/diff/unified-diff.ts
|
|
32302
|
-
function computeLineDiff(oldText, newText) {
|
|
32303
|
-
const oldLines = oldText.split("\n");
|
|
32304
|
-
const newLines = newText.split("\n");
|
|
32305
|
-
const m = oldLines.length;
|
|
32306
|
-
const n = newLines.length;
|
|
32307
|
-
const dp = Array(m + 1);
|
|
32308
|
-
for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
|
|
32309
|
-
for (let i2 = 1; i2 <= m; i2++) {
|
|
32310
|
-
for (let j2 = 1; j2 <= n; j2++) {
|
|
32311
|
-
if (oldLines[i2 - 1] === newLines[j2 - 1]) {
|
|
32312
|
-
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
32313
|
-
} else {
|
|
32314
|
-
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
32315
|
-
}
|
|
32316
|
-
}
|
|
32317
|
-
}
|
|
32318
|
-
const result = [];
|
|
32319
|
-
let i = m;
|
|
32320
|
-
let j = n;
|
|
32321
|
-
while (i > 0 || j > 0) {
|
|
32322
|
-
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
32323
|
-
result.unshift({ type: "context", line: oldLines[i - 1] });
|
|
32324
|
-
i--;
|
|
32325
|
-
j--;
|
|
32326
|
-
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
32327
|
-
result.unshift({ type: "add", line: newLines[j - 1] });
|
|
32328
|
-
j--;
|
|
32329
|
-
} else {
|
|
32330
|
-
result.unshift({ type: "remove", line: oldLines[i - 1] });
|
|
32331
|
-
i--;
|
|
32332
|
-
}
|
|
32333
|
-
}
|
|
32334
|
-
return result;
|
|
32335
|
-
}
|
|
32336
|
-
function editSnippetToUnifiedDiff(filePath, oldText, newText) {
|
|
32337
|
-
const lines = computeLineDiff(oldText, newText);
|
|
32338
|
-
const out = [`--- ${filePath}`, `+++ ${filePath}`];
|
|
32339
|
-
for (const d of lines) {
|
|
32340
|
-
if (d.type === "add") out.push(`+${d.line}`);
|
|
32341
|
-
else if (d.type === "remove") out.push(`-${d.line}`);
|
|
32342
|
-
else out.push(` ${d.line}`);
|
|
32343
|
-
}
|
|
32344
|
-
return out.join("\n");
|
|
32345
|
-
}
|
|
32346
|
-
|
|
32347
|
-
// src/agents/acp/safe-fs-path.ts
|
|
32348
|
-
import * as path9 from "node:path";
|
|
32349
|
-
function resolveSafePathUnderCwd(cwd, filePath) {
|
|
32350
|
-
const trimmed2 = filePath.trim();
|
|
32351
|
-
if (!trimmed2) return null;
|
|
32352
|
-
const normalizedCwd = path9.resolve(cwd);
|
|
32353
|
-
const resolved = path9.isAbsolute(trimmed2) ? path9.normalize(trimmed2) : path9.resolve(normalizedCwd, trimmed2);
|
|
32354
|
-
const rel = path9.relative(normalizedCwd, resolved);
|
|
32355
|
-
if (rel.startsWith("..") || path9.isAbsolute(rel)) return null;
|
|
32356
|
-
return resolved;
|
|
32357
|
-
}
|
|
32358
|
-
function toDisplayPathRelativeToCwd(cwd, absolutePath) {
|
|
32359
|
-
const normalizedCwd = path9.resolve(cwd);
|
|
32360
|
-
const rel = path9.relative(normalizedCwd, path9.resolve(absolutePath));
|
|
32361
|
-
if (!rel || rel === "") return path9.basename(absolutePath);
|
|
32362
|
-
return rel.split(path9.sep).join("/");
|
|
32363
|
-
}
|
|
32364
|
-
|
|
32365
32377
|
// src/agents/acp/clients/agent-stderr-capture.ts
|
|
32366
32378
|
var STDERR_CAPTURE_MAX = 48e3;
|
|
32367
32379
|
function createStderrCapture(child) {
|
|
@@ -32426,7 +32438,7 @@ function createKiroSdkExtNotificationHandler(options) {
|
|
|
32426
32438
|
};
|
|
32427
32439
|
}
|
|
32428
32440
|
|
|
32429
|
-
// src/agents/acp/clients/sdk-stdio-ext-notifications.ts
|
|
32441
|
+
// src/agents/acp/clients/sdk/sdk-stdio-ext-notifications.ts
|
|
32430
32442
|
var noopExtNotification = async () => {
|
|
32431
32443
|
};
|
|
32432
32444
|
function createSdkStdioExtNotificationHandler(options) {
|
|
@@ -32485,23 +32497,380 @@ function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
|
|
|
32485
32497
|
};
|
|
32486
32498
|
}
|
|
32487
32499
|
|
|
32488
|
-
// src/agents/acp/clients/
|
|
32489
|
-
|
|
32490
|
-
|
|
32491
|
-
|
|
32500
|
+
// src/agents/acp/clients/shared/acp-fs-read-write.ts
|
|
32501
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
32502
|
+
import { dirname as dirname2 } from "node:path";
|
|
32503
|
+
|
|
32504
|
+
// src/files/diff/unified-diff.ts
|
|
32505
|
+
function computeLineDiff(oldText, newText) {
|
|
32506
|
+
const oldLines = oldText.split("\n");
|
|
32507
|
+
const newLines = newText.split("\n");
|
|
32508
|
+
const m = oldLines.length;
|
|
32509
|
+
const n = newLines.length;
|
|
32510
|
+
const dp = Array(m + 1);
|
|
32511
|
+
for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
|
|
32512
|
+
for (let i2 = 1; i2 <= m; i2++) {
|
|
32513
|
+
for (let j2 = 1; j2 <= n; j2++) {
|
|
32514
|
+
if (oldLines[i2 - 1] === newLines[j2 - 1]) {
|
|
32515
|
+
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
32516
|
+
} else {
|
|
32517
|
+
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
32518
|
+
}
|
|
32519
|
+
}
|
|
32492
32520
|
}
|
|
32493
|
-
|
|
32521
|
+
const result = [];
|
|
32522
|
+
let i = m;
|
|
32523
|
+
let j = n;
|
|
32524
|
+
while (i > 0 || j > 0) {
|
|
32525
|
+
if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
|
|
32526
|
+
result.unshift({ type: "context", line: oldLines[i - 1] });
|
|
32527
|
+
i--;
|
|
32528
|
+
j--;
|
|
32529
|
+
} else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
|
|
32530
|
+
result.unshift({ type: "add", line: newLines[j - 1] });
|
|
32531
|
+
j--;
|
|
32532
|
+
} else {
|
|
32533
|
+
result.unshift({ type: "remove", line: oldLines[i - 1] });
|
|
32534
|
+
i--;
|
|
32535
|
+
}
|
|
32536
|
+
}
|
|
32537
|
+
return result;
|
|
32538
|
+
}
|
|
32539
|
+
function editSnippetToUnifiedDiff(filePath, oldText, newText) {
|
|
32540
|
+
const lines = computeLineDiff(oldText, newText);
|
|
32541
|
+
const out = [`--- ${filePath}`, `+++ ${filePath}`];
|
|
32542
|
+
for (const d of lines) {
|
|
32543
|
+
if (d.type === "add") out.push(`+${d.line}`);
|
|
32544
|
+
else if (d.type === "remove") out.push(`-${d.line}`);
|
|
32545
|
+
else out.push(` ${d.line}`);
|
|
32546
|
+
}
|
|
32547
|
+
return out.join("\n");
|
|
32548
|
+
}
|
|
32549
|
+
|
|
32550
|
+
// src/agents/acp/safe-fs-path.ts
|
|
32551
|
+
import * as path9 from "node:path";
|
|
32552
|
+
function resolveSafePathUnderCwd(cwd, filePath) {
|
|
32553
|
+
const trimmed2 = filePath.trim();
|
|
32554
|
+
if (!trimmed2) return null;
|
|
32555
|
+
const normalizedCwd = path9.resolve(cwd);
|
|
32556
|
+
const resolved = path9.isAbsolute(trimmed2) ? path9.normalize(trimmed2) : path9.resolve(normalizedCwd, trimmed2);
|
|
32557
|
+
const rel = path9.relative(normalizedCwd, resolved);
|
|
32558
|
+
if (rel.startsWith("..") || path9.isAbsolute(rel)) return null;
|
|
32559
|
+
return resolved;
|
|
32494
32560
|
}
|
|
32495
|
-
function
|
|
32561
|
+
function toDisplayPathRelativeToCwd(cwd, absolutePath) {
|
|
32562
|
+
const normalizedCwd = path9.resolve(cwd);
|
|
32563
|
+
const rel = path9.relative(normalizedCwd, path9.resolve(absolutePath));
|
|
32564
|
+
if (!rel || rel === "") return path9.basename(absolutePath);
|
|
32565
|
+
return rel.split(path9.sep).join("/");
|
|
32566
|
+
}
|
|
32567
|
+
|
|
32568
|
+
// src/agents/acp/clients/shared/acp-fs-read-write.ts
|
|
32569
|
+
function sliceFileContentForAcp(content, line, limit) {
|
|
32496
32570
|
if (line == null && limit == null) return content;
|
|
32497
32571
|
const lines = content.split("\n");
|
|
32498
32572
|
const start = line != null && line > 0 ? line - 1 : 0;
|
|
32499
32573
|
const end = limit != null && limit > 0 ? start + limit : lines.length;
|
|
32500
32574
|
return lines.slice(start, end).join("\n");
|
|
32501
32575
|
}
|
|
32502
|
-
function
|
|
32576
|
+
function acpReadTextFileInProcess(ctx, filePath, line, limit) {
|
|
32577
|
+
const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
|
|
32578
|
+
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32579
|
+
try {
|
|
32580
|
+
let content = readFileSync2(resolvedPath, "utf8");
|
|
32581
|
+
content = sliceFileContentForAcp(content, line, limit);
|
|
32582
|
+
return { content };
|
|
32583
|
+
} catch (e) {
|
|
32584
|
+
if (e.code === "ENOENT") return { content: "" };
|
|
32585
|
+
throw e;
|
|
32586
|
+
}
|
|
32587
|
+
}
|
|
32588
|
+
function acpWriteTextFileInProcess(ctx, filePath, newText) {
|
|
32589
|
+
const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
|
|
32590
|
+
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32591
|
+
let oldText = "";
|
|
32592
|
+
try {
|
|
32593
|
+
oldText = readFileSync2(resolvedPath, "utf8");
|
|
32594
|
+
} catch (e) {
|
|
32595
|
+
if (e.code !== "ENOENT") throw e;
|
|
32596
|
+
}
|
|
32597
|
+
mkdirSync2(dirname2(resolvedPath), { recursive: true });
|
|
32598
|
+
writeFileSync2(resolvedPath, newText, "utf8");
|
|
32599
|
+
const displayPath = toDisplayPathRelativeToCwd(ctx.cwd, resolvedPath);
|
|
32600
|
+
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
32601
|
+
ctx.onFileChange?.({ path: displayPath, oldText, newText, patchContent });
|
|
32602
|
+
return {};
|
|
32603
|
+
}
|
|
32604
|
+
|
|
32605
|
+
// src/agents/acp/claude-acp-permission-from-session.ts
|
|
32606
|
+
function flattenSelectOptions(options) {
|
|
32607
|
+
if (options == null || options.length === 0) return [];
|
|
32608
|
+
const first2 = options[0];
|
|
32609
|
+
if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
|
|
32610
|
+
return options.flatMap(
|
|
32611
|
+
(g) => Array.isArray(g.options) ? g.options : []
|
|
32612
|
+
);
|
|
32613
|
+
}
|
|
32614
|
+
return options;
|
|
32615
|
+
}
|
|
32616
|
+
function pickModeConfigOption(configOptions) {
|
|
32617
|
+
if (configOptions == null || configOptions.length === 0) return null;
|
|
32618
|
+
const byCategory = configOptions.find((o) => o.category === "mode");
|
|
32619
|
+
if (byCategory) return byCategory;
|
|
32620
|
+
return configOptions.find((o) => o.id === "mode") ?? null;
|
|
32621
|
+
}
|
|
32622
|
+
async function applyClaudePermissionFromAcpSession(params) {
|
|
32623
|
+
const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
|
|
32624
|
+
const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
|
|
32625
|
+
if (desiredMode == null) return;
|
|
32626
|
+
const modeOpt = pickModeConfigOption(configOptions ?? null);
|
|
32627
|
+
if (modeOpt != null) {
|
|
32628
|
+
const flat = flattenSelectOptions(modeOpt.options);
|
|
32629
|
+
const allowed = flat.some((o) => o.value === desiredMode);
|
|
32630
|
+
if (allowed && modeOpt.currentValue !== desiredMode) {
|
|
32631
|
+
try {
|
|
32632
|
+
logDebug2(
|
|
32633
|
+
`[Agent] Claude Code: sending ACP session/set_config_option (permission mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
|
|
32634
|
+
);
|
|
32635
|
+
await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
|
|
32636
|
+
} catch (e) {
|
|
32637
|
+
logDebug2(
|
|
32638
|
+
`[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
|
|
32639
|
+
);
|
|
32640
|
+
}
|
|
32641
|
+
}
|
|
32642
|
+
return;
|
|
32643
|
+
}
|
|
32644
|
+
if (modes?.availableModes?.length) {
|
|
32645
|
+
const allowed = modes.availableModes.some((m) => m.id === desiredMode);
|
|
32646
|
+
if (allowed && desiredMode !== modes.currentModeId) {
|
|
32647
|
+
try {
|
|
32648
|
+
logDebug2(
|
|
32649
|
+
`[Agent] Claude Code: sending ACP session/set_mode (permission mode) modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
|
|
32650
|
+
);
|
|
32651
|
+
await setSessionMode({ sessionId, modeId: desiredMode });
|
|
32652
|
+
} catch (e) {
|
|
32653
|
+
logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
32654
|
+
}
|
|
32655
|
+
}
|
|
32656
|
+
}
|
|
32657
|
+
}
|
|
32658
|
+
|
|
32659
|
+
// src/agents/acp/clients/shared/config-options-for-permission.ts
|
|
32660
|
+
function configOptionsForPermission(getActive, established) {
|
|
32661
|
+
const mem = getActive?.();
|
|
32662
|
+
if (Array.isArray(mem) && mem.length > 0) return mem;
|
|
32663
|
+
return established ?? void 0;
|
|
32664
|
+
}
|
|
32665
|
+
|
|
32666
|
+
// src/agents/acp/clients/shared/establish-acp-session.ts
|
|
32667
|
+
function establishedFromResult(raw, sessionId) {
|
|
32668
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
32669
|
+
return {
|
|
32670
|
+
sessionId,
|
|
32671
|
+
configOptions: Array.isArray(r.configOptions) ? r.configOptions : null,
|
|
32672
|
+
modes: r.modes ?? null
|
|
32673
|
+
};
|
|
32674
|
+
}
|
|
32675
|
+
function sessionIdFromNewSessionResult(raw) {
|
|
32676
|
+
const r = raw && typeof raw === "object" ? raw : {};
|
|
32677
|
+
return typeof r.sessionId === "string" ? r.sessionId : "";
|
|
32678
|
+
}
|
|
32679
|
+
async function establishAcpSessionWithTransport(transport, ctx, canResume, canLoad) {
|
|
32680
|
+
const { cwd, mcpServers, persistedAcpSessionId, agentLabel, suppressLoadReplay } = ctx;
|
|
32681
|
+
const prev = typeof persistedAcpSessionId === "string" && persistedAcpSessionId.trim() !== "" ? persistedAcpSessionId.trim() : "";
|
|
32682
|
+
if (prev) {
|
|
32683
|
+
if (canResume) {
|
|
32684
|
+
try {
|
|
32685
|
+
logDebug(`[Agent] ${agentLabel} ACP session/resume for stored session ${prev.slice(0, 8)}\u2026`);
|
|
32686
|
+
const result2 = await transport.resumeSession({ sessionId: prev, cwd, mcpServers });
|
|
32687
|
+
return establishedFromResult(result2, prev);
|
|
32688
|
+
} catch (e) {
|
|
32689
|
+
logDebug(`[Agent] ${agentLabel} ACP session/resume failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
32690
|
+
}
|
|
32691
|
+
}
|
|
32692
|
+
if (canLoad) {
|
|
32693
|
+
suppressLoadReplay.value = true;
|
|
32694
|
+
try {
|
|
32695
|
+
logDebug(`[Agent] ${agentLabel} ACP session/load for stored session ${prev.slice(0, 8)}\u2026`);
|
|
32696
|
+
const result2 = await transport.loadSession({ sessionId: prev, cwd, mcpServers });
|
|
32697
|
+
return establishedFromResult(result2, prev);
|
|
32698
|
+
} catch (e) {
|
|
32699
|
+
logDebug(`[Agent] ${agentLabel} ACP session/load failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
32700
|
+
} finally {
|
|
32701
|
+
suppressLoadReplay.value = false;
|
|
32702
|
+
}
|
|
32703
|
+
}
|
|
32704
|
+
}
|
|
32705
|
+
const result = await transport.newSession({ cwd, mcpServers });
|
|
32706
|
+
const sid = sessionIdFromNewSessionResult(result);
|
|
32707
|
+
if (!sid) throw new Error(`${agentLabel} ACP session/new did not return sessionId`);
|
|
32708
|
+
return establishedFromResult(result, sid);
|
|
32709
|
+
}
|
|
32710
|
+
|
|
32711
|
+
// src/agents/acp/clients/shared/parse-acp-init-capabilities.ts
|
|
32712
|
+
function parseAcpInitAgentCapabilities(initResult) {
|
|
32713
|
+
const agentCapabilities = initResult?.agentCapabilities;
|
|
32714
|
+
const canLoad = agentCapabilities?.loadSession === true;
|
|
32715
|
+
const sessionCaps = agentCapabilities?.sessionCapabilities;
|
|
32716
|
+
const canResume = Boolean(sessionCaps?.resume);
|
|
32717
|
+
return { canResume, canLoad };
|
|
32718
|
+
}
|
|
32719
|
+
|
|
32720
|
+
// src/agents/acp/clients/shared/bootstrap-acp-wire-session.ts
|
|
32721
|
+
async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
|
|
32722
|
+
const initResult = await transport.initialize(initializeRequest);
|
|
32723
|
+
const { canResume, canLoad } = parseAcpInitAgentCapabilities(initResult);
|
|
32724
|
+
await transport.afterInitialize?.();
|
|
32725
|
+
const established = await establishAcpSessionWithTransport(transport, ctx, canResume, canLoad);
|
|
32726
|
+
const sessionId = established.sessionId;
|
|
32727
|
+
ctx.onAcpSessionEstablished?.({
|
|
32728
|
+
acpSessionId: sessionId,
|
|
32729
|
+
configOptions: established.configOptions,
|
|
32730
|
+
modes: established.modes
|
|
32731
|
+
});
|
|
32732
|
+
if (ctx.backendAgentType === "claude-code") {
|
|
32733
|
+
const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
|
|
32734
|
+
const configOptionsTyped = established.configOptions;
|
|
32735
|
+
const modesTyped = established.modes;
|
|
32736
|
+
await applyClaudePermissionFromAcpSession({
|
|
32737
|
+
sessionId,
|
|
32738
|
+
agentConfig: cfg,
|
|
32739
|
+
configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
|
|
32740
|
+
modes: modesTyped,
|
|
32741
|
+
setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
|
|
32742
|
+
},
|
|
32743
|
+
setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
|
|
32744
|
+
},
|
|
32745
|
+
logDebug: ctx.logDebug
|
|
32746
|
+
});
|
|
32747
|
+
}
|
|
32748
|
+
return established;
|
|
32749
|
+
}
|
|
32750
|
+
|
|
32751
|
+
// src/agents/acp/clients/shared/dispatch-session-update.ts
|
|
32752
|
+
function dispatchAcpSessionUpdate(opts) {
|
|
32753
|
+
const { flatPayload, onAcpConfigOptionsUpdated, onSessionUpdate, suppressLoadReplay } = opts;
|
|
32754
|
+
const su = flatPayload.sessionUpdate ?? flatPayload.session_update;
|
|
32755
|
+
if (su === "config_option_update") {
|
|
32756
|
+
const co = flatPayload.configOptions;
|
|
32757
|
+
if (Array.isArray(co)) onAcpConfigOptionsUpdated?.(co);
|
|
32758
|
+
return;
|
|
32759
|
+
}
|
|
32760
|
+
if (suppressLoadReplay()) return;
|
|
32761
|
+
onSessionUpdate?.(flatPayload);
|
|
32762
|
+
}
|
|
32763
|
+
|
|
32764
|
+
// src/agents/acp/clients/shared/flatten-sdk-session-notification.ts
|
|
32765
|
+
function flattenSdkSessionNotificationParams(params) {
|
|
32503
32766
|
return { sessionId: params.sessionId, ...params.update };
|
|
32504
32767
|
}
|
|
32768
|
+
|
|
32769
|
+
// src/agents/acp/clients/shared/normalize-acp-prompt-result.ts
|
|
32770
|
+
function normalizeAcpPromptTurnSuccess(opts) {
|
|
32771
|
+
const { stopReason, output, stderrCaptureText, backendAgentType } = opts;
|
|
32772
|
+
const mergedOutput = output || void 0;
|
|
32773
|
+
const stop = (stopReason ?? "").toLowerCase();
|
|
32774
|
+
const cancelled = stop === "cancelled";
|
|
32775
|
+
const refusal = stop === "refusal";
|
|
32776
|
+
const stderrEvaluated = Boolean(stderrCaptureText && backendAgentType);
|
|
32777
|
+
const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(backendAgentType, stderrCaptureText) : false;
|
|
32778
|
+
if (cancelled) {
|
|
32779
|
+
return {
|
|
32780
|
+
success: false,
|
|
32781
|
+
stopReason,
|
|
32782
|
+
output: mergedOutput,
|
|
32783
|
+
error: mergeErrorWithStderr("Stopped by user", stderrCaptureText)
|
|
32784
|
+
};
|
|
32785
|
+
}
|
|
32786
|
+
if (refusal) {
|
|
32787
|
+
return {
|
|
32788
|
+
success: false,
|
|
32789
|
+
stopReason,
|
|
32790
|
+
output: mergedOutput,
|
|
32791
|
+
error: mergeErrorWithStderr("The agent refused the request.", stderrCaptureText)
|
|
32792
|
+
};
|
|
32793
|
+
}
|
|
32794
|
+
if (stderrSuggestsAuth) {
|
|
32795
|
+
return {
|
|
32796
|
+
success: false,
|
|
32797
|
+
stopReason,
|
|
32798
|
+
output: mergedOutput,
|
|
32799
|
+
error: stderrCaptureText
|
|
32800
|
+
};
|
|
32801
|
+
}
|
|
32802
|
+
return {
|
|
32803
|
+
success: true,
|
|
32804
|
+
stopReason,
|
|
32805
|
+
output: mergedOutput
|
|
32806
|
+
};
|
|
32807
|
+
}
|
|
32808
|
+
function normalizeAcpPromptTurnFailure(err, stderrCaptureText) {
|
|
32809
|
+
const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCaptureText);
|
|
32810
|
+
return { success: false, error: merged };
|
|
32811
|
+
}
|
|
32812
|
+
|
|
32813
|
+
// src/agents/acp/clients/shared/send-acp-prompt-via-transport.ts
|
|
32814
|
+
async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText) {
|
|
32815
|
+
try {
|
|
32816
|
+
const response = await transport.prompt({
|
|
32817
|
+
sessionId,
|
|
32818
|
+
prompt: [{ type: "text", text: promptText }]
|
|
32819
|
+
});
|
|
32820
|
+
await new Promise((r2) => setImmediate(r2));
|
|
32821
|
+
const r = response;
|
|
32822
|
+
return normalizeAcpPromptTurnSuccess({
|
|
32823
|
+
stopReason: r?.stopReason,
|
|
32824
|
+
output: r?.output,
|
|
32825
|
+
stderrCaptureText: ctx.getStderrText(),
|
|
32826
|
+
backendAgentType: ctx.backendAgentType
|
|
32827
|
+
});
|
|
32828
|
+
} catch (err) {
|
|
32829
|
+
await new Promise((r) => setImmediate(r));
|
|
32830
|
+
return normalizeAcpPromptTurnFailure(err, ctx.getStderrText());
|
|
32831
|
+
}
|
|
32832
|
+
}
|
|
32833
|
+
|
|
32834
|
+
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
32835
|
+
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
32836
|
+
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
32837
|
+
return new Promise((resolve18) => {
|
|
32838
|
+
pending.set(requestId, { resolve: resolve18, params: paramsRecord });
|
|
32839
|
+
try {
|
|
32840
|
+
onRequest?.({
|
|
32841
|
+
requestId,
|
|
32842
|
+
method: "session/request_permission",
|
|
32843
|
+
params: paramsRecord
|
|
32844
|
+
});
|
|
32845
|
+
} catch {
|
|
32846
|
+
}
|
|
32847
|
+
});
|
|
32848
|
+
}
|
|
32849
|
+
|
|
32850
|
+
// src/agents/acp/clients/sdk/sdk-acp-session-transport.ts
|
|
32851
|
+
function createSdkAcpSessionTransport(connection) {
|
|
32852
|
+
const c = connection;
|
|
32853
|
+
return {
|
|
32854
|
+
initialize: (request) => c.initialize(request),
|
|
32855
|
+
resumeSession: (p) => c.unstable_resumeSession(p),
|
|
32856
|
+
loadSession: (p) => c.loadSession(p),
|
|
32857
|
+
newSession: (p) => c.newSession(p),
|
|
32858
|
+
prompt: (p) => c.prompt(p),
|
|
32859
|
+
cancelSession: async (sessionId) => {
|
|
32860
|
+
await c.cancel({ sessionId });
|
|
32861
|
+
},
|
|
32862
|
+
setSessionConfigOption: c.setSessionConfigOption ? (p) => c.setSessionConfigOption(p) : void 0,
|
|
32863
|
+
setSessionMode: c.setSessionMode ? (p) => c.setSessionMode(p) : void 0
|
|
32864
|
+
};
|
|
32865
|
+
}
|
|
32866
|
+
|
|
32867
|
+
// src/agents/acp/clients/sdk/sdk-stdio-acp-client.ts
|
|
32868
|
+
function formatSpawnError(err, command) {
|
|
32869
|
+
if (err.code === "ENOENT") {
|
|
32870
|
+
return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
|
|
32871
|
+
}
|
|
32872
|
+
return err.message || String(err);
|
|
32873
|
+
}
|
|
32505
32874
|
async function createSdkStdioAcpClient(options) {
|
|
32506
32875
|
const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
|
|
32507
32876
|
const {
|
|
@@ -32513,7 +32882,11 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32513
32882
|
onFileChange,
|
|
32514
32883
|
killSubprocessAfterCancelMs,
|
|
32515
32884
|
onAgentSubprocessExit,
|
|
32516
|
-
agentConfig
|
|
32885
|
+
agentConfig,
|
|
32886
|
+
persistedAcpSessionId,
|
|
32887
|
+
onAcpSessionEstablished,
|
|
32888
|
+
onAcpConfigOptionsUpdated,
|
|
32889
|
+
getActiveConfigOptions
|
|
32517
32890
|
} = options;
|
|
32518
32891
|
const isWindows = process.platform === "win32";
|
|
32519
32892
|
const child = spawn2(command[0], command.slice(1), {
|
|
@@ -32562,54 +32935,49 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32562
32935
|
backendAgentType,
|
|
32563
32936
|
onSessionUpdate
|
|
32564
32937
|
});
|
|
32938
|
+
const suppressLoadReplayRef = { value: false };
|
|
32939
|
+
const sessionCtx = {
|
|
32940
|
+
cwd,
|
|
32941
|
+
onFileChange,
|
|
32942
|
+
mcpServers: [],
|
|
32943
|
+
persistedAcpSessionId,
|
|
32944
|
+
agentLabel: "ACP",
|
|
32945
|
+
suppressLoadReplay: suppressLoadReplayRef,
|
|
32946
|
+
backendAgentType: backendAgentType ?? null,
|
|
32947
|
+
agentConfig,
|
|
32948
|
+
getActiveConfigOptions,
|
|
32949
|
+
onAcpSessionEstablished,
|
|
32950
|
+
onAcpConfigOptionsUpdated,
|
|
32951
|
+
logDebug,
|
|
32952
|
+
getStderrText: () => stderrCapture.getText()
|
|
32953
|
+
};
|
|
32565
32954
|
let permissionSeq = 0;
|
|
32566
32955
|
const pendingPermissionReplies = /* @__PURE__ */ new Map();
|
|
32567
32956
|
const client = (_agent) => ({
|
|
32568
32957
|
async requestPermission(params) {
|
|
32569
32958
|
const requestId = `perm-${++permissionSeq}`;
|
|
32570
32959
|
const paramsRecord = params != null && typeof params === "object" ? params : {};
|
|
32571
|
-
|
|
32572
|
-
|
|
32573
|
-
|
|
32574
|
-
|
|
32575
|
-
|
|
32576
|
-
});
|
|
32577
|
-
} catch {
|
|
32578
|
-
}
|
|
32579
|
-
return await new Promise((resolve19) => {
|
|
32580
|
-
pendingPermissionReplies.set(requestId, { resolve: resolve19, params: paramsRecord });
|
|
32960
|
+
return await awaitSdkStdioPermissionRequestHandshake({
|
|
32961
|
+
requestId,
|
|
32962
|
+
paramsRecord,
|
|
32963
|
+
pending: pendingPermissionReplies,
|
|
32964
|
+
onRequest
|
|
32581
32965
|
});
|
|
32582
32966
|
},
|
|
32583
32967
|
async readTextFile(params) {
|
|
32584
|
-
|
|
32585
|
-
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32586
|
-
try {
|
|
32587
|
-
let content = readFileSync2(resolvedPath, "utf8");
|
|
32588
|
-
content = sliceFileContentRange(content, params.line, params.limit);
|
|
32589
|
-
return { content };
|
|
32590
|
-
} catch (e) {
|
|
32591
|
-
if (e.code === "ENOENT") return { content: "" };
|
|
32592
|
-
throw e;
|
|
32593
|
-
}
|
|
32968
|
+
return acpReadTextFileInProcess(sessionCtx, params.path, params.line, params.limit);
|
|
32594
32969
|
},
|
|
32595
32970
|
async writeTextFile(params) {
|
|
32596
|
-
|
|
32597
|
-
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32598
|
-
let oldText = "";
|
|
32599
|
-
try {
|
|
32600
|
-
oldText = readFileSync2(resolvedPath, "utf8");
|
|
32601
|
-
} catch (e) {
|
|
32602
|
-
if (e.code !== "ENOENT") throw e;
|
|
32603
|
-
}
|
|
32604
|
-
mkdirSync2(dirname2(resolvedPath), { recursive: true });
|
|
32605
|
-
writeFileSync2(resolvedPath, params.content, "utf8");
|
|
32606
|
-
const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
|
|
32607
|
-
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, params.content);
|
|
32608
|
-
onFileChange?.({ path: displayPath, oldText, newText: params.content, patchContent });
|
|
32609
|
-
return {};
|
|
32971
|
+
return acpWriteTextFileInProcess(sessionCtx, params.path, params.content);
|
|
32610
32972
|
},
|
|
32611
32973
|
async sessionUpdate(params) {
|
|
32612
|
-
|
|
32974
|
+
const bridged = flattenSdkSessionNotificationParams(params);
|
|
32975
|
+
dispatchAcpSessionUpdate({
|
|
32976
|
+
flatPayload: bridged,
|
|
32977
|
+
onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
|
|
32978
|
+
onSessionUpdate,
|
|
32979
|
+
suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
|
|
32980
|
+
});
|
|
32613
32981
|
},
|
|
32614
32982
|
async extNotification(method, params) {
|
|
32615
32983
|
await extNotification(method, params);
|
|
@@ -32619,84 +32987,19 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32619
32987
|
connection.signal.addEventListener("abort", () => {
|
|
32620
32988
|
child.kill();
|
|
32621
32989
|
});
|
|
32622
|
-
|
|
32990
|
+
const transport = createSdkAcpSessionTransport(connection);
|
|
32991
|
+
const established = await bootstrapAcpWireSession(transport, sessionCtx, {
|
|
32623
32992
|
protocolVersion: PROTOCOL_VERSION2,
|
|
32624
32993
|
clientCapabilities: {
|
|
32625
32994
|
fs: { readTextFile: true, writeTextFile: true }
|
|
32626
32995
|
},
|
|
32627
32996
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
32628
32997
|
});
|
|
32629
|
-
const
|
|
32630
|
-
const sessionId = newSessionRes.sessionId;
|
|
32631
|
-
if (backendAgentType === "claude-code") {
|
|
32632
|
-
const cfg = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
|
|
32633
|
-
const desiredMode = getClaudePermissionModeFromAgentConfig(cfg);
|
|
32634
|
-
const modes = newSessionRes.modes;
|
|
32635
|
-
if (desiredMode != null && modes?.availableModes?.length) {
|
|
32636
|
-
const allowed = modes.availableModes.some((m) => m.id === desiredMode);
|
|
32637
|
-
if (allowed && desiredMode !== modes.currentModeId) {
|
|
32638
|
-
try {
|
|
32639
|
-
await connection.setSessionMode({ sessionId, modeId: desiredMode });
|
|
32640
|
-
} catch {
|
|
32641
|
-
}
|
|
32642
|
-
}
|
|
32643
|
-
}
|
|
32644
|
-
}
|
|
32998
|
+
const sessionId = established.sessionId;
|
|
32645
32999
|
settleResolve({
|
|
32646
33000
|
sessionId,
|
|
32647
33001
|
async sendPrompt(prompt, _options) {
|
|
32648
|
-
|
|
32649
|
-
const response = await connection.prompt({
|
|
32650
|
-
sessionId,
|
|
32651
|
-
prompt: [{ type: "text", text: prompt }]
|
|
32652
|
-
});
|
|
32653
|
-
await new Promise((r2) => setImmediate(r2));
|
|
32654
|
-
const r = response;
|
|
32655
|
-
const stopReason = (r?.stopReason ?? "").toLowerCase();
|
|
32656
|
-
const cancelled = stopReason === "cancelled";
|
|
32657
|
-
const refusal = stopReason === "refusal";
|
|
32658
|
-
const stderrAfter = stderrCapture.getText();
|
|
32659
|
-
const agentType = backendAgentType ?? null;
|
|
32660
|
-
const stderrEvaluated = Boolean(stderrAfter && agentType);
|
|
32661
|
-
const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
|
|
32662
|
-
if (cancelled) {
|
|
32663
|
-
return {
|
|
32664
|
-
success: false,
|
|
32665
|
-
stopReason: r?.stopReason,
|
|
32666
|
-
output: r?.output,
|
|
32667
|
-
error: mergeErrorWithStderr("Stopped by user", stderrAfter)
|
|
32668
|
-
};
|
|
32669
|
-
}
|
|
32670
|
-
if (refusal) {
|
|
32671
|
-
return {
|
|
32672
|
-
success: false,
|
|
32673
|
-
stopReason: r?.stopReason,
|
|
32674
|
-
output: r?.output,
|
|
32675
|
-
error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
|
|
32676
|
-
};
|
|
32677
|
-
}
|
|
32678
|
-
if (stderrSuggestsAuth) {
|
|
32679
|
-
return {
|
|
32680
|
-
success: false,
|
|
32681
|
-
stopReason: r?.stopReason,
|
|
32682
|
-
output: r?.output,
|
|
32683
|
-
error: stderrAfter
|
|
32684
|
-
};
|
|
32685
|
-
}
|
|
32686
|
-
return {
|
|
32687
|
-
success: true,
|
|
32688
|
-
stopReason: r?.stopReason,
|
|
32689
|
-
output: r?.output
|
|
32690
|
-
};
|
|
32691
|
-
} catch (err) {
|
|
32692
|
-
await new Promise((r) => setImmediate(r));
|
|
32693
|
-
const stderrAfter = stderrCapture.getText();
|
|
32694
|
-
const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
|
|
32695
|
-
return {
|
|
32696
|
-
success: false,
|
|
32697
|
-
error: merged
|
|
32698
|
-
};
|
|
32699
|
-
}
|
|
33002
|
+
return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
|
|
32700
33003
|
},
|
|
32701
33004
|
async cancel() {
|
|
32702
33005
|
for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
|
|
@@ -32704,7 +33007,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32704
33007
|
entry.resolve({ outcome: { outcome: "cancelled" } });
|
|
32705
33008
|
}
|
|
32706
33009
|
try {
|
|
32707
|
-
await
|
|
33010
|
+
await transport.cancelSession(sessionId);
|
|
32708
33011
|
} catch {
|
|
32709
33012
|
}
|
|
32710
33013
|
if (killSubprocessAfterCancelMs != null && killSubprocessAfterCancelMs >= 0) {
|
|
@@ -32795,7 +33098,7 @@ async function createCodexAcpClient(options) {
|
|
|
32795
33098
|
return createSdkStdioAcpClient({ ...options, command });
|
|
32796
33099
|
}
|
|
32797
33100
|
|
|
32798
|
-
// src/agents/acp/clients/cursor-acp-client.ts
|
|
33101
|
+
// src/agents/acp/clients/cursor/cursor-acp-client.ts
|
|
32799
33102
|
var cursor_acp_client_exports = {};
|
|
32800
33103
|
__export(cursor_acp_client_exports, {
|
|
32801
33104
|
BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
|
|
@@ -32803,8 +33106,6 @@ __export(cursor_acp_client_exports, {
|
|
|
32803
33106
|
createCursorAcpClient: () => createCursorAcpClient,
|
|
32804
33107
|
detectLocalAgentPresence: () => detectLocalAgentPresence3
|
|
32805
33108
|
});
|
|
32806
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
|
|
32807
|
-
import { dirname as dirname3 } from "node:path";
|
|
32808
33109
|
import { spawn as spawn3 } from "node:child_process";
|
|
32809
33110
|
import * as readline from "node:readline";
|
|
32810
33111
|
|
|
@@ -32821,7 +33122,23 @@ function formatSessionUpdateKindForLog(kind) {
|
|
|
32821
33122
|
return kind.split("_").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
|
|
32822
33123
|
}
|
|
32823
33124
|
|
|
32824
|
-
// src/agents/acp/clients/cursor-acp-
|
|
33125
|
+
// src/agents/acp/clients/cursor/cursor-json-rpc-acp-transport.ts
|
|
33126
|
+
function createCursorJsonRpcAcpTransport(deps) {
|
|
33127
|
+
const { send, cancelSessionNotification } = deps;
|
|
33128
|
+
return {
|
|
33129
|
+
initialize: (request) => send("initialize", request),
|
|
33130
|
+
afterInitialize: async () => {
|
|
33131
|
+
await send("authenticate", { methodId: "cursor_login" });
|
|
33132
|
+
},
|
|
33133
|
+
resumeSession: (p) => send("session/resume", p),
|
|
33134
|
+
loadSession: (p) => send("session/load", p),
|
|
33135
|
+
newSession: (p) => send("session/new", p),
|
|
33136
|
+
prompt: (p) => send("session/prompt", p),
|
|
33137
|
+
cancelSession: (sessionId) => cancelSessionNotification(sessionId)
|
|
33138
|
+
};
|
|
33139
|
+
}
|
|
33140
|
+
|
|
33141
|
+
// src/agents/acp/clients/cursor/cursor-acp-client.ts
|
|
32825
33142
|
var FS_READ_METHODS = /* @__PURE__ */ new Set(["fs/read_text_file", "fs/readTextFile"]);
|
|
32826
33143
|
var FS_WRITE_METHODS = /* @__PURE__ */ new Set(["fs/write_text_file", "fs/writeTextFile"]);
|
|
32827
33144
|
function formatSpawnError2(err, command) {
|
|
@@ -32838,13 +33155,6 @@ function safeJsonParse(value) {
|
|
|
32838
33155
|
return null;
|
|
32839
33156
|
}
|
|
32840
33157
|
}
|
|
32841
|
-
function sliceLinesByRange(content, line, limit) {
|
|
32842
|
-
if (line == null && limit == null) return content;
|
|
32843
|
-
const lines = content.split("\n");
|
|
32844
|
-
const start = line != null && line > 0 ? line - 1 : 0;
|
|
32845
|
-
const end = limit != null && limit > 0 ? start + limit : lines.length;
|
|
32846
|
-
return lines.slice(start, end).join("\n");
|
|
32847
|
-
}
|
|
32848
33158
|
function buildCursorAcpSpawnCommand(base, sessionMode) {
|
|
32849
33159
|
if (!sessionMode) return [...base];
|
|
32850
33160
|
const m = sessionMode.trim();
|
|
@@ -32858,7 +33168,11 @@ async function createCursorAcpClient(options) {
|
|
|
32858
33168
|
backendAgentType,
|
|
32859
33169
|
onSessionUpdate,
|
|
32860
33170
|
onRequest,
|
|
32861
|
-
onFileChange
|
|
33171
|
+
onFileChange,
|
|
33172
|
+
persistedAcpSessionId,
|
|
33173
|
+
onAcpSessionEstablished,
|
|
33174
|
+
onAcpConfigOptionsUpdated,
|
|
33175
|
+
onAgentSubprocessExit
|
|
32862
33176
|
} = options;
|
|
32863
33177
|
const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
|
|
32864
33178
|
const isWindows = process.platform === "win32";
|
|
@@ -32870,6 +33184,25 @@ async function createCursorAcpClient(options) {
|
|
|
32870
33184
|
});
|
|
32871
33185
|
const stderrCapture = createStderrCapture(child);
|
|
32872
33186
|
child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
|
|
33187
|
+
child.once("close", (code, signal) => {
|
|
33188
|
+
onAgentSubprocessExit?.({ code, signal });
|
|
33189
|
+
});
|
|
33190
|
+
const suppressLoadReplayRef = { value: false };
|
|
33191
|
+
const sessionCtx = {
|
|
33192
|
+
cwd,
|
|
33193
|
+
onFileChange,
|
|
33194
|
+
mcpServers: [],
|
|
33195
|
+
persistedAcpSessionId,
|
|
33196
|
+
agentLabel: "Cursor",
|
|
33197
|
+
suppressLoadReplay: suppressLoadReplayRef,
|
|
33198
|
+
backendAgentType: backendAgentType ?? null,
|
|
33199
|
+
agentConfig: options.agentConfig,
|
|
33200
|
+
getActiveConfigOptions: options.getActiveConfigOptions,
|
|
33201
|
+
onAcpSessionEstablished,
|
|
33202
|
+
onAcpConfigOptionsUpdated,
|
|
33203
|
+
logDebug,
|
|
33204
|
+
getStderrText: () => stderrCapture.getText()
|
|
33205
|
+
};
|
|
32873
33206
|
return new Promise((resolve18, reject) => {
|
|
32874
33207
|
child.on("error", (err) => {
|
|
32875
33208
|
child.kill();
|
|
@@ -32878,6 +33211,16 @@ async function createCursorAcpClient(options) {
|
|
|
32878
33211
|
let nextId = 1;
|
|
32879
33212
|
const pending = /* @__PURE__ */ new Map();
|
|
32880
33213
|
const pendingRequests = /* @__PURE__ */ new Map();
|
|
33214
|
+
function cancelSessionNotification(sessionId) {
|
|
33215
|
+
const line = JSON.stringify({
|
|
33216
|
+
jsonrpc: "2.0",
|
|
33217
|
+
method: "session/cancel",
|
|
33218
|
+
params: { sessionId }
|
|
33219
|
+
}) + "\n";
|
|
33220
|
+
return new Promise((res, rej) => {
|
|
33221
|
+
child.stdin.write(line, (err) => err ? rej(err) : res());
|
|
33222
|
+
});
|
|
33223
|
+
}
|
|
32881
33224
|
function send(method, params) {
|
|
32882
33225
|
const id = nextId++;
|
|
32883
33226
|
const line = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
|
|
@@ -32901,7 +33244,6 @@ async function createCursorAcpClient(options) {
|
|
|
32901
33244
|
respond(requestId, payload);
|
|
32902
33245
|
pendingRequests.delete(requestId);
|
|
32903
33246
|
}
|
|
32904
|
-
let promptOutputBuffer = "";
|
|
32905
33247
|
const rl = readline.createInterface({ input: child.stdout });
|
|
32906
33248
|
rl.on("line", (line) => {
|
|
32907
33249
|
const msg = safeJsonParse(line);
|
|
@@ -32930,11 +33272,12 @@ async function createCursorAcpClient(options) {
|
|
|
32930
33272
|
`[acp] Received session update (${kindLabel}) tool=${toolName || "(none)"}`
|
|
32931
33273
|
);
|
|
32932
33274
|
}
|
|
32933
|
-
|
|
32934
|
-
|
|
32935
|
-
|
|
32936
|
-
|
|
32937
|
-
|
|
33275
|
+
dispatchAcpSessionUpdate({
|
|
33276
|
+
flatPayload: update,
|
|
33277
|
+
onAcpConfigOptionsUpdated: sessionCtx.onAcpConfigOptionsUpdated,
|
|
33278
|
+
onSessionUpdate,
|
|
33279
|
+
suppressLoadReplay: () => sessionCtx.suppressLoadReplay.value
|
|
33280
|
+
});
|
|
32938
33281
|
return;
|
|
32939
33282
|
}
|
|
32940
33283
|
if (method === "session/request_permission" && typeof id === "number") {
|
|
@@ -32954,21 +33297,13 @@ async function createCursorAcpClient(options) {
|
|
|
32954
33297
|
if (dbgFs) {
|
|
32955
33298
|
console.error(`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""}`);
|
|
32956
33299
|
}
|
|
32957
|
-
const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
|
|
32958
|
-
if (!resolvedPath) {
|
|
32959
|
-
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty)`);
|
|
32960
|
-
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
32961
|
-
return;
|
|
32962
|
-
}
|
|
32963
33300
|
try {
|
|
32964
|
-
|
|
32965
|
-
const
|
|
32966
|
-
const
|
|
32967
|
-
|
|
32968
|
-
respond(id, { content });
|
|
33301
|
+
const lineNum = typeof params.line === "number" ? params.line : void 0;
|
|
33302
|
+
const limitNum = typeof params.limit === "number" ? params.limit : void 0;
|
|
33303
|
+
const out = acpReadTextFileInProcess(sessionCtx, filePath, lineNum, limitNum);
|
|
33304
|
+
respond(id, out);
|
|
32969
33305
|
} catch (e) {
|
|
32970
|
-
|
|
32971
|
-
if (code === "ENOENT") {
|
|
33306
|
+
if (e?.code === "ENOENT") {
|
|
32972
33307
|
respond(id, { content: "" });
|
|
32973
33308
|
} else {
|
|
32974
33309
|
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
@@ -32985,32 +33320,17 @@ async function createCursorAcpClient(options) {
|
|
|
32985
33320
|
`[acp-fs] ${method} path=${filePath.slice(0, 200)}${filePath.length > 200 ? "\u2026" : ""} newBytes=${newText.length}`
|
|
32986
33321
|
);
|
|
32987
33322
|
}
|
|
32988
|
-
const resolvedPath = resolveSafePathUnderCwd(cwd, filePath);
|
|
32989
|
-
if (!resolvedPath) {
|
|
32990
|
-
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
|
|
32991
|
-
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
32992
|
-
return;
|
|
32993
|
-
}
|
|
32994
|
-
let oldText = "";
|
|
32995
33323
|
try {
|
|
32996
|
-
|
|
33324
|
+
acpWriteTextFileInProcess(sessionCtx, filePath, newText);
|
|
33325
|
+
respond(id, null);
|
|
32997
33326
|
} catch (e) {
|
|
32998
|
-
if (e.
|
|
33327
|
+
if (e.message === "Invalid or disallowed path") {
|
|
33328
|
+
if (dbgFs) console.error(`[acp-fs] ${method} rejected path (outside cwd or empty): ${filePath.slice(0, 120)}`);
|
|
33329
|
+
respondJsonRpcError(id, -32602, "Invalid or disallowed path");
|
|
33330
|
+
} else {
|
|
32999
33331
|
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
33000
|
-
return;
|
|
33001
33332
|
}
|
|
33002
33333
|
}
|
|
33003
|
-
try {
|
|
33004
|
-
mkdirSync3(dirname3(resolvedPath), { recursive: true });
|
|
33005
|
-
writeFileSync3(resolvedPath, newText, "utf8");
|
|
33006
|
-
} catch (e) {
|
|
33007
|
-
respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
|
|
33008
|
-
return;
|
|
33009
|
-
}
|
|
33010
|
-
const displayPath = toDisplayPathRelativeToCwd(cwd, resolvedPath);
|
|
33011
|
-
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
33012
|
-
onFileChange?.({ path: displayPath, oldText, newText, patchContent });
|
|
33013
|
-
respond(id, null);
|
|
33014
33334
|
return;
|
|
33015
33335
|
}
|
|
33016
33336
|
if (method === "cursor/create_plan" || method === "cursor/ask_question") {
|
|
@@ -33032,16 +33352,7 @@ async function createCursorAcpClient(options) {
|
|
|
33032
33352
|
});
|
|
33033
33353
|
(async () => {
|
|
33034
33354
|
try {
|
|
33035
|
-
let
|
|
33036
|
-
const line = JSON.stringify({
|
|
33037
|
-
jsonrpc: "2.0",
|
|
33038
|
-
method: "session/cancel",
|
|
33039
|
-
params: { sessionId }
|
|
33040
|
-
}) + "\n";
|
|
33041
|
-
return new Promise((res, rej) => {
|
|
33042
|
-
child.stdin.write(line, (err) => err ? rej(err) : res());
|
|
33043
|
-
});
|
|
33044
|
-
}, cancelPendingPermissionRequests2 = function() {
|
|
33355
|
+
let cancelPendingPermissionRequests2 = function() {
|
|
33045
33356
|
for (const [reqId, pending2] of [...pendingRequests.entries()]) {
|
|
33046
33357
|
if (pending2.method === "session/request_permission") {
|
|
33047
33358
|
respond(reqId, { outcome: { outcome: "cancelled" } });
|
|
@@ -33049,76 +33360,25 @@ async function createCursorAcpClient(options) {
|
|
|
33049
33360
|
}
|
|
33050
33361
|
}
|
|
33051
33362
|
};
|
|
33052
|
-
var
|
|
33053
|
-
|
|
33363
|
+
var cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
|
|
33364
|
+
const transport = createCursorJsonRpcAcpTransport({
|
|
33365
|
+
send,
|
|
33366
|
+
cancelSessionNotification
|
|
33367
|
+
});
|
|
33368
|
+
const established = await bootstrapAcpWireSession(transport, sessionCtx, {
|
|
33054
33369
|
protocolVersion: 1,
|
|
33055
33370
|
clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: false },
|
|
33056
33371
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
33057
33372
|
});
|
|
33058
|
-
|
|
33059
|
-
const newResult = await send("session/new", { cwd, mcpServers: [] });
|
|
33060
|
-
const sessionId = newResult?.sessionId ?? "";
|
|
33061
|
-
if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
|
|
33373
|
+
const sessionId = established.sessionId;
|
|
33062
33374
|
resolve18({
|
|
33063
33375
|
sessionId,
|
|
33064
33376
|
async sendPrompt(prompt, _options) {
|
|
33065
|
-
|
|
33066
|
-
try {
|
|
33067
|
-
const result = await send("session/prompt", {
|
|
33068
|
-
sessionId,
|
|
33069
|
-
prompt: [{ type: "text", text: prompt }]
|
|
33070
|
-
});
|
|
33071
|
-
await new Promise((r) => setImmediate(r));
|
|
33072
|
-
const output = (result?.output ?? promptOutputBuffer) || void 0;
|
|
33073
|
-
const stopReason = (result?.stopReason ?? "").toLowerCase();
|
|
33074
|
-
const cancelled = stopReason === "cancelled";
|
|
33075
|
-
const refusal = stopReason === "refusal";
|
|
33076
|
-
const stderrAfter = stderrCapture.getText();
|
|
33077
|
-
const agentType = backendAgentType ?? null;
|
|
33078
|
-
const stderrEvaluated = Boolean(stderrAfter && agentType);
|
|
33079
|
-
const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
|
|
33080
|
-
if (cancelled) {
|
|
33081
|
-
return {
|
|
33082
|
-
success: false,
|
|
33083
|
-
stopReason: result?.stopReason,
|
|
33084
|
-
output: output || void 0,
|
|
33085
|
-
error: mergeErrorWithStderr("Stopped by user", stderrAfter)
|
|
33086
|
-
};
|
|
33087
|
-
}
|
|
33088
|
-
if (refusal) {
|
|
33089
|
-
return {
|
|
33090
|
-
success: false,
|
|
33091
|
-
stopReason: result?.stopReason,
|
|
33092
|
-
output: output || void 0,
|
|
33093
|
-
error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
|
|
33094
|
-
};
|
|
33095
|
-
}
|
|
33096
|
-
if (stderrSuggestsAuth) {
|
|
33097
|
-
return {
|
|
33098
|
-
success: false,
|
|
33099
|
-
stopReason: result?.stopReason,
|
|
33100
|
-
output: output || void 0,
|
|
33101
|
-
error: stderrAfter
|
|
33102
|
-
};
|
|
33103
|
-
}
|
|
33104
|
-
return {
|
|
33105
|
-
success: true,
|
|
33106
|
-
stopReason: result?.stopReason,
|
|
33107
|
-
output: output || void 0
|
|
33108
|
-
};
|
|
33109
|
-
} catch (err) {
|
|
33110
|
-
await new Promise((r) => setImmediate(r));
|
|
33111
|
-
const stderrAfter = stderrCapture.getText();
|
|
33112
|
-
const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
|
|
33113
|
-
return {
|
|
33114
|
-
success: false,
|
|
33115
|
-
error: merged
|
|
33116
|
-
};
|
|
33117
|
-
}
|
|
33377
|
+
return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt);
|
|
33118
33378
|
},
|
|
33119
33379
|
async cancel() {
|
|
33120
33380
|
cancelPendingPermissionRequests2();
|
|
33121
|
-
await
|
|
33381
|
+
await transport.cancelSession(sessionId);
|
|
33122
33382
|
},
|
|
33123
33383
|
resolveRequest(requestId, result) {
|
|
33124
33384
|
const numericId = Number(requestId);
|
|
@@ -33266,7 +33526,7 @@ function getGitRepoRootSync(startDir) {
|
|
|
33266
33526
|
|
|
33267
33527
|
// src/agents/acp/workspace-files.ts
|
|
33268
33528
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
33269
|
-
import { readFileSync as
|
|
33529
|
+
import { readFileSync as readFileSync3 } from "node:fs";
|
|
33270
33530
|
import * as path11 from "node:path";
|
|
33271
33531
|
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
33272
33532
|
const trimmed2 = rawPath.trim();
|
|
@@ -33298,7 +33558,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
33298
33558
|
const rel = path11.relative(gitRoot, resolvedPath2);
|
|
33299
33559
|
if (!rel.startsWith("..") && !path11.isAbsolute(rel)) {
|
|
33300
33560
|
try {
|
|
33301
|
-
return
|
|
33561
|
+
return readFileSync3(resolvedPath2, "utf8");
|
|
33302
33562
|
} catch {
|
|
33303
33563
|
}
|
|
33304
33564
|
}
|
|
@@ -33306,7 +33566,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
33306
33566
|
const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
33307
33567
|
if (!resolvedPath) return "";
|
|
33308
33568
|
try {
|
|
33309
|
-
return
|
|
33569
|
+
return readFileSync3(resolvedPath, "utf8");
|
|
33310
33570
|
} catch {
|
|
33311
33571
|
return "";
|
|
33312
33572
|
}
|
|
@@ -33402,7 +33662,7 @@ function createBridgeOnFileChange(opts) {
|
|
|
33402
33662
|
|
|
33403
33663
|
// src/agents/acp/hooks/bridge-on-request.ts
|
|
33404
33664
|
function createBridgeOnRequest(opts) {
|
|
33405
|
-
const { routing, getSendRequest, log: log2 } = opts;
|
|
33665
|
+
const { routing, getSendRequest, log: log2, getAutoApproveAcpPermissions, resolveAcpPermissionRequest } = opts;
|
|
33406
33666
|
return (request) => {
|
|
33407
33667
|
const runId = routing.runId;
|
|
33408
33668
|
const sessionId = routing.sessionId;
|
|
@@ -33410,6 +33670,26 @@ function createBridgeOnRequest(opts) {
|
|
|
33410
33670
|
if (!runId || !sendReq) return;
|
|
33411
33671
|
const kind = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
|
|
33412
33672
|
const sessionUpdate = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
|
|
33673
|
+
if (request.method === "session/request_permission" && getAutoApproveAcpPermissions() && resolveAcpPermissionRequest) {
|
|
33674
|
+
const params = request.params != null && typeof request.params === "object" && !Array.isArray(request.params) ? request.params : {};
|
|
33675
|
+
const auto = buildCliAutoApprovedPermissionRpcResult(params);
|
|
33676
|
+
if (auto != null) {
|
|
33677
|
+
try {
|
|
33678
|
+
resolveAcpPermissionRequest(request.requestId, auto);
|
|
33679
|
+
log2(
|
|
33680
|
+
`[Bridge service] CLI dangerous mode: auto-approved permission requestId=${request.requestId} runId=${runId}`
|
|
33681
|
+
);
|
|
33682
|
+
return;
|
|
33683
|
+
} catch (err) {
|
|
33684
|
+
log2(
|
|
33685
|
+
`[Bridge service] CLI dangerous mode: auto-approve failed (${errorMessage(err)}); forwarding permission`
|
|
33686
|
+
);
|
|
33687
|
+
}
|
|
33688
|
+
}
|
|
33689
|
+
log2(
|
|
33690
|
+
`[Bridge service] CLI dangerous mode: no allow option to auto-select; forwarding permission requestId=${request.requestId}`
|
|
33691
|
+
);
|
|
33692
|
+
}
|
|
33413
33693
|
try {
|
|
33414
33694
|
sendReq({
|
|
33415
33695
|
type: "session_update",
|
|
@@ -33810,6 +34090,9 @@ function createBridgeOnSessionUpdate(opts) {
|
|
|
33810
34090
|
const sentFileChangePaths = /* @__PURE__ */ new Set();
|
|
33811
34091
|
const p = params;
|
|
33812
34092
|
const updateKind = p.sessionUpdate ?? p.session_update ?? p.type ?? "update";
|
|
34093
|
+
if (updateKind === "config_option_update") {
|
|
34094
|
+
return;
|
|
34095
|
+
}
|
|
33813
34096
|
const isCompletedToolCallUpdate = updateKind === "tool_call_update" && isCompletedToolStatus(p.status);
|
|
33814
34097
|
const toolName = p.toolCall?.name ?? p.tool_call?.name ?? "";
|
|
33815
34098
|
const isToolUpdate = updateKind === "tool_call" || updateKind === "tool_call_update" || typeof toolName === "string" && toolName.length > 0;
|
|
@@ -33896,14 +34179,73 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
33896
34179
|
};
|
|
33897
34180
|
}
|
|
33898
34181
|
|
|
34182
|
+
// src/agents/acp/local-agent-session-file.ts
|
|
34183
|
+
import fs10 from "node:fs";
|
|
34184
|
+
import os3 from "node:os";
|
|
34185
|
+
import path12 from "node:path";
|
|
34186
|
+
var LOCAL_AGENT_SESSION_DIR = path12.join(os3.homedir(), ".buildautomaton", "agent-sessions");
|
|
34187
|
+
function safeFileSlug(cloudSessionId) {
|
|
34188
|
+
const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
|
|
34189
|
+
return t.length > 0 ? t : "session";
|
|
34190
|
+
}
|
|
34191
|
+
function localAgentSessionFilePath(cloudSessionId) {
|
|
34192
|
+
return path12.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
|
|
34193
|
+
}
|
|
34194
|
+
function readLocalAgentSessionFile(cloudSessionId) {
|
|
34195
|
+
try {
|
|
34196
|
+
const p = localAgentSessionFilePath(cloudSessionId);
|
|
34197
|
+
const raw = fs10.readFileSync(p, "utf8");
|
|
34198
|
+
const parsed = JSON.parse(raw);
|
|
34199
|
+
if (parsed.v !== 1) return null;
|
|
34200
|
+
return {
|
|
34201
|
+
v: 1,
|
|
34202
|
+
acpSessionId: typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null,
|
|
34203
|
+
backendAgentType: typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null,
|
|
34204
|
+
configOptions: Array.isArray(parsed.configOptions) ? parsed.configOptions : null,
|
|
34205
|
+
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
34206
|
+
};
|
|
34207
|
+
} catch {
|
|
34208
|
+
return null;
|
|
34209
|
+
}
|
|
34210
|
+
}
|
|
34211
|
+
function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
34212
|
+
try {
|
|
34213
|
+
const dir = LOCAL_AGENT_SESSION_DIR;
|
|
34214
|
+
if (!fs10.existsSync(dir)) fs10.mkdirSync(dir, { recursive: true });
|
|
34215
|
+
const p = localAgentSessionFilePath(cloudSessionId);
|
|
34216
|
+
const prev = readLocalAgentSessionFile(cloudSessionId);
|
|
34217
|
+
const next = {
|
|
34218
|
+
v: 1,
|
|
34219
|
+
acpSessionId: patch.acpSessionId !== void 0 ? patch.acpSessionId : prev?.acpSessionId ?? null,
|
|
34220
|
+
backendAgentType: patch.backendAgentType !== void 0 ? patch.backendAgentType : prev?.backendAgentType ?? null,
|
|
34221
|
+
configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
|
|
34222
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
34223
|
+
};
|
|
34224
|
+
fs10.writeFileSync(p, JSON.stringify(next, null, 2), "utf8");
|
|
34225
|
+
} catch {
|
|
34226
|
+
}
|
|
34227
|
+
}
|
|
34228
|
+
|
|
33899
34229
|
// src/agents/acp/ensure-acp-client.ts
|
|
33900
34230
|
async function ensureAcpClient(options) {
|
|
33901
|
-
const {
|
|
34231
|
+
const {
|
|
34232
|
+
state,
|
|
34233
|
+
preferredAgentType,
|
|
34234
|
+
mode,
|
|
34235
|
+
agentConfig,
|
|
34236
|
+
sessionParentPath,
|
|
34237
|
+
routing,
|
|
34238
|
+
cloudSessionId,
|
|
34239
|
+
sendSessionUpdate,
|
|
34240
|
+
sendRequest,
|
|
34241
|
+
log: log2
|
|
34242
|
+
} = options;
|
|
34243
|
+
state.latestAgentConfigForBridgeHooks = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
|
|
33902
34244
|
const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
|
|
33903
34245
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
33904
34246
|
await state.acpStartPromise;
|
|
33905
34247
|
}
|
|
33906
|
-
if (state.acpHandle && state.lastAcpCwd != null &&
|
|
34248
|
+
if (state.acpHandle && state.lastAcpCwd != null && path13.resolve(state.lastAcpCwd) !== path13.resolve(targetSessionParentPath)) {
|
|
33907
34249
|
try {
|
|
33908
34250
|
state.acpHandle.disconnect();
|
|
33909
34251
|
} catch {
|
|
@@ -33911,6 +34253,7 @@ async function ensureAcpClient(options) {
|
|
|
33911
34253
|
state.acpHandle = null;
|
|
33912
34254
|
state.acpStartPromise = null;
|
|
33913
34255
|
state.acpAgentKey = null;
|
|
34256
|
+
state.activeSessionConfigOptions = null;
|
|
33914
34257
|
}
|
|
33915
34258
|
const resolved = resolveAgentCommand(preferredAgentType);
|
|
33916
34259
|
if (!resolved) {
|
|
@@ -33931,12 +34274,13 @@ async function ensureAcpClient(options) {
|
|
|
33931
34274
|
state.acpHandle = null;
|
|
33932
34275
|
state.acpStartPromise = null;
|
|
33933
34276
|
state.acpAgentKey = null;
|
|
34277
|
+
state.activeSessionConfigOptions = null;
|
|
33934
34278
|
}
|
|
33935
34279
|
if (state.acpHandle) return state.acpHandle;
|
|
33936
34280
|
if (!state.acpStartPromise) {
|
|
33937
34281
|
let statOk = false;
|
|
33938
34282
|
try {
|
|
33939
|
-
const st =
|
|
34283
|
+
const st = fs11.statSync(targetSessionParentPath);
|
|
33940
34284
|
statOk = st.isDirectory();
|
|
33941
34285
|
if (!statOk) {
|
|
33942
34286
|
state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
|
|
@@ -33954,17 +34298,47 @@ async function ensureAcpClient(options) {
|
|
|
33954
34298
|
sessionParentPath: targetSessionParentPath,
|
|
33955
34299
|
getSendSessionUpdate: () => sendSessionUpdate,
|
|
33956
34300
|
getSendRequest: () => sendRequest,
|
|
33957
|
-
log: log2
|
|
34301
|
+
log: log2,
|
|
34302
|
+
getAutoApproveAcpPermissions: () => getCliPermissionModeFromAgentConfig(state.latestAgentConfigForBridgeHooks) === CLI_PERMISSION_MODE_DANGEROUS,
|
|
34303
|
+
resolveAcpPermissionRequest: (requestId, result) => {
|
|
34304
|
+
state.acpHandle?.resolveRequest?.(requestId, result);
|
|
34305
|
+
}
|
|
33958
34306
|
});
|
|
34307
|
+
const persisted = cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "" ? readLocalAgentSessionFile(cloudSessionId) : null;
|
|
34308
|
+
const persistedAcpSessionId = persisted && persisted.backendAgentType === preferredAgentType && typeof persisted.acpSessionId === "string" && persisted.acpSessionId.trim() !== "" ? persisted.acpSessionId.trim() : null;
|
|
34309
|
+
state.activeSessionConfigOptions = Array.isArray(persisted?.configOptions) ? persisted.configOptions : null;
|
|
33959
34310
|
state.acpStartPromise = resolved.createClient({
|
|
33960
34311
|
command: resolved.command,
|
|
33961
34312
|
sessionMode: mode,
|
|
33962
34313
|
agentConfig: agentConfig ?? null,
|
|
33963
34314
|
backendAgentType: preferredAgentType,
|
|
34315
|
+
persistedAcpSessionId,
|
|
34316
|
+
getActiveConfigOptions: () => state.activeSessionConfigOptions,
|
|
34317
|
+
onAcpSessionEstablished: (info) => {
|
|
34318
|
+
state.activeSessionConfigOptions = info.configOptions ?? state.activeSessionConfigOptions;
|
|
34319
|
+
if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
|
|
34320
|
+
writeLocalAgentSessionFile(cloudSessionId, {
|
|
34321
|
+
acpSessionId: info.acpSessionId,
|
|
34322
|
+
configOptions: info.configOptions,
|
|
34323
|
+
backendAgentType: preferredAgentType
|
|
34324
|
+
});
|
|
34325
|
+
}
|
|
34326
|
+
},
|
|
34327
|
+
onAcpConfigOptionsUpdated: (configOptions) => {
|
|
34328
|
+
state.activeSessionConfigOptions = configOptions;
|
|
34329
|
+
if (cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "") {
|
|
34330
|
+
writeLocalAgentSessionFile(cloudSessionId, {
|
|
34331
|
+
configOptions,
|
|
34332
|
+
backendAgentType: preferredAgentType
|
|
34333
|
+
});
|
|
34334
|
+
}
|
|
34335
|
+
},
|
|
33964
34336
|
onAgentSubprocessExit: () => {
|
|
33965
34337
|
state.acpHandle = null;
|
|
33966
34338
|
state.acpStartPromise = null;
|
|
33967
34339
|
state.acpAgentKey = null;
|
|
34340
|
+
state.activeSessionConfigOptions = null;
|
|
34341
|
+
state.latestAgentConfigForBridgeHooks = null;
|
|
33968
34342
|
state.lastAcpStartError = "Agent subprocess exited";
|
|
33969
34343
|
},
|
|
33970
34344
|
...hooks,
|
|
@@ -33994,7 +34368,9 @@ async function createAcpManager(options) {
|
|
|
33994
34368
|
acpStartPromise: null,
|
|
33995
34369
|
lastAcpStartError: null,
|
|
33996
34370
|
lastAcpCwd: null,
|
|
33997
|
-
acpAgentKey: null
|
|
34371
|
+
acpAgentKey: null,
|
|
34372
|
+
activeSessionConfigOptions: null,
|
|
34373
|
+
latestAgentConfigForBridgeHooks: null
|
|
33998
34374
|
};
|
|
33999
34375
|
let backendFallbackAgentType = null;
|
|
34000
34376
|
const promptRouting = {};
|
|
@@ -34044,6 +34420,7 @@ async function createAcpManager(options) {
|
|
|
34044
34420
|
agentConfig: agentConfig ?? null,
|
|
34045
34421
|
sessionParentPath,
|
|
34046
34422
|
routing: promptRouting,
|
|
34423
|
+
cloudSessionId: sessionId,
|
|
34047
34424
|
sendSessionUpdate,
|
|
34048
34425
|
sendRequest: sendSessionUpdate,
|
|
34049
34426
|
log: log2
|
|
@@ -34134,6 +34511,8 @@ async function createAcpManager(options) {
|
|
|
34134
34511
|
state.acpHandle = null;
|
|
34135
34512
|
state.acpStartPromise = null;
|
|
34136
34513
|
state.acpAgentKey = null;
|
|
34514
|
+
state.activeSessionConfigOptions = null;
|
|
34515
|
+
state.latestAgentConfigForBridgeHooks = null;
|
|
34137
34516
|
}
|
|
34138
34517
|
return {
|
|
34139
34518
|
setPreferredAgentType,
|
|
@@ -34146,12 +34525,12 @@ async function createAcpManager(options) {
|
|
|
34146
34525
|
}
|
|
34147
34526
|
|
|
34148
34527
|
// src/worktrees/session-worktree-manager.ts
|
|
34149
|
-
import * as
|
|
34150
|
-
import
|
|
34528
|
+
import * as path20 from "node:path";
|
|
34529
|
+
import os5 from "node:os";
|
|
34151
34530
|
|
|
34152
34531
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34153
|
-
import * as
|
|
34154
|
-
import * as
|
|
34532
|
+
import * as fs13 from "node:fs";
|
|
34533
|
+
import * as path15 from "node:path";
|
|
34155
34534
|
|
|
34156
34535
|
// src/git/worktree-add.ts
|
|
34157
34536
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -34160,12 +34539,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
34160
34539
|
}
|
|
34161
34540
|
|
|
34162
34541
|
// src/worktrees/worktree-layout-file.ts
|
|
34163
|
-
import * as
|
|
34164
|
-
import * as
|
|
34165
|
-
import
|
|
34542
|
+
import * as fs12 from "node:fs";
|
|
34543
|
+
import * as path14 from "node:path";
|
|
34544
|
+
import os4 from "node:os";
|
|
34166
34545
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
34167
34546
|
function defaultWorktreeLayoutPath() {
|
|
34168
|
-
return
|
|
34547
|
+
return path14.join(os4.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
34169
34548
|
}
|
|
34170
34549
|
function normalizeLoadedLayout(raw) {
|
|
34171
34550
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -34177,8 +34556,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
34177
34556
|
function loadWorktreeLayout() {
|
|
34178
34557
|
try {
|
|
34179
34558
|
const p = defaultWorktreeLayoutPath();
|
|
34180
|
-
if (!
|
|
34181
|
-
const raw = JSON.parse(
|
|
34559
|
+
if (!fs12.existsSync(p)) return { launcherCwds: [] };
|
|
34560
|
+
const raw = JSON.parse(fs12.readFileSync(p, "utf8"));
|
|
34182
34561
|
return normalizeLoadedLayout(raw);
|
|
34183
34562
|
} catch {
|
|
34184
34563
|
return { launcherCwds: [] };
|
|
@@ -34186,24 +34565,24 @@ function loadWorktreeLayout() {
|
|
|
34186
34565
|
}
|
|
34187
34566
|
function saveWorktreeLayout(layout) {
|
|
34188
34567
|
try {
|
|
34189
|
-
const dir =
|
|
34190
|
-
|
|
34191
|
-
|
|
34568
|
+
const dir = path14.dirname(defaultWorktreeLayoutPath());
|
|
34569
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
34570
|
+
fs12.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
34192
34571
|
} catch {
|
|
34193
34572
|
}
|
|
34194
34573
|
}
|
|
34195
34574
|
function baseNameSafe(pathString) {
|
|
34196
|
-
return
|
|
34575
|
+
return path14.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
34197
34576
|
}
|
|
34198
34577
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
34199
|
-
const norm =
|
|
34200
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
34578
|
+
const norm = path14.resolve(bridgeRootPath2);
|
|
34579
|
+
const existing = layout.launcherCwds.find((e) => path14.resolve(e.absolutePath) === norm);
|
|
34201
34580
|
return existing?.dirName;
|
|
34202
34581
|
}
|
|
34203
34582
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
34204
34583
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
34205
34584
|
if (existing) return existing;
|
|
34206
|
-
const norm =
|
|
34585
|
+
const norm = path14.resolve(bridgeRootPath2);
|
|
34207
34586
|
const base = baseNameSafe(norm);
|
|
34208
34587
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
34209
34588
|
let name = base;
|
|
@@ -34220,10 +34599,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
34220
34599
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34221
34600
|
async function prepareNewSessionWorktrees(options) {
|
|
34222
34601
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
|
|
34223
|
-
const bridgeResolved =
|
|
34602
|
+
const bridgeResolved = path15.resolve(bridgeRoot);
|
|
34224
34603
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
34225
|
-
const bridgeKeyDir =
|
|
34226
|
-
const sessionDir =
|
|
34604
|
+
const bridgeKeyDir = path15.join(worktreesRootPath, cwdKey);
|
|
34605
|
+
const sessionDir = path15.join(bridgeKeyDir, sessionId);
|
|
34227
34606
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
34228
34607
|
if (repos.length === 0) {
|
|
34229
34608
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -34231,14 +34610,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
34231
34610
|
}
|
|
34232
34611
|
const branch = `session-${sessionId}`;
|
|
34233
34612
|
const worktreePaths = [];
|
|
34234
|
-
|
|
34613
|
+
fs13.mkdirSync(sessionDir, { recursive: true });
|
|
34235
34614
|
for (const repo of repos) {
|
|
34236
|
-
let rel =
|
|
34237
|
-
if (rel.startsWith("..") ||
|
|
34615
|
+
let rel = path15.relative(bridgeResolved, repo.absolutePath);
|
|
34616
|
+
if (rel.startsWith("..") || path15.isAbsolute(rel)) continue;
|
|
34238
34617
|
const relNorm = rel === "" ? "." : rel;
|
|
34239
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
34618
|
+
const wtPath = relNorm === "." ? sessionDir : path15.join(sessionDir, relNorm);
|
|
34240
34619
|
if (relNorm !== ".") {
|
|
34241
|
-
|
|
34620
|
+
fs13.mkdirSync(path15.dirname(wtPath), { recursive: true });
|
|
34242
34621
|
}
|
|
34243
34622
|
try {
|
|
34244
34623
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
@@ -34280,23 +34659,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
34280
34659
|
}
|
|
34281
34660
|
|
|
34282
34661
|
// src/worktrees/remove-session-worktrees.ts
|
|
34283
|
-
import * as
|
|
34662
|
+
import * as fs16 from "node:fs";
|
|
34284
34663
|
|
|
34285
34664
|
// src/git/worktree-remove.ts
|
|
34286
|
-
import * as
|
|
34665
|
+
import * as fs15 from "node:fs";
|
|
34287
34666
|
|
|
34288
34667
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
34289
|
-
import * as
|
|
34290
|
-
import * as
|
|
34668
|
+
import * as fs14 from "node:fs";
|
|
34669
|
+
import * as path16 from "node:path";
|
|
34291
34670
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
34292
|
-
const gitDirFile =
|
|
34293
|
-
if (!
|
|
34294
|
-
const first2 =
|
|
34671
|
+
const gitDirFile = path16.join(wt, ".git");
|
|
34672
|
+
if (!fs14.existsSync(gitDirFile) || !fs14.statSync(gitDirFile).isFile()) return "";
|
|
34673
|
+
const first2 = fs14.readFileSync(gitDirFile, "utf8").trim();
|
|
34295
34674
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
34296
34675
|
if (!m) return "";
|
|
34297
|
-
const gitWorktreePath =
|
|
34298
|
-
const gitDir =
|
|
34299
|
-
return
|
|
34676
|
+
const gitWorktreePath = path16.resolve(wt, m[1].trim());
|
|
34677
|
+
const gitDir = path16.dirname(path16.dirname(gitWorktreePath));
|
|
34678
|
+
return path16.dirname(gitDir);
|
|
34300
34679
|
}
|
|
34301
34680
|
|
|
34302
34681
|
// src/git/worktree-remove.ts
|
|
@@ -34305,7 +34684,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
34305
34684
|
if (mainRepo) {
|
|
34306
34685
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
34307
34686
|
} else {
|
|
34308
|
-
|
|
34687
|
+
fs15.rmSync(worktreePath, { recursive: true, force: true });
|
|
34309
34688
|
}
|
|
34310
34689
|
}
|
|
34311
34690
|
|
|
@@ -34318,7 +34697,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
34318
34697
|
} catch (e) {
|
|
34319
34698
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
34320
34699
|
try {
|
|
34321
|
-
|
|
34700
|
+
fs16.rmSync(wt, { recursive: true, force: true });
|
|
34322
34701
|
} catch {
|
|
34323
34702
|
}
|
|
34324
34703
|
}
|
|
@@ -34538,7 +34917,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
34538
34917
|
}
|
|
34539
34918
|
|
|
34540
34919
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
34541
|
-
import * as
|
|
34920
|
+
import * as path18 from "node:path";
|
|
34542
34921
|
|
|
34543
34922
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
34544
34923
|
function parseNameStatusLines(lines) {
|
|
@@ -34658,8 +35037,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
34658
35037
|
}
|
|
34659
35038
|
|
|
34660
35039
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
34661
|
-
import * as
|
|
34662
|
-
import * as
|
|
35040
|
+
import * as fs18 from "node:fs";
|
|
35041
|
+
import * as path17 from "node:path";
|
|
34663
35042
|
|
|
34664
35043
|
// src/git/working-directory/changes/count-lines.ts
|
|
34665
35044
|
import { createReadStream } from "node:fs";
|
|
@@ -34683,7 +35062,7 @@ async function countTextFileLines(filePath) {
|
|
|
34683
35062
|
}
|
|
34684
35063
|
|
|
34685
35064
|
// src/git/working-directory/changes/hydrate-patch.ts
|
|
34686
|
-
import * as
|
|
35065
|
+
import * as fs17 from "node:fs";
|
|
34687
35066
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
34688
35067
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
34689
35068
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -34698,7 +35077,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
34698
35077
|
}
|
|
34699
35078
|
async function readWorktreeFileLines(filePath) {
|
|
34700
35079
|
try {
|
|
34701
|
-
const raw = await
|
|
35080
|
+
const raw = await fs17.promises.readFile(filePath, "utf8");
|
|
34702
35081
|
return raw.split(/\r?\n/);
|
|
34703
35082
|
} catch {
|
|
34704
35083
|
return null;
|
|
@@ -34833,7 +35212,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
34833
35212
|
const rows = [];
|
|
34834
35213
|
for (const pathInRepo of paths) {
|
|
34835
35214
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
34836
|
-
const repoFilePath =
|
|
35215
|
+
const repoFilePath = path17.join(repoGitCwd, pathInRepo);
|
|
34837
35216
|
const nums = numByPath.get(pathInRepo);
|
|
34838
35217
|
let additions = nums?.additions ?? 0;
|
|
34839
35218
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -34846,7 +35225,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
34846
35225
|
deletions = fromGit.deletions;
|
|
34847
35226
|
} else {
|
|
34848
35227
|
try {
|
|
34849
|
-
const st = await
|
|
35228
|
+
const st = await fs18.promises.stat(repoFilePath);
|
|
34850
35229
|
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
34851
35230
|
else additions = 0;
|
|
34852
35231
|
} catch {
|
|
@@ -34872,7 +35251,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
34872
35251
|
} else {
|
|
34873
35252
|
pathInRepo = row.pathRelLauncher;
|
|
34874
35253
|
}
|
|
34875
|
-
const filePath =
|
|
35254
|
+
const filePath = path17.join(repoGitCwd, pathInRepo);
|
|
34876
35255
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
34877
35256
|
if (patch) {
|
|
34878
35257
|
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
@@ -34888,8 +35267,8 @@ function normRepoRel(p) {
|
|
|
34888
35267
|
return x === "" ? "." : x;
|
|
34889
35268
|
}
|
|
34890
35269
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
34891
|
-
const bridgeRoot =
|
|
34892
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
35270
|
+
const bridgeRoot = path18.resolve(getBridgeRoot());
|
|
35271
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path18.resolve(options.sessionWorktreeRootPath) : null;
|
|
34893
35272
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
34894
35273
|
const out = [];
|
|
34895
35274
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -34902,7 +35281,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34902
35281
|
}
|
|
34903
35282
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
34904
35283
|
for (const target of options.commitTargetPaths) {
|
|
34905
|
-
const t =
|
|
35284
|
+
const t = path18.resolve(target);
|
|
34906
35285
|
if (!await isGitRepoDirectory(t)) continue;
|
|
34907
35286
|
const g = cliSimpleGit(t);
|
|
34908
35287
|
let branch = "HEAD";
|
|
@@ -34915,8 +35294,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34915
35294
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
34916
35295
|
let repoRelPath;
|
|
34917
35296
|
if (sessionWtRoot) {
|
|
34918
|
-
const anchor = legacyNested ?
|
|
34919
|
-
const relNorm =
|
|
35297
|
+
const anchor = legacyNested ? path18.dirname(t) : t;
|
|
35298
|
+
const relNorm = path18.relative(sessionWtRoot, anchor);
|
|
34920
35299
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
34921
35300
|
} else {
|
|
34922
35301
|
let top = t;
|
|
@@ -34925,8 +35304,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34925
35304
|
} catch {
|
|
34926
35305
|
top = t;
|
|
34927
35306
|
}
|
|
34928
|
-
const rel =
|
|
34929
|
-
repoRelPath = rel.startsWith("..") ?
|
|
35307
|
+
const rel = path18.relative(bridgeRoot, path18.resolve(top)).replace(/\\/g, "/") || ".";
|
|
35308
|
+
repoRelPath = rel.startsWith("..") ? path18.basename(path18.resolve(top)) : rel;
|
|
34930
35309
|
}
|
|
34931
35310
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
34932
35311
|
if (filter && norm !== filter) continue;
|
|
@@ -34991,11 +35370,11 @@ async function commitSessionWorktrees(options) {
|
|
|
34991
35370
|
}
|
|
34992
35371
|
|
|
34993
35372
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
34994
|
-
import * as
|
|
34995
|
-
import * as
|
|
35373
|
+
import * as fs19 from "node:fs";
|
|
35374
|
+
import * as path19 from "node:path";
|
|
34996
35375
|
function isGitDir(dirPath) {
|
|
34997
35376
|
try {
|
|
34998
|
-
return
|
|
35377
|
+
return fs19.existsSync(path19.join(dirPath, ".git"));
|
|
34999
35378
|
} catch {
|
|
35000
35379
|
return false;
|
|
35001
35380
|
}
|
|
@@ -35004,23 +35383,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
35004
35383
|
const out = [];
|
|
35005
35384
|
const walk = (dir) => {
|
|
35006
35385
|
if (isGitDir(dir)) {
|
|
35007
|
-
out.push(
|
|
35386
|
+
out.push(path19.resolve(dir));
|
|
35008
35387
|
return;
|
|
35009
35388
|
}
|
|
35010
35389
|
let entries;
|
|
35011
35390
|
try {
|
|
35012
|
-
entries =
|
|
35391
|
+
entries = fs19.readdirSync(dir, { withFileTypes: true });
|
|
35013
35392
|
} catch {
|
|
35014
35393
|
return;
|
|
35015
35394
|
}
|
|
35016
35395
|
for (const e of entries) {
|
|
35017
35396
|
if (e.name.startsWith(".")) continue;
|
|
35018
|
-
const full =
|
|
35397
|
+
const full = path19.join(dir, e.name);
|
|
35019
35398
|
if (!e.isDirectory()) continue;
|
|
35020
35399
|
walk(full);
|
|
35021
35400
|
}
|
|
35022
35401
|
};
|
|
35023
|
-
walk(
|
|
35402
|
+
walk(path19.resolve(rootPath));
|
|
35024
35403
|
return [...new Set(out)];
|
|
35025
35404
|
}
|
|
35026
35405
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -35029,16 +35408,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
35029
35408
|
if (depth > maxDepth) return;
|
|
35030
35409
|
let entries;
|
|
35031
35410
|
try {
|
|
35032
|
-
entries =
|
|
35411
|
+
entries = fs19.readdirSync(dir, { withFileTypes: true });
|
|
35033
35412
|
} catch {
|
|
35034
35413
|
return;
|
|
35035
35414
|
}
|
|
35036
35415
|
for (const e of entries) {
|
|
35037
35416
|
if (e.name.startsWith(".")) continue;
|
|
35038
|
-
const full =
|
|
35417
|
+
const full = path19.join(dir, e.name);
|
|
35039
35418
|
if (!e.isDirectory()) continue;
|
|
35040
35419
|
if (e.name === sessionId) {
|
|
35041
|
-
if (isGitDir(full)) out.push(
|
|
35420
|
+
if (isGitDir(full)) out.push(path19.resolve(full));
|
|
35042
35421
|
} else {
|
|
35043
35422
|
walk(full, depth + 1);
|
|
35044
35423
|
}
|
|
@@ -35050,14 +35429,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
35050
35429
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
35051
35430
|
let st;
|
|
35052
35431
|
try {
|
|
35053
|
-
st =
|
|
35432
|
+
st = fs19.statSync(sessionDir);
|
|
35054
35433
|
} catch {
|
|
35055
35434
|
return null;
|
|
35056
35435
|
}
|
|
35057
35436
|
if (!st.isDirectory()) return null;
|
|
35058
35437
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
35059
35438
|
if (worktreePaths.length === 0) return null;
|
|
35060
|
-
const abs =
|
|
35439
|
+
const abs = path19.resolve(sessionDir);
|
|
35061
35440
|
return {
|
|
35062
35441
|
sessionParentPath: abs,
|
|
35063
35442
|
workingTreeRelRoot: abs,
|
|
@@ -35067,20 +35446,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
35067
35446
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
35068
35447
|
const sid = sessionId.trim();
|
|
35069
35448
|
if (!sid) return null;
|
|
35070
|
-
const hintR =
|
|
35449
|
+
const hintR = path19.resolve(checkoutPath);
|
|
35071
35450
|
let best = null;
|
|
35072
|
-
let cur =
|
|
35451
|
+
let cur = path19.dirname(hintR);
|
|
35073
35452
|
for (let i = 0; i < 40; i++) {
|
|
35074
35453
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
35075
|
-
if (paths.some((p) =>
|
|
35076
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
35454
|
+
if (paths.some((p) => path19.resolve(p) === hintR)) {
|
|
35455
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path19.resolve(paths[0]);
|
|
35077
35456
|
best = {
|
|
35078
|
-
sessionParentPath:
|
|
35079
|
-
workingTreeRelRoot:
|
|
35080
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
35457
|
+
sessionParentPath: path19.resolve(isolated),
|
|
35458
|
+
workingTreeRelRoot: path19.resolve(cur),
|
|
35459
|
+
repoCheckoutPaths: paths.map((p) => path19.resolve(p))
|
|
35081
35460
|
};
|
|
35082
35461
|
}
|
|
35083
|
-
const next =
|
|
35462
|
+
const next = path19.dirname(cur);
|
|
35084
35463
|
if (next === cur) break;
|
|
35085
35464
|
cur = next;
|
|
35086
35465
|
}
|
|
@@ -35088,33 +35467,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
35088
35467
|
}
|
|
35089
35468
|
function discoverSessionWorktreeOnDisk(options) {
|
|
35090
35469
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
35091
|
-
if (!sessionId.trim() || !
|
|
35470
|
+
if (!sessionId.trim() || !fs19.existsSync(worktreesRootPath)) return null;
|
|
35092
35471
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
35093
35472
|
const keys = [];
|
|
35094
35473
|
if (preferredKey) keys.push(preferredKey);
|
|
35095
35474
|
try {
|
|
35096
|
-
for (const name of
|
|
35475
|
+
for (const name of fs19.readdirSync(worktreesRootPath)) {
|
|
35097
35476
|
if (name.startsWith(".")) continue;
|
|
35098
|
-
const p =
|
|
35099
|
-
if (!
|
|
35477
|
+
const p = path19.join(worktreesRootPath, name);
|
|
35478
|
+
if (!fs19.statSync(p).isDirectory()) continue;
|
|
35100
35479
|
if (name !== preferredKey) keys.push(name);
|
|
35101
35480
|
}
|
|
35102
35481
|
} catch {
|
|
35103
35482
|
return null;
|
|
35104
35483
|
}
|
|
35105
35484
|
for (const key of keys) {
|
|
35106
|
-
const layoutRoot =
|
|
35107
|
-
if (!
|
|
35108
|
-
const sessionDir =
|
|
35485
|
+
const layoutRoot = path19.join(worktreesRootPath, key);
|
|
35486
|
+
if (!fs19.existsSync(layoutRoot) || !fs19.statSync(layoutRoot).isDirectory()) continue;
|
|
35487
|
+
const sessionDir = path19.join(layoutRoot, sessionId);
|
|
35109
35488
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
35110
35489
|
if (nested) return nested;
|
|
35111
35490
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
35112
35491
|
if (legacyPaths.length > 0) {
|
|
35113
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
35492
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path19.resolve(legacyPaths[0]);
|
|
35114
35493
|
return {
|
|
35115
|
-
sessionParentPath:
|
|
35116
|
-
workingTreeRelRoot:
|
|
35117
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
35494
|
+
sessionParentPath: path19.resolve(isolated),
|
|
35495
|
+
workingTreeRelRoot: path19.resolve(layoutRoot),
|
|
35496
|
+
repoCheckoutPaths: legacyPaths.map((p) => path19.resolve(p))
|
|
35118
35497
|
};
|
|
35119
35498
|
}
|
|
35120
35499
|
}
|
|
@@ -35123,12 +35502,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
35123
35502
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
35124
35503
|
const sid = sessionId.trim();
|
|
35125
35504
|
if (!sid) return null;
|
|
35126
|
-
const hint =
|
|
35127
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
35505
|
+
const hint = path19.resolve(sessionWorktreeRootPathOrHint);
|
|
35506
|
+
const underHint = tryBindingFromSessionDirectory(path19.join(hint, sid));
|
|
35128
35507
|
if (underHint) return underHint;
|
|
35129
35508
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
35130
35509
|
if (direct) {
|
|
35131
|
-
if (
|
|
35510
|
+
if (path19.basename(hint) === sid && isGitDir(hint)) {
|
|
35132
35511
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
35133
35512
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
35134
35513
|
return legacyFromCheckout;
|
|
@@ -35136,24 +35515,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
35136
35515
|
}
|
|
35137
35516
|
return direct;
|
|
35138
35517
|
}
|
|
35139
|
-
if (
|
|
35518
|
+
if (path19.basename(hint) === sid && isGitDir(hint)) {
|
|
35140
35519
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
35141
35520
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
35142
35521
|
}
|
|
35143
35522
|
let st;
|
|
35144
35523
|
try {
|
|
35145
|
-
st =
|
|
35524
|
+
st = fs19.statSync(hint);
|
|
35146
35525
|
} catch {
|
|
35147
35526
|
return null;
|
|
35148
35527
|
}
|
|
35149
35528
|
if (!st.isDirectory()) return null;
|
|
35150
35529
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
35151
35530
|
if (legacyPaths.length === 0) return null;
|
|
35152
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
35531
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path19.resolve(legacyPaths[0]);
|
|
35153
35532
|
return {
|
|
35154
|
-
sessionParentPath:
|
|
35533
|
+
sessionParentPath: path19.resolve(isolated),
|
|
35155
35534
|
workingTreeRelRoot: hint,
|
|
35156
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
35535
|
+
repoCheckoutPaths: legacyPaths.map((p) => path19.resolve(p))
|
|
35157
35536
|
};
|
|
35158
35537
|
}
|
|
35159
35538
|
|
|
@@ -35176,10 +35555,10 @@ var SessionWorktreeManager = class {
|
|
|
35176
35555
|
this.layout = loadWorktreeLayout();
|
|
35177
35556
|
}
|
|
35178
35557
|
rememberSessionWorktrees(sessionId, binding) {
|
|
35179
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
35558
|
+
const paths = binding.repoCheckoutPaths.map((p) => path20.resolve(p));
|
|
35180
35559
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
35181
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
35182
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
35560
|
+
this.sessionParentPathBySession.set(sessionId, path20.resolve(binding.sessionParentPath));
|
|
35561
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path20.resolve(binding.workingTreeRelRoot));
|
|
35183
35562
|
}
|
|
35184
35563
|
sessionParentPathAfterRemember(sessionId) {
|
|
35185
35564
|
return this.sessionParentPathBySession.get(sessionId);
|
|
@@ -35196,7 +35575,7 @@ var SessionWorktreeManager = class {
|
|
|
35196
35575
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
35197
35576
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
35198
35577
|
if (!parent || !relRoot) return false;
|
|
35199
|
-
return
|
|
35578
|
+
return path20.resolve(parent) !== path20.resolve(relRoot);
|
|
35200
35579
|
}
|
|
35201
35580
|
/**
|
|
35202
35581
|
* Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
|
|
@@ -35205,7 +35584,7 @@ var SessionWorktreeManager = class {
|
|
|
35205
35584
|
if (!sessionId) return null;
|
|
35206
35585
|
const sid = sessionId.trim();
|
|
35207
35586
|
const cached2 = this.sessionParentPathBySession.get(sid);
|
|
35208
|
-
if (cached2) return
|
|
35587
|
+
if (cached2) return path20.resolve(cached2);
|
|
35209
35588
|
const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
|
|
35210
35589
|
if (!paths?.length) return null;
|
|
35211
35590
|
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
@@ -35219,7 +35598,7 @@ var SessionWorktreeManager = class {
|
|
|
35219
35598
|
const sid = sessionId.trim();
|
|
35220
35599
|
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
35221
35600
|
if (parentPathRaw) {
|
|
35222
|
-
const resolved =
|
|
35601
|
+
const resolved = path20.resolve(parentPathRaw);
|
|
35223
35602
|
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
35224
35603
|
const diskFirst = this.tryDiscoverFromDisk(sid);
|
|
35225
35604
|
if (diskFirst) {
|
|
@@ -35238,7 +35617,7 @@ var SessionWorktreeManager = class {
|
|
|
35238
35617
|
this.rememberSessionWorktrees(sid, tryRoot);
|
|
35239
35618
|
return this.sessionParentPathAfterRemember(sid);
|
|
35240
35619
|
}
|
|
35241
|
-
const next =
|
|
35620
|
+
const next = path20.dirname(cur);
|
|
35242
35621
|
if (next === cur) break;
|
|
35243
35622
|
cur = next;
|
|
35244
35623
|
}
|
|
@@ -35391,15 +35770,15 @@ var SessionWorktreeManager = class {
|
|
|
35391
35770
|
}
|
|
35392
35771
|
};
|
|
35393
35772
|
function defaultWorktreesRootPath() {
|
|
35394
|
-
return
|
|
35773
|
+
return path20.join(os5.homedir(), ".buildautomaton", "worktrees");
|
|
35395
35774
|
}
|
|
35396
35775
|
|
|
35397
35776
|
// src/files/watch-file-index.ts
|
|
35398
35777
|
import { watch } from "node:fs";
|
|
35399
|
-
import
|
|
35778
|
+
import path27 from "node:path";
|
|
35400
35779
|
|
|
35401
35780
|
// src/files/index/build-file-index.ts
|
|
35402
|
-
import
|
|
35781
|
+
import path24 from "node:path";
|
|
35403
35782
|
|
|
35404
35783
|
// src/runtime/yield-to-event-loop.ts
|
|
35405
35784
|
function yieldToEventLoop() {
|
|
@@ -35407,14 +35786,14 @@ function yieldToEventLoop() {
|
|
|
35407
35786
|
}
|
|
35408
35787
|
|
|
35409
35788
|
// src/files/index/walk-workspace-tree.ts
|
|
35410
|
-
import
|
|
35411
|
-
import
|
|
35789
|
+
import fs20 from "node:fs";
|
|
35790
|
+
import path22 from "node:path";
|
|
35412
35791
|
|
|
35413
35792
|
// src/files/index/constants.ts
|
|
35414
|
-
import
|
|
35415
|
-
import
|
|
35793
|
+
import path21 from "node:path";
|
|
35794
|
+
import os6 from "node:os";
|
|
35416
35795
|
var INDEX_WORK_YIELD_EVERY = 256;
|
|
35417
|
-
var INDEX_DIR =
|
|
35796
|
+
var INDEX_DIR = path21.join(os6.homedir(), ".buildautomaton");
|
|
35418
35797
|
var INDEX_HASH_LEN = 16;
|
|
35419
35798
|
var INDEX_VERSION = 2;
|
|
35420
35799
|
var INDEX_LOG_PREFIX = "[file-index]";
|
|
@@ -35423,20 +35802,20 @@ var INDEX_LOG_PREFIX = "[file-index]";
|
|
|
35423
35802
|
function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
35424
35803
|
let names;
|
|
35425
35804
|
try {
|
|
35426
|
-
names =
|
|
35805
|
+
names = fs20.readdirSync(dir);
|
|
35427
35806
|
} catch {
|
|
35428
35807
|
return;
|
|
35429
35808
|
}
|
|
35430
35809
|
for (const name of names) {
|
|
35431
35810
|
if (name.startsWith(".")) continue;
|
|
35432
|
-
const full =
|
|
35811
|
+
const full = path22.join(dir, name);
|
|
35433
35812
|
let stat3;
|
|
35434
35813
|
try {
|
|
35435
|
-
stat3 =
|
|
35814
|
+
stat3 = fs20.statSync(full);
|
|
35436
35815
|
} catch {
|
|
35437
35816
|
continue;
|
|
35438
35817
|
}
|
|
35439
|
-
const relative5 =
|
|
35818
|
+
const relative5 = path22.relative(baseDir, full).replace(/\\/g, "/");
|
|
35440
35819
|
if (stat3.isDirectory()) {
|
|
35441
35820
|
walkWorkspaceTreeSync(full, baseDir, out);
|
|
35442
35821
|
} else if (stat3.isFile()) {
|
|
@@ -35447,7 +35826,7 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
|
35447
35826
|
async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
35448
35827
|
let names;
|
|
35449
35828
|
try {
|
|
35450
|
-
names = await
|
|
35829
|
+
names = await fs20.promises.readdir(dir);
|
|
35451
35830
|
} catch {
|
|
35452
35831
|
return;
|
|
35453
35832
|
}
|
|
@@ -35457,14 +35836,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
35457
35836
|
await yieldToEventLoop();
|
|
35458
35837
|
}
|
|
35459
35838
|
state.n++;
|
|
35460
|
-
const full =
|
|
35839
|
+
const full = path22.join(dir, name);
|
|
35461
35840
|
let stat3;
|
|
35462
35841
|
try {
|
|
35463
|
-
stat3 = await
|
|
35842
|
+
stat3 = await fs20.promises.stat(full);
|
|
35464
35843
|
} catch {
|
|
35465
35844
|
continue;
|
|
35466
35845
|
}
|
|
35467
|
-
const relative5 =
|
|
35846
|
+
const relative5 = path22.relative(baseDir, full).replace(/\\/g, "/");
|
|
35468
35847
|
if (stat3.isDirectory()) {
|
|
35469
35848
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
35470
35849
|
} else if (stat3.isFile()) {
|
|
@@ -35545,22 +35924,22 @@ async function buildTrigramMapForPathsAsync(paths) {
|
|
|
35545
35924
|
}
|
|
35546
35925
|
|
|
35547
35926
|
// src/files/index/write-index-file.ts
|
|
35548
|
-
import
|
|
35927
|
+
import fs21 from "node:fs";
|
|
35549
35928
|
|
|
35550
35929
|
// src/files/index/paths.ts
|
|
35551
|
-
import
|
|
35930
|
+
import path23 from "node:path";
|
|
35552
35931
|
import crypto2 from "node:crypto";
|
|
35553
35932
|
function getIndexPathForCwd(resolvedCwd) {
|
|
35554
35933
|
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
35555
|
-
return
|
|
35934
|
+
return path23.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
35556
35935
|
}
|
|
35557
35936
|
|
|
35558
35937
|
// src/files/index/write-index-file.ts
|
|
35559
35938
|
function writeIndexFileSync(resolvedCwd, data) {
|
|
35560
35939
|
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
35561
35940
|
try {
|
|
35562
|
-
if (!
|
|
35563
|
-
|
|
35941
|
+
if (!fs21.existsSync(INDEX_DIR)) fs21.mkdirSync(INDEX_DIR, { recursive: true });
|
|
35942
|
+
fs21.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
35564
35943
|
} catch (e) {
|
|
35565
35944
|
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
35566
35945
|
}
|
|
@@ -35568,8 +35947,8 @@ function writeIndexFileSync(resolvedCwd, data) {
|
|
|
35568
35947
|
async function writeIndexFileAsync(resolvedCwd, data) {
|
|
35569
35948
|
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
35570
35949
|
try {
|
|
35571
|
-
await
|
|
35572
|
-
await
|
|
35950
|
+
await fs21.promises.mkdir(INDEX_DIR, { recursive: true });
|
|
35951
|
+
await fs21.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
|
|
35573
35952
|
} catch (e) {
|
|
35574
35953
|
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
35575
35954
|
}
|
|
@@ -35583,7 +35962,7 @@ function sortPaths(paths) {
|
|
|
35583
35962
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
35584
35963
|
}
|
|
35585
35964
|
function buildFileIndex(cwd) {
|
|
35586
|
-
const resolved =
|
|
35965
|
+
const resolved = path24.resolve(cwd);
|
|
35587
35966
|
const paths = [];
|
|
35588
35967
|
walkWorkspaceTreeSync(resolved, resolved, paths);
|
|
35589
35968
|
sortPaths(paths);
|
|
@@ -35593,7 +35972,7 @@ function buildFileIndex(cwd) {
|
|
|
35593
35972
|
return data;
|
|
35594
35973
|
}
|
|
35595
35974
|
async function buildFileIndexAsync(cwd) {
|
|
35596
|
-
const resolved =
|
|
35975
|
+
const resolved = path24.resolve(cwd);
|
|
35597
35976
|
const paths = [];
|
|
35598
35977
|
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
35599
35978
|
await yieldToEventLoop();
|
|
@@ -35605,13 +35984,13 @@ async function buildFileIndexAsync(cwd) {
|
|
|
35605
35984
|
}
|
|
35606
35985
|
|
|
35607
35986
|
// src/files/index/load-file-index.ts
|
|
35608
|
-
import
|
|
35609
|
-
import
|
|
35987
|
+
import fs22 from "node:fs";
|
|
35988
|
+
import path25 from "node:path";
|
|
35610
35989
|
function loadFileIndex(cwd) {
|
|
35611
|
-
const resolved =
|
|
35990
|
+
const resolved = path25.resolve(cwd);
|
|
35612
35991
|
const indexPath = getIndexPathForCwd(resolved);
|
|
35613
35992
|
try {
|
|
35614
|
-
const raw =
|
|
35993
|
+
const raw = fs22.readFileSync(indexPath, "utf8");
|
|
35615
35994
|
const parsed = JSON.parse(raw);
|
|
35616
35995
|
if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
|
|
35617
35996
|
const obj = parsed;
|
|
@@ -35630,9 +36009,9 @@ function loadFileIndex(cwd) {
|
|
|
35630
36009
|
}
|
|
35631
36010
|
|
|
35632
36011
|
// src/files/index/ensure-file-index.ts
|
|
35633
|
-
import
|
|
36012
|
+
import path26 from "node:path";
|
|
35634
36013
|
async function ensureFileIndexAsync(cwd) {
|
|
35635
|
-
const resolved =
|
|
36014
|
+
const resolved = path26.resolve(cwd);
|
|
35636
36015
|
const cached2 = loadFileIndex(resolved);
|
|
35637
36016
|
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
35638
36017
|
const data = await buildFileIndexAsync(resolved);
|
|
@@ -35715,7 +36094,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
35715
36094
|
}
|
|
35716
36095
|
}
|
|
35717
36096
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
35718
|
-
const resolved =
|
|
36097
|
+
const resolved = path27.resolve(cwd);
|
|
35719
36098
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
35720
36099
|
console.error("[file-index] Initial index build failed:", e);
|
|
35721
36100
|
});
|
|
@@ -35743,7 +36122,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
35743
36122
|
}
|
|
35744
36123
|
|
|
35745
36124
|
// src/connection/create-bridge-connection.ts
|
|
35746
|
-
import * as
|
|
36125
|
+
import * as path35 from "node:path";
|
|
35747
36126
|
|
|
35748
36127
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
35749
36128
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -35787,7 +36166,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
35787
36166
|
}
|
|
35788
36167
|
|
|
35789
36168
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
35790
|
-
import
|
|
36169
|
+
import fs23 from "node:fs";
|
|
35791
36170
|
|
|
35792
36171
|
// src/dev-servers/manager/forward-pipe.ts
|
|
35793
36172
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -35823,7 +36202,7 @@ function wireDevServerChildProcess(d) {
|
|
|
35823
36202
|
d.setPollInterval(void 0);
|
|
35824
36203
|
return;
|
|
35825
36204
|
}
|
|
35826
|
-
|
|
36205
|
+
fs23.readFile(d.mergedLogPath, (err, buf) => {
|
|
35827
36206
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
35828
36207
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
35829
36208
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -35861,7 +36240,7 @@ ${errTail}` : ""}`);
|
|
|
35861
36240
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
35862
36241
|
};
|
|
35863
36242
|
if (mergedPath) {
|
|
35864
|
-
|
|
36243
|
+
fs23.readFile(mergedPath, (err, buf) => {
|
|
35865
36244
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
35866
36245
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
35867
36246
|
if (chunk.length > 0) {
|
|
@@ -35963,13 +36342,13 @@ function parseDevServerDefs(servers) {
|
|
|
35963
36342
|
}
|
|
35964
36343
|
|
|
35965
36344
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
35966
|
-
import
|
|
36345
|
+
import fs24 from "node:fs";
|
|
35967
36346
|
function isSpawnEbadf(e) {
|
|
35968
36347
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
35969
36348
|
}
|
|
35970
36349
|
function rmDirQuiet(dir) {
|
|
35971
36350
|
try {
|
|
35972
|
-
|
|
36351
|
+
fs24.rmSync(dir, { recursive: true, force: true });
|
|
35973
36352
|
} catch {
|
|
35974
36353
|
}
|
|
35975
36354
|
}
|
|
@@ -35977,7 +36356,7 @@ var cachedDevNullReadFd;
|
|
|
35977
36356
|
function devNullReadFd() {
|
|
35978
36357
|
if (cachedDevNullReadFd === void 0) {
|
|
35979
36358
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
35980
|
-
cachedDevNullReadFd =
|
|
36359
|
+
cachedDevNullReadFd = fs24.openSync(devPath, "r");
|
|
35981
36360
|
}
|
|
35982
36361
|
return cachedDevNullReadFd;
|
|
35983
36362
|
}
|
|
@@ -36051,15 +36430,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
36051
36430
|
|
|
36052
36431
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
36053
36432
|
import { spawn as spawn6 } from "node:child_process";
|
|
36054
|
-
import
|
|
36433
|
+
import fs25 from "node:fs";
|
|
36055
36434
|
import { tmpdir } from "node:os";
|
|
36056
|
-
import
|
|
36435
|
+
import path28 from "node:path";
|
|
36057
36436
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
36058
|
-
const tmpRoot =
|
|
36059
|
-
const logPath =
|
|
36437
|
+
const tmpRoot = fs25.mkdtempSync(path28.join(tmpdir(), "ba-devsrv-log-"));
|
|
36438
|
+
const logPath = path28.join(tmpRoot, "combined.log");
|
|
36060
36439
|
let logFd;
|
|
36061
36440
|
try {
|
|
36062
|
-
logFd =
|
|
36441
|
+
logFd = fs25.openSync(logPath, "a");
|
|
36063
36442
|
} catch {
|
|
36064
36443
|
rmDirQuiet(tmpRoot);
|
|
36065
36444
|
return null;
|
|
@@ -36078,7 +36457,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36078
36457
|
} else {
|
|
36079
36458
|
proc = spawn6("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
36080
36459
|
}
|
|
36081
|
-
|
|
36460
|
+
fs25.closeSync(logFd);
|
|
36082
36461
|
return {
|
|
36083
36462
|
proc,
|
|
36084
36463
|
pipedStdoutStderr: true,
|
|
@@ -36087,7 +36466,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36087
36466
|
};
|
|
36088
36467
|
} catch (e) {
|
|
36089
36468
|
try {
|
|
36090
|
-
|
|
36469
|
+
fs25.closeSync(logFd);
|
|
36091
36470
|
} catch {
|
|
36092
36471
|
}
|
|
36093
36472
|
rmDirQuiet(tmpRoot);
|
|
@@ -36098,22 +36477,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36098
36477
|
|
|
36099
36478
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
36100
36479
|
import { spawn as spawn7 } from "node:child_process";
|
|
36101
|
-
import
|
|
36480
|
+
import fs26 from "node:fs";
|
|
36102
36481
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
36103
|
-
import
|
|
36482
|
+
import path29 from "node:path";
|
|
36104
36483
|
function shSingleQuote(s) {
|
|
36105
36484
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
36106
36485
|
}
|
|
36107
36486
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
36108
|
-
const tmpRoot =
|
|
36109
|
-
const logPath =
|
|
36110
|
-
const innerPath =
|
|
36111
|
-
const runnerPath =
|
|
36487
|
+
const tmpRoot = fs26.mkdtempSync(path29.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36488
|
+
const logPath = path29.join(tmpRoot, "combined.log");
|
|
36489
|
+
const innerPath = path29.join(tmpRoot, "_cmd.sh");
|
|
36490
|
+
const runnerPath = path29.join(tmpRoot, "_run.sh");
|
|
36112
36491
|
try {
|
|
36113
|
-
|
|
36492
|
+
fs26.writeFileSync(innerPath, `#!/bin/sh
|
|
36114
36493
|
${command}
|
|
36115
36494
|
`);
|
|
36116
|
-
|
|
36495
|
+
fs26.writeFileSync(
|
|
36117
36496
|
runnerPath,
|
|
36118
36497
|
`#!/bin/sh
|
|
36119
36498
|
cd ${shSingleQuote(cwd)}
|
|
@@ -36139,13 +36518,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
36139
36518
|
}
|
|
36140
36519
|
}
|
|
36141
36520
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
36142
|
-
const tmpRoot =
|
|
36143
|
-
const logPath =
|
|
36144
|
-
const runnerPath =
|
|
36521
|
+
const tmpRoot = fs26.mkdtempSync(path29.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36522
|
+
const logPath = path29.join(tmpRoot, "combined.log");
|
|
36523
|
+
const runnerPath = path29.join(tmpRoot, "_run.bat");
|
|
36145
36524
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
36146
36525
|
const com = process.env.ComSpec || "cmd.exe";
|
|
36147
36526
|
try {
|
|
36148
|
-
|
|
36527
|
+
fs26.writeFileSync(
|
|
36149
36528
|
runnerPath,
|
|
36150
36529
|
`@ECHO OFF\r
|
|
36151
36530
|
CD /D ${q(cwd)}\r
|
|
@@ -37082,30 +37461,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
37082
37461
|
}
|
|
37083
37462
|
|
|
37084
37463
|
// src/skills/discover-local-agent-skills.ts
|
|
37085
|
-
import
|
|
37086
|
-
import
|
|
37464
|
+
import fs27 from "node:fs";
|
|
37465
|
+
import path30 from "node:path";
|
|
37087
37466
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
37088
37467
|
function discoverLocalSkills(cwd) {
|
|
37089
37468
|
const out = [];
|
|
37090
37469
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
37091
37470
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
37092
|
-
const base =
|
|
37093
|
-
if (!
|
|
37471
|
+
const base = path30.join(cwd, rel);
|
|
37472
|
+
if (!fs27.existsSync(base) || !fs27.statSync(base).isDirectory()) continue;
|
|
37094
37473
|
let entries = [];
|
|
37095
37474
|
try {
|
|
37096
|
-
entries =
|
|
37475
|
+
entries = fs27.readdirSync(base);
|
|
37097
37476
|
} catch {
|
|
37098
37477
|
continue;
|
|
37099
37478
|
}
|
|
37100
37479
|
for (const name of entries) {
|
|
37101
|
-
const dir =
|
|
37480
|
+
const dir = path30.join(base, name);
|
|
37102
37481
|
try {
|
|
37103
|
-
if (!
|
|
37482
|
+
if (!fs27.statSync(dir).isDirectory()) continue;
|
|
37104
37483
|
} catch {
|
|
37105
37484
|
continue;
|
|
37106
37485
|
}
|
|
37107
|
-
const skillMd =
|
|
37108
|
-
if (!
|
|
37486
|
+
const skillMd = path30.join(dir, "SKILL.md");
|
|
37487
|
+
if (!fs27.existsSync(skillMd)) continue;
|
|
37109
37488
|
const key = `${rel}/${name}`;
|
|
37110
37489
|
if (seenKeys.has(key)) continue;
|
|
37111
37490
|
seenKeys.add(key);
|
|
@@ -37117,23 +37496,23 @@ function discoverLocalSkills(cwd) {
|
|
|
37117
37496
|
function discoverSkillLayoutRoots(cwd) {
|
|
37118
37497
|
const roots = [];
|
|
37119
37498
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
37120
|
-
const base =
|
|
37121
|
-
if (!
|
|
37499
|
+
const base = path30.join(cwd, rel);
|
|
37500
|
+
if (!fs27.existsSync(base) || !fs27.statSync(base).isDirectory()) continue;
|
|
37122
37501
|
let entries = [];
|
|
37123
37502
|
try {
|
|
37124
|
-
entries =
|
|
37503
|
+
entries = fs27.readdirSync(base);
|
|
37125
37504
|
} catch {
|
|
37126
37505
|
continue;
|
|
37127
37506
|
}
|
|
37128
37507
|
const skills2 = [];
|
|
37129
37508
|
for (const name of entries) {
|
|
37130
|
-
const dir =
|
|
37509
|
+
const dir = path30.join(base, name);
|
|
37131
37510
|
try {
|
|
37132
|
-
if (!
|
|
37511
|
+
if (!fs27.statSync(dir).isDirectory()) continue;
|
|
37133
37512
|
} catch {
|
|
37134
37513
|
continue;
|
|
37135
37514
|
}
|
|
37136
|
-
if (!
|
|
37515
|
+
if (!fs27.existsSync(path30.join(dir, "SKILL.md"))) continue;
|
|
37137
37516
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
37138
37517
|
skills2.push({ name, relPath });
|
|
37139
37518
|
}
|
|
@@ -37315,7 +37694,7 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
37315
37694
|
};
|
|
37316
37695
|
|
|
37317
37696
|
// src/prompt-turn-queue/runner.ts
|
|
37318
|
-
import
|
|
37697
|
+
import fs30 from "node:fs";
|
|
37319
37698
|
|
|
37320
37699
|
// src/prompt-turn-queue/client-report.ts
|
|
37321
37700
|
function sendPromptQueueClientReport(ws, queues) {
|
|
@@ -37325,13 +37704,13 @@ function sendPromptQueueClientReport(ws, queues) {
|
|
|
37325
37704
|
}
|
|
37326
37705
|
|
|
37327
37706
|
// src/prompt-turn-queue/disk-store.ts
|
|
37328
|
-
import
|
|
37707
|
+
import fs29 from "node:fs";
|
|
37329
37708
|
|
|
37330
37709
|
// src/prompt-turn-queue/paths.ts
|
|
37331
37710
|
import crypto3 from "node:crypto";
|
|
37332
|
-
import
|
|
37333
|
-
import
|
|
37334
|
-
import
|
|
37711
|
+
import fs28 from "node:fs";
|
|
37712
|
+
import path31 from "node:path";
|
|
37713
|
+
import os7 from "node:os";
|
|
37335
37714
|
var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
|
|
37336
37715
|
function queueStateFileSlug(queueKey) {
|
|
37337
37716
|
if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
|
|
@@ -37339,15 +37718,15 @@ function queueStateFileSlug(queueKey) {
|
|
|
37339
37718
|
}
|
|
37340
37719
|
function getPromptQueuesDirectory() {
|
|
37341
37720
|
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
37342
|
-
if (override) return
|
|
37343
|
-
return
|
|
37721
|
+
if (override) return path31.resolve(override);
|
|
37722
|
+
return path31.join(os7.homedir(), ".buildautomaton", "queues");
|
|
37344
37723
|
}
|
|
37345
37724
|
function ensurePromptQueuesDirectory() {
|
|
37346
37725
|
const dir = getPromptQueuesDirectory();
|
|
37347
|
-
if (!
|
|
37726
|
+
if (!fs28.existsSync(dir)) fs28.mkdirSync(dir, { recursive: true });
|
|
37348
37727
|
}
|
|
37349
37728
|
function queueStateFilePath(queueKey) {
|
|
37350
|
-
return
|
|
37729
|
+
return path31.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
|
|
37351
37730
|
}
|
|
37352
37731
|
|
|
37353
37732
|
// src/prompt-turn-queue/disk-store.ts
|
|
@@ -37372,7 +37751,7 @@ function parsePersistedQueueFile(raw) {
|
|
|
37372
37751
|
function readPersistedQueue(queueKey) {
|
|
37373
37752
|
const p = queueStateFilePath(queueKey);
|
|
37374
37753
|
try {
|
|
37375
|
-
return parsePersistedQueueFile(
|
|
37754
|
+
return parsePersistedQueueFile(fs29.readFileSync(p, "utf8"));
|
|
37376
37755
|
} catch {
|
|
37377
37756
|
return null;
|
|
37378
37757
|
}
|
|
@@ -37380,7 +37759,7 @@ function readPersistedQueue(queueKey) {
|
|
|
37380
37759
|
function writePersistedQueue(file2) {
|
|
37381
37760
|
ensurePromptQueuesDirectory();
|
|
37382
37761
|
const p = queueStateFilePath(file2.queueKey);
|
|
37383
|
-
|
|
37762
|
+
fs29.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
|
|
37384
37763
|
}
|
|
37385
37764
|
function mergeServerQueueSnapshot(queueKey, serverTurns) {
|
|
37386
37765
|
const prev = readPersistedQueue(queueKey);
|
|
@@ -37438,7 +37817,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
37438
37817
|
const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
|
|
37439
37818
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
37440
37819
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
37441
|
-
if (!
|
|
37820
|
+
if (!fs30.existsSync(file2)) {
|
|
37442
37821
|
deps.log(
|
|
37443
37822
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
37444
37823
|
);
|
|
@@ -37661,9 +38040,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
37661
38040
|
for (const item of raw) {
|
|
37662
38041
|
if (!item || typeof item !== "object") continue;
|
|
37663
38042
|
const o = item;
|
|
37664
|
-
const
|
|
37665
|
-
if (!
|
|
37666
|
-
const row = { path:
|
|
38043
|
+
const path37 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
38044
|
+
if (!path37) continue;
|
|
38045
|
+
const row = { path: path37 };
|
|
37667
38046
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
37668
38047
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
37669
38048
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -37864,8 +38243,8 @@ function randomSecret() {
|
|
|
37864
38243
|
}
|
|
37865
38244
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
37866
38245
|
}
|
|
37867
|
-
async function requestPreviewApi(port, secret, method,
|
|
37868
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
38246
|
+
async function requestPreviewApi(port, secret, method, path37, body) {
|
|
38247
|
+
const url2 = `http://127.0.0.1:${port}${path37}`;
|
|
37869
38248
|
const headers = {
|
|
37870
38249
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
37871
38250
|
"Content-Type": "application/json"
|
|
@@ -37877,7 +38256,7 @@ async function requestPreviewApi(port, secret, method, path36, body) {
|
|
|
37877
38256
|
});
|
|
37878
38257
|
const data = await res.json().catch(() => ({}));
|
|
37879
38258
|
if (!res.ok) {
|
|
37880
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
38259
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path37}: ${res.status}`);
|
|
37881
38260
|
}
|
|
37882
38261
|
return data;
|
|
37883
38262
|
}
|
|
@@ -38042,15 +38421,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
38042
38421
|
};
|
|
38043
38422
|
|
|
38044
38423
|
// src/files/list-dir.ts
|
|
38045
|
-
import
|
|
38046
|
-
import
|
|
38424
|
+
import fs31 from "node:fs";
|
|
38425
|
+
import path33 from "node:path";
|
|
38047
38426
|
|
|
38048
38427
|
// src/files/ensure-under-cwd.ts
|
|
38049
|
-
import
|
|
38428
|
+
import path32 from "node:path";
|
|
38050
38429
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
38051
|
-
const normalized =
|
|
38052
|
-
const resolved =
|
|
38053
|
-
if (!resolved.startsWith(cwd +
|
|
38430
|
+
const normalized = path32.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
38431
|
+
const resolved = path32.resolve(cwd, normalized);
|
|
38432
|
+
if (!resolved.startsWith(cwd + path32.sep) && resolved !== cwd) {
|
|
38054
38433
|
return null;
|
|
38055
38434
|
}
|
|
38056
38435
|
return resolved;
|
|
@@ -38064,7 +38443,7 @@ async function listDirAsync(relativePath) {
|
|
|
38064
38443
|
return { error: "Path is outside working directory" };
|
|
38065
38444
|
}
|
|
38066
38445
|
try {
|
|
38067
|
-
const names = await
|
|
38446
|
+
const names = await fs31.promises.readdir(resolved, { withFileTypes: true });
|
|
38068
38447
|
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
38069
38448
|
const entries = [];
|
|
38070
38449
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -38072,12 +38451,12 @@ async function listDirAsync(relativePath) {
|
|
|
38072
38451
|
await yieldToEventLoop();
|
|
38073
38452
|
}
|
|
38074
38453
|
const d = visible[i];
|
|
38075
|
-
const entryPath =
|
|
38076
|
-
const fullPath =
|
|
38454
|
+
const entryPath = path33.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
38455
|
+
const fullPath = path33.join(resolved, d.name);
|
|
38077
38456
|
let isDir = d.isDirectory();
|
|
38078
38457
|
if (d.isSymbolicLink()) {
|
|
38079
38458
|
try {
|
|
38080
|
-
const targetStat = await
|
|
38459
|
+
const targetStat = await fs31.promises.stat(fullPath);
|
|
38081
38460
|
isDir = targetStat.isDirectory();
|
|
38082
38461
|
} catch {
|
|
38083
38462
|
isDir = false;
|
|
@@ -38102,25 +38481,25 @@ async function listDirAsync(relativePath) {
|
|
|
38102
38481
|
}
|
|
38103
38482
|
|
|
38104
38483
|
// src/files/read-file.ts
|
|
38105
|
-
import
|
|
38484
|
+
import fs32 from "node:fs";
|
|
38106
38485
|
import { StringDecoder } from "node:string_decoder";
|
|
38107
38486
|
function resolveFilePath(relativePath) {
|
|
38108
38487
|
const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
|
|
38109
38488
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
38110
38489
|
let real;
|
|
38111
38490
|
try {
|
|
38112
|
-
real =
|
|
38491
|
+
real = fs32.realpathSync(resolved);
|
|
38113
38492
|
} catch {
|
|
38114
38493
|
real = resolved;
|
|
38115
38494
|
}
|
|
38116
|
-
const stat3 =
|
|
38495
|
+
const stat3 = fs32.statSync(real);
|
|
38117
38496
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
38118
38497
|
return real;
|
|
38119
38498
|
}
|
|
38120
38499
|
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
38121
38500
|
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
38122
|
-
const fileSize =
|
|
38123
|
-
const fd =
|
|
38501
|
+
const fileSize = fs32.statSync(filePath).size;
|
|
38502
|
+
const fd = fs32.openSync(filePath, "r");
|
|
38124
38503
|
const bufSize = 64 * 1024;
|
|
38125
38504
|
const buf = Buffer.alloc(bufSize);
|
|
38126
38505
|
const decoder = new StringDecoder("utf8");
|
|
@@ -38133,7 +38512,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
38133
38512
|
let line0Accum = "";
|
|
38134
38513
|
try {
|
|
38135
38514
|
let bytesRead;
|
|
38136
|
-
while (!done && (bytesRead =
|
|
38515
|
+
while (!done && (bytesRead = fs32.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
38137
38516
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
38138
38517
|
partial2 = "";
|
|
38139
38518
|
let lineStart = 0;
|
|
@@ -38268,7 +38647,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
38268
38647
|
}
|
|
38269
38648
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
38270
38649
|
} finally {
|
|
38271
|
-
|
|
38650
|
+
fs32.closeSync(fd);
|
|
38272
38651
|
}
|
|
38273
38652
|
}
|
|
38274
38653
|
function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
@@ -38279,8 +38658,8 @@ function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
38279
38658
|
if (hasRange) {
|
|
38280
38659
|
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
38281
38660
|
}
|
|
38282
|
-
const stat3 =
|
|
38283
|
-
const raw =
|
|
38661
|
+
const stat3 = fs32.statSync(result);
|
|
38662
|
+
const raw = fs32.readFileSync(result, "utf8");
|
|
38284
38663
|
const lines = raw.split(/\r?\n/);
|
|
38285
38664
|
return { content: raw, totalLines: lines.length, size: stat3.size };
|
|
38286
38665
|
} catch (err) {
|
|
@@ -38398,8 +38777,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
38398
38777
|
}
|
|
38399
38778
|
|
|
38400
38779
|
// src/skills/install-remote-skills.ts
|
|
38401
|
-
import
|
|
38402
|
-
import
|
|
38780
|
+
import fs33 from "node:fs";
|
|
38781
|
+
import path34 from "node:path";
|
|
38403
38782
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
38404
38783
|
const installed2 = [];
|
|
38405
38784
|
if (!Array.isArray(items)) {
|
|
@@ -38410,15 +38789,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
38410
38789
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
38411
38790
|
continue;
|
|
38412
38791
|
}
|
|
38413
|
-
const skillDir =
|
|
38792
|
+
const skillDir = path34.join(cwd, targetDir, item.skillName);
|
|
38414
38793
|
for (const f of item.files) {
|
|
38415
38794
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
38416
|
-
const dest =
|
|
38417
|
-
|
|
38795
|
+
const dest = path34.join(skillDir, f.path);
|
|
38796
|
+
fs33.mkdirSync(path34.dirname(dest), { recursive: true });
|
|
38418
38797
|
if (f.text !== void 0) {
|
|
38419
|
-
|
|
38798
|
+
fs33.writeFileSync(dest, f.text, "utf8");
|
|
38420
38799
|
} else if (f.base64) {
|
|
38421
|
-
|
|
38800
|
+
fs33.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
38422
38801
|
}
|
|
38423
38802
|
}
|
|
38424
38803
|
installed2.push({
|
|
@@ -38568,7 +38947,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
38568
38947
|
};
|
|
38569
38948
|
|
|
38570
38949
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
38571
|
-
import * as
|
|
38950
|
+
import * as fs34 from "node:fs";
|
|
38572
38951
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
38573
38952
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
38574
38953
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -38580,7 +38959,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
38580
38959
|
if (!s) return;
|
|
38581
38960
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
38582
38961
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
38583
|
-
if (!
|
|
38962
|
+
if (!fs34.existsSync(file2)) {
|
|
38584
38963
|
sendWsMessage(s, {
|
|
38585
38964
|
type: "revert_turn_snapshot_result",
|
|
38586
38965
|
id,
|
|
@@ -38953,8 +39332,8 @@ async function createBridgeConnection(options) {
|
|
|
38953
39332
|
getCloudAccessToken: () => tokens.accessToken
|
|
38954
39333
|
};
|
|
38955
39334
|
const identifyReportedPaths = {
|
|
38956
|
-
bridgeRootPath:
|
|
38957
|
-
worktreesRootPath:
|
|
39335
|
+
bridgeRootPath: path35.resolve(getBridgeRoot()),
|
|
39336
|
+
worktreesRootPath: path35.resolve(worktreesRootPath)
|
|
38958
39337
|
};
|
|
38959
39338
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
38960
39339
|
state,
|
|
@@ -39190,9 +39569,9 @@ async function runCliAction(program2, opts) {
|
|
|
39190
39569
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
39191
39570
|
const bridgeRootOpt = (opts.bridgeRoot && typeof opts.bridgeRoot === "string" && opts.bridgeRoot.trim() ? opts.bridgeRoot.trim() : null) ?? (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim() ? opts.cwd.trim() : null);
|
|
39192
39571
|
if (bridgeRootOpt) {
|
|
39193
|
-
const resolvedBridgeRoot =
|
|
39572
|
+
const resolvedBridgeRoot = path36.resolve(process.cwd(), bridgeRootOpt);
|
|
39194
39573
|
try {
|
|
39195
|
-
const st =
|
|
39574
|
+
const st = fs35.statSync(resolvedBridgeRoot);
|
|
39196
39575
|
if (!st.isDirectory()) {
|
|
39197
39576
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
39198
39577
|
process.exit(1);
|
|
@@ -39212,7 +39591,7 @@ async function runCliAction(program2, opts) {
|
|
|
39212
39591
|
);
|
|
39213
39592
|
let worktreesRootPath;
|
|
39214
39593
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
39215
|
-
worktreesRootPath =
|
|
39594
|
+
worktreesRootPath = path36.resolve(opts.worktreesRoot.trim());
|
|
39216
39595
|
}
|
|
39217
39596
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
39218
39597
|
if (e2eCertificates) {
|