@buildautomaton/cli 0.1.68 → 0.1.70
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 +1201 -883
- package/dist/cli.js.map +4 -4
- package/dist/index.js +935 -617
- 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 path84 = __require("node:path");
|
|
977
|
+
var fs63 = __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 = path84.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs63.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path84.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs63.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 = fs63.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path84.resolve(
|
|
1930
|
+
path84.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 = path84.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path84.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(path84.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 = path84.basename(filename, path84.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(path85) {
|
|
2805
|
+
if (path85 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path85;
|
|
2807
2807
|
return this;
|
|
2808
2808
|
}
|
|
2809
2809
|
/**
|
|
@@ -7729,7 +7729,7 @@ function readMigrationSql(filename, ...searchSubdirs) {
|
|
|
7729
7729
|
join2(moduleDir, "..", sub, filename),
|
|
7730
7730
|
join2(moduleDir, "..", "..", "dist", sub, filename)
|
|
7731
7731
|
]);
|
|
7732
|
-
const resolved = candidates.find((
|
|
7732
|
+
const resolved = candidates.find((path84) => existsSync(path84));
|
|
7733
7733
|
if (!resolved) {
|
|
7734
7734
|
throw new Error(`Missing SQLite migration SQL: ${filename} (searched ${searchSubdirs.join(", ")})`);
|
|
7735
7735
|
}
|
|
@@ -8800,7 +8800,7 @@ var require_ignore = __commonJS({
|
|
|
8800
8800
|
// path matching.
|
|
8801
8801
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
8802
8802
|
// @returns {TestResult} true if a file is ignored
|
|
8803
|
-
test(
|
|
8803
|
+
test(path84, checkUnignored, mode) {
|
|
8804
8804
|
let ignored = false;
|
|
8805
8805
|
let unignored = false;
|
|
8806
8806
|
let matchedRule;
|
|
@@ -8809,7 +8809,7 @@ var require_ignore = __commonJS({
|
|
|
8809
8809
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
8810
8810
|
return;
|
|
8811
8811
|
}
|
|
8812
|
-
const matched = rule[mode].test(
|
|
8812
|
+
const matched = rule[mode].test(path84);
|
|
8813
8813
|
if (!matched) {
|
|
8814
8814
|
return;
|
|
8815
8815
|
}
|
|
@@ -8830,17 +8830,17 @@ var require_ignore = __commonJS({
|
|
|
8830
8830
|
var throwError = (message, Ctor) => {
|
|
8831
8831
|
throw new Ctor(message);
|
|
8832
8832
|
};
|
|
8833
|
-
var checkPath = (
|
|
8834
|
-
if (!isString(
|
|
8833
|
+
var checkPath = (path84, originalPath, doThrow) => {
|
|
8834
|
+
if (!isString(path84)) {
|
|
8835
8835
|
return doThrow(
|
|
8836
8836
|
`path must be a string, but got \`${originalPath}\``,
|
|
8837
8837
|
TypeError
|
|
8838
8838
|
);
|
|
8839
8839
|
}
|
|
8840
|
-
if (!
|
|
8840
|
+
if (!path84) {
|
|
8841
8841
|
return doThrow(`path must not be empty`, TypeError);
|
|
8842
8842
|
}
|
|
8843
|
-
if (checkPath.isNotRelative(
|
|
8843
|
+
if (checkPath.isNotRelative(path84)) {
|
|
8844
8844
|
const r = "`path.relative()`d";
|
|
8845
8845
|
return doThrow(
|
|
8846
8846
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -8849,7 +8849,7 @@ var require_ignore = __commonJS({
|
|
|
8849
8849
|
}
|
|
8850
8850
|
return true;
|
|
8851
8851
|
};
|
|
8852
|
-
var isNotRelative = (
|
|
8852
|
+
var isNotRelative = (path84) => REGEX_TEST_INVALID_PATH.test(path84);
|
|
8853
8853
|
checkPath.isNotRelative = isNotRelative;
|
|
8854
8854
|
checkPath.convert = (p) => p;
|
|
8855
8855
|
var Ignore = class {
|
|
@@ -8879,19 +8879,19 @@ var require_ignore = __commonJS({
|
|
|
8879
8879
|
}
|
|
8880
8880
|
// @returns {TestResult}
|
|
8881
8881
|
_test(originalPath, cache2, checkUnignored, slices) {
|
|
8882
|
-
const
|
|
8882
|
+
const path84 = originalPath && checkPath.convert(originalPath);
|
|
8883
8883
|
checkPath(
|
|
8884
|
-
|
|
8884
|
+
path84,
|
|
8885
8885
|
originalPath,
|
|
8886
8886
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
8887
8887
|
);
|
|
8888
|
-
return this._t(
|
|
8888
|
+
return this._t(path84, cache2, checkUnignored, slices);
|
|
8889
8889
|
}
|
|
8890
|
-
checkIgnore(
|
|
8891
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
8892
|
-
return this.test(
|
|
8890
|
+
checkIgnore(path84) {
|
|
8891
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path84)) {
|
|
8892
|
+
return this.test(path84);
|
|
8893
8893
|
}
|
|
8894
|
-
const slices =
|
|
8894
|
+
const slices = path84.split(SLASH).filter(Boolean);
|
|
8895
8895
|
slices.pop();
|
|
8896
8896
|
if (slices.length) {
|
|
8897
8897
|
const parent = this._t(
|
|
@@ -8904,18 +8904,18 @@ var require_ignore = __commonJS({
|
|
|
8904
8904
|
return parent;
|
|
8905
8905
|
}
|
|
8906
8906
|
}
|
|
8907
|
-
return this._rules.test(
|
|
8907
|
+
return this._rules.test(path84, false, MODE_CHECK_IGNORE);
|
|
8908
8908
|
}
|
|
8909
|
-
_t(
|
|
8910
|
-
if (
|
|
8911
|
-
return cache2[
|
|
8909
|
+
_t(path84, cache2, checkUnignored, slices) {
|
|
8910
|
+
if (path84 in cache2) {
|
|
8911
|
+
return cache2[path84];
|
|
8912
8912
|
}
|
|
8913
8913
|
if (!slices) {
|
|
8914
|
-
slices =
|
|
8914
|
+
slices = path84.split(SLASH).filter(Boolean);
|
|
8915
8915
|
}
|
|
8916
8916
|
slices.pop();
|
|
8917
8917
|
if (!slices.length) {
|
|
8918
|
-
return cache2[
|
|
8918
|
+
return cache2[path84] = this._rules.test(path84, checkUnignored, MODE_IGNORE);
|
|
8919
8919
|
}
|
|
8920
8920
|
const parent = this._t(
|
|
8921
8921
|
slices.join(SLASH) + SLASH,
|
|
@@ -8923,29 +8923,29 @@ var require_ignore = __commonJS({
|
|
|
8923
8923
|
checkUnignored,
|
|
8924
8924
|
slices
|
|
8925
8925
|
);
|
|
8926
|
-
return cache2[
|
|
8926
|
+
return cache2[path84] = parent.ignored ? parent : this._rules.test(path84, checkUnignored, MODE_IGNORE);
|
|
8927
8927
|
}
|
|
8928
|
-
ignores(
|
|
8929
|
-
return this._test(
|
|
8928
|
+
ignores(path84) {
|
|
8929
|
+
return this._test(path84, this._ignoreCache, false).ignored;
|
|
8930
8930
|
}
|
|
8931
8931
|
createFilter() {
|
|
8932
|
-
return (
|
|
8932
|
+
return (path84) => !this.ignores(path84);
|
|
8933
8933
|
}
|
|
8934
8934
|
filter(paths) {
|
|
8935
8935
|
return makeArray(paths).filter(this.createFilter());
|
|
8936
8936
|
}
|
|
8937
8937
|
// @returns {TestResult}
|
|
8938
|
-
test(
|
|
8939
|
-
return this._test(
|
|
8938
|
+
test(path84) {
|
|
8939
|
+
return this._test(path84, this._testCache, true);
|
|
8940
8940
|
}
|
|
8941
8941
|
};
|
|
8942
8942
|
var factory = (options) => new Ignore(options);
|
|
8943
|
-
var isPathValid = (
|
|
8943
|
+
var isPathValid = (path84) => checkPath(path84 && checkPath.convert(path84), path84, RETURN_FALSE);
|
|
8944
8944
|
var setupWindows = () => {
|
|
8945
8945
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
8946
8946
|
checkPath.convert = makePosix;
|
|
8947
8947
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
8948
|
-
checkPath.isNotRelative = (
|
|
8948
|
+
checkPath.isNotRelative = (path84) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path84) || isNotRelative(path84);
|
|
8949
8949
|
};
|
|
8950
8950
|
if (
|
|
8951
8951
|
// Detect `process` so that it can run in browsers.
|
|
@@ -12951,8 +12951,8 @@ var init_parseUtil = __esm({
|
|
|
12951
12951
|
init_errors();
|
|
12952
12952
|
init_en();
|
|
12953
12953
|
makeIssue = (params) => {
|
|
12954
|
-
const { data, path:
|
|
12955
|
-
const fullPath = [...
|
|
12954
|
+
const { data, path: path84, errorMaps, issueData } = params;
|
|
12955
|
+
const fullPath = [...path84, ...issueData.path || []];
|
|
12956
12956
|
const fullIssue = {
|
|
12957
12957
|
...issueData,
|
|
12958
12958
|
path: fullPath
|
|
@@ -13260,11 +13260,11 @@ var init_types2 = __esm({
|
|
|
13260
13260
|
init_parseUtil();
|
|
13261
13261
|
init_util();
|
|
13262
13262
|
ParseInputLazyPath = class {
|
|
13263
|
-
constructor(parent, value,
|
|
13263
|
+
constructor(parent, value, path84, key) {
|
|
13264
13264
|
this._cachedPath = [];
|
|
13265
13265
|
this.parent = parent;
|
|
13266
13266
|
this.data = value;
|
|
13267
|
-
this._path =
|
|
13267
|
+
this._path = path84;
|
|
13268
13268
|
this._key = key;
|
|
13269
13269
|
}
|
|
13270
13270
|
get path() {
|
|
@@ -16989,10 +16989,10 @@ function assignProp(target, prop, value) {
|
|
|
16989
16989
|
configurable: true
|
|
16990
16990
|
});
|
|
16991
16991
|
}
|
|
16992
|
-
function getElementAtPath(obj,
|
|
16993
|
-
if (!
|
|
16992
|
+
function getElementAtPath(obj, path84) {
|
|
16993
|
+
if (!path84)
|
|
16994
16994
|
return obj;
|
|
16995
|
-
return
|
|
16995
|
+
return path84.reduce((acc, key) => acc?.[key], obj);
|
|
16996
16996
|
}
|
|
16997
16997
|
function promiseAllObject(promisesObj) {
|
|
16998
16998
|
const keys = Object.keys(promisesObj);
|
|
@@ -17241,11 +17241,11 @@ function aborted(x, startIndex = 0) {
|
|
|
17241
17241
|
}
|
|
17242
17242
|
return false;
|
|
17243
17243
|
}
|
|
17244
|
-
function prefixIssues(
|
|
17244
|
+
function prefixIssues(path84, issues) {
|
|
17245
17245
|
return issues.map((iss) => {
|
|
17246
17246
|
var _a2;
|
|
17247
17247
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
17248
|
-
iss.path.unshift(
|
|
17248
|
+
iss.path.unshift(path84);
|
|
17249
17249
|
return iss;
|
|
17250
17250
|
});
|
|
17251
17251
|
}
|
|
@@ -17434,7 +17434,7 @@ function treeifyError(error40, _mapper) {
|
|
|
17434
17434
|
return issue2.message;
|
|
17435
17435
|
};
|
|
17436
17436
|
const result = { errors: [] };
|
|
17437
|
-
const processError = (error41,
|
|
17437
|
+
const processError = (error41, path84 = []) => {
|
|
17438
17438
|
var _a2, _b;
|
|
17439
17439
|
for (const issue2 of error41.issues) {
|
|
17440
17440
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -17444,7 +17444,7 @@ function treeifyError(error40, _mapper) {
|
|
|
17444
17444
|
} else if (issue2.code === "invalid_element") {
|
|
17445
17445
|
processError({ issues: issue2.issues }, issue2.path);
|
|
17446
17446
|
} else {
|
|
17447
|
-
const fullpath = [...
|
|
17447
|
+
const fullpath = [...path84, ...issue2.path];
|
|
17448
17448
|
if (fullpath.length === 0) {
|
|
17449
17449
|
result.errors.push(mapper(issue2));
|
|
17450
17450
|
continue;
|
|
@@ -17474,9 +17474,9 @@ function treeifyError(error40, _mapper) {
|
|
|
17474
17474
|
processError(error40);
|
|
17475
17475
|
return result;
|
|
17476
17476
|
}
|
|
17477
|
-
function toDotPath(
|
|
17477
|
+
function toDotPath(path84) {
|
|
17478
17478
|
const segs = [];
|
|
17479
|
-
for (const seg of
|
|
17479
|
+
for (const seg of path84) {
|
|
17480
17480
|
if (typeof seg === "number")
|
|
17481
17481
|
segs.push(`[${seg}]`);
|
|
17482
17482
|
else if (typeof seg === "symbol")
|
|
@@ -30959,10 +30959,10 @@ var require_src2 = __commonJS({
|
|
|
30959
30959
|
var fs_1 = __require("fs");
|
|
30960
30960
|
var debug_1 = __importDefault(require_src());
|
|
30961
30961
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
30962
|
-
function check2(
|
|
30963
|
-
log2(`checking %s`,
|
|
30962
|
+
function check2(path84, isFile, isDirectory) {
|
|
30963
|
+
log2(`checking %s`, path84);
|
|
30964
30964
|
try {
|
|
30965
|
-
const stat3 = fs_1.statSync(
|
|
30965
|
+
const stat3 = fs_1.statSync(path84);
|
|
30966
30966
|
if (stat3.isFile() && isFile) {
|
|
30967
30967
|
log2(`[OK] path represents a file`);
|
|
30968
30968
|
return true;
|
|
@@ -30982,8 +30982,8 @@ var require_src2 = __commonJS({
|
|
|
30982
30982
|
throw e;
|
|
30983
30983
|
}
|
|
30984
30984
|
}
|
|
30985
|
-
function exists2(
|
|
30986
|
-
return check2(
|
|
30985
|
+
function exists2(path84, type = exports.READABLE) {
|
|
30986
|
+
return check2(path84, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
30987
30987
|
}
|
|
30988
30988
|
exports.exists = exists2;
|
|
30989
30989
|
exports.FILE = 1;
|
|
@@ -31064,7 +31064,7 @@ var {
|
|
|
31064
31064
|
} = import_index.default;
|
|
31065
31065
|
|
|
31066
31066
|
// src/cli-version.ts
|
|
31067
|
-
var CLI_VERSION = "0.1.
|
|
31067
|
+
var CLI_VERSION = "0.1.70".length > 0 ? "0.1.70" : "0.0.0-dev";
|
|
31068
31068
|
|
|
31069
31069
|
// src/cli/defaults.ts
|
|
31070
31070
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
@@ -31072,8 +31072,8 @@ var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
|
31072
31072
|
|
|
31073
31073
|
// src/cli/run-cli-action.ts
|
|
31074
31074
|
init_cli_log_level();
|
|
31075
|
-
import * as
|
|
31076
|
-
import * as
|
|
31075
|
+
import * as fs62 from "node:fs";
|
|
31076
|
+
import * as path83 from "node:path";
|
|
31077
31077
|
|
|
31078
31078
|
// src/config.ts
|
|
31079
31079
|
import fs from "node:fs";
|
|
@@ -34902,6 +34902,18 @@ function getAgentModelFromAgentConfig(config2) {
|
|
|
34902
34902
|
return t !== "" ? t : null;
|
|
34903
34903
|
}
|
|
34904
34904
|
|
|
34905
|
+
// ../types/src/overview/heatmap/constants.ts
|
|
34906
|
+
var HOUR_MS = 36e5;
|
|
34907
|
+
var DAY_MS = 24 * HOUR_MS;
|
|
34908
|
+
|
|
34909
|
+
// ../types/src/bridges/agents/types.ts
|
|
34910
|
+
var INSTALLABLE_BRIDGE_AGENTS = [
|
|
34911
|
+
{ value: "claude-code", label: "Anthropic Claude Code", tokenLabel: "Anthropic API key", tokenEnvVar: "ANTHROPIC_API_KEY" },
|
|
34912
|
+
{ value: "codex-acp", label: "Codex", tokenLabel: "OpenAI API key", tokenEnvVar: "OPENAI_API_KEY" },
|
|
34913
|
+
{ value: "cursor-cli", label: "Cursor CLI agent", tokenLabel: "Cursor API key", tokenEnvVar: "CURSOR_API_KEY" },
|
|
34914
|
+
{ value: "opencode", label: "OpenCode agent", tokenLabel: "Provider API key", tokenEnvVar: "OPENCODE_API_KEY" }
|
|
34915
|
+
];
|
|
34916
|
+
|
|
34905
34917
|
// src/paths/session-layout-paths.ts
|
|
34906
34918
|
import * as path26 from "node:path";
|
|
34907
34919
|
function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
|
|
@@ -37952,8 +37964,8 @@ async function execGitFile(args, options) {
|
|
|
37952
37964
|
}
|
|
37953
37965
|
|
|
37954
37966
|
// src/git/changes/parse/normalize-git-diff-path.ts
|
|
37955
|
-
function normalizeGitDiffPath(
|
|
37956
|
-
return
|
|
37967
|
+
function normalizeGitDiffPath(path84) {
|
|
37968
|
+
return path84.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
|
|
37957
37969
|
}
|
|
37958
37970
|
|
|
37959
37971
|
// src/git/changes/parse/parse-name-status-entries.ts
|
|
@@ -39291,6 +39303,21 @@ function createBridgeMcpToolRegistry(shared) {
|
|
|
39291
39303
|
// src/mcp/bridge-access/start-server.ts
|
|
39292
39304
|
import * as http from "node:http";
|
|
39293
39305
|
|
|
39306
|
+
// src/http/close-http-server.ts
|
|
39307
|
+
function isServerNotRunningError(err) {
|
|
39308
|
+
return err.code === "ERR_SERVER_NOT_RUNNING";
|
|
39309
|
+
}
|
|
39310
|
+
function closeHttpServer(server) {
|
|
39311
|
+
if (!server) return Promise.resolve();
|
|
39312
|
+
return new Promise((resolve37) => {
|
|
39313
|
+
server.close((err) => {
|
|
39314
|
+
if (err && !isServerNotRunningError(err)) {
|
|
39315
|
+
}
|
|
39316
|
+
resolve37();
|
|
39317
|
+
});
|
|
39318
|
+
});
|
|
39319
|
+
}
|
|
39320
|
+
|
|
39294
39321
|
// src/mcp/bridge-access/read-json-body.ts
|
|
39295
39322
|
function readJsonBody(req) {
|
|
39296
39323
|
return new Promise((resolve37, reject) => {
|
|
@@ -39372,9 +39399,7 @@ function startBridgeAccessServer(registry2) {
|
|
|
39372
39399
|
}
|
|
39373
39400
|
resolve37({
|
|
39374
39401
|
port: addr.port,
|
|
39375
|
-
close: () =>
|
|
39376
|
-
server.close((err) => err ? closeReject(err) : closeResolve());
|
|
39377
|
-
})
|
|
39402
|
+
close: () => closeHttpServer(server)
|
|
39378
39403
|
});
|
|
39379
39404
|
});
|
|
39380
39405
|
});
|
|
@@ -42215,8 +42240,8 @@ function pathspec(...paths) {
|
|
|
42215
42240
|
cache.set(key, paths);
|
|
42216
42241
|
return key;
|
|
42217
42242
|
}
|
|
42218
|
-
function isPathSpec(
|
|
42219
|
-
return
|
|
42243
|
+
function isPathSpec(path84) {
|
|
42244
|
+
return path84 instanceof String && cache.has(path84);
|
|
42220
42245
|
}
|
|
42221
42246
|
function toPaths(pathSpec) {
|
|
42222
42247
|
return cache.get(pathSpec) || [];
|
|
@@ -42305,8 +42330,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
42305
42330
|
function forEachLineWithContent(input, callback) {
|
|
42306
42331
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
42307
42332
|
}
|
|
42308
|
-
function folderExists(
|
|
42309
|
-
return (0, import_file_exists.exists)(
|
|
42333
|
+
function folderExists(path84) {
|
|
42334
|
+
return (0, import_file_exists.exists)(path84, import_file_exists.FOLDER);
|
|
42310
42335
|
}
|
|
42311
42336
|
function append(target, item) {
|
|
42312
42337
|
if (Array.isArray(target)) {
|
|
@@ -42710,8 +42735,8 @@ function checkIsRepoRootTask() {
|
|
|
42710
42735
|
commands,
|
|
42711
42736
|
format: "utf-8",
|
|
42712
42737
|
onError,
|
|
42713
|
-
parser(
|
|
42714
|
-
return /^\.(git)?$/.test(
|
|
42738
|
+
parser(path84) {
|
|
42739
|
+
return /^\.(git)?$/.test(path84.trim());
|
|
42715
42740
|
}
|
|
42716
42741
|
};
|
|
42717
42742
|
}
|
|
@@ -43145,11 +43170,11 @@ function parseGrep(grep) {
|
|
|
43145
43170
|
const paths = /* @__PURE__ */ new Set();
|
|
43146
43171
|
const results = {};
|
|
43147
43172
|
forEachLineWithContent(grep, (input) => {
|
|
43148
|
-
const [
|
|
43149
|
-
paths.add(
|
|
43150
|
-
(results[
|
|
43173
|
+
const [path84, line, preview] = input.split(NULL);
|
|
43174
|
+
paths.add(path84);
|
|
43175
|
+
(results[path84] = results[path84] || []).push({
|
|
43151
43176
|
line: asNumber(line),
|
|
43152
|
-
path:
|
|
43177
|
+
path: path84,
|
|
43153
43178
|
preview
|
|
43154
43179
|
});
|
|
43155
43180
|
});
|
|
@@ -43914,14 +43939,14 @@ var init_hash_object = __esm2({
|
|
|
43914
43939
|
init_task();
|
|
43915
43940
|
}
|
|
43916
43941
|
});
|
|
43917
|
-
function parseInit(bare,
|
|
43942
|
+
function parseInit(bare, path84, text) {
|
|
43918
43943
|
const response = String(text).trim();
|
|
43919
43944
|
let result;
|
|
43920
43945
|
if (result = initResponseRegex.exec(response)) {
|
|
43921
|
-
return new InitSummary(bare,
|
|
43946
|
+
return new InitSummary(bare, path84, false, result[1]);
|
|
43922
43947
|
}
|
|
43923
43948
|
if (result = reInitResponseRegex.exec(response)) {
|
|
43924
|
-
return new InitSummary(bare,
|
|
43949
|
+
return new InitSummary(bare, path84, true, result[1]);
|
|
43925
43950
|
}
|
|
43926
43951
|
let gitDir = "";
|
|
43927
43952
|
const tokens = response.split(" ");
|
|
@@ -43932,7 +43957,7 @@ function parseInit(bare, path82, text) {
|
|
|
43932
43957
|
break;
|
|
43933
43958
|
}
|
|
43934
43959
|
}
|
|
43935
|
-
return new InitSummary(bare,
|
|
43960
|
+
return new InitSummary(bare, path84, /^re/i.test(response), gitDir);
|
|
43936
43961
|
}
|
|
43937
43962
|
var InitSummary;
|
|
43938
43963
|
var initResponseRegex;
|
|
@@ -43941,9 +43966,9 @@ var init_InitSummary = __esm2({
|
|
|
43941
43966
|
"src/lib/responses/InitSummary.ts"() {
|
|
43942
43967
|
"use strict";
|
|
43943
43968
|
InitSummary = class {
|
|
43944
|
-
constructor(bare,
|
|
43969
|
+
constructor(bare, path84, existing, gitDir) {
|
|
43945
43970
|
this.bare = bare;
|
|
43946
|
-
this.path =
|
|
43971
|
+
this.path = path84;
|
|
43947
43972
|
this.existing = existing;
|
|
43948
43973
|
this.gitDir = gitDir;
|
|
43949
43974
|
}
|
|
@@ -43955,7 +43980,7 @@ var init_InitSummary = __esm2({
|
|
|
43955
43980
|
function hasBareCommand(command) {
|
|
43956
43981
|
return command.includes(bareCommand);
|
|
43957
43982
|
}
|
|
43958
|
-
function initTask(bare = false,
|
|
43983
|
+
function initTask(bare = false, path84, customArgs) {
|
|
43959
43984
|
const commands = ["init", ...customArgs];
|
|
43960
43985
|
if (bare && !hasBareCommand(commands)) {
|
|
43961
43986
|
commands.splice(1, 0, bareCommand);
|
|
@@ -43964,7 +43989,7 @@ function initTask(bare = false, path82, customArgs) {
|
|
|
43964
43989
|
commands,
|
|
43965
43990
|
format: "utf-8",
|
|
43966
43991
|
parser(text) {
|
|
43967
|
-
return parseInit(commands.includes("--bare"),
|
|
43992
|
+
return parseInit(commands.includes("--bare"), path84, text);
|
|
43968
43993
|
}
|
|
43969
43994
|
};
|
|
43970
43995
|
}
|
|
@@ -44780,12 +44805,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
44780
44805
|
"use strict";
|
|
44781
44806
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
44782
44807
|
FileStatusSummary = class {
|
|
44783
|
-
constructor(
|
|
44784
|
-
this.path =
|
|
44808
|
+
constructor(path84, index, working_dir) {
|
|
44809
|
+
this.path = path84;
|
|
44785
44810
|
this.index = index;
|
|
44786
44811
|
this.working_dir = working_dir;
|
|
44787
44812
|
if (index === "R" || working_dir === "R") {
|
|
44788
|
-
const detail = fromPathRegex.exec(
|
|
44813
|
+
const detail = fromPathRegex.exec(path84) || [null, path84, path84];
|
|
44789
44814
|
this.from = detail[2] || "";
|
|
44790
44815
|
this.path = detail[1] || "";
|
|
44791
44816
|
}
|
|
@@ -44816,14 +44841,14 @@ function splitLine(result, lineStr) {
|
|
|
44816
44841
|
default:
|
|
44817
44842
|
return;
|
|
44818
44843
|
}
|
|
44819
|
-
function data(index, workingDir,
|
|
44844
|
+
function data(index, workingDir, path84) {
|
|
44820
44845
|
const raw = `${index}${workingDir}`;
|
|
44821
44846
|
const handler = parsers6.get(raw);
|
|
44822
44847
|
if (handler) {
|
|
44823
|
-
handler(result,
|
|
44848
|
+
handler(result, path84);
|
|
44824
44849
|
}
|
|
44825
44850
|
if (raw !== "##" && raw !== "!!") {
|
|
44826
|
-
result.files.push(new FileStatusSummary(
|
|
44851
|
+
result.files.push(new FileStatusSummary(path84, index, workingDir));
|
|
44827
44852
|
}
|
|
44828
44853
|
}
|
|
44829
44854
|
}
|
|
@@ -45132,9 +45157,9 @@ var init_simple_git_api = __esm2({
|
|
|
45132
45157
|
next
|
|
45133
45158
|
);
|
|
45134
45159
|
}
|
|
45135
|
-
hashObject(
|
|
45160
|
+
hashObject(path84, write) {
|
|
45136
45161
|
return this._runTask(
|
|
45137
|
-
hashObjectTask(
|
|
45162
|
+
hashObjectTask(path84, write === true),
|
|
45138
45163
|
trailingFunctionArgument(arguments)
|
|
45139
45164
|
);
|
|
45140
45165
|
}
|
|
@@ -45487,8 +45512,8 @@ var init_branch = __esm2({
|
|
|
45487
45512
|
}
|
|
45488
45513
|
});
|
|
45489
45514
|
function toPath(input) {
|
|
45490
|
-
const
|
|
45491
|
-
return
|
|
45515
|
+
const path84 = input.trim().replace(/^["']|["']$/g, "");
|
|
45516
|
+
return path84 && normalize3(path84);
|
|
45492
45517
|
}
|
|
45493
45518
|
var parseCheckIgnore;
|
|
45494
45519
|
var init_CheckIgnore = __esm2({
|
|
@@ -45802,8 +45827,8 @@ __export2(sub_module_exports, {
|
|
|
45802
45827
|
subModuleTask: () => subModuleTask,
|
|
45803
45828
|
updateSubModuleTask: () => updateSubModuleTask
|
|
45804
45829
|
});
|
|
45805
|
-
function addSubModuleTask(repo,
|
|
45806
|
-
return subModuleTask(["add", repo,
|
|
45830
|
+
function addSubModuleTask(repo, path84) {
|
|
45831
|
+
return subModuleTask(["add", repo, path84]);
|
|
45807
45832
|
}
|
|
45808
45833
|
function initSubModuleTask(customArgs) {
|
|
45809
45834
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -46136,8 +46161,8 @@ var require_git = __commonJS2({
|
|
|
46136
46161
|
}
|
|
46137
46162
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
46138
46163
|
};
|
|
46139
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
46140
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
46164
|
+
Git2.prototype.submoduleAdd = function(repo, path84, then) {
|
|
46165
|
+
return this._runTask(addSubModuleTask2(repo, path84), trailingFunctionArgument2(arguments));
|
|
46141
46166
|
};
|
|
46142
46167
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
46143
46168
|
return this._runTask(
|
|
@@ -46876,8 +46901,8 @@ function parseNumstatEntries(lines) {
|
|
|
46876
46901
|
}
|
|
46877
46902
|
function parseNumstat(lines) {
|
|
46878
46903
|
const m = /* @__PURE__ */ new Map();
|
|
46879
|
-
for (const [
|
|
46880
|
-
m.set(
|
|
46904
|
+
for (const [path84, entry] of parseNumstatEntries(lines)) {
|
|
46905
|
+
m.set(path84, { additions: entry.additions, deletions: entry.deletions });
|
|
46881
46906
|
}
|
|
46882
46907
|
return m;
|
|
46883
46908
|
}
|
|
@@ -48672,9 +48697,8 @@ function parseSessionParent(v) {
|
|
|
48672
48697
|
return null;
|
|
48673
48698
|
}
|
|
48674
48699
|
|
|
48675
|
-
// src/worktrees/prepare-new-isolated-worktrees.ts
|
|
48676
|
-
import * as
|
|
48677
|
-
import * as path65 from "node:path";
|
|
48700
|
+
// src/worktrees/prepare/prepare-new-isolated-worktrees.ts
|
|
48701
|
+
import * as fs47 from "node:fs";
|
|
48678
48702
|
|
|
48679
48703
|
// src/git/discover-repos.ts
|
|
48680
48704
|
import * as fs44 from "node:fs";
|
|
@@ -48745,6 +48769,10 @@ async function discoverGitReposUnderRoot(rootPath) {
|
|
|
48745
48769
|
return out;
|
|
48746
48770
|
}
|
|
48747
48771
|
|
|
48772
|
+
// src/worktrees/prepare/add-isolated-repo-worktree.ts
|
|
48773
|
+
import * as fs46 from "node:fs";
|
|
48774
|
+
import * as path66 from "node:path";
|
|
48775
|
+
|
|
48748
48776
|
// src/git/worktrees/worktree-add.ts
|
|
48749
48777
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
48750
48778
|
const mainGit = cliSimpleGit(mainRepoPath);
|
|
@@ -48758,6 +48786,100 @@ async function gitWorktreeAddExistingBranch(mainRepoPath, worktreePath, branch)
|
|
|
48758
48786
|
await mainGit.raw(["worktree", "add", worktreePath, branch]);
|
|
48759
48787
|
}
|
|
48760
48788
|
|
|
48789
|
+
// src/worktrees/prepare/copy-bridge-files-along-worktree-path.ts
|
|
48790
|
+
import * as fs45 from "node:fs";
|
|
48791
|
+
import * as path65 from "node:path";
|
|
48792
|
+
var BRIDGE_FILES_ALONG_WORKTREE_PATH = ["AGENTS.md"];
|
|
48793
|
+
function copyBridgeFilesAlongWorktreePath(options) {
|
|
48794
|
+
const { bridgeRoot, scopeDir, repoPathRelativeToBridgeRoot, log: log2 } = options;
|
|
48795
|
+
const fileNames = options.fileNames ?? BRIDGE_FILES_ALONG_WORKTREE_PATH;
|
|
48796
|
+
if (repoPathRelativeToBridgeRoot === ".") return;
|
|
48797
|
+
const segments = repoPathRelativeToBridgeRoot.split("/").filter(Boolean);
|
|
48798
|
+
for (let i = 0; i < segments.length; i++) {
|
|
48799
|
+
const prefix = segments.slice(0, i).join("/");
|
|
48800
|
+
const bridgeDir = prefix ? path65.join(bridgeRoot, prefix) : bridgeRoot;
|
|
48801
|
+
const destDir = prefix ? path65.join(scopeDir, prefix) : scopeDir;
|
|
48802
|
+
for (const fileName of fileNames) {
|
|
48803
|
+
copyFileIfPresent(bridgeDir, destDir, fileName, log2);
|
|
48804
|
+
}
|
|
48805
|
+
}
|
|
48806
|
+
}
|
|
48807
|
+
function copyFileIfPresent(srcDir, destDir, fileName, log2) {
|
|
48808
|
+
const src = path65.join(srcDir, fileName);
|
|
48809
|
+
if (!fs45.existsSync(src)) return;
|
|
48810
|
+
const dest = path65.join(destDir, fileName);
|
|
48811
|
+
try {
|
|
48812
|
+
fs45.copyFileSync(src, dest);
|
|
48813
|
+
log2?.(`[worktrees] Copied ${fileName} to ${dest}`);
|
|
48814
|
+
} catch (e) {
|
|
48815
|
+
log2?.(
|
|
48816
|
+
`[worktrees] Failed to copy ${fileName} to ${dest}: ${e instanceof Error ? e.message : String(e)}`
|
|
48817
|
+
);
|
|
48818
|
+
}
|
|
48819
|
+
}
|
|
48820
|
+
|
|
48821
|
+
// src/worktrees/prepare/resolve-base-ref-for-repo.ts
|
|
48822
|
+
function resolveBaseRefForRepo(repoPathRelativeToBridgeRoot, baseBranches) {
|
|
48823
|
+
if (!baseBranches) return "HEAD";
|
|
48824
|
+
const direct = baseBranches[repoPathRelativeToBridgeRoot]?.trim();
|
|
48825
|
+
if (direct) return direct;
|
|
48826
|
+
if (repoPathRelativeToBridgeRoot !== "." && baseBranches["."]?.trim()) {
|
|
48827
|
+
return baseBranches["."].trim();
|
|
48828
|
+
}
|
|
48829
|
+
return "HEAD";
|
|
48830
|
+
}
|
|
48831
|
+
|
|
48832
|
+
// src/worktrees/prepare/add-isolated-repo-worktree.ts
|
|
48833
|
+
async function addIsolatedRepoWorktree(options) {
|
|
48834
|
+
const {
|
|
48835
|
+
kind,
|
|
48836
|
+
bridgeResolved,
|
|
48837
|
+
scopeDir,
|
|
48838
|
+
repoAbsolutePath,
|
|
48839
|
+
branch,
|
|
48840
|
+
existingBranch,
|
|
48841
|
+
worktreeBaseBranches,
|
|
48842
|
+
log: log2
|
|
48843
|
+
} = options;
|
|
48844
|
+
const repoPathRelativeToBridgeRootRaw = path66.relative(bridgeResolved, repoAbsolutePath);
|
|
48845
|
+
if (repoPathRelativeToBridgeRootRaw.startsWith("..") || path66.isAbsolute(repoPathRelativeToBridgeRootRaw)) {
|
|
48846
|
+
return null;
|
|
48847
|
+
}
|
|
48848
|
+
const repoPathRelativeToBridgeRoot = normalizeRepoPathRelativeToWorkspaceRoot(
|
|
48849
|
+
repoPathRelativeToBridgeRootRaw === "" ? "." : repoPathRelativeToBridgeRootRaw
|
|
48850
|
+
);
|
|
48851
|
+
const worktreePath = repoPathRelativeToBridgeRoot === "." ? scopeDir : path66.join(scopeDir, repoPathRelativeToBridgeRoot);
|
|
48852
|
+
if (repoPathRelativeToBridgeRoot !== ".") {
|
|
48853
|
+
fs46.mkdirSync(path66.dirname(worktreePath), { recursive: true });
|
|
48854
|
+
copyBridgeFilesAlongWorktreePath({
|
|
48855
|
+
bridgeRoot: bridgeResolved,
|
|
48856
|
+
scopeDir,
|
|
48857
|
+
repoPathRelativeToBridgeRoot,
|
|
48858
|
+
log: log2
|
|
48859
|
+
});
|
|
48860
|
+
}
|
|
48861
|
+
const checkoutBranch = existingBranch?.trim() || branch;
|
|
48862
|
+
try {
|
|
48863
|
+
if (existingBranch?.trim()) {
|
|
48864
|
+
await gitWorktreeAddExistingBranch(repoAbsolutePath, worktreePath, checkoutBranch);
|
|
48865
|
+
log2(`[worktrees] Added ${kind} worktree ${worktreePath} (existing branch ${checkoutBranch}).`);
|
|
48866
|
+
} else {
|
|
48867
|
+
const baseRef = resolveBaseRefForRepo(repoPathRelativeToBridgeRoot, worktreeBaseBranches);
|
|
48868
|
+
await gitWorktreeAddBranch(repoAbsolutePath, worktreePath, branch, baseRef);
|
|
48869
|
+
log2(`[worktrees] Added ${kind} worktree ${worktreePath} (branch ${branch}, base ${baseRef}).`);
|
|
48870
|
+
}
|
|
48871
|
+
return worktreePath;
|
|
48872
|
+
} catch (e) {
|
|
48873
|
+
log2(
|
|
48874
|
+
`[worktrees] Worktree add failed for ${repoAbsolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
48875
|
+
);
|
|
48876
|
+
return null;
|
|
48877
|
+
}
|
|
48878
|
+
}
|
|
48879
|
+
|
|
48880
|
+
// src/worktrees/prepare/resolve-isolated-scope-dir.ts
|
|
48881
|
+
import * as path67 from "node:path";
|
|
48882
|
+
|
|
48761
48883
|
// src/worktrees/worktree-layout-kind.ts
|
|
48762
48884
|
function sanitizeWorktreeBranchSegment(value) {
|
|
48763
48885
|
return value.replace(/[^a-zA-Z0-9/_-]+/g, "-").slice(0, 80) || "worktree";
|
|
@@ -48784,16 +48906,16 @@ function previewDeployBranchName(environmentId) {
|
|
|
48784
48906
|
return `preview-deploy-${sanitizeWorktreeBranchSegment(environmentId.trim())}`;
|
|
48785
48907
|
}
|
|
48786
48908
|
|
|
48787
|
-
// src/worktrees/prepare-
|
|
48788
|
-
function
|
|
48789
|
-
|
|
48790
|
-
const
|
|
48791
|
-
|
|
48792
|
-
|
|
48793
|
-
|
|
48794
|
-
}
|
|
48795
|
-
return "HEAD";
|
|
48909
|
+
// src/worktrees/prepare/resolve-isolated-scope-dir.ts
|
|
48910
|
+
function resolveIsolatedScopeDir(options) {
|
|
48911
|
+
const bridgeResolved = path67.resolve(options.bridgeRoot);
|
|
48912
|
+
const cwdKey = allocateDirNameForLauncherCwd(options.layout, bridgeResolved);
|
|
48913
|
+
const bridgeKeyDir = path67.join(options.worktreesRootPath, cwdKey);
|
|
48914
|
+
const scopeDir = path67.join(bridgeKeyDir, ...layoutDirSegments(options.kind, options.scopeId));
|
|
48915
|
+
return { bridgeResolved, scopeDir };
|
|
48796
48916
|
}
|
|
48917
|
+
|
|
48918
|
+
// src/worktrees/prepare/prepare-new-isolated-worktrees.ts
|
|
48797
48919
|
async function prepareNewIsolatedWorktrees(options) {
|
|
48798
48920
|
const {
|
|
48799
48921
|
kind,
|
|
@@ -48806,45 +48928,32 @@ async function prepareNewIsolatedWorktrees(options) {
|
|
|
48806
48928
|
worktreeBaseBranches,
|
|
48807
48929
|
existingBranch
|
|
48808
48930
|
} = options;
|
|
48809
|
-
const bridgeResolved =
|
|
48810
|
-
|
|
48811
|
-
|
|
48812
|
-
|
|
48931
|
+
const { bridgeResolved, scopeDir } = resolveIsolatedScopeDir({
|
|
48932
|
+
worktreesRootPath,
|
|
48933
|
+
bridgeRoot,
|
|
48934
|
+
kind,
|
|
48935
|
+
scopeId,
|
|
48936
|
+
layout
|
|
48937
|
+
});
|
|
48813
48938
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
48814
48939
|
if (repos.length === 0) {
|
|
48815
48940
|
log2(`[worktrees] No Git repositories under bridge root; skipping ${kind} worktree creation.`);
|
|
48816
48941
|
return null;
|
|
48817
48942
|
}
|
|
48818
48943
|
const worktreePaths = [];
|
|
48819
|
-
|
|
48944
|
+
fs47.mkdirSync(scopeDir, { recursive: true });
|
|
48820
48945
|
await forEachWithGitYield(repos, async (repo) => {
|
|
48821
|
-
const
|
|
48822
|
-
|
|
48823
|
-
|
|
48824
|
-
|
|
48825
|
-
|
|
48826
|
-
|
|
48827
|
-
|
|
48828
|
-
|
|
48829
|
-
|
|
48830
|
-
|
|
48831
|
-
|
|
48832
|
-
const checkoutBranch = existingBranch?.trim() || branch;
|
|
48833
|
-
try {
|
|
48834
|
-
if (existingBranch?.trim()) {
|
|
48835
|
-
await gitWorktreeAddExistingBranch(repo.absolutePath, worktreePath, checkoutBranch);
|
|
48836
|
-
log2(`[worktrees] Added ${kind} worktree ${worktreePath} (existing branch ${checkoutBranch}).`);
|
|
48837
|
-
} else {
|
|
48838
|
-
const baseRef = resolveBaseRefForRepo(repoPathRelativeToBridgeRoot, worktreeBaseBranches);
|
|
48839
|
-
await gitWorktreeAddBranch(repo.absolutePath, worktreePath, branch, baseRef);
|
|
48840
|
-
log2(`[worktrees] Added ${kind} worktree ${worktreePath} (branch ${branch}, base ${baseRef}).`);
|
|
48841
|
-
}
|
|
48842
|
-
worktreePaths.push(worktreePath);
|
|
48843
|
-
} catch (e) {
|
|
48844
|
-
log2(
|
|
48845
|
-
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
48846
|
-
);
|
|
48847
|
-
}
|
|
48946
|
+
const worktreePath = await addIsolatedRepoWorktree({
|
|
48947
|
+
kind,
|
|
48948
|
+
bridgeResolved,
|
|
48949
|
+
scopeDir,
|
|
48950
|
+
repoAbsolutePath: repo.absolutePath,
|
|
48951
|
+
branch,
|
|
48952
|
+
existingBranch,
|
|
48953
|
+
worktreeBaseBranches,
|
|
48954
|
+
log: log2
|
|
48955
|
+
});
|
|
48956
|
+
if (worktreePath) worktreePaths.push(worktreePath);
|
|
48848
48957
|
});
|
|
48849
48958
|
if (worktreePaths.length === 0) return null;
|
|
48850
48959
|
return {
|
|
@@ -48904,10 +49013,10 @@ async function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
|
48904
49013
|
}
|
|
48905
49014
|
|
|
48906
49015
|
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
48907
|
-
import * as
|
|
49016
|
+
import * as path68 from "node:path";
|
|
48908
49017
|
init_yield_to_event_loop();
|
|
48909
49018
|
async function resolveExplicitSessionParentPath(params) {
|
|
48910
|
-
const resolved =
|
|
49019
|
+
const resolved = path68.resolve(params.parentPathRaw);
|
|
48911
49020
|
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
48912
49021
|
return resolved;
|
|
48913
49022
|
}
|
|
@@ -48924,7 +49033,7 @@ async function resolveExplicitSessionParentPath(params) {
|
|
|
48924
49033
|
await yieldToEventLoop();
|
|
48925
49034
|
const tryRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
48926
49035
|
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
48927
|
-
const next =
|
|
49036
|
+
const next = path68.dirname(cur);
|
|
48928
49037
|
if (next === cur) break;
|
|
48929
49038
|
cur = next;
|
|
48930
49039
|
}
|
|
@@ -49072,15 +49181,15 @@ var SessionWorktreeManager = class {
|
|
|
49072
49181
|
};
|
|
49073
49182
|
|
|
49074
49183
|
// src/worktrees/discovery/discover-preview-worktree-on-disk.ts
|
|
49075
|
-
import * as
|
|
49076
|
-
import * as
|
|
49184
|
+
import * as fs48 from "node:fs";
|
|
49185
|
+
import * as path69 from "node:path";
|
|
49077
49186
|
init_yield_to_event_loop();
|
|
49078
49187
|
async function discoverPreviewWorktreeOnDisk(options) {
|
|
49079
49188
|
const { environmentId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
49080
49189
|
const eid = environmentId.trim();
|
|
49081
49190
|
if (!eid) return null;
|
|
49082
49191
|
try {
|
|
49083
|
-
await
|
|
49192
|
+
await fs48.promises.access(worktreesRootPath);
|
|
49084
49193
|
} catch {
|
|
49085
49194
|
return null;
|
|
49086
49195
|
}
|
|
@@ -49089,13 +49198,13 @@ async function discoverPreviewWorktreeOnDisk(options) {
|
|
|
49089
49198
|
if (preferredKey) keysOnDisk.push(preferredKey);
|
|
49090
49199
|
const scanState = { entries: 0 };
|
|
49091
49200
|
try {
|
|
49092
|
-
for (const name of await
|
|
49201
|
+
for (const name of await fs48.promises.readdir(worktreesRootPath)) {
|
|
49093
49202
|
if (!await yieldDuringDiskWalk(scanState)) break;
|
|
49094
49203
|
if (name.startsWith(".")) continue;
|
|
49095
|
-
const p =
|
|
49204
|
+
const p = path69.join(worktreesRootPath, name);
|
|
49096
49205
|
let st;
|
|
49097
49206
|
try {
|
|
49098
|
-
st = await
|
|
49207
|
+
st = await fs48.promises.stat(p);
|
|
49099
49208
|
} catch {
|
|
49100
49209
|
continue;
|
|
49101
49210
|
}
|
|
@@ -49109,7 +49218,7 @@ async function discoverPreviewWorktreeOnDisk(options) {
|
|
|
49109
49218
|
const previewDirRel = layoutDirSegments("preview_environment", eid);
|
|
49110
49219
|
for (const key of keys) {
|
|
49111
49220
|
await yieldToEventLoop();
|
|
49112
|
-
const previewDir =
|
|
49221
|
+
const previewDir = path69.join(worktreesRootPath, key, ...previewDirRel);
|
|
49113
49222
|
const binding = await tryBindingFromIsolatedDirectory(previewDir);
|
|
49114
49223
|
if (binding) return binding;
|
|
49115
49224
|
}
|
|
@@ -49236,7 +49345,7 @@ var PreviewWorktreeManager = class {
|
|
|
49236
49345
|
};
|
|
49237
49346
|
|
|
49238
49347
|
// src/worktrees/deploy/deploy-session-to-preview-environment.ts
|
|
49239
|
-
import * as
|
|
49348
|
+
import * as path73 from "node:path";
|
|
49240
49349
|
|
|
49241
49350
|
// src/git/worktrees/reset-worktree-to-branch.ts
|
|
49242
49351
|
async function gitResetWorktreeToBranch(worktreePath, branch) {
|
|
@@ -49247,8 +49356,8 @@ async function gitResetWorktreeToBranch(worktreePath, branch) {
|
|
|
49247
49356
|
}
|
|
49248
49357
|
|
|
49249
49358
|
// src/worktrees/deploy/capture-and-apply-wip.ts
|
|
49250
|
-
import * as
|
|
49251
|
-
import * as
|
|
49359
|
+
import * as fs49 from "node:fs";
|
|
49360
|
+
import * as path70 from "node:path";
|
|
49252
49361
|
|
|
49253
49362
|
// src/git/snapshot/git.ts
|
|
49254
49363
|
async function gitStashCreate(repoRoot, log2) {
|
|
@@ -49296,12 +49405,12 @@ async function applyWorkingTreeWip(targetRepoPath, sourceRepoPath, wip, log2) {
|
|
|
49296
49405
|
if (!ap.ok) return ap;
|
|
49297
49406
|
}
|
|
49298
49407
|
await forEachWithGitYield(wip.untrackedPaths, async (rel) => {
|
|
49299
|
-
const src =
|
|
49300
|
-
const dst =
|
|
49408
|
+
const src = path70.join(sourceRepoPath, rel);
|
|
49409
|
+
const dst = path70.join(targetRepoPath, rel);
|
|
49301
49410
|
try {
|
|
49302
|
-
if (!
|
|
49303
|
-
|
|
49304
|
-
|
|
49411
|
+
if (!fs49.existsSync(src)) return;
|
|
49412
|
+
fs49.mkdirSync(path70.dirname(dst), { recursive: true });
|
|
49413
|
+
fs49.copyFileSync(src, dst);
|
|
49305
49414
|
} catch (e) {
|
|
49306
49415
|
log2(
|
|
49307
49416
|
`[worktrees] Failed to copy untracked ${rel}: ${e instanceof Error ? e.message : String(e)}`
|
|
@@ -49312,14 +49421,14 @@ async function applyWorkingTreeWip(targetRepoPath, sourceRepoPath, wip, log2) {
|
|
|
49312
49421
|
}
|
|
49313
49422
|
|
|
49314
49423
|
// src/worktrees/deploy/resolve-isolated-checkout-for-repo-path-relative-to-workspace-root.ts
|
|
49315
|
-
import * as
|
|
49424
|
+
import * as path71 from "node:path";
|
|
49316
49425
|
async function resolveIsolatedCheckoutForRepoPathRelativeToWorkspaceRoot(options) {
|
|
49317
49426
|
const { checkoutPaths, sessionParentPath, bridgeRoot, repoPathRelativeToWorkspaceRoot } = options;
|
|
49318
|
-
const resolvedSessionParentPath = sessionParentPath ?
|
|
49427
|
+
const resolvedSessionParentPath = sessionParentPath ? path71.resolve(sessionParentPath) : null;
|
|
49319
49428
|
let match = null;
|
|
49320
49429
|
await forEachWithGitYield(checkoutPaths, async (checkoutPath) => {
|
|
49321
49430
|
if (match) return;
|
|
49322
|
-
const resolvedCheckoutPath =
|
|
49431
|
+
const resolvedCheckoutPath = path71.resolve(checkoutPath);
|
|
49323
49432
|
if (!await isGitRepoDirectory(resolvedCheckoutPath)) return;
|
|
49324
49433
|
const resolvedRepoPathRelativeToWorkspaceRoot = await resolveRepoPathRelativeToWorkspaceRoot({
|
|
49325
49434
|
checkoutPath: resolvedCheckoutPath,
|
|
@@ -49373,7 +49482,7 @@ async function applySessionWipToPreviewCheckouts(options) {
|
|
|
49373
49482
|
}
|
|
49374
49483
|
|
|
49375
49484
|
// src/worktrees/deploy/collect-session-repo-deploy-states.ts
|
|
49376
|
-
import * as
|
|
49485
|
+
import * as path72 from "node:path";
|
|
49377
49486
|
|
|
49378
49487
|
// src/git/branches/create-or-update-branch.ts
|
|
49379
49488
|
async function gitCreateOrUpdateBranch(repoPath, branch, startRef, options) {
|
|
@@ -49410,19 +49519,19 @@ async function collectSessionRepoDeployStates(options) {
|
|
|
49410
49519
|
const sessionParentPath = sessionWorktreeManager.getSessionParentPath(sid);
|
|
49411
49520
|
const states = [];
|
|
49412
49521
|
await forEachWithGitYield(sessionTargets, async (sessionCheckout) => {
|
|
49413
|
-
const checkoutPath =
|
|
49522
|
+
const checkoutPath = path72.resolve(sessionCheckout);
|
|
49414
49523
|
if (!await isGitRepoDirectory(checkoutPath)) return;
|
|
49415
49524
|
const repoPathRelativeToWorkspaceRoot = await resolveRepoPathRelativeToWorkspaceRoot({
|
|
49416
49525
|
checkoutPath,
|
|
49417
49526
|
bridgeRoot,
|
|
49418
|
-
sessionParentPath: sessionParentPath ?
|
|
49527
|
+
sessionParentPath: sessionParentPath ? path72.resolve(sessionParentPath) : null
|
|
49419
49528
|
});
|
|
49420
49529
|
if (!repoPathRelativeToWorkspaceRoot) return;
|
|
49421
49530
|
const mainRepoPath = resolveMainRepoPath(checkoutPath);
|
|
49422
49531
|
const headSha = (await cliSimpleGit(checkoutPath).revparse(["HEAD"])).trim();
|
|
49423
49532
|
const previewCheckout = previewCheckoutPaths.length > 0 ? await resolveIsolatedCheckoutForRepoPathRelativeToWorkspaceRoot({
|
|
49424
49533
|
checkoutPaths: previewCheckoutPaths,
|
|
49425
|
-
sessionParentPath: previewParentPath ?
|
|
49534
|
+
sessionParentPath: previewParentPath ? path72.resolve(previewParentPath) : null,
|
|
49426
49535
|
bridgeRoot,
|
|
49427
49536
|
repoPathRelativeToWorkspaceRoot
|
|
49428
49537
|
}) : null;
|
|
@@ -49442,7 +49551,7 @@ async function deploySessionToPreviewEnvironment(options) {
|
|
|
49442
49551
|
const eid = options.environmentId.trim();
|
|
49443
49552
|
if (!sid || !eid) return { ok: false, error: "sessionId and environmentId are required" };
|
|
49444
49553
|
const deployBranch = previewDeployBranchName(eid);
|
|
49445
|
-
const bridgeRoot =
|
|
49554
|
+
const bridgeRoot = path73.resolve(getBridgeRoot());
|
|
49446
49555
|
await previewWorktreeManager.ensureCached(eid);
|
|
49447
49556
|
const existingPreviewParentPath = previewWorktreeManager.getPreviewParentPath(eid) ?? null;
|
|
49448
49557
|
const existingPreviewCheckoutPaths = previewWorktreeManager.getRepoCheckoutPaths(eid) ?? [];
|
|
@@ -49482,10 +49591,10 @@ async function deploySessionToPreviewEnvironment(options) {
|
|
|
49482
49591
|
}
|
|
49483
49592
|
|
|
49484
49593
|
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
49485
|
-
import * as
|
|
49594
|
+
import * as path74 from "node:path";
|
|
49486
49595
|
import os9 from "node:os";
|
|
49487
49596
|
function defaultWorktreesRootPath() {
|
|
49488
|
-
return
|
|
49597
|
+
return path74.join(os9.homedir(), ".buildautomaton", "worktrees");
|
|
49489
49598
|
}
|
|
49490
49599
|
|
|
49491
49600
|
// src/connection/create-bridge-worktree-managers.ts
|
|
@@ -49615,14 +49724,14 @@ function assertBridgeWorkspace(ctx) {
|
|
|
49615
49724
|
}
|
|
49616
49725
|
|
|
49617
49726
|
// src/files/list-dir/index.ts
|
|
49618
|
-
import
|
|
49727
|
+
import fs51 from "node:fs";
|
|
49619
49728
|
|
|
49620
49729
|
// src/files/ensure-under-cwd.ts
|
|
49621
|
-
import
|
|
49730
|
+
import path75 from "node:path";
|
|
49622
49731
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
49623
|
-
const normalized =
|
|
49624
|
-
const resolved =
|
|
49625
|
-
if (!resolved.startsWith(cwd +
|
|
49732
|
+
const normalized = path75.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
49733
|
+
const resolved = path75.resolve(cwd, normalized);
|
|
49734
|
+
if (!resolved.startsWith(cwd + path75.sep) && resolved !== cwd) {
|
|
49626
49735
|
return null;
|
|
49627
49736
|
}
|
|
49628
49737
|
return resolved;
|
|
@@ -49635,15 +49744,15 @@ init_yield_to_event_loop();
|
|
|
49635
49744
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
49636
49745
|
|
|
49637
49746
|
// src/files/list-dir/map-dir-entry.ts
|
|
49638
|
-
import
|
|
49639
|
-
import
|
|
49747
|
+
import path76 from "node:path";
|
|
49748
|
+
import fs50 from "node:fs";
|
|
49640
49749
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
49641
|
-
const entryPath =
|
|
49642
|
-
const fullPath =
|
|
49750
|
+
const entryPath = path76.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
49751
|
+
const fullPath = path76.join(resolved, d.name);
|
|
49643
49752
|
let isDir = d.isDirectory();
|
|
49644
49753
|
if (d.isSymbolicLink()) {
|
|
49645
49754
|
try {
|
|
49646
|
-
const targetStat = await
|
|
49755
|
+
const targetStat = await fs50.promises.stat(fullPath);
|
|
49647
49756
|
isDir = targetStat.isDirectory();
|
|
49648
49757
|
} catch {
|
|
49649
49758
|
isDir = false;
|
|
@@ -49673,7 +49782,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
49673
49782
|
return { error: "Path is outside working directory" };
|
|
49674
49783
|
}
|
|
49675
49784
|
try {
|
|
49676
|
-
const names = await
|
|
49785
|
+
const names = await fs51.promises.readdir(resolved, { withFileTypes: true });
|
|
49677
49786
|
const entries = [];
|
|
49678
49787
|
for (let i = 0; i < names.length; i++) {
|
|
49679
49788
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
@@ -49689,13 +49798,13 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
49689
49798
|
}
|
|
49690
49799
|
|
|
49691
49800
|
// src/git/tree/resolve-repo-abs-path.ts
|
|
49692
|
-
import * as
|
|
49801
|
+
import * as path77 from "node:path";
|
|
49693
49802
|
function resolveRepoAbsPathFromBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
49694
|
-
const bridgeResolved =
|
|
49803
|
+
const bridgeResolved = path77.resolve(bridgeRoot);
|
|
49695
49804
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
49696
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
49697
|
-
const resolved =
|
|
49698
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
49805
|
+
const repoPath = rel === "" ? bridgeResolved : path77.join(bridgeResolved, rel);
|
|
49806
|
+
const resolved = path77.resolve(repoPath);
|
|
49807
|
+
if (!resolved.startsWith(bridgeResolved + path77.sep) && resolved !== bridgeResolved) {
|
|
49699
49808
|
return null;
|
|
49700
49809
|
}
|
|
49701
49810
|
return resolved;
|
|
@@ -50176,25 +50285,25 @@ async function GET2(ctx) {
|
|
|
50176
50285
|
init_in_flight();
|
|
50177
50286
|
|
|
50178
50287
|
// src/files/read/read-file-async.ts
|
|
50179
|
-
import
|
|
50288
|
+
import fs57 from "node:fs";
|
|
50180
50289
|
init_yield_to_event_loop();
|
|
50181
50290
|
|
|
50182
50291
|
// src/files/read/resolve-file-cache.ts
|
|
50183
|
-
import
|
|
50184
|
-
import
|
|
50292
|
+
import fs52 from "node:fs";
|
|
50293
|
+
import path78 from "node:path";
|
|
50185
50294
|
var RESOLVE_CACHE_MAX = 4096;
|
|
50186
50295
|
var resolveCache = /* @__PURE__ */ new Map();
|
|
50187
50296
|
function resolveCacheKey(sessionParentPath, relativePath) {
|
|
50188
50297
|
return `${sessionParentPath}\0${relativePath}`;
|
|
50189
50298
|
}
|
|
50190
50299
|
function pathStaysUnderParent(filePath, sessionParentPath) {
|
|
50191
|
-
const parent =
|
|
50192
|
-
const resolved =
|
|
50193
|
-
return resolved === parent || resolved.startsWith(`${parent}${
|
|
50300
|
+
const parent = path78.resolve(sessionParentPath);
|
|
50301
|
+
const resolved = path78.resolve(filePath);
|
|
50302
|
+
return resolved === parent || resolved.startsWith(`${parent}${path78.sep}`);
|
|
50194
50303
|
}
|
|
50195
50304
|
function statMatchesCacheSync(entry) {
|
|
50196
50305
|
try {
|
|
50197
|
-
const stat3 =
|
|
50306
|
+
const stat3 = fs52.statSync(entry.path);
|
|
50198
50307
|
return stat3.isFile() && stat3.mtimeMs === entry.mtimeMs && stat3.size === entry.size;
|
|
50199
50308
|
} catch {
|
|
50200
50309
|
return false;
|
|
@@ -50227,7 +50336,7 @@ function joinInflightResolve(cacheKey, factory) {
|
|
|
50227
50336
|
}
|
|
50228
50337
|
|
|
50229
50338
|
// src/files/read/resolve-file-for-read-core.ts
|
|
50230
|
-
import
|
|
50339
|
+
import fs53 from "node:fs";
|
|
50231
50340
|
import { isMainThread as isMainThread4 } from "node:worker_threads";
|
|
50232
50341
|
function resolveFileForReadImplSync(relativePath, sessionParentPath) {
|
|
50233
50342
|
const cacheKey = resolveCacheKey(sessionParentPath, relativePath);
|
|
@@ -50237,13 +50346,13 @@ function resolveFileForReadImplSync(relativePath, sessionParentPath) {
|
|
|
50237
50346
|
let size;
|
|
50238
50347
|
let mtimeMs;
|
|
50239
50348
|
try {
|
|
50240
|
-
const lstat =
|
|
50349
|
+
const lstat = fs53.lstatSync(resolved);
|
|
50241
50350
|
if (lstat.isSymbolicLink()) {
|
|
50242
|
-
real =
|
|
50351
|
+
real = fs53.realpathSync(resolved);
|
|
50243
50352
|
if (!pathStaysUnderParent(real, sessionParentPath)) {
|
|
50244
50353
|
return { error: "Path is outside working directory" };
|
|
50245
50354
|
}
|
|
50246
|
-
const stat3 =
|
|
50355
|
+
const stat3 = fs53.statSync(real);
|
|
50247
50356
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
50248
50357
|
size = stat3.size;
|
|
50249
50358
|
mtimeMs = stat3.mtimeMs;
|
|
@@ -50271,13 +50380,13 @@ async function resolveFileForReadImpl(relativePath, sessionParentPath) {
|
|
|
50271
50380
|
let size;
|
|
50272
50381
|
let mtimeMs;
|
|
50273
50382
|
try {
|
|
50274
|
-
const lstat = await
|
|
50383
|
+
const lstat = await fs53.promises.lstat(resolved);
|
|
50275
50384
|
if (lstat.isSymbolicLink()) {
|
|
50276
|
-
real = await
|
|
50385
|
+
real = await fs53.promises.realpath(resolved);
|
|
50277
50386
|
if (!pathStaysUnderParent(real, sessionParentPath)) {
|
|
50278
50387
|
return { error: "Path is outside working directory" };
|
|
50279
50388
|
}
|
|
50280
|
-
const stat3 = await
|
|
50389
|
+
const stat3 = await fs53.promises.stat(real);
|
|
50281
50390
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
50282
50391
|
size = stat3.size;
|
|
50283
50392
|
mtimeMs = stat3.mtimeMs;
|
|
@@ -50326,7 +50435,7 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
|
|
|
50326
50435
|
|
|
50327
50436
|
// src/files/read/read-file-range-async.ts
|
|
50328
50437
|
init_yield_to_event_loop();
|
|
50329
|
-
import
|
|
50438
|
+
import fs54 from "node:fs";
|
|
50330
50439
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
50331
50440
|
|
|
50332
50441
|
// src/files/read/read-file-range-line-zero.ts
|
|
@@ -50440,8 +50549,8 @@ function finishLineZeroTail(state, tail, resultLines, fileSize, lineChunkSize, l
|
|
|
50440
50549
|
|
|
50441
50550
|
// src/files/read/read-file-range-async.ts
|
|
50442
50551
|
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE, fileSizeIn) {
|
|
50443
|
-
const fileSize = fileSizeIn ?? (await
|
|
50444
|
-
const fd = await
|
|
50552
|
+
const fileSize = fileSizeIn ?? (await fs54.promises.stat(filePath)).size;
|
|
50553
|
+
const fd = await fs54.promises.open(filePath, "r");
|
|
50445
50554
|
const bufSize = 64 * 1024;
|
|
50446
50555
|
const buf = Buffer.alloc(bufSize);
|
|
50447
50556
|
const decoder = new StringDecoder2("utf8");
|
|
@@ -50542,7 +50651,7 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
|
|
|
50542
50651
|
}
|
|
50543
50652
|
|
|
50544
50653
|
// src/files/read/read-small-file-range-async.ts
|
|
50545
|
-
import
|
|
50654
|
+
import fs55 from "node:fs";
|
|
50546
50655
|
import { isMainThread as isMainThread5 } from "node:worker_threads";
|
|
50547
50656
|
var SMALL_FILE_RANGE_MAX_BYTES = 512 * 1024;
|
|
50548
50657
|
function sliceLineRange(lines, startLine, endLine, lineOffsetIn, lineChunkSize, fileSize) {
|
|
@@ -50572,7 +50681,7 @@ function sliceLineRange(lines, startLine, endLine, lineOffsetIn, lineChunkSize,
|
|
|
50572
50681
|
};
|
|
50573
50682
|
}
|
|
50574
50683
|
function readSmallFileRangeSync(filePath, fileSize, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
50575
|
-
const raw =
|
|
50684
|
+
const raw = fs55.readFileSync(filePath, "utf8");
|
|
50576
50685
|
const lines = raw.split(/\r?\n/);
|
|
50577
50686
|
return sliceLineRange(lines, startLine, endLine, lineOffsetIn, lineChunkSize, fileSize);
|
|
50578
50687
|
}
|
|
@@ -50580,28 +50689,28 @@ async function readSmallFileRangeAsync(filePath, fileSize, startLine, endLine, l
|
|
|
50580
50689
|
if (isMainThread5) {
|
|
50581
50690
|
return readSmallFileRangeSync(filePath, fileSize, startLine, endLine, lineOffsetIn, lineChunkSize);
|
|
50582
50691
|
}
|
|
50583
|
-
const raw = await
|
|
50692
|
+
const raw = await fs55.promises.readFile(filePath, "utf8");
|
|
50584
50693
|
const lines = raw.split(/\r?\n/);
|
|
50585
50694
|
return sliceLineRange(lines, startLine, endLine, lineOffsetIn, lineChunkSize, fileSize);
|
|
50586
50695
|
}
|
|
50587
50696
|
|
|
50588
50697
|
// src/files/read/read-file-buffer-full-async.ts
|
|
50589
50698
|
init_yield_to_event_loop();
|
|
50590
|
-
import
|
|
50699
|
+
import fs56 from "node:fs";
|
|
50591
50700
|
import { isMainThread as isMainThread6 } from "node:worker_threads";
|
|
50592
50701
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
50593
50702
|
var MAIN_THREAD_SYNC_READ_MAX_BYTES = 512 * 1024;
|
|
50594
50703
|
async function readFileBufferFullAsync(filePath, knownSize) {
|
|
50595
50704
|
if (isMainThread6) {
|
|
50596
|
-
const size2 = knownSize ??
|
|
50705
|
+
const size2 = knownSize ?? fs56.statSync(filePath).size;
|
|
50597
50706
|
if (size2 <= MAIN_THREAD_SYNC_READ_MAX_BYTES) {
|
|
50598
50707
|
await yieldToEventLoop();
|
|
50599
|
-
const buffer =
|
|
50708
|
+
const buffer = fs56.readFileSync(filePath);
|
|
50600
50709
|
return { buffer, size: buffer.length };
|
|
50601
50710
|
}
|
|
50602
50711
|
}
|
|
50603
|
-
const size = knownSize ?? (await
|
|
50604
|
-
const fd = await
|
|
50712
|
+
const size = knownSize ?? (await fs56.promises.stat(filePath)).size;
|
|
50713
|
+
const fd = await fs56.promises.open(filePath, "r");
|
|
50605
50714
|
const chunks = [];
|
|
50606
50715
|
let position = 0;
|
|
50607
50716
|
let bytesSinceYield = 0;
|
|
@@ -50704,7 +50813,7 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
50704
50813
|
}
|
|
50705
50814
|
if (hasRange) {
|
|
50706
50815
|
if (fileSize == null) {
|
|
50707
|
-
const stat3 = await
|
|
50816
|
+
const stat3 = await fs57.promises.stat(resolvedPath);
|
|
50708
50817
|
fileSize = stat3.size;
|
|
50709
50818
|
}
|
|
50710
50819
|
const read2 = fileSize <= SMALL_FILE_RANGE_MAX_BYTES ? await readSmallFileRangeAsync(
|
|
@@ -51002,12 +51111,12 @@ function parseOptionalInt2(raw) {
|
|
|
51002
51111
|
return Number.isInteger(parsed) ? parsed : void 0;
|
|
51003
51112
|
}
|
|
51004
51113
|
function parseCodeNavParams(url2) {
|
|
51005
|
-
const
|
|
51114
|
+
const path84 = url2.searchParams.get("path") ?? "";
|
|
51006
51115
|
const opRaw = url2.searchParams.get("op")?.trim();
|
|
51007
51116
|
const op = opRaw === "references" ? "references" : opRaw === "symbols" ? "symbols" : opRaw === "definitions" ? "definitions" : "definition";
|
|
51008
51117
|
const line = parseOptionalInt2(url2.searchParams.get("line")) ?? 1;
|
|
51009
51118
|
const column = parseOptionalInt2(url2.searchParams.get("column")) ?? 0;
|
|
51010
|
-
return { path:
|
|
51119
|
+
return { path: path84, op, line, column };
|
|
51011
51120
|
}
|
|
51012
51121
|
function parseCodeNavPath(url2) {
|
|
51013
51122
|
const raw = url2.searchParams.get("path")?.trim();
|
|
@@ -51195,12 +51304,6 @@ function listenOnPort(server, port) {
|
|
|
51195
51304
|
});
|
|
51196
51305
|
});
|
|
51197
51306
|
}
|
|
51198
|
-
function closeServer(server) {
|
|
51199
|
-
if (!server) return Promise.resolve();
|
|
51200
|
-
return new Promise((resolve37, reject) => {
|
|
51201
|
-
server.close((err) => err ? reject(err) : resolve37());
|
|
51202
|
-
});
|
|
51203
|
-
}
|
|
51204
51307
|
function delay3(ms) {
|
|
51205
51308
|
return new Promise((resolve37) => setTimeout(resolve37, ms));
|
|
51206
51309
|
}
|
|
@@ -51225,8 +51328,7 @@ function startLocalShortcutServer(ctx) {
|
|
|
51225
51328
|
if (restartAttempts >= MAX_RESTART_ATTEMPTS) return;
|
|
51226
51329
|
restartAttempts += 1;
|
|
51227
51330
|
restarting = (async () => {
|
|
51228
|
-
await
|
|
51229
|
-
});
|
|
51331
|
+
await closeHttpServer(currentServer);
|
|
51230
51332
|
currentServer = null;
|
|
51231
51333
|
if (closed) return;
|
|
51232
51334
|
await delay3(RESTART_DELAY_MS);
|
|
@@ -51246,7 +51348,7 @@ function startLocalShortcutServer(ctx) {
|
|
|
51246
51348
|
token: ctx.token,
|
|
51247
51349
|
close: async () => {
|
|
51248
51350
|
closed = true;
|
|
51249
|
-
await
|
|
51351
|
+
await closeHttpServer(currentServer);
|
|
51250
51352
|
currentServer = null;
|
|
51251
51353
|
}
|
|
51252
51354
|
}));
|
|
@@ -51399,6 +51501,7 @@ var API_TO_BRIDGE_MESSAGE_TYPES = [
|
|
|
51399
51501
|
"code_nav",
|
|
51400
51502
|
"skill_layout_request",
|
|
51401
51503
|
"install_skills",
|
|
51504
|
+
"install_agent",
|
|
51402
51505
|
"refresh_local_skills",
|
|
51403
51506
|
"bridge_git_context_request",
|
|
51404
51507
|
"list_repo_branches_request"
|
|
@@ -51474,6 +51577,100 @@ var handleBridgeHeartbeatAck = (msg, deps) => {
|
|
|
51474
51577
|
deps.onBridgeHeartbeatAck?.(Math.trunc(raw));
|
|
51475
51578
|
};
|
|
51476
51579
|
|
|
51580
|
+
// src/routing/dispatch/connection.ts
|
|
51581
|
+
function dispatchBridgeConnectionMessage(msg, deps) {
|
|
51582
|
+
switch (msg.type) {
|
|
51583
|
+
case "auth_token":
|
|
51584
|
+
handleAuthToken(msg, deps);
|
|
51585
|
+
break;
|
|
51586
|
+
case "bridge_identified":
|
|
51587
|
+
handleBridgeIdentified(msg, deps);
|
|
51588
|
+
break;
|
|
51589
|
+
case "ha":
|
|
51590
|
+
handleBridgeHeartbeatAck(msg, deps);
|
|
51591
|
+
break;
|
|
51592
|
+
}
|
|
51593
|
+
}
|
|
51594
|
+
|
|
51595
|
+
// src/routing/handlers/preview-environment-control.ts
|
|
51596
|
+
var handlePreviewEnvironmentControl = (msg, deps) => {
|
|
51597
|
+
let wire;
|
|
51598
|
+
try {
|
|
51599
|
+
wire = deps.e2ee ? deps.e2ee.decryptMessage(msg) : msg;
|
|
51600
|
+
} catch (e) {
|
|
51601
|
+
deps.log(`[E2EE] Could not decrypt preview environment command: ${e instanceof Error ? e.message : String(e)}`);
|
|
51602
|
+
return;
|
|
51603
|
+
}
|
|
51604
|
+
const environmentId = typeof wire.environmentId === "string" ? wire.environmentId : "";
|
|
51605
|
+
const action = wire.action === "start" || wire.action === "stop" ? wire.action : null;
|
|
51606
|
+
if (!environmentId || !action) return;
|
|
51607
|
+
deps.previewEnvironmentManager?.handleControl(environmentId, action);
|
|
51608
|
+
};
|
|
51609
|
+
|
|
51610
|
+
// src/routing/handlers/preview-environments-config.ts
|
|
51611
|
+
var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
|
|
51612
|
+
var handlePreviewEnvironmentsConfig = (msg, deps) => {
|
|
51613
|
+
const previewEnvironments = msg.previewEnvironments;
|
|
51614
|
+
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
|
|
51615
|
+
setImmediate(() => {
|
|
51616
|
+
deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
|
|
51617
|
+
const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
|
|
51618
|
+
void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
|
|
51619
|
+
if (proxyPorts !== void 0) {
|
|
51620
|
+
deps.updateFirehoseProxyPorts?.(proxyPorts);
|
|
51621
|
+
}
|
|
51622
|
+
});
|
|
51623
|
+
};
|
|
51624
|
+
|
|
51625
|
+
// src/routing/handlers/send-deploy-session-to-preview-result.ts
|
|
51626
|
+
function sendDeploySessionToPreviewResult(ws, id, payload) {
|
|
51627
|
+
if (!ws) return;
|
|
51628
|
+
sendWsMessage(ws, { type: "deploy_session_to_preview_result", id, ...payload });
|
|
51629
|
+
}
|
|
51630
|
+
|
|
51631
|
+
// src/routing/handlers/deploy-session-to-preview.ts
|
|
51632
|
+
var handleDeploySessionToPreviewMessage = (msg, deps) => {
|
|
51633
|
+
if (typeof msg.id !== "string") return;
|
|
51634
|
+
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
51635
|
+
const environmentId = typeof msg.environmentId === "string" ? msg.environmentId : "";
|
|
51636
|
+
if (!sessionId || !environmentId) return;
|
|
51637
|
+
void (async () => {
|
|
51638
|
+
const ws = deps.getWs();
|
|
51639
|
+
const reply = (payload) => sendDeploySessionToPreviewResult(ws, msg.id, payload);
|
|
51640
|
+
try {
|
|
51641
|
+
if (!deps.previewWorktreeManager) {
|
|
51642
|
+
reply({ ok: false, error: "Preview worktree manager unavailable" });
|
|
51643
|
+
return;
|
|
51644
|
+
}
|
|
51645
|
+
const result = await deploySessionToPreviewEnvironment({
|
|
51646
|
+
sessionWorktreeManager: deps.sessionWorktreeManager,
|
|
51647
|
+
previewWorktreeManager: deps.previewWorktreeManager,
|
|
51648
|
+
sessionId,
|
|
51649
|
+
environmentId,
|
|
51650
|
+
log: deps.log
|
|
51651
|
+
});
|
|
51652
|
+
reply(result);
|
|
51653
|
+
} catch (e) {
|
|
51654
|
+
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
51655
|
+
}
|
|
51656
|
+
})();
|
|
51657
|
+
};
|
|
51658
|
+
|
|
51659
|
+
// src/routing/dispatch/preview.ts
|
|
51660
|
+
function dispatchBridgePreviewMessage(msg, deps) {
|
|
51661
|
+
switch (msg.type) {
|
|
51662
|
+
case "preview_environments_config":
|
|
51663
|
+
handlePreviewEnvironmentsConfig(msg, deps);
|
|
51664
|
+
break;
|
|
51665
|
+
case "preview_environment_control":
|
|
51666
|
+
handlePreviewEnvironmentControl(msg, deps);
|
|
51667
|
+
break;
|
|
51668
|
+
case "deploy_session_to_preview":
|
|
51669
|
+
handleDeploySessionToPreviewMessage(msg, deps);
|
|
51670
|
+
break;
|
|
51671
|
+
}
|
|
51672
|
+
}
|
|
51673
|
+
|
|
51477
51674
|
// src/agents/acp/from-bridge/handle-bridge-agent-config.ts
|
|
51478
51675
|
function handleBridgeAgentConfig(msg, { acpManager }) {
|
|
51479
51676
|
if (!Array.isArray(msg.agents) || msg.agents.length === 0) return;
|
|
@@ -51623,15 +51820,15 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
|
51623
51820
|
}
|
|
51624
51821
|
|
|
51625
51822
|
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
51626
|
-
import
|
|
51823
|
+
import fs59 from "node:fs";
|
|
51627
51824
|
|
|
51628
51825
|
// src/git/snapshot/capture.ts
|
|
51629
|
-
import * as
|
|
51630
|
-
import * as
|
|
51826
|
+
import * as fs58 from "node:fs";
|
|
51827
|
+
import * as path79 from "node:path";
|
|
51631
51828
|
async function resolveSnapshotRepoRoots(options) {
|
|
51632
51829
|
const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
|
|
51633
51830
|
if (worktreePaths?.length) {
|
|
51634
|
-
const uniq = [...new Set(worktreePaths.map((p) =>
|
|
51831
|
+
const uniq = [...new Set(worktreePaths.map((p) => path79.resolve(p)))];
|
|
51635
51832
|
return uniq;
|
|
51636
51833
|
}
|
|
51637
51834
|
try {
|
|
@@ -51639,7 +51836,7 @@ async function resolveSnapshotRepoRoots(options) {
|
|
|
51639
51836
|
const mapped = repos.map((r) => r.absolutePath);
|
|
51640
51837
|
const sid = sessionId?.trim();
|
|
51641
51838
|
if (sid) {
|
|
51642
|
-
const filtered = mapped.filter((root) =>
|
|
51839
|
+
const filtered = mapped.filter((root) => path79.basename(root) === sid);
|
|
51643
51840
|
if (filtered.length > 0) return filtered;
|
|
51644
51841
|
}
|
|
51645
51842
|
return mapped;
|
|
@@ -51661,7 +51858,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
51661
51858
|
});
|
|
51662
51859
|
const dir = snapshotsDirForCwd(agentCwd);
|
|
51663
51860
|
try {
|
|
51664
|
-
|
|
51861
|
+
fs58.mkdirSync(dir, { recursive: true });
|
|
51665
51862
|
} catch (e) {
|
|
51666
51863
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
51667
51864
|
}
|
|
@@ -51670,9 +51867,9 @@ async function capturePreTurnSnapshot(options) {
|
|
|
51670
51867
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
51671
51868
|
repos
|
|
51672
51869
|
};
|
|
51673
|
-
const filePath =
|
|
51870
|
+
const filePath = path79.join(dir, `${runId}.json`);
|
|
51674
51871
|
try {
|
|
51675
|
-
|
|
51872
|
+
fs58.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
51676
51873
|
} catch (e) {
|
|
51677
51874
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
51678
51875
|
}
|
|
@@ -51685,7 +51882,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
51685
51882
|
async function applyPreTurnSnapshot(filePath, log2) {
|
|
51686
51883
|
let data;
|
|
51687
51884
|
try {
|
|
51688
|
-
const raw =
|
|
51885
|
+
const raw = fs58.readFileSync(filePath, "utf8");
|
|
51689
51886
|
data = JSON.parse(raw);
|
|
51690
51887
|
} catch (e) {
|
|
51691
51888
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
@@ -51725,7 +51922,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
51725
51922
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
51726
51923
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
51727
51924
|
try {
|
|
51728
|
-
await
|
|
51925
|
+
await fs59.promises.access(file2, fs59.constants.F_OK);
|
|
51729
51926
|
} catch {
|
|
51730
51927
|
deps.log(
|
|
51731
51928
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
@@ -52112,551 +52309,93 @@ var handleSessionRequestResponseMessage = (msg, deps) => {
|
|
|
52112
52309
|
handleBridgeSessionRequestResponse(msg, deps);
|
|
52113
52310
|
};
|
|
52114
52311
|
|
|
52115
|
-
// src/
|
|
52116
|
-
|
|
52117
|
-
|
|
52118
|
-
|
|
52119
|
-
|
|
52120
|
-
|
|
52121
|
-
|
|
52122
|
-
|
|
52123
|
-
var previewProcess = null;
|
|
52124
|
-
var previewPort = DEFAULT_PORT;
|
|
52125
|
-
var previewSecret = "";
|
|
52126
|
-
function getPreviewCommand() {
|
|
52127
|
-
return process.env[PREVIEW_COMMAND_ENV]?.trim() || DEFAULT_COMMAND;
|
|
52128
|
-
}
|
|
52129
|
-
function randomSecret() {
|
|
52130
|
-
const bytes = new Uint8Array(32);
|
|
52131
|
-
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
52132
|
-
crypto.getRandomValues(bytes);
|
|
52312
|
+
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
52313
|
+
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
52314
|
+
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
52315
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
52316
|
+
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
52317
|
+
if (!branch.trim() || !message.trim()) {
|
|
52318
|
+
reply({ ok: false, error: "branch and message are required for commit" });
|
|
52319
|
+
return;
|
|
52133
52320
|
}
|
|
52134
|
-
|
|
52135
|
-
|
|
52136
|
-
|
|
52137
|
-
|
|
52138
|
-
|
|
52139
|
-
[PREVIEW_SECRET_HEADER]: secret,
|
|
52140
|
-
"Content-Type": "application/json"
|
|
52141
|
-
};
|
|
52142
|
-
const res = await fetch(url2, {
|
|
52143
|
-
method,
|
|
52144
|
-
headers,
|
|
52145
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
52321
|
+
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
52322
|
+
sessionId,
|
|
52323
|
+
branch: branch.trim(),
|
|
52324
|
+
message: message.trim(),
|
|
52325
|
+
push: pushAfterCommit
|
|
52146
52326
|
});
|
|
52147
|
-
|
|
52148
|
-
|
|
52149
|
-
|
|
52327
|
+
if (!commitRes.ok) {
|
|
52328
|
+
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
52329
|
+
return;
|
|
52150
52330
|
}
|
|
52151
|
-
|
|
52331
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52332
|
+
reply({
|
|
52333
|
+
ok: true,
|
|
52334
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52335
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52336
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
52337
|
+
});
|
|
52152
52338
|
}
|
|
52153
|
-
var OPERATIONS = [
|
|
52154
|
-
{
|
|
52155
|
-
id: "start",
|
|
52156
|
-
description: "Start the preview server process (runs the configured command with PORT and PREVIEW_SECRET).",
|
|
52157
|
-
params: [
|
|
52158
|
-
{ name: "port", description: "Port for the preview server", type: "number", required: false }
|
|
52159
|
-
]
|
|
52160
|
-
},
|
|
52161
|
-
{
|
|
52162
|
-
id: "stop",
|
|
52163
|
-
description: "Stop the preview server via POST /__preview/stop (graceful shutdown).",
|
|
52164
|
-
params: []
|
|
52165
|
-
},
|
|
52166
|
-
{
|
|
52167
|
-
id: "status",
|
|
52168
|
-
description: "Return status from GET /__preview/status (running, url).",
|
|
52169
|
-
params: []
|
|
52170
|
-
}
|
|
52171
|
-
];
|
|
52172
|
-
var previewSkill = {
|
|
52173
|
-
id: "preview",
|
|
52174
|
-
name: "Preview",
|
|
52175
|
-
description: "Start and manage a local preview server that implements the BuildAutomaton Preview Server API. Configure the command with BUILDAUTOMATON_PREVIEW_COMMAND (default: npm run preview). The server receives PORT and PREVIEW_SECRET and must expose /__preview/status and /__preview/stop.",
|
|
52176
|
-
operations: OPERATIONS,
|
|
52177
|
-
async execute(operationId, params) {
|
|
52178
|
-
const command = getPreviewCommand();
|
|
52179
|
-
switch (operationId) {
|
|
52180
|
-
case "start": {
|
|
52181
|
-
if (previewProcess) {
|
|
52182
|
-
return {
|
|
52183
|
-
ok: false,
|
|
52184
|
-
message: "Preview server already running",
|
|
52185
|
-
url: `http://localhost:${previewPort}`
|
|
52186
|
-
};
|
|
52187
|
-
}
|
|
52188
|
-
const port = params.port ?? (Number(process.env[PREVIEW_PORT_ENV]) || DEFAULT_PORT);
|
|
52189
|
-
previewPort = port;
|
|
52190
|
-
previewSecret = randomSecret();
|
|
52191
|
-
const isWindows = process.platform === "win32";
|
|
52192
|
-
const parts = command.split(/\s+/);
|
|
52193
|
-
const exe = parts[0];
|
|
52194
|
-
const args = parts.slice(1);
|
|
52195
|
-
previewProcess = spawn10(isWindows && exe === "npm" ? "npm.cmd" : exe, args, {
|
|
52196
|
-
cwd: getBridgeRoot(),
|
|
52197
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
52198
|
-
env: {
|
|
52199
|
-
...process.env,
|
|
52200
|
-
PORT: String(port),
|
|
52201
|
-
PREVIEW_SECRET: previewSecret
|
|
52202
|
-
}
|
|
52203
|
-
});
|
|
52204
|
-
previewProcess.stdout?.on("data", (d) => process.stdout.write(d));
|
|
52205
|
-
previewProcess.stderr?.on("data", (d) => process.stderr.write(d));
|
|
52206
|
-
previewProcess.on("exit", (code) => {
|
|
52207
|
-
previewProcess = null;
|
|
52208
|
-
if (code !== null && code !== 0) {
|
|
52209
|
-
process.stderr.write(`Preview server exited with code ${code}
|
|
52210
|
-
`);
|
|
52211
|
-
}
|
|
52212
|
-
});
|
|
52213
|
-
return {
|
|
52214
|
-
ok: true,
|
|
52215
|
-
message: `Preview server starting (${command}, port=${port})`,
|
|
52216
|
-
url: `http://localhost:${port}`,
|
|
52217
|
-
port
|
|
52218
|
-
};
|
|
52219
|
-
}
|
|
52220
|
-
case "stop": {
|
|
52221
|
-
if (!previewProcess) {
|
|
52222
|
-
return { ok: true, message: "No preview server was running" };
|
|
52223
|
-
}
|
|
52224
|
-
if (!previewSecret) {
|
|
52225
|
-
previewProcess.kill("SIGTERM");
|
|
52226
|
-
previewProcess = null;
|
|
52227
|
-
return { ok: true, message: "Preview process stopped (no secret)" };
|
|
52228
|
-
}
|
|
52229
|
-
try {
|
|
52230
|
-
await requestPreviewApi(
|
|
52231
|
-
previewPort,
|
|
52232
|
-
previewSecret,
|
|
52233
|
-
"POST",
|
|
52234
|
-
`${PREVIEW_API_BASE_PATH}/stop`
|
|
52235
|
-
);
|
|
52236
|
-
} catch (e) {
|
|
52237
|
-
previewProcess.kill("SIGTERM");
|
|
52238
|
-
}
|
|
52239
|
-
previewProcess = null;
|
|
52240
|
-
previewSecret = "";
|
|
52241
|
-
return { ok: true, message: "Preview server stop requested" };
|
|
52242
|
-
}
|
|
52243
|
-
case "status": {
|
|
52244
|
-
if (!previewProcess || !previewSecret) {
|
|
52245
|
-
return {
|
|
52246
|
-
running: previewProcess != null,
|
|
52247
|
-
url: previewProcess ? `http://localhost:${previewPort}` : void 0,
|
|
52248
|
-
message: previewProcess ? `Process running at http://localhost:${previewPort}` : "No preview server running"
|
|
52249
|
-
};
|
|
52250
|
-
}
|
|
52251
|
-
try {
|
|
52252
|
-
const status = await requestPreviewApi(
|
|
52253
|
-
previewPort,
|
|
52254
|
-
previewSecret,
|
|
52255
|
-
"GET",
|
|
52256
|
-
`${PREVIEW_API_BASE_PATH}/status`
|
|
52257
|
-
);
|
|
52258
|
-
return {
|
|
52259
|
-
running: status.status === "running",
|
|
52260
|
-
status: status.status,
|
|
52261
|
-
url: status.url ?? `http://localhost:${previewPort}`,
|
|
52262
|
-
message: status.message ?? (status.status === "running" ? "Preview server running" : "Stopping")
|
|
52263
|
-
};
|
|
52264
|
-
} catch {
|
|
52265
|
-
return {
|
|
52266
|
-
running: previewProcess != null,
|
|
52267
|
-
url: `http://localhost:${previewPort}`,
|
|
52268
|
-
message: "Process running but status endpoint unreachable (server may not implement Preview Server API yet)"
|
|
52269
|
-
};
|
|
52270
|
-
}
|
|
52271
|
-
}
|
|
52272
|
-
default:
|
|
52273
|
-
throw new Error(`Unknown operation: ${operationId}`);
|
|
52274
|
-
}
|
|
52275
|
-
}
|
|
52276
|
-
};
|
|
52277
52339
|
|
|
52278
|
-
// src/
|
|
52279
|
-
|
|
52280
|
-
|
|
52281
|
-
return skills.find((s) => s.id === id);
|
|
52282
|
-
}
|
|
52283
|
-
async function callSkill(skillId, operationId, params) {
|
|
52284
|
-
const skill = getSkill(skillId);
|
|
52285
|
-
if (!skill) throw new Error(`Skill not found: ${skillId}`);
|
|
52286
|
-
return skill.execute(operationId, params);
|
|
52340
|
+
// src/routing/handlers/git/session-git-changes-params.ts
|
|
52341
|
+
function readString(value) {
|
|
52342
|
+
return typeof value === "string" ? value.trim() : "";
|
|
52287
52343
|
}
|
|
52288
|
-
|
|
52289
|
-
|
|
52290
|
-
|
|
52291
|
-
|
|
52292
|
-
sendWsMessage(socket, { type: "skill_result", id: msg.id, result });
|
|
52293
|
-
}).catch((err) => {
|
|
52294
|
-
sendWsMessage(socket, { type: "skill_result", id: msg.id, error: String(err) });
|
|
52295
|
-
log2(`[Bridge service] Skill invocation failed (${msg.skillId}/${msg.operationId}): ${err}`);
|
|
52296
|
-
});
|
|
52344
|
+
function readChangesObject(msg) {
|
|
52345
|
+
const changes = msg.changes;
|
|
52346
|
+
if (!changes || typeof changes !== "object" || Array.isArray(changes)) return null;
|
|
52347
|
+
return changes;
|
|
52297
52348
|
}
|
|
52298
|
-
|
|
52299
|
-
|
|
52300
|
-
|
|
52301
|
-
const
|
|
52302
|
-
const
|
|
52303
|
-
|
|
52304
|
-
const
|
|
52305
|
-
|
|
52306
|
-
|
|
52307
|
-
|
|
52308
|
-
|
|
52309
|
-
|
|
52310
|
-
|
|
52311
|
-
|
|
52312
|
-
|
|
52313
|
-
|
|
52314
|
-
|
|
52315
|
-
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
|
|
52349
|
+
function parseSessionGitChangesParams(msg) {
|
|
52350
|
+
const nested = readChangesObject(msg);
|
|
52351
|
+
const file2 = nested?.file && typeof nested.file === "object" && !Array.isArray(nested.file) ? nested.file : null;
|
|
52352
|
+
const repoRelPath = readString(nested?.repoRelPath) || readString(msg.changesRepoRelPath);
|
|
52353
|
+
const viewRaw = nested?.view ?? msg.changesView;
|
|
52354
|
+
const view = viewRaw === "commit" ? "commit" : "working";
|
|
52355
|
+
const commitSha = readString(nested?.commitSha) || readString(msg.changesCommitSha);
|
|
52356
|
+
const recentCommitsLimit = nested?.recentCommitsLimit ?? msg.changesRecentCommitsLimit;
|
|
52357
|
+
return {
|
|
52358
|
+
repoRelPath,
|
|
52359
|
+
view,
|
|
52360
|
+
commitSha,
|
|
52361
|
+
recentCommitsLimit: typeof recentCommitsLimit === "number" || typeof recentCommitsLimit === "string" ? recentCommitsLimit : void 0,
|
|
52362
|
+
fileWorkspaceRelPath: readString(file2?.workspaceRelPath),
|
|
52363
|
+
fileChange: readString(file2?.change),
|
|
52364
|
+
fileMovedFromWorkspaceRelPath: readString(file2?.movedFromWorkspaceRelPath)
|
|
52365
|
+
};
|
|
52316
52366
|
}
|
|
52317
52367
|
|
|
52318
|
-
// src/
|
|
52319
|
-
async function
|
|
52320
|
-
const
|
|
52321
|
-
|
|
52322
|
-
|
|
52368
|
+
// src/routing/handlers/git/handle-session-git-get-change-file-patch.ts
|
|
52369
|
+
async function handleSessionGitGetChangeFilePatchAction(deps, msg, reply) {
|
|
52370
|
+
const changes = parseSessionGitChangesParams(msg);
|
|
52371
|
+
const { repoRelPath: repoRel, view, commitSha, fileWorkspaceRelPath, fileChange, fileMovedFromWorkspaceRelPath } = changes;
|
|
52372
|
+
const change = parseWorkingTreeChangeKind(fileChange);
|
|
52373
|
+
if (!repoRel || !fileWorkspaceRelPath || !change) {
|
|
52374
|
+
reply({
|
|
52375
|
+
ok: false,
|
|
52376
|
+
error: "changes.repoRelPath, changes.file.workspaceRelPath, and changes.file.change are required"
|
|
52377
|
+
});
|
|
52323
52378
|
return;
|
|
52324
52379
|
}
|
|
52325
|
-
|
|
52326
|
-
}
|
|
52327
|
-
|
|
52328
|
-
// src/files/browser/handle-file-browser-read.ts
|
|
52329
|
-
async function handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope) {
|
|
52330
|
-
const result = await executeFileBrowserRead({ msg, reqPath, sessionParentPath, gitScope });
|
|
52331
|
-
if ("error" in result) {
|
|
52332
|
-
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
52380
|
+
if (view === "commit" && !commitSha) {
|
|
52381
|
+
reply({ ok: false, error: "changes.commitSha is required for commit file patch" });
|
|
52333
52382
|
return;
|
|
52334
52383
|
}
|
|
52335
|
-
const
|
|
52336
|
-
|
|
52337
|
-
|
|
52338
|
-
|
|
52339
|
-
|
|
52340
|
-
|
|
52341
|
-
};
|
|
52342
|
-
|
|
52343
|
-
|
|
52344
|
-
|
|
52345
|
-
|
|
52346
|
-
|
|
52347
|
-
|
|
52348
|
-
|
|
52349
|
-
|
|
52350
|
-
function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
52351
|
-
beginFileBrowserRequest();
|
|
52352
|
-
void (async () => {
|
|
52353
|
-
try {
|
|
52354
|
-
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
52355
|
-
const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
52356
|
-
const gitScope = resolveGitBranchScope(msg);
|
|
52357
|
-
if (msg.source === "git_branch" && typeof msg.repoRelPath === "string" && typeof msg.branch === "string" && msg.branch.trim().length > 0 && !gitScope) {
|
|
52358
|
-
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: "Invalid repository path" });
|
|
52359
|
-
return;
|
|
52360
|
-
}
|
|
52361
|
-
if (msg.op === "read") {
|
|
52362
|
-
await handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope);
|
|
52363
|
-
} else {
|
|
52364
|
-
await handleFileBrowserList(socket, e2ee, msg.id, reqPath, sessionParentPath, gitScope);
|
|
52365
|
-
}
|
|
52366
|
-
} finally {
|
|
52367
|
-
endFileBrowserRequest();
|
|
52368
|
-
}
|
|
52369
|
-
})();
|
|
52370
|
-
}
|
|
52371
|
-
|
|
52372
|
-
// src/files/handle-file-browser-search.ts
|
|
52373
|
-
init_yield_to_event_loop();
|
|
52374
|
-
import path78 from "node:path";
|
|
52375
|
-
var SEARCH_LIMIT = 100;
|
|
52376
|
-
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
52377
|
-
void (async () => {
|
|
52378
|
-
await yieldToEventLoop();
|
|
52379
|
-
const q = typeof msg.q === "string" ? msg.q : "";
|
|
52380
|
-
const sessionParentPath = path78.resolve(
|
|
52381
|
-
sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
52382
|
-
);
|
|
52383
|
-
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
52384
|
-
triggerFileIndexBuild(sessionParentPath);
|
|
52385
|
-
const payload2 = {
|
|
52386
|
-
type: "file_browser_search_response",
|
|
52387
|
-
id: msg.id,
|
|
52388
|
-
paths: [],
|
|
52389
|
-
indexReady: false
|
|
52390
|
-
};
|
|
52391
|
-
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
52392
|
-
return;
|
|
52393
|
-
}
|
|
52394
|
-
const results = await searchBridgeFilePathsAsync(sessionParentPath, q, SEARCH_LIMIT);
|
|
52395
|
-
const payload = {
|
|
52396
|
-
type: "file_browser_search_response",
|
|
52397
|
-
id: msg.id,
|
|
52398
|
-
paths: results,
|
|
52399
|
-
indexReady: true
|
|
52400
|
-
};
|
|
52401
|
-
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["paths"]) : payload);
|
|
52402
|
-
})();
|
|
52403
|
-
}
|
|
52404
|
-
function triggerFileIndexBuild(sessionParentPath = getBridgeRoot()) {
|
|
52405
|
-
setImmediate(() => {
|
|
52406
|
-
void ensureFileIndexAsync(sessionParentPath).catch((e) => {
|
|
52407
|
-
console.error("[file-index] Background build failed:", e);
|
|
52408
|
-
});
|
|
52409
|
-
});
|
|
52410
|
-
}
|
|
52411
|
-
|
|
52412
|
-
// src/routing/handlers/file-browser-messages.ts
|
|
52413
|
-
function handleFileBrowserRequestMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
52414
|
-
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
52415
|
-
const socket = getWs();
|
|
52416
|
-
if (!socket) return;
|
|
52417
|
-
handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager);
|
|
52418
|
-
}
|
|
52419
|
-
function handleFileBrowserSearchMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
52420
|
-
if (typeof msg.id !== "string") return;
|
|
52421
|
-
const socket = getWs();
|
|
52422
|
-
if (!socket) return;
|
|
52423
|
-
handleFileBrowserSearch(
|
|
52424
|
-
msg,
|
|
52425
|
-
socket,
|
|
52426
|
-
e2ee,
|
|
52427
|
-
sessionWorktreeManager
|
|
52428
|
-
);
|
|
52429
|
-
}
|
|
52430
|
-
|
|
52431
|
-
// src/code-nav/handlers/send-code-nav-response.ts
|
|
52432
|
-
var ENCRYPTED_FIELDS = ["definition", "definitions", "references", "symbols", "confidentTarget"];
|
|
52433
|
-
function sendCodeNavResponse(socket, e2ee, payload) {
|
|
52434
|
-
const fieldsToEncrypt = ENCRYPTED_FIELDS.filter((field) => field in payload && payload[field] !== void 0);
|
|
52435
|
-
sendWsMessage(
|
|
52436
|
-
socket,
|
|
52437
|
-
e2ee && fieldsToEncrypt.length > 0 ? e2ee.encryptFields(payload, [...fieldsToEncrypt]) : payload
|
|
52438
|
-
);
|
|
52439
|
-
}
|
|
52440
|
-
|
|
52441
|
-
// src/code-nav/handlers/handle-code-nav-request.ts
|
|
52442
|
-
function handleCodeNavRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
52443
|
-
void (async () => {
|
|
52444
|
-
const body = await executeCodeNavRequest(msg, sessionWorktreeManager);
|
|
52445
|
-
sendCodeNavResponse(socket, e2ee, {
|
|
52446
|
-
type: "code_nav_response",
|
|
52447
|
-
id: msg.id,
|
|
52448
|
-
...body
|
|
52449
|
-
});
|
|
52450
|
-
})();
|
|
52451
|
-
}
|
|
52452
|
-
|
|
52453
|
-
// src/code-nav/handlers/trigger-symbol-index-build.ts
|
|
52454
|
-
init_normalize_resolved_path();
|
|
52455
|
-
|
|
52456
|
-
// src/routing/handlers/code-nav-messages.ts
|
|
52457
|
-
function handleFileBrowserCodeNavMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
52458
|
-
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
52459
|
-
const socket = getWs();
|
|
52460
|
-
if (!socket) return;
|
|
52461
|
-
handleCodeNavRequest(
|
|
52462
|
-
{
|
|
52463
|
-
id: msg.id,
|
|
52464
|
-
type: "code_nav",
|
|
52465
|
-
op: msg.op === "references" ? "references" : msg.op === "symbols" ? "symbols" : msg.op === "definitions" ? "definitions" : "definition",
|
|
52466
|
-
path: msg.path,
|
|
52467
|
-
line: typeof msg.line === "number" ? msg.line : 1,
|
|
52468
|
-
column: typeof msg.column === "number" ? msg.column : 0,
|
|
52469
|
-
sessionId: msg.sessionId
|
|
52470
|
-
},
|
|
52471
|
-
socket,
|
|
52472
|
-
e2ee,
|
|
52473
|
-
sessionWorktreeManager
|
|
52474
|
-
);
|
|
52475
|
-
}
|
|
52476
|
-
|
|
52477
|
-
// src/routing/handlers/skill-layout-request.ts
|
|
52478
|
-
function handleSkillLayoutRequest(msg, deps) {
|
|
52479
|
-
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52480
|
-
void (async () => {
|
|
52481
|
-
const socket = deps.getWs();
|
|
52482
|
-
const roots = await discoverSkillLayoutRootsAsync(getBridgeRoot());
|
|
52483
|
-
if (socket) {
|
|
52484
|
-
sendWsMessage(socket, { type: "skill_layout_response", id, roots });
|
|
52485
|
-
}
|
|
52486
|
-
})();
|
|
52487
|
-
}
|
|
52488
|
-
|
|
52489
|
-
// src/skills/install/is-valid-install-item.ts
|
|
52490
|
-
function isValidRemoteSkillInstallItem(item) {
|
|
52491
|
-
if (item === null || typeof item !== "object") return false;
|
|
52492
|
-
const o = item;
|
|
52493
|
-
return typeof o.sourceId === "string" && typeof o.skillName === "string" && typeof o.versionHash === "string" && Array.isArray(o.files);
|
|
52494
|
-
}
|
|
52495
|
-
|
|
52496
|
-
// src/skills/install/install-remote-skills-async.ts
|
|
52497
|
-
init_yield_to_event_loop();
|
|
52498
|
-
import fs58 from "node:fs";
|
|
52499
|
-
import path79 from "node:path";
|
|
52500
|
-
|
|
52501
|
-
// src/skills/install/constants.ts
|
|
52502
|
-
var INSTALL_SKILLS_YIELD_EVERY = 16;
|
|
52503
|
-
|
|
52504
|
-
// src/skills/install/install-remote-skills-async.ts
|
|
52505
|
-
async function writeInstallFileAsync(skillDir, f, filesWritten) {
|
|
52506
|
-
if (typeof f.path !== "string" || !f.text && !f.base64) return;
|
|
52507
|
-
if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
|
|
52508
|
-
await yieldToEventLoop();
|
|
52509
|
-
}
|
|
52510
|
-
const dest = path79.join(skillDir, f.path);
|
|
52511
|
-
await fs58.promises.mkdir(path79.dirname(dest), { recursive: true });
|
|
52512
|
-
if (f.text !== void 0) {
|
|
52513
|
-
await fs58.promises.writeFile(dest, f.text, "utf8");
|
|
52514
|
-
} else if (f.base64) {
|
|
52515
|
-
await fs58.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
|
|
52516
|
-
}
|
|
52517
|
-
}
|
|
52518
|
-
async function installRemoteSkillsAsync(cwd, targetDir, items) {
|
|
52519
|
-
const installed2 = [];
|
|
52520
|
-
if (!Array.isArray(items)) {
|
|
52521
|
-
return { success: false, error: "Invalid items" };
|
|
52522
|
-
}
|
|
52523
|
-
const filesWritten = { count: 0 };
|
|
52524
|
-
try {
|
|
52525
|
-
for (const item of items) {
|
|
52526
|
-
if (!isValidRemoteSkillInstallItem(item)) continue;
|
|
52527
|
-
const skillDir = path79.join(cwd, targetDir, item.skillName);
|
|
52528
|
-
for (const f of item.files) {
|
|
52529
|
-
await writeInstallFileAsync(skillDir, f, filesWritten);
|
|
52530
|
-
}
|
|
52531
|
-
installed2.push({
|
|
52532
|
-
sourceId: item.sourceId,
|
|
52533
|
-
skillName: item.skillName,
|
|
52534
|
-
versionHash: item.versionHash
|
|
52535
|
-
});
|
|
52536
|
-
}
|
|
52537
|
-
return { success: true, installed: installed2 };
|
|
52538
|
-
} catch (e) {
|
|
52539
|
-
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
52540
|
-
}
|
|
52541
|
-
}
|
|
52542
|
-
|
|
52543
|
-
// src/routing/handlers/install-skills.ts
|
|
52544
|
-
var handleInstallSkillsMessage = (msg, deps) => {
|
|
52545
|
-
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52546
|
-
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
52547
|
-
const rawItems = msg.items;
|
|
52548
|
-
const cwd = getBridgeRoot();
|
|
52549
|
-
void (async () => {
|
|
52550
|
-
const socket = deps.getWs();
|
|
52551
|
-
const result = await installRemoteSkillsAsync(cwd, targetDir, rawItems);
|
|
52552
|
-
if (!result.success) {
|
|
52553
|
-
const err = result.error ?? "Invalid items";
|
|
52554
|
-
deps.log(`[Bridge service] Install skills failed: ${err}`);
|
|
52555
|
-
if (socket) {
|
|
52556
|
-
sendWsMessage(socket, { type: "install_skills_result", id, success: false, error: err });
|
|
52557
|
-
}
|
|
52558
|
-
return;
|
|
52559
|
-
}
|
|
52560
|
-
if (socket) {
|
|
52561
|
-
sendWsMessage(socket, { type: "install_skills_result", id, success: true, installed: result.installed });
|
|
52562
|
-
}
|
|
52563
|
-
})();
|
|
52564
|
-
};
|
|
52565
|
-
|
|
52566
|
-
// src/routing/handlers/refresh-local-skills.ts
|
|
52567
|
-
var handleRefreshLocalSkills = (_msg, deps) => {
|
|
52568
|
-
setImmediate(() => {
|
|
52569
|
-
deps.sendLocalSkillsReport?.();
|
|
52570
|
-
});
|
|
52571
|
-
};
|
|
52572
|
-
|
|
52573
|
-
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
52574
|
-
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
52575
|
-
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
52576
|
-
const message = typeof msg.message === "string" ? msg.message : "";
|
|
52577
|
-
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
52578
|
-
if (!branch.trim() || !message.trim()) {
|
|
52579
|
-
reply({ ok: false, error: "branch and message are required for commit" });
|
|
52580
|
-
return;
|
|
52581
|
-
}
|
|
52582
|
-
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
52583
|
-
sessionId,
|
|
52584
|
-
branch: branch.trim(),
|
|
52585
|
-
message: message.trim(),
|
|
52586
|
-
push: pushAfterCommit
|
|
52587
|
-
});
|
|
52588
|
-
if (!commitRes.ok) {
|
|
52589
|
-
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
52590
|
-
return;
|
|
52591
|
-
}
|
|
52592
|
-
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
52593
|
-
reply({
|
|
52594
|
-
ok: true,
|
|
52595
|
-
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
52596
|
-
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
52597
|
-
uncommittedFileCount: st.uncommittedFileCount
|
|
52598
|
-
});
|
|
52599
|
-
}
|
|
52600
|
-
|
|
52601
|
-
// src/routing/handlers/git/session-git-changes-params.ts
|
|
52602
|
-
function readString(value) {
|
|
52603
|
-
return typeof value === "string" ? value.trim() : "";
|
|
52604
|
-
}
|
|
52605
|
-
function readChangesObject(msg) {
|
|
52606
|
-
const changes = msg.changes;
|
|
52607
|
-
if (!changes || typeof changes !== "object" || Array.isArray(changes)) return null;
|
|
52608
|
-
return changes;
|
|
52609
|
-
}
|
|
52610
|
-
function parseSessionGitChangesParams(msg) {
|
|
52611
|
-
const nested = readChangesObject(msg);
|
|
52612
|
-
const file2 = nested?.file && typeof nested.file === "object" && !Array.isArray(nested.file) ? nested.file : null;
|
|
52613
|
-
const repoRelPath = readString(nested?.repoRelPath) || readString(msg.changesRepoRelPath);
|
|
52614
|
-
const viewRaw = nested?.view ?? msg.changesView;
|
|
52615
|
-
const view = viewRaw === "commit" ? "commit" : "working";
|
|
52616
|
-
const commitSha = readString(nested?.commitSha) || readString(msg.changesCommitSha);
|
|
52617
|
-
const recentCommitsLimit = nested?.recentCommitsLimit ?? msg.changesRecentCommitsLimit;
|
|
52618
|
-
return {
|
|
52619
|
-
repoRelPath,
|
|
52620
|
-
view,
|
|
52621
|
-
commitSha,
|
|
52622
|
-
recentCommitsLimit: typeof recentCommitsLimit === "number" || typeof recentCommitsLimit === "string" ? recentCommitsLimit : void 0,
|
|
52623
|
-
fileWorkspaceRelPath: readString(file2?.workspaceRelPath),
|
|
52624
|
-
fileChange: readString(file2?.change),
|
|
52625
|
-
fileMovedFromWorkspaceRelPath: readString(file2?.movedFromWorkspaceRelPath)
|
|
52626
|
-
};
|
|
52627
|
-
}
|
|
52628
|
-
|
|
52629
|
-
// src/routing/handlers/git/handle-session-git-get-change-file-patch.ts
|
|
52630
|
-
async function handleSessionGitGetChangeFilePatchAction(deps, msg, reply) {
|
|
52631
|
-
const changes = parseSessionGitChangesParams(msg);
|
|
52632
|
-
const { repoRelPath: repoRel, view, commitSha, fileWorkspaceRelPath, fileChange, fileMovedFromWorkspaceRelPath } = changes;
|
|
52633
|
-
const change = parseWorkingTreeChangeKind(fileChange);
|
|
52634
|
-
if (!repoRel || !fileWorkspaceRelPath || !change) {
|
|
52635
|
-
reply({
|
|
52636
|
-
ok: false,
|
|
52637
|
-
error: "changes.repoRelPath, changes.file.workspaceRelPath, and changes.file.change are required"
|
|
52638
|
-
});
|
|
52639
|
-
return;
|
|
52640
|
-
}
|
|
52641
|
-
if (view === "commit" && !commitSha) {
|
|
52642
|
-
reply({ ok: false, error: "changes.commitSha is required for commit file patch" });
|
|
52643
|
-
return;
|
|
52644
|
-
}
|
|
52645
|
-
const patch = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeFilePatch(msg.sessionId, {
|
|
52646
|
-
repoRelPath: repoRel,
|
|
52647
|
-
workspaceRelPath: fileWorkspaceRelPath,
|
|
52648
|
-
change,
|
|
52649
|
-
movedFromWorkspaceRelPath: fileMovedFromWorkspaceRelPath || null,
|
|
52650
|
-
basis: view === "commit" ? { kind: "commit", sha: commitSha } : { kind: "working" }
|
|
52651
|
-
});
|
|
52652
|
-
reply(
|
|
52653
|
-
{
|
|
52654
|
-
ok: true,
|
|
52655
|
-
patchContent: patch.patchContent ?? null,
|
|
52656
|
-
totalLines: patch.totalLines
|
|
52657
|
-
},
|
|
52658
|
-
["patchContent"]
|
|
52659
|
-
);
|
|
52384
|
+
const patch = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeFilePatch(msg.sessionId, {
|
|
52385
|
+
repoRelPath: repoRel,
|
|
52386
|
+
workspaceRelPath: fileWorkspaceRelPath,
|
|
52387
|
+
change,
|
|
52388
|
+
movedFromWorkspaceRelPath: fileMovedFromWorkspaceRelPath || null,
|
|
52389
|
+
basis: view === "commit" ? { kind: "commit", sha: commitSha } : { kind: "working" }
|
|
52390
|
+
});
|
|
52391
|
+
reply(
|
|
52392
|
+
{
|
|
52393
|
+
ok: true,
|
|
52394
|
+
patchContent: patch.patchContent ?? null,
|
|
52395
|
+
totalLines: patch.totalLines
|
|
52396
|
+
},
|
|
52397
|
+
["patchContent"]
|
|
52398
|
+
);
|
|
52660
52399
|
}
|
|
52661
52400
|
|
|
52662
52401
|
// src/routing/handlers/git/coalesce-list-changes.ts
|
|
@@ -52806,7 +52545,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
52806
52545
|
};
|
|
52807
52546
|
|
|
52808
52547
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
52809
|
-
import * as
|
|
52548
|
+
import * as fs60 from "node:fs";
|
|
52810
52549
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
52811
52550
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52812
52551
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -52819,7 +52558,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
52819
52558
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
52820
52559
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
52821
52560
|
try {
|
|
52822
|
-
await
|
|
52561
|
+
await fs60.promises.access(file2, fs60.constants.F_OK);
|
|
52823
52562
|
} catch {
|
|
52824
52563
|
sendWsMessage(s, {
|
|
52825
52564
|
type: "revert_turn_snapshot_result",
|
|
@@ -52839,72 +52578,664 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
52839
52578
|
})();
|
|
52840
52579
|
};
|
|
52841
52580
|
|
|
52842
|
-
// src/routing/
|
|
52843
|
-
|
|
52844
|
-
|
|
52581
|
+
// src/routing/dispatch/session.ts
|
|
52582
|
+
function dispatchBridgeSessionMessage(msg, deps) {
|
|
52583
|
+
switch (msg.type) {
|
|
52584
|
+
case "agent_config":
|
|
52585
|
+
handleAgentConfigMessage(msg, deps);
|
|
52586
|
+
break;
|
|
52587
|
+
case "prompt_queue_state":
|
|
52588
|
+
handlePromptQueueStateMessage(msg, deps);
|
|
52589
|
+
break;
|
|
52590
|
+
case "prompt":
|
|
52591
|
+
handlePromptMessage(msg, deps);
|
|
52592
|
+
break;
|
|
52593
|
+
case "session_git_request":
|
|
52594
|
+
handleSessionGitRequestMessage(msg, deps);
|
|
52595
|
+
break;
|
|
52596
|
+
case "rename_session_branch":
|
|
52597
|
+
handleRenameSessionBranchMessage(msg, deps);
|
|
52598
|
+
break;
|
|
52599
|
+
case "session_archived":
|
|
52600
|
+
handleSessionArchivedMessage(msg, deps);
|
|
52601
|
+
break;
|
|
52602
|
+
case "session_discarded":
|
|
52603
|
+
handleSessionDiscardedMessage(msg, deps);
|
|
52604
|
+
break;
|
|
52605
|
+
case "revert_turn_snapshot":
|
|
52606
|
+
handleRevertTurnSnapshotMessage(msg, deps);
|
|
52607
|
+
break;
|
|
52608
|
+
case "cursor_request_response":
|
|
52609
|
+
handleSessionRequestResponseMessage(msg, deps);
|
|
52610
|
+
break;
|
|
52611
|
+
}
|
|
52612
|
+
}
|
|
52613
|
+
|
|
52614
|
+
// src/skills/preview.ts
|
|
52615
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
52616
|
+
var PREVIEW_API_BASE_PATH = "/__preview";
|
|
52617
|
+
var PREVIEW_SECRET_HEADER = "X-Preview-Secret";
|
|
52618
|
+
var DEFAULT_PORT = 3e3;
|
|
52619
|
+
var DEFAULT_COMMAND = "npm run preview";
|
|
52620
|
+
var PREVIEW_COMMAND_ENV = "BUILDAUTOMATON_PREVIEW_COMMAND";
|
|
52621
|
+
var PREVIEW_PORT_ENV = "BUILDAUTOMATON_PREVIEW_PORT";
|
|
52622
|
+
var previewProcess = null;
|
|
52623
|
+
var previewPort = DEFAULT_PORT;
|
|
52624
|
+
var previewSecret = "";
|
|
52625
|
+
function getPreviewCommand() {
|
|
52626
|
+
return process.env[PREVIEW_COMMAND_ENV]?.trim() || DEFAULT_COMMAND;
|
|
52627
|
+
}
|
|
52628
|
+
function randomSecret() {
|
|
52629
|
+
const bytes = new Uint8Array(32);
|
|
52630
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
52631
|
+
crypto.getRandomValues(bytes);
|
|
52632
|
+
}
|
|
52633
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
52634
|
+
}
|
|
52635
|
+
async function requestPreviewApi(port, secret, method, path84, body) {
|
|
52636
|
+
const url2 = `http://127.0.0.1:${port}${path84}`;
|
|
52637
|
+
const headers = {
|
|
52638
|
+
[PREVIEW_SECRET_HEADER]: secret,
|
|
52639
|
+
"Content-Type": "application/json"
|
|
52640
|
+
};
|
|
52641
|
+
const res = await fetch(url2, {
|
|
52642
|
+
method,
|
|
52643
|
+
headers,
|
|
52644
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
52645
|
+
});
|
|
52646
|
+
const data = await res.json().catch(() => ({}));
|
|
52647
|
+
if (!res.ok) {
|
|
52648
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path84}: ${res.status}`);
|
|
52649
|
+
}
|
|
52650
|
+
return data;
|
|
52651
|
+
}
|
|
52652
|
+
var OPERATIONS = [
|
|
52653
|
+
{
|
|
52654
|
+
id: "start",
|
|
52655
|
+
description: "Start the preview server process (runs the configured command with PORT and PREVIEW_SECRET).",
|
|
52656
|
+
params: [
|
|
52657
|
+
{ name: "port", description: "Port for the preview server", type: "number", required: false }
|
|
52658
|
+
]
|
|
52659
|
+
},
|
|
52660
|
+
{
|
|
52661
|
+
id: "stop",
|
|
52662
|
+
description: "Stop the preview server via POST /__preview/stop (graceful shutdown).",
|
|
52663
|
+
params: []
|
|
52664
|
+
},
|
|
52665
|
+
{
|
|
52666
|
+
id: "status",
|
|
52667
|
+
description: "Return status from GET /__preview/status (running, url).",
|
|
52668
|
+
params: []
|
|
52669
|
+
}
|
|
52670
|
+
];
|
|
52671
|
+
var previewSkill = {
|
|
52672
|
+
id: "preview",
|
|
52673
|
+
name: "Preview",
|
|
52674
|
+
description: "Start and manage a local preview server that implements the BuildAutomaton Preview Server API. Configure the command with BUILDAUTOMATON_PREVIEW_COMMAND (default: npm run preview). The server receives PORT and PREVIEW_SECRET and must expose /__preview/status and /__preview/stop.",
|
|
52675
|
+
operations: OPERATIONS,
|
|
52676
|
+
async execute(operationId, params) {
|
|
52677
|
+
const command = getPreviewCommand();
|
|
52678
|
+
switch (operationId) {
|
|
52679
|
+
case "start": {
|
|
52680
|
+
if (previewProcess) {
|
|
52681
|
+
return {
|
|
52682
|
+
ok: false,
|
|
52683
|
+
message: "Preview server already running",
|
|
52684
|
+
url: `http://localhost:${previewPort}`
|
|
52685
|
+
};
|
|
52686
|
+
}
|
|
52687
|
+
const port = params.port ?? (Number(process.env[PREVIEW_PORT_ENV]) || DEFAULT_PORT);
|
|
52688
|
+
previewPort = port;
|
|
52689
|
+
previewSecret = randomSecret();
|
|
52690
|
+
const isWindows = process.platform === "win32";
|
|
52691
|
+
const parts = command.split(/\s+/);
|
|
52692
|
+
const exe = parts[0];
|
|
52693
|
+
const args = parts.slice(1);
|
|
52694
|
+
previewProcess = spawn10(isWindows && exe === "npm" ? "npm.cmd" : exe, args, {
|
|
52695
|
+
cwd: getBridgeRoot(),
|
|
52696
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
52697
|
+
env: {
|
|
52698
|
+
...process.env,
|
|
52699
|
+
PORT: String(port),
|
|
52700
|
+
PREVIEW_SECRET: previewSecret
|
|
52701
|
+
}
|
|
52702
|
+
});
|
|
52703
|
+
previewProcess.stdout?.on("data", (d) => process.stdout.write(d));
|
|
52704
|
+
previewProcess.stderr?.on("data", (d) => process.stderr.write(d));
|
|
52705
|
+
previewProcess.on("exit", (code) => {
|
|
52706
|
+
previewProcess = null;
|
|
52707
|
+
if (code !== null && code !== 0) {
|
|
52708
|
+
process.stderr.write(`Preview server exited with code ${code}
|
|
52709
|
+
`);
|
|
52710
|
+
}
|
|
52711
|
+
});
|
|
52712
|
+
return {
|
|
52713
|
+
ok: true,
|
|
52714
|
+
message: `Preview server starting (${command}, port=${port})`,
|
|
52715
|
+
url: `http://localhost:${port}`,
|
|
52716
|
+
port
|
|
52717
|
+
};
|
|
52718
|
+
}
|
|
52719
|
+
case "stop": {
|
|
52720
|
+
if (!previewProcess) {
|
|
52721
|
+
return { ok: true, message: "No preview server was running" };
|
|
52722
|
+
}
|
|
52723
|
+
if (!previewSecret) {
|
|
52724
|
+
previewProcess.kill("SIGTERM");
|
|
52725
|
+
previewProcess = null;
|
|
52726
|
+
return { ok: true, message: "Preview process stopped (no secret)" };
|
|
52727
|
+
}
|
|
52728
|
+
try {
|
|
52729
|
+
await requestPreviewApi(
|
|
52730
|
+
previewPort,
|
|
52731
|
+
previewSecret,
|
|
52732
|
+
"POST",
|
|
52733
|
+
`${PREVIEW_API_BASE_PATH}/stop`
|
|
52734
|
+
);
|
|
52735
|
+
} catch (e) {
|
|
52736
|
+
previewProcess.kill("SIGTERM");
|
|
52737
|
+
}
|
|
52738
|
+
previewProcess = null;
|
|
52739
|
+
previewSecret = "";
|
|
52740
|
+
return { ok: true, message: "Preview server stop requested" };
|
|
52741
|
+
}
|
|
52742
|
+
case "status": {
|
|
52743
|
+
if (!previewProcess || !previewSecret) {
|
|
52744
|
+
return {
|
|
52745
|
+
running: previewProcess != null,
|
|
52746
|
+
url: previewProcess ? `http://localhost:${previewPort}` : void 0,
|
|
52747
|
+
message: previewProcess ? `Process running at http://localhost:${previewPort}` : "No preview server running"
|
|
52748
|
+
};
|
|
52749
|
+
}
|
|
52750
|
+
try {
|
|
52751
|
+
const status = await requestPreviewApi(
|
|
52752
|
+
previewPort,
|
|
52753
|
+
previewSecret,
|
|
52754
|
+
"GET",
|
|
52755
|
+
`${PREVIEW_API_BASE_PATH}/status`
|
|
52756
|
+
);
|
|
52757
|
+
return {
|
|
52758
|
+
running: status.status === "running",
|
|
52759
|
+
status: status.status,
|
|
52760
|
+
url: status.url ?? `http://localhost:${previewPort}`,
|
|
52761
|
+
message: status.message ?? (status.status === "running" ? "Preview server running" : "Stopping")
|
|
52762
|
+
};
|
|
52763
|
+
} catch {
|
|
52764
|
+
return {
|
|
52765
|
+
running: previewProcess != null,
|
|
52766
|
+
url: `http://localhost:${previewPort}`,
|
|
52767
|
+
message: "Process running but status endpoint unreachable (server may not implement Preview Server API yet)"
|
|
52768
|
+
};
|
|
52769
|
+
}
|
|
52770
|
+
}
|
|
52771
|
+
default:
|
|
52772
|
+
throw new Error(`Unknown operation: ${operationId}`);
|
|
52773
|
+
}
|
|
52774
|
+
}
|
|
52775
|
+
};
|
|
52776
|
+
|
|
52777
|
+
// src/skills/index.ts
|
|
52778
|
+
var skills = [previewSkill];
|
|
52779
|
+
function getSkill(id) {
|
|
52780
|
+
return skills.find((s) => s.id === id);
|
|
52781
|
+
}
|
|
52782
|
+
async function callSkill(skillId, operationId, params) {
|
|
52783
|
+
const skill = getSkill(skillId);
|
|
52784
|
+
if (!skill) throw new Error(`Skill not found: ${skillId}`);
|
|
52785
|
+
return skill.execute(operationId, params);
|
|
52786
|
+
}
|
|
52787
|
+
|
|
52788
|
+
// src/skills/handle-skill-call.ts
|
|
52789
|
+
function handleSkillCall(msg, socket, log2) {
|
|
52790
|
+
callSkill(msg.skillId, msg.operationId, msg.params ?? {}).then((result) => {
|
|
52791
|
+
sendWsMessage(socket, { type: "skill_result", id: msg.id, result });
|
|
52792
|
+
}).catch((err) => {
|
|
52793
|
+
sendWsMessage(socket, { type: "skill_result", id: msg.id, error: String(err) });
|
|
52794
|
+
log2(`[Bridge service] Skill invocation failed (${msg.skillId}/${msg.operationId}): ${err}`);
|
|
52795
|
+
});
|
|
52796
|
+
}
|
|
52797
|
+
|
|
52798
|
+
// src/routing/handlers/skill-call.ts
|
|
52799
|
+
var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
52800
|
+
const skillId = typeof msg.skillId === "string" ? msg.skillId : "";
|
|
52801
|
+
const operationId = typeof msg.operationId === "string" ? msg.operationId : "";
|
|
52802
|
+
if (!skillId || !operationId) return;
|
|
52803
|
+
const socket = getWs();
|
|
52804
|
+
if (!socket) return;
|
|
52805
|
+
handleSkillCall(
|
|
52806
|
+
{ id: msg.id, skillId, operationId, params: msg.params },
|
|
52807
|
+
socket,
|
|
52808
|
+
log2
|
|
52809
|
+
);
|
|
52810
|
+
};
|
|
52811
|
+
|
|
52812
|
+
// src/routing/handlers/skill-layout-request.ts
|
|
52813
|
+
function handleSkillLayoutRequest(msg, deps) {
|
|
52814
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52815
|
+
void (async () => {
|
|
52816
|
+
const socket = deps.getWs();
|
|
52817
|
+
const roots = await discoverSkillLayoutRootsAsync(getBridgeRoot());
|
|
52818
|
+
if (socket) {
|
|
52819
|
+
sendWsMessage(socket, { type: "skill_layout_response", id, roots });
|
|
52820
|
+
}
|
|
52821
|
+
})();
|
|
52822
|
+
}
|
|
52823
|
+
|
|
52824
|
+
// src/skills/install/is-valid-install-item.ts
|
|
52825
|
+
function isValidRemoteSkillInstallItem(item) {
|
|
52826
|
+
if (item === null || typeof item !== "object") return false;
|
|
52827
|
+
const o = item;
|
|
52828
|
+
return typeof o.sourceId === "string" && typeof o.skillName === "string" && typeof o.versionHash === "string" && Array.isArray(o.files);
|
|
52829
|
+
}
|
|
52830
|
+
|
|
52831
|
+
// src/skills/install/install-remote-skills-async.ts
|
|
52832
|
+
init_yield_to_event_loop();
|
|
52833
|
+
import fs61 from "node:fs";
|
|
52834
|
+
import path80 from "node:path";
|
|
52835
|
+
|
|
52836
|
+
// src/skills/install/constants.ts
|
|
52837
|
+
var INSTALL_SKILLS_YIELD_EVERY = 16;
|
|
52838
|
+
|
|
52839
|
+
// src/skills/install/install-remote-skills-async.ts
|
|
52840
|
+
async function writeInstallFileAsync(skillDir, f, filesWritten) {
|
|
52841
|
+
if (typeof f.path !== "string" || !f.text && !f.base64) return;
|
|
52842
|
+
if (++filesWritten.count % INSTALL_SKILLS_YIELD_EVERY === 0) {
|
|
52843
|
+
await yieldToEventLoop();
|
|
52844
|
+
}
|
|
52845
|
+
const dest = path80.join(skillDir, f.path);
|
|
52846
|
+
await fs61.promises.mkdir(path80.dirname(dest), { recursive: true });
|
|
52847
|
+
if (f.text !== void 0) {
|
|
52848
|
+
await fs61.promises.writeFile(dest, f.text, "utf8");
|
|
52849
|
+
} else if (f.base64) {
|
|
52850
|
+
await fs61.promises.writeFile(dest, Buffer.from(f.base64, "base64"));
|
|
52851
|
+
}
|
|
52852
|
+
}
|
|
52853
|
+
async function installRemoteSkillsAsync(cwd, targetDir, items) {
|
|
52854
|
+
const installed2 = [];
|
|
52855
|
+
if (!Array.isArray(items)) {
|
|
52856
|
+
return { success: false, error: "Invalid items" };
|
|
52857
|
+
}
|
|
52858
|
+
const filesWritten = { count: 0 };
|
|
52845
52859
|
try {
|
|
52846
|
-
|
|
52860
|
+
for (const item of items) {
|
|
52861
|
+
if (!isValidRemoteSkillInstallItem(item)) continue;
|
|
52862
|
+
const skillDir = path80.join(cwd, targetDir, item.skillName);
|
|
52863
|
+
for (const f of item.files) {
|
|
52864
|
+
await writeInstallFileAsync(skillDir, f, filesWritten);
|
|
52865
|
+
}
|
|
52866
|
+
installed2.push({
|
|
52867
|
+
sourceId: item.sourceId,
|
|
52868
|
+
skillName: item.skillName,
|
|
52869
|
+
versionHash: item.versionHash
|
|
52870
|
+
});
|
|
52871
|
+
}
|
|
52872
|
+
return { success: true, installed: installed2 };
|
|
52847
52873
|
} catch (e) {
|
|
52848
|
-
|
|
52849
|
-
return;
|
|
52874
|
+
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
52850
52875
|
}
|
|
52851
|
-
|
|
52852
|
-
|
|
52853
|
-
|
|
52854
|
-
|
|
52876
|
+
}
|
|
52877
|
+
|
|
52878
|
+
// src/routing/handlers/install-skills.ts
|
|
52879
|
+
var handleInstallSkillsMessage = (msg, deps) => {
|
|
52880
|
+
const id = typeof msg.id === "string" ? msg.id : "";
|
|
52881
|
+
const targetDir = typeof msg.targetDir === "string" && msg.targetDir.trim() ? msg.targetDir.trim() : ".agents/skills";
|
|
52882
|
+
const rawItems = msg.items;
|
|
52883
|
+
const cwd = getBridgeRoot();
|
|
52884
|
+
void (async () => {
|
|
52885
|
+
const socket = deps.getWs();
|
|
52886
|
+
const result = await installRemoteSkillsAsync(cwd, targetDir, rawItems);
|
|
52887
|
+
if (!result.success) {
|
|
52888
|
+
const err = result.error ?? "Invalid items";
|
|
52889
|
+
deps.log(`[Bridge service] Install skills failed: ${err}`);
|
|
52890
|
+
if (socket) {
|
|
52891
|
+
sendWsMessage(socket, { type: "install_skills_result", id, success: false, error: err });
|
|
52892
|
+
}
|
|
52893
|
+
return;
|
|
52894
|
+
}
|
|
52895
|
+
if (socket) {
|
|
52896
|
+
sendWsMessage(socket, { type: "install_skills_result", id, success: true, installed: result.installed });
|
|
52897
|
+
}
|
|
52898
|
+
})();
|
|
52855
52899
|
};
|
|
52856
52900
|
|
|
52857
|
-
// src/
|
|
52858
|
-
|
|
52859
|
-
|
|
52860
|
-
|
|
52861
|
-
|
|
52862
|
-
|
|
52863
|
-
|
|
52864
|
-
|
|
52865
|
-
|
|
52866
|
-
|
|
52867
|
-
|
|
52901
|
+
// src/agents/install/commands/run-npm-global-install.ts
|
|
52902
|
+
import { execFile as execFile9 } from "node:child_process";
|
|
52903
|
+
import { promisify as promisify10 } from "node:util";
|
|
52904
|
+
var execFileAsync8 = promisify10(execFile9);
|
|
52905
|
+
async function runNpmGlobalInstall(packageName, env, timeoutMs = 3e5) {
|
|
52906
|
+
await execFileAsync8("npm", ["install", "-g", packageName], { timeout: timeoutMs, env });
|
|
52907
|
+
}
|
|
52908
|
+
|
|
52909
|
+
// src/agents/install/commands/claude-code.ts
|
|
52910
|
+
var claudeCodeInstallCommand = {
|
|
52911
|
+
agentType: "claude-code",
|
|
52912
|
+
detectCommand: "claude",
|
|
52913
|
+
async install(ctx) {
|
|
52914
|
+
ctx.onProgress?.("Installing Anthropic Claude Code");
|
|
52915
|
+
await runNpmGlobalInstall("@anthropic-ai/claude-code", {
|
|
52916
|
+
...ctx.env,
|
|
52917
|
+
ANTHROPIC_API_KEY: ctx.authToken
|
|
52918
|
+
});
|
|
52919
|
+
}
|
|
52920
|
+
};
|
|
52921
|
+
|
|
52922
|
+
// src/agents/install/commands/codex-acp.ts
|
|
52923
|
+
var codexAcpInstallCommand = {
|
|
52924
|
+
agentType: "codex-acp",
|
|
52925
|
+
detectCommand: "codex",
|
|
52926
|
+
async install(ctx) {
|
|
52927
|
+
ctx.onProgress?.("Installing Codex");
|
|
52928
|
+
await runNpmGlobalInstall("@openai/codex", {
|
|
52929
|
+
...ctx.env,
|
|
52930
|
+
OPENAI_API_KEY: ctx.authToken
|
|
52931
|
+
});
|
|
52932
|
+
}
|
|
52933
|
+
};
|
|
52934
|
+
|
|
52935
|
+
// src/agents/install/commands/cursor-cli.ts
|
|
52936
|
+
import { execFile as execFile10 } from "node:child_process";
|
|
52937
|
+
import { promisify as promisify11 } from "node:util";
|
|
52938
|
+
var execFileAsync9 = promisify11(execFile10);
|
|
52939
|
+
var cursorCliInstallCommand = {
|
|
52940
|
+
agentType: "cursor-cli",
|
|
52941
|
+
detectCommand: "agent",
|
|
52942
|
+
async install(ctx) {
|
|
52943
|
+
ctx.onProgress?.("Installing Cursor CLI");
|
|
52944
|
+
await execFileAsync9("bash", ["-lc", "curl -fsSL https://cursor.com/install | bash"], {
|
|
52945
|
+
timeout: 3e5,
|
|
52946
|
+
env: { ...ctx.env, CURSOR_API_KEY: ctx.authToken }
|
|
52947
|
+
});
|
|
52948
|
+
}
|
|
52949
|
+
};
|
|
52950
|
+
|
|
52951
|
+
// src/agents/install/commands/opencode.ts
|
|
52952
|
+
var opencodeInstallCommand = {
|
|
52953
|
+
agentType: "opencode",
|
|
52954
|
+
detectCommand: "opencode",
|
|
52955
|
+
async install(ctx) {
|
|
52956
|
+
ctx.onProgress?.("Installing OpenCode");
|
|
52957
|
+
await runNpmGlobalInstall("opencode-ai", {
|
|
52958
|
+
...ctx.env,
|
|
52959
|
+
OPENCODE_API_KEY: ctx.authToken
|
|
52960
|
+
});
|
|
52961
|
+
}
|
|
52962
|
+
};
|
|
52963
|
+
|
|
52964
|
+
// src/agents/install/commands/index.ts
|
|
52965
|
+
var COMMANDS = [
|
|
52966
|
+
claudeCodeInstallCommand,
|
|
52967
|
+
codexAcpInstallCommand,
|
|
52968
|
+
cursorCliInstallCommand,
|
|
52969
|
+
opencodeInstallCommand
|
|
52970
|
+
];
|
|
52971
|
+
var byType = new Map(COMMANDS.map((c) => [c.agentType, c]));
|
|
52972
|
+
function getAgentInstallCommand(agentType) {
|
|
52973
|
+
return byType.get(agentType);
|
|
52974
|
+
}
|
|
52975
|
+
|
|
52976
|
+
// src/agents/install/install-local-agent.ts
|
|
52977
|
+
async function installLocalAgentOnBridge(params) {
|
|
52978
|
+
const spec = INSTALLABLE_BRIDGE_AGENTS.find((a) => a.value === params.agentType);
|
|
52979
|
+
if (!spec) return { success: false, error: `Unsupported agent type: ${params.agentType}` };
|
|
52980
|
+
const command = getAgentInstallCommand(params.agentType);
|
|
52981
|
+
if (!command) return { success: false, error: `No install command for ${params.agentType}` };
|
|
52982
|
+
params.onProgress?.(`Configuring ${spec.label} credentials`);
|
|
52983
|
+
try {
|
|
52984
|
+
await command.install({
|
|
52985
|
+
authToken: params.authToken,
|
|
52986
|
+
onProgress: params.onProgress,
|
|
52987
|
+
env: { ...process.env, [spec.tokenEnvVar]: params.authToken }
|
|
52988
|
+
});
|
|
52989
|
+
} catch (e) {
|
|
52990
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
52991
|
+
return { success: false, error: msg };
|
|
52992
|
+
}
|
|
52993
|
+
const found = await isCommandOnPath(command.detectCommand);
|
|
52994
|
+
if (!found) {
|
|
52995
|
+
return { success: false, error: `${command.detectCommand} not found on PATH after install` };
|
|
52996
|
+
}
|
|
52997
|
+
return { success: true };
|
|
52998
|
+
}
|
|
52999
|
+
|
|
53000
|
+
// src/routing/handlers/install-agent.ts
|
|
53001
|
+
var handleInstallAgentMessage = (msg, deps) => {
|
|
53002
|
+
const processId = typeof msg.processId === "string" ? msg.processId : "";
|
|
53003
|
+
const agentId = typeof msg.agentId === "string" ? msg.agentId : "";
|
|
53004
|
+
const tokenId = typeof msg.tokenId === "string" ? msg.tokenId : "";
|
|
53005
|
+
const agentType = typeof msg.agentType === "string" ? msg.agentType : "";
|
|
53006
|
+
const authToken = typeof msg.authToken === "string" ? msg.authToken : "";
|
|
53007
|
+
if (!processId || !agentId || !tokenId || !agentType || !authToken) return;
|
|
53008
|
+
void (async () => {
|
|
53009
|
+
const socket = deps.getWs();
|
|
53010
|
+
const report = (step, message) => {
|
|
53011
|
+
if (socket) {
|
|
53012
|
+
sendWsMessage(socket, {
|
|
53013
|
+
type: "install_agent_progress",
|
|
53014
|
+
processId,
|
|
53015
|
+
agentId,
|
|
53016
|
+
tokenId,
|
|
53017
|
+
agentType,
|
|
53018
|
+
step,
|
|
53019
|
+
message
|
|
53020
|
+
});
|
|
53021
|
+
}
|
|
53022
|
+
};
|
|
53023
|
+
const result = await installLocalAgentOnBridge({
|
|
53024
|
+
agentType,
|
|
53025
|
+
authToken,
|
|
53026
|
+
onProgress: (message) => report("agent_install_package", message)
|
|
53027
|
+
});
|
|
53028
|
+
if (socket) {
|
|
53029
|
+
sendWsMessage(socket, {
|
|
53030
|
+
type: "install_agent_result",
|
|
53031
|
+
processId,
|
|
53032
|
+
agentId,
|
|
53033
|
+
tokenId,
|
|
53034
|
+
agentType,
|
|
53035
|
+
success: result.success,
|
|
53036
|
+
error: result.error
|
|
53037
|
+
});
|
|
53038
|
+
}
|
|
53039
|
+
if (!result.success) {
|
|
53040
|
+
deps.log(`[Bridge service] Install agent failed: ${result.error ?? "unknown"}`);
|
|
52868
53041
|
}
|
|
53042
|
+
})();
|
|
53043
|
+
};
|
|
53044
|
+
|
|
53045
|
+
// src/routing/handlers/refresh-local-skills.ts
|
|
53046
|
+
var handleRefreshLocalSkills = (_msg, deps) => {
|
|
53047
|
+
setImmediate(() => {
|
|
53048
|
+
deps.sendLocalSkillsReport?.();
|
|
52869
53049
|
});
|
|
52870
53050
|
};
|
|
52871
53051
|
|
|
52872
|
-
// src/routing/
|
|
52873
|
-
function
|
|
52874
|
-
|
|
52875
|
-
|
|
53052
|
+
// src/routing/dispatch/skills.ts
|
|
53053
|
+
function dispatchBridgeSkillsMessage(msg, deps) {
|
|
53054
|
+
switch (msg.type) {
|
|
53055
|
+
case "skill_call":
|
|
53056
|
+
handleSkillCallMessage(msg, deps);
|
|
53057
|
+
break;
|
|
53058
|
+
case "skill_layout_request":
|
|
53059
|
+
handleSkillLayoutRequest(msg, deps);
|
|
53060
|
+
break;
|
|
53061
|
+
case "install_skills":
|
|
53062
|
+
handleInstallSkillsMessage(msg, deps);
|
|
53063
|
+
break;
|
|
53064
|
+
case "install_agent":
|
|
53065
|
+
handleInstallAgentMessage(msg, deps);
|
|
53066
|
+
break;
|
|
53067
|
+
case "refresh_local_skills":
|
|
53068
|
+
handleRefreshLocalSkills(msg, deps);
|
|
53069
|
+
break;
|
|
53070
|
+
}
|
|
52876
53071
|
}
|
|
52877
53072
|
|
|
52878
|
-
// src/
|
|
52879
|
-
|
|
52880
|
-
|
|
52881
|
-
|
|
52882
|
-
|
|
52883
|
-
|
|
53073
|
+
// src/files/browser/send-file-browser-message.ts
|
|
53074
|
+
function sendFileBrowserMessage(socket, e2ee, payload) {
|
|
53075
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
|
|
53076
|
+
}
|
|
53077
|
+
|
|
53078
|
+
// src/files/browser/handle-file-browser-list.ts
|
|
53079
|
+
async function handleFileBrowserList(socket, e2ee, id, reqPath, sessionParentPath, gitScope) {
|
|
53080
|
+
const result = await executeFileBrowserList({ reqPath, sessionParentPath, gitScope });
|
|
53081
|
+
if ("error" in result) {
|
|
53082
|
+
sendWsMessage(socket, { type: "file_browser_response", id, error: result.error });
|
|
53083
|
+
return;
|
|
53084
|
+
}
|
|
53085
|
+
sendFileBrowserMessage(socket, e2ee, { type: "file_browser_response", id, entries: result.entries });
|
|
53086
|
+
}
|
|
53087
|
+
|
|
53088
|
+
// src/files/browser/handle-file-browser-read.ts
|
|
53089
|
+
async function handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope) {
|
|
53090
|
+
const result = await executeFileBrowserRead({ msg, reqPath, sessionParentPath, gitScope });
|
|
53091
|
+
if ("error" in result) {
|
|
53092
|
+
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
53093
|
+
return;
|
|
53094
|
+
}
|
|
53095
|
+
const payload = {
|
|
53096
|
+
type: "file_browser_response",
|
|
53097
|
+
id: msg.id,
|
|
53098
|
+
content: result.content,
|
|
53099
|
+
totalLines: result.totalLines,
|
|
53100
|
+
size: result.size
|
|
53101
|
+
};
|
|
53102
|
+
if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
|
|
53103
|
+
if (result.mimeType != null) payload.mimeType = result.mimeType;
|
|
53104
|
+
if (result.resolvedPath != null) payload.resolvedPath = result.resolvedPath;
|
|
53105
|
+
sendFileBrowserMessage(socket, e2ee, payload);
|
|
53106
|
+
}
|
|
53107
|
+
|
|
53108
|
+
// src/files/browser/index.ts
|
|
53109
|
+
init_in_flight();
|
|
53110
|
+
function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
53111
|
+
beginFileBrowserRequest();
|
|
52884
53112
|
void (async () => {
|
|
52885
|
-
const ws = deps.getWs();
|
|
52886
|
-
const reply = (payload) => sendDeploySessionToPreviewResult(ws, msg.id, payload);
|
|
52887
53113
|
try {
|
|
52888
|
-
|
|
52889
|
-
|
|
53114
|
+
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
53115
|
+
const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
53116
|
+
const gitScope = resolveGitBranchScope(msg);
|
|
53117
|
+
if (msg.source === "git_branch" && typeof msg.repoRelPath === "string" && typeof msg.branch === "string" && msg.branch.trim().length > 0 && !gitScope) {
|
|
53118
|
+
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: "Invalid repository path" });
|
|
52890
53119
|
return;
|
|
52891
53120
|
}
|
|
52892
|
-
|
|
52893
|
-
|
|
52894
|
-
|
|
52895
|
-
|
|
52896
|
-
|
|
52897
|
-
|
|
52898
|
-
|
|
52899
|
-
reply(result);
|
|
52900
|
-
} catch (e) {
|
|
52901
|
-
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
53121
|
+
if (msg.op === "read") {
|
|
53122
|
+
await handleFileBrowserRead(socket, e2ee, msg, reqPath, sessionParentPath, gitScope);
|
|
53123
|
+
} else {
|
|
53124
|
+
await handleFileBrowserList(socket, e2ee, msg.id, reqPath, sessionParentPath, gitScope);
|
|
53125
|
+
}
|
|
53126
|
+
} finally {
|
|
53127
|
+
endFileBrowserRequest();
|
|
52902
53128
|
}
|
|
52903
53129
|
})();
|
|
52904
|
-
}
|
|
53130
|
+
}
|
|
53131
|
+
|
|
53132
|
+
// src/files/handle-file-browser-search.ts
|
|
53133
|
+
init_yield_to_event_loop();
|
|
53134
|
+
import path81 from "node:path";
|
|
53135
|
+
var SEARCH_LIMIT = 100;
|
|
53136
|
+
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
53137
|
+
void (async () => {
|
|
53138
|
+
await yieldToEventLoop();
|
|
53139
|
+
const q = typeof msg.q === "string" ? msg.q : "";
|
|
53140
|
+
const sessionParentPath = path81.resolve(
|
|
53141
|
+
sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
53142
|
+
);
|
|
53143
|
+
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
53144
|
+
triggerFileIndexBuild(sessionParentPath);
|
|
53145
|
+
const payload2 = {
|
|
53146
|
+
type: "file_browser_search_response",
|
|
53147
|
+
id: msg.id,
|
|
53148
|
+
paths: [],
|
|
53149
|
+
indexReady: false
|
|
53150
|
+
};
|
|
53151
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
53152
|
+
return;
|
|
53153
|
+
}
|
|
53154
|
+
const results = await searchBridgeFilePathsAsync(sessionParentPath, q, SEARCH_LIMIT);
|
|
53155
|
+
const payload = {
|
|
53156
|
+
type: "file_browser_search_response",
|
|
53157
|
+
id: msg.id,
|
|
53158
|
+
paths: results,
|
|
53159
|
+
indexReady: true
|
|
53160
|
+
};
|
|
53161
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["paths"]) : payload);
|
|
53162
|
+
})();
|
|
53163
|
+
}
|
|
53164
|
+
function triggerFileIndexBuild(sessionParentPath = getBridgeRoot()) {
|
|
53165
|
+
setImmediate(() => {
|
|
53166
|
+
void ensureFileIndexAsync(sessionParentPath).catch((e) => {
|
|
53167
|
+
console.error("[file-index] Background build failed:", e);
|
|
53168
|
+
});
|
|
53169
|
+
});
|
|
53170
|
+
}
|
|
53171
|
+
|
|
53172
|
+
// src/routing/handlers/file-browser-messages.ts
|
|
53173
|
+
function handleFileBrowserRequestMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
53174
|
+
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
53175
|
+
const socket = getWs();
|
|
53176
|
+
if (!socket) return;
|
|
53177
|
+
handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager);
|
|
53178
|
+
}
|
|
53179
|
+
function handleFileBrowserSearchMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
53180
|
+
if (typeof msg.id !== "string") return;
|
|
53181
|
+
const socket = getWs();
|
|
53182
|
+
if (!socket) return;
|
|
53183
|
+
handleFileBrowserSearch(
|
|
53184
|
+
msg,
|
|
53185
|
+
socket,
|
|
53186
|
+
e2ee,
|
|
53187
|
+
sessionWorktreeManager
|
|
53188
|
+
);
|
|
53189
|
+
}
|
|
53190
|
+
|
|
53191
|
+
// src/code-nav/handlers/send-code-nav-response.ts
|
|
53192
|
+
var ENCRYPTED_FIELDS = ["definition", "definitions", "references", "symbols", "confidentTarget"];
|
|
53193
|
+
function sendCodeNavResponse(socket, e2ee, payload) {
|
|
53194
|
+
const fieldsToEncrypt = ENCRYPTED_FIELDS.filter((field) => field in payload && payload[field] !== void 0);
|
|
53195
|
+
sendWsMessage(
|
|
53196
|
+
socket,
|
|
53197
|
+
e2ee && fieldsToEncrypt.length > 0 ? e2ee.encryptFields(payload, [...fieldsToEncrypt]) : payload
|
|
53198
|
+
);
|
|
53199
|
+
}
|
|
53200
|
+
|
|
53201
|
+
// src/code-nav/handlers/handle-code-nav-request.ts
|
|
53202
|
+
function handleCodeNavRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
53203
|
+
void (async () => {
|
|
53204
|
+
const body = await executeCodeNavRequest(msg, sessionWorktreeManager);
|
|
53205
|
+
sendCodeNavResponse(socket, e2ee, {
|
|
53206
|
+
type: "code_nav_response",
|
|
53207
|
+
id: msg.id,
|
|
53208
|
+
...body
|
|
53209
|
+
});
|
|
53210
|
+
})();
|
|
53211
|
+
}
|
|
53212
|
+
|
|
53213
|
+
// src/code-nav/handlers/trigger-symbol-index-build.ts
|
|
53214
|
+
init_normalize_resolved_path();
|
|
53215
|
+
|
|
53216
|
+
// src/routing/handlers/code-nav-messages.ts
|
|
53217
|
+
function handleFileBrowserCodeNavMessage(msg, { getWs, e2ee, sessionWorktreeManager }) {
|
|
53218
|
+
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
53219
|
+
const socket = getWs();
|
|
53220
|
+
if (!socket) return;
|
|
53221
|
+
handleCodeNavRequest(
|
|
53222
|
+
{
|
|
53223
|
+
id: msg.id,
|
|
53224
|
+
type: "code_nav",
|
|
53225
|
+
op: msg.op === "references" ? "references" : msg.op === "symbols" ? "symbols" : msg.op === "definitions" ? "definitions" : "definition",
|
|
53226
|
+
path: msg.path,
|
|
53227
|
+
line: typeof msg.line === "number" ? msg.line : 1,
|
|
53228
|
+
column: typeof msg.column === "number" ? msg.column : 0,
|
|
53229
|
+
sessionId: msg.sessionId
|
|
53230
|
+
},
|
|
53231
|
+
socket,
|
|
53232
|
+
e2ee,
|
|
53233
|
+
sessionWorktreeManager
|
|
53234
|
+
);
|
|
53235
|
+
}
|
|
52905
53236
|
|
|
52906
53237
|
// src/git/bridge-git-context.ts
|
|
52907
|
-
import * as
|
|
53238
|
+
import * as path82 from "node:path";
|
|
52908
53239
|
init_yield_to_event_loop();
|
|
52909
53240
|
|
|
52910
53241
|
// src/git/branches/get-current-branch.ts
|
|
@@ -52955,12 +53286,12 @@ async function listRepoBranchRefs(repoPath) {
|
|
|
52955
53286
|
// src/git/bridge-git-context.ts
|
|
52956
53287
|
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
52957
53288
|
if (relPath === "." || relPath === "") {
|
|
52958
|
-
return
|
|
53289
|
+
return path82.basename(path82.resolve(bridgeRoot)) || "repo";
|
|
52959
53290
|
}
|
|
52960
|
-
return
|
|
53291
|
+
return path82.basename(relPath) || relPath;
|
|
52961
53292
|
}
|
|
52962
53293
|
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
52963
|
-
const root =
|
|
53294
|
+
const root = path82.resolve(bridgeRoot);
|
|
52964
53295
|
if (await isGitRepoDirectory(root)) {
|
|
52965
53296
|
const remoteUrl = await getRemoteOriginUrl(root);
|
|
52966
53297
|
return [{ absolutePath: root, remoteUrl }];
|
|
@@ -52968,19 +53299,19 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
|
52968
53299
|
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
52969
53300
|
const byPath = /* @__PURE__ */ new Map();
|
|
52970
53301
|
for (const repo of [...deep, ...shallow]) {
|
|
52971
|
-
byPath.set(
|
|
53302
|
+
byPath.set(path82.resolve(repo.absolutePath), repo);
|
|
52972
53303
|
}
|
|
52973
53304
|
return [...byPath.values()];
|
|
52974
53305
|
}
|
|
52975
53306
|
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
52976
|
-
const bridgeResolved =
|
|
53307
|
+
const bridgeResolved = path82.resolve(bridgeRoot);
|
|
52977
53308
|
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
52978
53309
|
const rows = [];
|
|
52979
53310
|
for (let i = 0; i < repos.length; i++) {
|
|
52980
53311
|
if (i > 0) await yieldToEventLoop();
|
|
52981
53312
|
const repo = repos[i];
|
|
52982
|
-
let rel =
|
|
52983
|
-
if (rel.startsWith("..") ||
|
|
53313
|
+
let rel = path82.relative(bridgeResolved, repo.absolutePath);
|
|
53314
|
+
if (rel.startsWith("..") || path82.isAbsolute(rel)) continue;
|
|
52984
53315
|
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
52985
53316
|
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
52986
53317
|
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
@@ -52995,11 +53326,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
|
52995
53326
|
return rows;
|
|
52996
53327
|
}
|
|
52997
53328
|
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
52998
|
-
const bridgeResolved =
|
|
53329
|
+
const bridgeResolved = path82.resolve(bridgeRoot);
|
|
52999
53330
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
53000
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
53001
|
-
const resolved =
|
|
53002
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
53331
|
+
const repoPath = rel === "" ? bridgeResolved : path82.join(bridgeResolved, rel);
|
|
53332
|
+
const resolved = path82.resolve(repoPath);
|
|
53333
|
+
if (!resolved.startsWith(bridgeResolved + path82.sep) && resolved !== bridgeResolved) {
|
|
53003
53334
|
return [];
|
|
53004
53335
|
}
|
|
53005
53336
|
return listRepoBranchRefs(resolved);
|
|
@@ -53048,80 +53379,64 @@ function handleListRepoBranchesRequestMessage(msg, getWs) {
|
|
|
53048
53379
|
})();
|
|
53049
53380
|
}
|
|
53050
53381
|
|
|
53051
|
-
// src/routing/dispatch-
|
|
53382
|
+
// src/routing/dispatch/file-browser.ts
|
|
53383
|
+
function dispatchBridgeFileBrowserMessage(msg, deps) {
|
|
53384
|
+
switch (msg.type) {
|
|
53385
|
+
case "file_browser_request":
|
|
53386
|
+
handleFileBrowserRequestMessage(msg, deps);
|
|
53387
|
+
break;
|
|
53388
|
+
case "file_browser_search":
|
|
53389
|
+
handleFileBrowserSearchMessage(msg, deps);
|
|
53390
|
+
break;
|
|
53391
|
+
case "code_nav":
|
|
53392
|
+
handleFileBrowserCodeNavMessage(msg, deps);
|
|
53393
|
+
break;
|
|
53394
|
+
case "bridge_git_context_request":
|
|
53395
|
+
handleBridgeGitContextRequestMessage(msg, deps.getWs);
|
|
53396
|
+
break;
|
|
53397
|
+
case "list_repo_branches_request":
|
|
53398
|
+
handleListRepoBranchesRequestMessage(msg, deps.getWs);
|
|
53399
|
+
break;
|
|
53400
|
+
}
|
|
53401
|
+
}
|
|
53402
|
+
|
|
53403
|
+
// src/routing/dispatch/index.ts
|
|
53052
53404
|
function dispatchBridgeMessage(msg, deps) {
|
|
53053
53405
|
switch (msg.type) {
|
|
53054
53406
|
case "auth_token":
|
|
53055
|
-
handleAuthToken(msg, deps);
|
|
53056
|
-
break;
|
|
53057
53407
|
case "bridge_identified":
|
|
53058
|
-
handleBridgeIdentified(msg, deps);
|
|
53059
|
-
break;
|
|
53060
53408
|
case "ha":
|
|
53061
|
-
|
|
53409
|
+
dispatchBridgeConnectionMessage(msg, deps);
|
|
53062
53410
|
break;
|
|
53063
53411
|
case "preview_environments_config":
|
|
53064
|
-
handlePreviewEnvironmentsConfig(msg, deps);
|
|
53065
|
-
break;
|
|
53066
53412
|
case "preview_environment_control":
|
|
53067
|
-
handlePreviewEnvironmentControl(msg, deps);
|
|
53068
|
-
break;
|
|
53069
53413
|
case "deploy_session_to_preview":
|
|
53070
|
-
|
|
53414
|
+
dispatchBridgePreviewMessage(msg, deps);
|
|
53071
53415
|
break;
|
|
53072
53416
|
case "agent_config":
|
|
53073
|
-
handleAgentConfigMessage(msg, deps);
|
|
53074
|
-
break;
|
|
53075
53417
|
case "prompt_queue_state":
|
|
53076
|
-
handlePromptQueueStateMessage(msg, deps);
|
|
53077
|
-
break;
|
|
53078
53418
|
case "prompt":
|
|
53079
|
-
handlePromptMessage(msg, deps);
|
|
53080
|
-
break;
|
|
53081
53419
|
case "session_git_request":
|
|
53082
|
-
handleSessionGitRequestMessage(msg, deps);
|
|
53083
|
-
break;
|
|
53084
53420
|
case "rename_session_branch":
|
|
53085
|
-
handleRenameSessionBranchMessage(msg, deps);
|
|
53086
|
-
break;
|
|
53087
53421
|
case "session_archived":
|
|
53088
|
-
handleSessionArchivedMessage(msg, deps);
|
|
53089
|
-
break;
|
|
53090
53422
|
case "session_discarded":
|
|
53091
|
-
handleSessionDiscardedMessage(msg, deps);
|
|
53092
|
-
break;
|
|
53093
53423
|
case "revert_turn_snapshot":
|
|
53094
|
-
handleRevertTurnSnapshotMessage(msg, deps);
|
|
53095
|
-
break;
|
|
53096
53424
|
case "cursor_request_response":
|
|
53097
|
-
|
|
53425
|
+
dispatchBridgeSessionMessage(msg, deps);
|
|
53098
53426
|
break;
|
|
53099
53427
|
case "skill_call":
|
|
53100
|
-
handleSkillCallMessage(msg, deps);
|
|
53101
|
-
break;
|
|
53102
|
-
case "file_browser_request":
|
|
53103
|
-
handleFileBrowserRequestMessage(msg, deps);
|
|
53104
|
-
break;
|
|
53105
|
-
case "file_browser_search":
|
|
53106
|
-
handleFileBrowserSearchMessage(msg, deps);
|
|
53107
|
-
break;
|
|
53108
|
-
case "code_nav":
|
|
53109
|
-
handleFileBrowserCodeNavMessage(msg, deps);
|
|
53110
|
-
break;
|
|
53111
53428
|
case "skill_layout_request":
|
|
53112
|
-
handleSkillLayoutRequest(msg, deps);
|
|
53113
|
-
break;
|
|
53114
53429
|
case "install_skills":
|
|
53115
|
-
|
|
53116
|
-
break;
|
|
53430
|
+
case "install_agent":
|
|
53117
53431
|
case "refresh_local_skills":
|
|
53118
|
-
|
|
53432
|
+
dispatchBridgeSkillsMessage(msg, deps);
|
|
53119
53433
|
break;
|
|
53434
|
+
case "file_browser_request":
|
|
53435
|
+
case "file_browser_search":
|
|
53436
|
+
case "code_nav":
|
|
53120
53437
|
case "bridge_git_context_request":
|
|
53121
|
-
handleBridgeGitContextRequestMessage(msg, deps.getWs);
|
|
53122
|
-
break;
|
|
53123
53438
|
case "list_repo_branches_request":
|
|
53124
|
-
|
|
53439
|
+
dispatchBridgeFileBrowserMessage(msg, deps);
|
|
53125
53440
|
break;
|
|
53126
53441
|
}
|
|
53127
53442
|
}
|
|
@@ -53515,15 +53830,18 @@ async function runConnectedBridge(options, restartWithoutAuth) {
|
|
|
53515
53830
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
53516
53831
|
let cleanupKeyCommand;
|
|
53517
53832
|
let bridgeClose = null;
|
|
53833
|
+
let shutdownStarted = false;
|
|
53518
53834
|
const onSignal = (kind) => {
|
|
53519
53835
|
requestCliImmediateShutdown();
|
|
53520
53836
|
abortActiveGitChildProcesses();
|
|
53521
53837
|
cleanupKeyCommand?.();
|
|
53838
|
+
if (shutdownStarted) return;
|
|
53839
|
+
shutdownStarted = true;
|
|
53522
53840
|
logImmediate(
|
|
53523
53841
|
kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
|
|
53524
53842
|
);
|
|
53525
53843
|
if (bridgeClose) {
|
|
53526
|
-
void bridgeClose().
|
|
53844
|
+
void bridgeClose().finally(() => process.exit(0));
|
|
53527
53845
|
return;
|
|
53528
53846
|
}
|
|
53529
53847
|
process.exit(0);
|
|
@@ -53674,9 +53992,9 @@ async function runCliAction(program2, opts) {
|
|
|
53674
53992
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
53675
53993
|
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);
|
|
53676
53994
|
if (bridgeRootOpt) {
|
|
53677
|
-
const resolvedBridgeRoot =
|
|
53995
|
+
const resolvedBridgeRoot = path83.resolve(process.cwd(), bridgeRootOpt);
|
|
53678
53996
|
try {
|
|
53679
|
-
const st =
|
|
53997
|
+
const st = fs62.statSync(resolvedBridgeRoot);
|
|
53680
53998
|
if (!st.isDirectory()) {
|
|
53681
53999
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
53682
54000
|
process.exit(1);
|
|
@@ -53696,7 +54014,7 @@ async function runCliAction(program2, opts) {
|
|
|
53696
54014
|
);
|
|
53697
54015
|
let worktreesRootPath;
|
|
53698
54016
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
53699
|
-
worktreesRootPath =
|
|
54017
|
+
worktreesRootPath = path83.resolve(opts.worktreesRoot.trim());
|
|
53700
54018
|
}
|
|
53701
54019
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
53702
54020
|
if (e2eCertificates) {
|