usebeeline 0.0.114 → 0.0.115
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/usebeeline.mjs +1368 -730
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -2415,7 +2415,7 @@ var require_websocket = __commonJS({
|
|
|
2415
2415
|
var http = __require("http");
|
|
2416
2416
|
var net2 = __require("net");
|
|
2417
2417
|
var tls = __require("tls");
|
|
2418
|
-
var { randomBytes: randomBytes7, createHash:
|
|
2418
|
+
var { randomBytes: randomBytes7, createHash: createHash10 } = __require("crypto");
|
|
2419
2419
|
var { Duplex, Readable } = __require("stream");
|
|
2420
2420
|
var { URL: URL2 } = __require("url");
|
|
2421
2421
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -3083,7 +3083,7 @@ var require_websocket = __commonJS({
|
|
|
3083
3083
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
3084
3084
|
return;
|
|
3085
3085
|
}
|
|
3086
|
-
const digest =
|
|
3086
|
+
const digest = createHash10("sha1").update(key + GUID).digest("base64");
|
|
3087
3087
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
3088
3088
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
3089
3089
|
return;
|
|
@@ -3452,7 +3452,7 @@ var require_websocket_server = __commonJS({
|
|
|
3452
3452
|
var EventEmitter2 = __require("events");
|
|
3453
3453
|
var http = __require("http");
|
|
3454
3454
|
var { Duplex } = __require("stream");
|
|
3455
|
-
var { createHash:
|
|
3455
|
+
var { createHash: createHash10 } = __require("crypto");
|
|
3456
3456
|
var extension2 = require_extension();
|
|
3457
3457
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
3458
3458
|
var subprotocol2 = require_subprotocol();
|
|
@@ -3759,7 +3759,7 @@ var require_websocket_server = __commonJS({
|
|
|
3759
3759
|
);
|
|
3760
3760
|
}
|
|
3761
3761
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
3762
|
-
const digest =
|
|
3762
|
+
const digest = createHash10("sha1").update(key + GUID).digest("base64");
|
|
3763
3763
|
const headers = [
|
|
3764
3764
|
"HTTP/1.1 101 Switching Protocols",
|
|
3765
3765
|
"Upgrade: websocket",
|
|
@@ -3984,14 +3984,14 @@ __export(self_update_exports, {
|
|
|
3984
3984
|
writeUpdateAttemptFixture: () => writeUpdateAttemptFixture,
|
|
3985
3985
|
writeUpdateState: () => writeUpdateState
|
|
3986
3986
|
});
|
|
3987
|
-
import { createHash as
|
|
3987
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
3988
3988
|
import { constants as fsConstants2 } from "node:fs";
|
|
3989
3989
|
import { access, chmod as chmod5, lstat as lstat3, mkdir as mkdir15, open, readFile as readFile10, rename as rename4, rm as rm6, symlink as symlink3, writeFile as writeFile10 } from "node:fs/promises";
|
|
3990
|
-
import { spawn as
|
|
3991
|
-
import { homedir as
|
|
3992
|
-
import { dirname as
|
|
3990
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
3991
|
+
import { homedir as homedir10 } from "node:os";
|
|
3992
|
+
import { dirname as dirname12, join as join11, resolve as resolve23 } from "node:path";
|
|
3993
3993
|
function anchorLayout(rawLibDir) {
|
|
3994
|
-
const libDir =
|
|
3994
|
+
const libDir = resolve23(rawLibDir);
|
|
3995
3995
|
const segments = libDir.split(/[/\\]/);
|
|
3996
3996
|
const idx = segments.lastIndexOf(RELEASES_SEGMENT);
|
|
3997
3997
|
if (idx >= 2 && segments[idx - 1] === "lib") {
|
|
@@ -4007,9 +4007,9 @@ function anchorLayout(rawLibDir) {
|
|
|
4007
4007
|
// prefix's bin, NOT <prefix>/lib/bin — deriving it one level up was the
|
|
4008
4008
|
// defect that made activateRelease write its stable forwarders where
|
|
4009
4009
|
// nothing executed them, leaving stale raw wrappers in <prefix>/bin.
|
|
4010
|
-
binDir:
|
|
4010
|
+
binDir: resolve23(libDir, "../../bin"),
|
|
4011
4011
|
libDir,
|
|
4012
|
-
releasesRoot:
|
|
4012
|
+
releasesRoot: resolve23(libDir, `../${RELEASES_SEGMENT}`)
|
|
4013
4013
|
};
|
|
4014
4014
|
}
|
|
4015
4015
|
function beelineInstallLayout(env = process.env) {
|
|
@@ -4019,8 +4019,8 @@ function beelineInstallLayout(env = process.env) {
|
|
|
4019
4019
|
return anchorLayout(raw);
|
|
4020
4020
|
}
|
|
4021
4021
|
function defaultBeelineInstallLayout(env = process.env) {
|
|
4022
|
-
const home = env.HOME?.trim() ||
|
|
4023
|
-
return anchorLayout(
|
|
4022
|
+
const home = env.HOME?.trim() || homedir10();
|
|
4023
|
+
return anchorLayout(resolve23(home, ".local", "lib", "beeline"));
|
|
4024
4024
|
}
|
|
4025
4025
|
function discoveredBeelineInstallLayout(env = process.env) {
|
|
4026
4026
|
const explicitAnchor = env.BEELINE_INSTALL_LIB_DIR?.trim();
|
|
@@ -4028,7 +4028,7 @@ function discoveredBeelineInstallLayout(env = process.env) {
|
|
|
4028
4028
|
return anchorLayout(explicitAnchor);
|
|
4029
4029
|
const explicitBinDir = env.BEELINE_INSTALL_DIR?.trim();
|
|
4030
4030
|
if (explicitBinDir)
|
|
4031
|
-
return anchorLayout(
|
|
4031
|
+
return anchorLayout(resolve23(dirname12(resolve23(explicitBinDir)), "lib", "beeline"));
|
|
4032
4032
|
return defaultBeelineInstallLayout(env);
|
|
4033
4033
|
}
|
|
4034
4034
|
function hostPlatformKey() {
|
|
@@ -4039,7 +4039,7 @@ function hostPlatformKey() {
|
|
|
4039
4039
|
return `${os}-${arch}`;
|
|
4040
4040
|
}
|
|
4041
4041
|
function bundleJsonCandidates(bundleDir) {
|
|
4042
|
-
return [
|
|
4042
|
+
return [join11(bundleDir, "lib", "beeline", "bundle.json"), join11(bundleDir, "bundle.json")];
|
|
4043
4043
|
}
|
|
4044
4044
|
async function readBundleJson(bundleDir) {
|
|
4045
4045
|
let raw;
|
|
@@ -4063,7 +4063,7 @@ async function readBundleJson(bundleDir) {
|
|
|
4063
4063
|
}
|
|
4064
4064
|
}
|
|
4065
4065
|
function updateStatePath(layout) {
|
|
4066
|
-
return
|
|
4066
|
+
return join11(layout.releasesRoot, ".state", "update-state.json");
|
|
4067
4067
|
}
|
|
4068
4068
|
async function readUpdateState(layout) {
|
|
4069
4069
|
try {
|
|
@@ -4073,7 +4073,7 @@ async function readUpdateState(layout) {
|
|
|
4073
4073
|
}
|
|
4074
4074
|
}
|
|
4075
4075
|
async function writeUpdateState(layout, state) {
|
|
4076
|
-
await mkdir15(
|
|
4076
|
+
await mkdir15(join11(layout.releasesRoot, ".state"), { recursive: true });
|
|
4077
4077
|
await writeFile10(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
|
|
4078
4078
|
`, "utf8");
|
|
4079
4079
|
}
|
|
@@ -4137,7 +4137,7 @@ async function fetchText(url, fetchImpl) {
|
|
|
4137
4137
|
}
|
|
4138
4138
|
function run(command, args, timeoutMs) {
|
|
4139
4139
|
return new Promise((resolveRun) => {
|
|
4140
|
-
const child =
|
|
4140
|
+
const child = spawn8(command, args, { stdio: ["ignore", "ignore", "pipe"] });
|
|
4141
4141
|
let stderr = "";
|
|
4142
4142
|
child.stderr?.setEncoding("utf8");
|
|
4143
4143
|
child.stderr?.on("data", (chunk) => {
|
|
@@ -4155,7 +4155,7 @@ function run(command, args, timeoutMs) {
|
|
|
4155
4155
|
});
|
|
4156
4156
|
}
|
|
4157
4157
|
function entrypointCandidates(bundleDir) {
|
|
4158
|
-
return [
|
|
4158
|
+
return [join11(bundleDir, BUNDLE_ENTRYPOINT), join11(bundleDir, "beeline-cli.mjs")];
|
|
4159
4159
|
}
|
|
4160
4160
|
async function resolveBundleEntrypoint(bundleDir) {
|
|
4161
4161
|
for (const candidate of entrypointCandidates(bundleDir)) {
|
|
@@ -4177,8 +4177,8 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4177
4177
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
4178
4178
|
const log2 = opts.logger ?? ((line) => console.log(`[body] self-update: ${line}`));
|
|
4179
4179
|
const releaseId = sanitizeReleaseId(published.commit ?? published.version ?? `release-${Date.now()}`);
|
|
4180
|
-
const releaseDir =
|
|
4181
|
-
const okMarker =
|
|
4180
|
+
const releaseDir = join11(layout.releasesRoot, releaseId);
|
|
4181
|
+
const okMarker = join11(releaseDir, ".stage-ok");
|
|
4182
4182
|
let previouslyVerified = false;
|
|
4183
4183
|
try {
|
|
4184
4184
|
const recorded = await readFile10(okMarker, "utf8");
|
|
@@ -4188,7 +4188,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4188
4188
|
} catch {
|
|
4189
4189
|
}
|
|
4190
4190
|
await mkdir15(releaseDir, { recursive: true });
|
|
4191
|
-
const tempArchive =
|
|
4191
|
+
const tempArchive = join11(layout.releasesRoot, `.download-${releaseId}-${process.pid}.tar.gz`);
|
|
4192
4192
|
try {
|
|
4193
4193
|
log2(`downloading ${published.file}`);
|
|
4194
4194
|
const response = await fetchImpl(archiveUrlFor(manifestUrl, published.file), {
|
|
@@ -4197,7 +4197,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4197
4197
|
if (!response.ok || !response.body) {
|
|
4198
4198
|
throw new Error(`downloading ${published.file} failed: HTTP ${response.status}`);
|
|
4199
4199
|
}
|
|
4200
|
-
const hash =
|
|
4200
|
+
const hash = createHash8("sha256");
|
|
4201
4201
|
const chunks = [];
|
|
4202
4202
|
for await (const chunk of response.body) {
|
|
4203
4203
|
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
@@ -4210,7 +4210,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4210
4210
|
}
|
|
4211
4211
|
await writeFile10(tempArchive, Buffer.concat(chunks), { mode: 384 });
|
|
4212
4212
|
const entries = (await new Promise((resolveList, rejectList) => {
|
|
4213
|
-
const child =
|
|
4213
|
+
const child = spawn8("tar", ["-tzf", tempArchive], { stdio: ["ignore", "pipe", "inherit"] });
|
|
4214
4214
|
let out = "";
|
|
4215
4215
|
child.stdout?.on("data", (chunk) => {
|
|
4216
4216
|
out += chunk.toString("utf8");
|
|
@@ -4228,13 +4228,13 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4228
4228
|
throw new Error(`extracting bundle failed: ${extract2.stderr}`);
|
|
4229
4229
|
for (const relative3 of requiredBundlePaths()) {
|
|
4230
4230
|
try {
|
|
4231
|
-
await access(
|
|
4231
|
+
await access(join11(releaseDir, relative3), fsConstants2.F_OK);
|
|
4232
4232
|
} catch {
|
|
4233
4233
|
throw new Error(`staged bundle is missing ${relative3}`);
|
|
4234
4234
|
}
|
|
4235
4235
|
}
|
|
4236
4236
|
if (opts.smokeTestCli !== false) {
|
|
4237
|
-
const probe = await run(process.execPath, [
|
|
4237
|
+
const probe = await run(process.execPath, [join11(releaseDir, BUNDLE_ENTRYPOINT), "--version"], 6e4);
|
|
4238
4238
|
if (probe.status !== 0) {
|
|
4239
4239
|
throw new Error(`staged bundle failed its startup smoke test (--version exited ${probe.status})${probe.stderr ? `: ${probe.stderr.trim()}` : ""}`);
|
|
4240
4240
|
}
|
|
@@ -4272,8 +4272,8 @@ async function replaceFile(path, contents, mode) {
|
|
|
4272
4272
|
await rename4(temp, path);
|
|
4273
4273
|
}
|
|
4274
4274
|
async function activateRelease(layout, releaseId) {
|
|
4275
|
-
const releaseDir =
|
|
4276
|
-
await access(
|
|
4275
|
+
const releaseDir = join11(layout.releasesRoot, releaseId);
|
|
4276
|
+
await access(join11(releaseDir, BUNDLE_ENTRYPOINT), fsConstants2.F_OK);
|
|
4277
4277
|
await mkdir15(layout.releasesRoot, { recursive: true });
|
|
4278
4278
|
await mkdir15(layout.binDir, { recursive: true });
|
|
4279
4279
|
let previousReleaseId = await activeReleaseId(layout);
|
|
@@ -4281,12 +4281,12 @@ async function activateRelease(layout, releaseId) {
|
|
|
4281
4281
|
if (kind === "directory") {
|
|
4282
4282
|
const legacyIdentity = await readBundleJson(layout.libDir);
|
|
4283
4283
|
const legacyId = sanitizeReleaseId(legacyIdentity?.commit ?? legacyIdentity?.version ?? `legacy-${Date.now()}`);
|
|
4284
|
-
const legacyDir =
|
|
4284
|
+
const legacyDir = join11(layout.releasesRoot, legacyId);
|
|
4285
4285
|
try {
|
|
4286
4286
|
await access(legacyDir, fsConstants2.F_OK);
|
|
4287
4287
|
previousReleaseId = `${legacyId}-${Date.now()}`;
|
|
4288
|
-
await rename4(layout.libDir,
|
|
4289
|
-
await normalizeLegacyBundleShape(
|
|
4288
|
+
await rename4(layout.libDir, join11(layout.releasesRoot, previousReleaseId));
|
|
4289
|
+
await normalizeLegacyBundleShape(join11(layout.releasesRoot, previousReleaseId));
|
|
4290
4290
|
} catch {
|
|
4291
4291
|
await rename4(layout.libDir, legacyDir);
|
|
4292
4292
|
await normalizeLegacyBundleShape(legacyDir);
|
|
@@ -4295,18 +4295,18 @@ async function activateRelease(layout, releaseId) {
|
|
|
4295
4295
|
}
|
|
4296
4296
|
const tempLink = `${layout.libDir}.new-${process.pid}`;
|
|
4297
4297
|
await rm6(tempLink, { force: true });
|
|
4298
|
-
await symlink3(
|
|
4298
|
+
await symlink3(join11("beeline-releases", releaseId), tempLink);
|
|
4299
4299
|
await rename4(tempLink, layout.libDir);
|
|
4300
|
-
await fsyncDir(
|
|
4300
|
+
await fsyncDir(dirname12(layout.libDir));
|
|
4301
4301
|
await writeBinForwarders(layout, releaseDir);
|
|
4302
4302
|
return { previousReleaseId };
|
|
4303
4303
|
}
|
|
4304
4304
|
async function normalizeLegacyBundleShape(bundleDir) {
|
|
4305
|
-
const innerLib =
|
|
4305
|
+
const innerLib = join11(bundleDir, "lib", "beeline");
|
|
4306
4306
|
let anyFlat = false;
|
|
4307
4307
|
for (const name of LEGACY_FLAT_BUNDLE_FILES) {
|
|
4308
4308
|
try {
|
|
4309
|
-
await access(
|
|
4309
|
+
await access(join11(bundleDir, name), fsConstants2.F_OK);
|
|
4310
4310
|
anyFlat = true;
|
|
4311
4311
|
break;
|
|
4312
4312
|
} catch {
|
|
@@ -4317,11 +4317,11 @@ async function normalizeLegacyBundleShape(bundleDir) {
|
|
|
4317
4317
|
await mkdir15(innerLib, { recursive: true });
|
|
4318
4318
|
for (const name of LEGACY_FLAT_BUNDLE_FILES) {
|
|
4319
4319
|
try {
|
|
4320
|
-
await access(
|
|
4320
|
+
await access(join11(innerLib, name), fsConstants2.F_OK);
|
|
4321
4321
|
continue;
|
|
4322
4322
|
} catch {
|
|
4323
4323
|
}
|
|
4324
|
-
await rename4(
|
|
4324
|
+
await rename4(join11(bundleDir, name), join11(innerLib, name)).catch(() => void 0);
|
|
4325
4325
|
}
|
|
4326
4326
|
}
|
|
4327
4327
|
async function writeBinForwarders(layout, activeBundleRoot) {
|
|
@@ -4330,13 +4330,13 @@ async function writeBinForwarders(layout, activeBundleRoot) {
|
|
|
4330
4330
|
...Object.entries(FORWARDER_ALIASES).map(([alias, tool]) => [alias, tool])
|
|
4331
4331
|
];
|
|
4332
4332
|
for (const [name, tool] of entries) {
|
|
4333
|
-
const target =
|
|
4333
|
+
const target = join11(activeBundleRoot, "bin", tool);
|
|
4334
4334
|
try {
|
|
4335
4335
|
await access(target, fsConstants2.X_OK);
|
|
4336
4336
|
} catch {
|
|
4337
4337
|
continue;
|
|
4338
4338
|
}
|
|
4339
|
-
await replaceFile(
|
|
4339
|
+
await replaceFile(join11(layout.binDir, name), forwarderScript(tool), 493);
|
|
4340
4340
|
}
|
|
4341
4341
|
}
|
|
4342
4342
|
async function repairInstallForwarders(layout, opts = {}) {
|
|
@@ -4345,7 +4345,7 @@ async function repairInstallForwarders(layout, opts = {}) {
|
|
|
4345
4345
|
const forwarderHealthy = async (name, tool) => {
|
|
4346
4346
|
let current;
|
|
4347
4347
|
try {
|
|
4348
|
-
current = await readFile10(
|
|
4348
|
+
current = await readFile10(join11(layout.binDir, name), "utf8");
|
|
4349
4349
|
} catch {
|
|
4350
4350
|
current = void 0;
|
|
4351
4351
|
}
|
|
@@ -4364,19 +4364,19 @@ async function repairInstallForwarders(layout, opts = {}) {
|
|
|
4364
4364
|
return true;
|
|
4365
4365
|
}
|
|
4366
4366
|
async function rollbackToPreviousRelease(layout, previousReleaseId) {
|
|
4367
|
-
const releaseDir =
|
|
4367
|
+
const releaseDir = join11(layout.releasesRoot, previousReleaseId);
|
|
4368
4368
|
const entrypoint = await resolveBundleEntrypoint(releaseDir);
|
|
4369
4369
|
if (!entrypoint) {
|
|
4370
4370
|
throw new Error(`release ${previousReleaseId} has no runnable CLI entrypoint`);
|
|
4371
4371
|
}
|
|
4372
4372
|
const tempLink = `${layout.libDir}.rollback-${process.pid}`;
|
|
4373
4373
|
await rm6(tempLink, { force: true });
|
|
4374
|
-
await symlink3(
|
|
4374
|
+
await symlink3(join11("beeline-releases", previousReleaseId), tempLink);
|
|
4375
4375
|
await rename4(tempLink, layout.libDir);
|
|
4376
|
-
await fsyncDir(
|
|
4376
|
+
await fsyncDir(dirname12(layout.libDir));
|
|
4377
4377
|
}
|
|
4378
4378
|
function updateAttemptPath(layout) {
|
|
4379
|
-
return
|
|
4379
|
+
return join11(layout.releasesRoot, ".state", "update-attempt.json");
|
|
4380
4380
|
}
|
|
4381
4381
|
async function readUpdateAttempt(layout) {
|
|
4382
4382
|
try {
|
|
@@ -4390,7 +4390,7 @@ async function readUpdateAttempt(layout) {
|
|
|
4390
4390
|
}
|
|
4391
4391
|
}
|
|
4392
4392
|
async function writeUpdateAttempt(layout, record3) {
|
|
4393
|
-
await mkdir15(
|
|
4393
|
+
await mkdir15(join11(layout.releasesRoot, ".state"), { recursive: true });
|
|
4394
4394
|
const path = updateAttemptPath(layout);
|
|
4395
4395
|
const staged = `${path}.${process.pid}.tmp`;
|
|
4396
4396
|
await writeFile10(staged, `${JSON.stringify(record3, null, 2)}
|
|
@@ -4668,7 +4668,7 @@ function configureNetworkFamilyDefaults(network = net) {
|
|
|
4668
4668
|
configureNetworkFamilyDefaults();
|
|
4669
4669
|
|
|
4670
4670
|
// apps/body/dist/cli.js
|
|
4671
|
-
import { dirname as
|
|
4671
|
+
import { dirname as dirname18, resolve as resolve31 } from "node:path";
|
|
4672
4672
|
import { readFile as readFile15, unlink as unlink5, writeFile as writeFile16 } from "node:fs/promises";
|
|
4673
4673
|
import { stdin as stdin4, stdout as stdout5 } from "node:process";
|
|
4674
4674
|
|
|
@@ -6079,13 +6079,496 @@ ${r2}
|
|
|
6079
6079
|
var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
6080
6080
|
|
|
6081
6081
|
// apps/body/dist/config.js
|
|
6082
|
-
import { accessSync as accessSync2, constants as constants2, existsSync as
|
|
6082
|
+
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync3, readFileSync } from "node:fs";
|
|
6083
6083
|
import { basename, dirname, resolve as resolve2 } from "node:path";
|
|
6084
6084
|
|
|
6085
6085
|
// apps/body/dist/agent-command.js
|
|
6086
|
-
import { accessSync, constants, existsSync, readdirSync } from "node:fs";
|
|
6086
|
+
import { accessSync, constants, existsSync as existsSync2, readdirSync } from "node:fs";
|
|
6087
6087
|
import { homedir } from "node:os";
|
|
6088
6088
|
import { delimiter, isAbsolute, join, resolve } from "node:path";
|
|
6089
|
+
|
|
6090
|
+
// apps/body/dist/cursor-acp-bridge.js
|
|
6091
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
6092
|
+
import { existsSync } from "node:fs";
|
|
6093
|
+
import { createRequire } from "node:module";
|
|
6094
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
6095
|
+
import { resolve as resolvePath } from "node:path";
|
|
6096
|
+
import { fileURLToPath } from "node:url";
|
|
6097
|
+
import { randomUUID } from "node:crypto";
|
|
6098
|
+
|
|
6099
|
+
// apps/body/dist/cursor-models.js
|
|
6100
|
+
import { spawn } from "node:child_process";
|
|
6101
|
+
var CURSOR_MODELS_TIMEOUT_MS = 1e4;
|
|
6102
|
+
function parseCursorModelsOutput(output) {
|
|
6103
|
+
const options = [];
|
|
6104
|
+
for (const line of output.split(/\r?\n/)) {
|
|
6105
|
+
const match = /^\s*([A-Za-z0-9][A-Za-z0-9._-]*)\s+-\s+(\S.*?)\s*$/.exec(line);
|
|
6106
|
+
if (!match)
|
|
6107
|
+
continue;
|
|
6108
|
+
const id = match[1];
|
|
6109
|
+
const name = match[2].replace(/\s*\(current, default\)\s*$/i, "").trim();
|
|
6110
|
+
options.push({ id, ...name && name !== id ? { name } : {} });
|
|
6111
|
+
}
|
|
6112
|
+
if (!options.length)
|
|
6113
|
+
return void 0;
|
|
6114
|
+
return {
|
|
6115
|
+
currentValue: options.some((option) => option.id === "auto") ? "auto" : options[0].id,
|
|
6116
|
+
options
|
|
6117
|
+
};
|
|
6118
|
+
}
|
|
6119
|
+
async function enumerateCursorModels(env = process.env) {
|
|
6120
|
+
return new Promise((resolve32) => {
|
|
6121
|
+
const child = spawn("cursor-agent", ["models"], {
|
|
6122
|
+
env,
|
|
6123
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
6124
|
+
});
|
|
6125
|
+
let output = "";
|
|
6126
|
+
const timer = setTimeout(() => {
|
|
6127
|
+
child.kill("SIGKILL");
|
|
6128
|
+
}, CURSOR_MODELS_TIMEOUT_MS);
|
|
6129
|
+
child.stdout?.on("data", (chunk) => {
|
|
6130
|
+
output += chunk.toString();
|
|
6131
|
+
});
|
|
6132
|
+
child.on("error", () => {
|
|
6133
|
+
clearTimeout(timer);
|
|
6134
|
+
resolve32(void 0);
|
|
6135
|
+
});
|
|
6136
|
+
child.on("close", (code) => {
|
|
6137
|
+
clearTimeout(timer);
|
|
6138
|
+
resolve32(code === 0 ? parseCursorModelsOutput(output) : void 0);
|
|
6139
|
+
});
|
|
6140
|
+
});
|
|
6141
|
+
}
|
|
6142
|
+
|
|
6143
|
+
// apps/body/dist/cursor-acp-bridge.js
|
|
6144
|
+
var CURSOR_ACP_BRIDGE_FLAG = "--cursor-acp-bridge";
|
|
6145
|
+
var CURSOR_ACP_BRIDGE_LABEL = "cursor-acp-bridge";
|
|
6146
|
+
var CURSOR_AGENT_FORCE_FLAG = "--force";
|
|
6147
|
+
var CURSOR_AGENT_TRUST_FLAG = "--trust";
|
|
6148
|
+
var CURSOR_HARNESS_COMMAND = /(^|[/\\])(cursor-acp-bridge|cursor-agent-acp)(\.[a-z]+)?$/i;
|
|
6149
|
+
var STDERR_TAIL_MAX_CHARS = 2e3;
|
|
6150
|
+
var MODEL_AXIS_ID = "model";
|
|
6151
|
+
function harnessIdentityLabel(agent) {
|
|
6152
|
+
if (agent.kind === "cursor")
|
|
6153
|
+
return CURSOR_ACP_BRIDGE_LABEL;
|
|
6154
|
+
return agent.command ?? "";
|
|
6155
|
+
}
|
|
6156
|
+
function cursorAcpBridgeLaunch() {
|
|
6157
|
+
const meta = "usebeeline:npm";
|
|
6158
|
+
if (meta === "beeline:bundle" || meta.startsWith("beeline:")) {
|
|
6159
|
+
const entry = process.argv[1];
|
|
6160
|
+
if (!entry) {
|
|
6161
|
+
throw new Error("Cursor ACP bridge cannot resolve the Beeline CLI entry");
|
|
6162
|
+
}
|
|
6163
|
+
return { command: process.execPath, args: [entry, CURSOR_ACP_BRIDGE_FLAG] };
|
|
6164
|
+
}
|
|
6165
|
+
const js = fileURLToPath(new URL("./cursor-acp-bridge.js", meta));
|
|
6166
|
+
const ts = fileURLToPath(new URL("./cursor-acp-bridge.ts", meta));
|
|
6167
|
+
if (existsSync(js))
|
|
6168
|
+
return { command: process.execPath, args: [js] };
|
|
6169
|
+
if (existsSync(ts)) {
|
|
6170
|
+
const tsx = createRequire(meta).resolve("tsx");
|
|
6171
|
+
return { command: process.execPath, args: ["--import", tsx, ts] };
|
|
6172
|
+
}
|
|
6173
|
+
throw new Error("Cursor ACP bridge entry not found next to the Beeline helper");
|
|
6174
|
+
}
|
|
6175
|
+
function cursorAgentArgv(input) {
|
|
6176
|
+
const argv = [
|
|
6177
|
+
"--print",
|
|
6178
|
+
"--output-format",
|
|
6179
|
+
"stream-json",
|
|
6180
|
+
CURSOR_AGENT_TRUST_FLAG,
|
|
6181
|
+
CURSOR_AGENT_FORCE_FLAG
|
|
6182
|
+
];
|
|
6183
|
+
if (input.model && input.model !== "auto")
|
|
6184
|
+
argv.push("--model", input.model);
|
|
6185
|
+
argv.push(input.prompt);
|
|
6186
|
+
return argv;
|
|
6187
|
+
}
|
|
6188
|
+
function asRecord(value) {
|
|
6189
|
+
return value && typeof value === "object" ? value : void 0;
|
|
6190
|
+
}
|
|
6191
|
+
function textChunksFromContent(content) {
|
|
6192
|
+
if (typeof content === "string" && content)
|
|
6193
|
+
return [content];
|
|
6194
|
+
if (!Array.isArray(content))
|
|
6195
|
+
return [];
|
|
6196
|
+
const chunks = [];
|
|
6197
|
+
for (const block2 of content) {
|
|
6198
|
+
const record3 = asRecord(block2);
|
|
6199
|
+
if (!record3)
|
|
6200
|
+
continue;
|
|
6201
|
+
if (record3.type === "text" && typeof record3.text === "string" && record3.text) {
|
|
6202
|
+
chunks.push(record3.text);
|
|
6203
|
+
}
|
|
6204
|
+
}
|
|
6205
|
+
return chunks;
|
|
6206
|
+
}
|
|
6207
|
+
function thoughtText(event) {
|
|
6208
|
+
if (typeof event.text === "string")
|
|
6209
|
+
return event.text;
|
|
6210
|
+
const record3 = asRecord(event);
|
|
6211
|
+
if (!record3)
|
|
6212
|
+
return "";
|
|
6213
|
+
if (typeof record3.delta === "string")
|
|
6214
|
+
return record3.delta;
|
|
6215
|
+
return textChunksFromContent(record3.content).join("");
|
|
6216
|
+
}
|
|
6217
|
+
function assistantTexts(event) {
|
|
6218
|
+
if (typeof event.text === "string" && event.text)
|
|
6219
|
+
return [event.text];
|
|
6220
|
+
const message = asRecord(event.message);
|
|
6221
|
+
if (message)
|
|
6222
|
+
return textChunksFromContent(message.content);
|
|
6223
|
+
return textChunksFromContent(asRecord(event)?.content);
|
|
6224
|
+
}
|
|
6225
|
+
function chunkUpdate(sessionUpdate, text2) {
|
|
6226
|
+
return { sessionUpdate, content: { type: "text", text: text2 } };
|
|
6227
|
+
}
|
|
6228
|
+
function translateCursorStreamEvent(event) {
|
|
6229
|
+
if (event.type === "thinking") {
|
|
6230
|
+
if (event.subtype === "completed")
|
|
6231
|
+
return [];
|
|
6232
|
+
const text2 = thoughtText(event);
|
|
6233
|
+
return text2 ? [chunkUpdate("agent_thought_chunk", text2)] : [];
|
|
6234
|
+
}
|
|
6235
|
+
if (event.type === "assistant") {
|
|
6236
|
+
return assistantTexts(event).map((text2) => chunkUpdate("agent_message_chunk", text2));
|
|
6237
|
+
}
|
|
6238
|
+
return [];
|
|
6239
|
+
}
|
|
6240
|
+
function resultEventText(event) {
|
|
6241
|
+
if (typeof event.result === "string")
|
|
6242
|
+
return event.result;
|
|
6243
|
+
const record3 = asRecord(event.result);
|
|
6244
|
+
if (record3 && typeof record3.text === "string")
|
|
6245
|
+
return record3.text;
|
|
6246
|
+
return "";
|
|
6247
|
+
}
|
|
6248
|
+
function isCursorResultEvent(event) {
|
|
6249
|
+
return event.type === "result";
|
|
6250
|
+
}
|
|
6251
|
+
function cursorResultIsError(event) {
|
|
6252
|
+
return event.is_error === true || event.subtype === "error";
|
|
6253
|
+
}
|
|
6254
|
+
function trimReason(value) {
|
|
6255
|
+
return value.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
6256
|
+
}
|
|
6257
|
+
function describeCursorTurnFailure(input) {
|
|
6258
|
+
if (input.spawnError) {
|
|
6259
|
+
return trimReason(`cursor-agent failed to start: ${input.spawnError}`);
|
|
6260
|
+
}
|
|
6261
|
+
const stderr = input.stderr?.trim() ?? "";
|
|
6262
|
+
if (input.isError) {
|
|
6263
|
+
const named = input.resultText?.trim() || stderr || "cursor-agent reported an error with no answer text";
|
|
6264
|
+
return trimReason(`cursor-agent reported an error: ${named}`);
|
|
6265
|
+
}
|
|
6266
|
+
if (input.signal) {
|
|
6267
|
+
return trimReason(`cursor-agent terminated by ${input.signal}${stderr ? `: ${stderr}` : ""}`);
|
|
6268
|
+
}
|
|
6269
|
+
if (input.exitCode !== 0 && input.exitCode !== null) {
|
|
6270
|
+
return trimReason(`cursor-agent exited ${input.exitCode}${stderr ? `: ${stderr}` : " with no answer text"}`);
|
|
6271
|
+
}
|
|
6272
|
+
return void 0;
|
|
6273
|
+
}
|
|
6274
|
+
function promptTextFromParams(params, systemPrompt) {
|
|
6275
|
+
const record3 = asRecord(params);
|
|
6276
|
+
const blocks = Array.isArray(record3?.prompt) ? record3.prompt : [];
|
|
6277
|
+
const user = blocks.map((block2) => {
|
|
6278
|
+
const item = asRecord(block2);
|
|
6279
|
+
return item?.type === "text" && typeof item.text === "string" ? item.text : "";
|
|
6280
|
+
}).filter(Boolean).join("\n");
|
|
6281
|
+
return systemPrompt ? `${systemPrompt}
|
|
6282
|
+
|
|
6283
|
+
${user}` : user;
|
|
6284
|
+
}
|
|
6285
|
+
function defaultSpawnCursorAgent(input) {
|
|
6286
|
+
return spawn2("cursor-agent", input.argv, {
|
|
6287
|
+
cwd: input.cwd,
|
|
6288
|
+
env: input.env,
|
|
6289
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
6290
|
+
});
|
|
6291
|
+
}
|
|
6292
|
+
var CursorAcpServer = class {
|
|
6293
|
+
write;
|
|
6294
|
+
spawnCursorAgent;
|
|
6295
|
+
enumerateModels;
|
|
6296
|
+
env;
|
|
6297
|
+
sessions = /* @__PURE__ */ new Map();
|
|
6298
|
+
models;
|
|
6299
|
+
modelsLoaded = false;
|
|
6300
|
+
constructor(options) {
|
|
6301
|
+
this.write = options.write;
|
|
6302
|
+
this.spawnCursorAgent = options.spawnCursorAgent ?? defaultSpawnCursorAgent;
|
|
6303
|
+
this.enumerateModels = options.enumerateModels ?? enumerateCursorModels;
|
|
6304
|
+
this.env = options.env ?? process.env;
|
|
6305
|
+
}
|
|
6306
|
+
async handle(message) {
|
|
6307
|
+
const method = typeof message.method === "string" ? message.method : "";
|
|
6308
|
+
const id = message.id;
|
|
6309
|
+
if (!method)
|
|
6310
|
+
return;
|
|
6311
|
+
if (id === void 0) {
|
|
6312
|
+
if (method === "session/cancel")
|
|
6313
|
+
this.cancel(message.params);
|
|
6314
|
+
return;
|
|
6315
|
+
}
|
|
6316
|
+
try {
|
|
6317
|
+
const result = await this.dispatch(method, message.params);
|
|
6318
|
+
this.write({ jsonrpc: "2.0", id, result });
|
|
6319
|
+
} catch (error) {
|
|
6320
|
+
const rpcError = error;
|
|
6321
|
+
this.write({
|
|
6322
|
+
jsonrpc: "2.0",
|
|
6323
|
+
id,
|
|
6324
|
+
error: {
|
|
6325
|
+
code: typeof rpcError.code === "number" ? rpcError.code : -32e3,
|
|
6326
|
+
message: error instanceof Error ? error.message : String(error)
|
|
6327
|
+
}
|
|
6328
|
+
});
|
|
6329
|
+
}
|
|
6330
|
+
}
|
|
6331
|
+
async dispatch(method, params) {
|
|
6332
|
+
switch (method) {
|
|
6333
|
+
case "initialize":
|
|
6334
|
+
return {
|
|
6335
|
+
protocolVersion: 1,
|
|
6336
|
+
agentCapabilities: { promptCapabilities: { image: false } }
|
|
6337
|
+
};
|
|
6338
|
+
case "session/new":
|
|
6339
|
+
return this.sessionNew(params);
|
|
6340
|
+
case "session/prompt":
|
|
6341
|
+
return this.sessionPrompt(params);
|
|
6342
|
+
case "session/set_config_option":
|
|
6343
|
+
return this.setConfigOption(params);
|
|
6344
|
+
case "session/set_model":
|
|
6345
|
+
return this.setModel(params);
|
|
6346
|
+
case "shutdown":
|
|
6347
|
+
this.shutdown();
|
|
6348
|
+
return {};
|
|
6349
|
+
default:
|
|
6350
|
+
return {};
|
|
6351
|
+
}
|
|
6352
|
+
}
|
|
6353
|
+
async loadModels() {
|
|
6354
|
+
if (this.modelsLoaded) {
|
|
6355
|
+
return this.models ?? { currentValue: "auto", options: [{ id: "auto", name: "Auto" }] };
|
|
6356
|
+
}
|
|
6357
|
+
this.modelsLoaded = true;
|
|
6358
|
+
this.models = await this.enumerateModels(this.env);
|
|
6359
|
+
return this.models ?? { currentValue: "auto", options: [{ id: "auto", name: "Auto" }] };
|
|
6360
|
+
}
|
|
6361
|
+
async sessionNew(params) {
|
|
6362
|
+
const record3 = asRecord(params);
|
|
6363
|
+
const cwd = typeof record3?.cwd === "string" && record3.cwd ? record3.cwd : process.cwd();
|
|
6364
|
+
const systemPrompt = typeof record3?.systemPrompt === "string" ? record3.systemPrompt : void 0;
|
|
6365
|
+
const catalog = await this.loadModels();
|
|
6366
|
+
const session = {
|
|
6367
|
+
id: randomUUID(),
|
|
6368
|
+
cwd,
|
|
6369
|
+
...systemPrompt ? { systemPrompt } : {},
|
|
6370
|
+
model: catalog.currentValue
|
|
6371
|
+
};
|
|
6372
|
+
this.sessions.set(session.id, session);
|
|
6373
|
+
return {
|
|
6374
|
+
sessionId: session.id,
|
|
6375
|
+
configOptions: [
|
|
6376
|
+
{
|
|
6377
|
+
id: MODEL_AXIS_ID,
|
|
6378
|
+
category: "model",
|
|
6379
|
+
currentValue: session.model,
|
|
6380
|
+
options: catalog.options.map((option) => ({
|
|
6381
|
+
id: option.id,
|
|
6382
|
+
...option.name ? { name: option.name } : {}
|
|
6383
|
+
}))
|
|
6384
|
+
}
|
|
6385
|
+
]
|
|
6386
|
+
};
|
|
6387
|
+
}
|
|
6388
|
+
session(params) {
|
|
6389
|
+
const record3 = asRecord(params);
|
|
6390
|
+
const sessionId = typeof record3?.sessionId === "string" ? record3.sessionId : "";
|
|
6391
|
+
const session = this.sessions.get(sessionId);
|
|
6392
|
+
if (!session) {
|
|
6393
|
+
const error = new Error(`unknown ACP session ${sessionId || "(missing)"}`);
|
|
6394
|
+
error.code = -32602;
|
|
6395
|
+
throw error;
|
|
6396
|
+
}
|
|
6397
|
+
return session;
|
|
6398
|
+
}
|
|
6399
|
+
setConfigOption(params) {
|
|
6400
|
+
const session = this.session(params);
|
|
6401
|
+
const record3 = asRecord(params);
|
|
6402
|
+
if (record3?.configId === MODEL_AXIS_ID && typeof record3.value === "string" && record3.value) {
|
|
6403
|
+
session.model = record3.value;
|
|
6404
|
+
}
|
|
6405
|
+
return {};
|
|
6406
|
+
}
|
|
6407
|
+
setModel(params) {
|
|
6408
|
+
const session = this.session(params);
|
|
6409
|
+
const record3 = asRecord(params);
|
|
6410
|
+
if (typeof record3?.modelId === "string" && record3.modelId)
|
|
6411
|
+
session.model = record3.modelId;
|
|
6412
|
+
return {};
|
|
6413
|
+
}
|
|
6414
|
+
emitUpdate(sessionId, update) {
|
|
6415
|
+
this.write({
|
|
6416
|
+
jsonrpc: "2.0",
|
|
6417
|
+
method: "session/update",
|
|
6418
|
+
params: { sessionId, update }
|
|
6419
|
+
});
|
|
6420
|
+
}
|
|
6421
|
+
async sessionPrompt(params) {
|
|
6422
|
+
const session = this.session(params);
|
|
6423
|
+
if (session.child) {
|
|
6424
|
+
throw new Error("cursor-agent is already running a turn for this session");
|
|
6425
|
+
}
|
|
6426
|
+
const prompt = promptTextFromParams(params, session.systemPrompt);
|
|
6427
|
+
const argv = cursorAgentArgv({ prompt, model: session.model });
|
|
6428
|
+
let stderr = "";
|
|
6429
|
+
let spawnError;
|
|
6430
|
+
let sawAssistant = false;
|
|
6431
|
+
let resultEvent;
|
|
6432
|
+
const pending = [];
|
|
6433
|
+
const consumeLine = (line) => {
|
|
6434
|
+
const trimmed = line.trim();
|
|
6435
|
+
if (!trimmed)
|
|
6436
|
+
return;
|
|
6437
|
+
let event;
|
|
6438
|
+
try {
|
|
6439
|
+
event = JSON.parse(trimmed);
|
|
6440
|
+
} catch {
|
|
6441
|
+
return;
|
|
6442
|
+
}
|
|
6443
|
+
if (isCursorResultEvent(event)) {
|
|
6444
|
+
resultEvent = event;
|
|
6445
|
+
return;
|
|
6446
|
+
}
|
|
6447
|
+
for (const update of translateCursorStreamEvent(event)) {
|
|
6448
|
+
if (update.sessionUpdate === "agent_message_chunk")
|
|
6449
|
+
sawAssistant = true;
|
|
6450
|
+
this.emitUpdate(session.id, update);
|
|
6451
|
+
}
|
|
6452
|
+
};
|
|
6453
|
+
const child = this.spawnCursorAgent({ argv, cwd: session.cwd, env: this.env });
|
|
6454
|
+
session.child = child;
|
|
6455
|
+
child.stderr?.setEncoding("utf8");
|
|
6456
|
+
child.stderr?.on("data", (chunk) => {
|
|
6457
|
+
stderr = `${stderr}${chunk}`.slice(-STDERR_TAIL_MAX_CHARS);
|
|
6458
|
+
});
|
|
6459
|
+
child.stdout?.setEncoding("utf8");
|
|
6460
|
+
child.stdout?.on("data", (chunk) => {
|
|
6461
|
+
pending.push(chunk);
|
|
6462
|
+
const joined = pending.join("");
|
|
6463
|
+
const lines = joined.split(/\r?\n/);
|
|
6464
|
+
pending.length = 0;
|
|
6465
|
+
const rest = lines.pop();
|
|
6466
|
+
if (rest)
|
|
6467
|
+
pending.push(rest);
|
|
6468
|
+
for (const line of lines)
|
|
6469
|
+
consumeLine(line);
|
|
6470
|
+
});
|
|
6471
|
+
try {
|
|
6472
|
+
const { code, signal } = await new Promise((resolve32) => {
|
|
6473
|
+
let settled = false;
|
|
6474
|
+
const finish = (exitCode, exitSignal) => {
|
|
6475
|
+
if (settled)
|
|
6476
|
+
return;
|
|
6477
|
+
settled = true;
|
|
6478
|
+
resolve32({ code: exitCode, signal: exitSignal });
|
|
6479
|
+
};
|
|
6480
|
+
child.once("error", (error) => {
|
|
6481
|
+
spawnError = error instanceof Error ? error.message : String(error);
|
|
6482
|
+
finish(1, null);
|
|
6483
|
+
});
|
|
6484
|
+
child.once("close", (exitCode, exitSignal) => {
|
|
6485
|
+
finish(exitCode, exitSignal);
|
|
6486
|
+
});
|
|
6487
|
+
});
|
|
6488
|
+
if (pending.length)
|
|
6489
|
+
consumeLine(pending.join(""));
|
|
6490
|
+
const failure = describeCursorTurnFailure({
|
|
6491
|
+
isError: resultEvent ? cursorResultIsError(resultEvent) : false,
|
|
6492
|
+
resultText: resultEvent ? resultEventText(resultEvent) : void 0,
|
|
6493
|
+
exitCode: spawnError ? 1 : code,
|
|
6494
|
+
signal,
|
|
6495
|
+
stderr,
|
|
6496
|
+
spawnError
|
|
6497
|
+
});
|
|
6498
|
+
if (failure)
|
|
6499
|
+
throw new Error(failure);
|
|
6500
|
+
if (!sawAssistant) {
|
|
6501
|
+
const fallback = resultEvent && !cursorResultIsError(resultEvent) ? resultEventText(resultEvent) : "";
|
|
6502
|
+
if (fallback)
|
|
6503
|
+
this.emitUpdate(session.id, chunkUpdate("agent_message_chunk", fallback));
|
|
6504
|
+
}
|
|
6505
|
+
return { stopReason: "end_turn" };
|
|
6506
|
+
} finally {
|
|
6507
|
+
session.child = void 0;
|
|
6508
|
+
}
|
|
6509
|
+
}
|
|
6510
|
+
cancel(params) {
|
|
6511
|
+
const record3 = asRecord(params);
|
|
6512
|
+
const sessionId = typeof record3?.sessionId === "string" ? record3.sessionId : "";
|
|
6513
|
+
const session = this.sessions.get(sessionId);
|
|
6514
|
+
if (!session?.child?.pid)
|
|
6515
|
+
return;
|
|
6516
|
+
try {
|
|
6517
|
+
session.child.kill("SIGTERM");
|
|
6518
|
+
} catch {
|
|
6519
|
+
}
|
|
6520
|
+
}
|
|
6521
|
+
shutdown() {
|
|
6522
|
+
for (const session of this.sessions.values()) {
|
|
6523
|
+
if (!session.child?.pid)
|
|
6524
|
+
continue;
|
|
6525
|
+
try {
|
|
6526
|
+
session.child.kill("SIGTERM");
|
|
6527
|
+
} catch {
|
|
6528
|
+
}
|
|
6529
|
+
}
|
|
6530
|
+
this.sessions.clear();
|
|
6531
|
+
}
|
|
6532
|
+
};
|
|
6533
|
+
async function runCursorAcpStdioServer(options = {}) {
|
|
6534
|
+
const server = new CursorAcpServer({
|
|
6535
|
+
...options,
|
|
6536
|
+
write: (message) => {
|
|
6537
|
+
process.stdout.write(`${JSON.stringify(message)}
|
|
6538
|
+
`);
|
|
6539
|
+
}
|
|
6540
|
+
});
|
|
6541
|
+
const lines = createInterface2({ input: process.stdin });
|
|
6542
|
+
for await (const line of lines) {
|
|
6543
|
+
const trimmed = line.trim();
|
|
6544
|
+
if (!trimmed)
|
|
6545
|
+
continue;
|
|
6546
|
+
let message;
|
|
6547
|
+
try {
|
|
6548
|
+
message = JSON.parse(trimmed);
|
|
6549
|
+
} catch {
|
|
6550
|
+
continue;
|
|
6551
|
+
}
|
|
6552
|
+
await server.handle(message);
|
|
6553
|
+
if (message.method === "shutdown")
|
|
6554
|
+
break;
|
|
6555
|
+
}
|
|
6556
|
+
}
|
|
6557
|
+
function isDirectBridgeRun() {
|
|
6558
|
+
const entry = process.argv[1];
|
|
6559
|
+
if (!entry || entry.includes(".test."))
|
|
6560
|
+
return false;
|
|
6561
|
+
try {
|
|
6562
|
+
return resolvePath(entry) === resolvePath(fileURLToPath("usebeeline:npm"));
|
|
6563
|
+
} catch {
|
|
6564
|
+
return false;
|
|
6565
|
+
}
|
|
6566
|
+
}
|
|
6567
|
+
if (isDirectBridgeRun()) {
|
|
6568
|
+
void runCursorAcpStdioServer();
|
|
6569
|
+
}
|
|
6570
|
+
|
|
6571
|
+
// apps/body/dist/agent-command.js
|
|
6089
6572
|
var AGENT_KINDS = [
|
|
6090
6573
|
"codex",
|
|
6091
6574
|
"claude",
|
|
@@ -6117,10 +6600,6 @@ var ADAPTER_INSTALL_COMMANDS = {
|
|
|
6117
6600
|
pi: {
|
|
6118
6601
|
command: "npm",
|
|
6119
6602
|
args: ["install", "-g", "pi-acp"]
|
|
6120
|
-
},
|
|
6121
|
-
cursor: {
|
|
6122
|
-
command: "npm",
|
|
6123
|
-
args: ["install", "-g", "cursor-agent-acp"]
|
|
6124
6603
|
}
|
|
6125
6604
|
};
|
|
6126
6605
|
function adapterInstallHint(kind) {
|
|
@@ -6190,7 +6669,7 @@ function describeExecutableSearch(env = process.env) {
|
|
|
6190
6669
|
return augmentedSearchDirectories(env).join(", ");
|
|
6191
6670
|
}
|
|
6192
6671
|
function firstExisting(paths) {
|
|
6193
|
-
return paths.find((path) => path &&
|
|
6672
|
+
return paths.find((path) => path && existsSync2(path));
|
|
6194
6673
|
}
|
|
6195
6674
|
function executableOnPath(name, env = process.env) {
|
|
6196
6675
|
for (const directory of augmentedSearchDirectories(env)) {
|
|
@@ -6303,8 +6782,8 @@ function resolveAgentCommand(opts) {
|
|
|
6303
6782
|
}
|
|
6304
6783
|
if (typedKind === "cursor") {
|
|
6305
6784
|
requireExecutable("cursor-agent", env, cwd, "Cursor Agent CLI not found. Install it from https://cursor.com/docs/cli, then retry with `--agent cursor`.");
|
|
6306
|
-
const
|
|
6307
|
-
return { kind: typedKind, command:
|
|
6785
|
+
const bridge = cursorAcpBridgeLaunch();
|
|
6786
|
+
return { kind: typedKind, command: bridge.command, args: bridge.args };
|
|
6308
6787
|
}
|
|
6309
6788
|
if (typedKind === "grok") {
|
|
6310
6789
|
const command2 = requireExecutable("grok", env, cwd, "Grok CLI not found. Install it with `curl -fsSL https://x.ai/cli/install.sh | bash`, then retry with `--agent grok`.");
|
|
@@ -6341,7 +6820,7 @@ function detectInstalledAgentCommands(opts = {}) {
|
|
|
6341
6820
|
agent: resolveAgentCommand({ kind, env, cwd: opts.cwd })
|
|
6342
6821
|
});
|
|
6343
6822
|
} catch {
|
|
6344
|
-
if (kind !== "goose" && kind !== "grok") {
|
|
6823
|
+
if (kind !== "goose" && kind !== "grok" && kind !== "cursor") {
|
|
6345
6824
|
detected.push({
|
|
6346
6825
|
kind,
|
|
6347
6826
|
status: "missing-adapter",
|
|
@@ -6365,7 +6844,7 @@ function formatAdapterInstallCommand(install) {
|
|
|
6365
6844
|
// apps/body/dist/config.js
|
|
6366
6845
|
function firstExisting2(paths) {
|
|
6367
6846
|
for (const p of paths) {
|
|
6368
|
-
if (p &&
|
|
6847
|
+
if (p && existsSync3(p))
|
|
6369
6848
|
return p;
|
|
6370
6849
|
}
|
|
6371
6850
|
return void 0;
|
|
@@ -6418,7 +6897,7 @@ function resolveReadonlyMcpCommand(env = process.env) {
|
|
|
6418
6897
|
if (binary)
|
|
6419
6898
|
return { command: binary, args: [] };
|
|
6420
6899
|
const script = env.BEELINE_READONLY_MCP_SCRIPT;
|
|
6421
|
-
if (script &&
|
|
6900
|
+
if (script && existsSync3(script))
|
|
6422
6901
|
return { command: process.execPath, args: [script] };
|
|
6423
6902
|
const built = firstExisting2([
|
|
6424
6903
|
resolve2(process.cwd(), "apps", "body", "dist", "read-only-mcp.js"),
|
|
@@ -6453,7 +6932,7 @@ function resolveCodegraphCommand(env = process.env) {
|
|
|
6453
6932
|
}
|
|
6454
6933
|
function parseEnvFile(path) {
|
|
6455
6934
|
const out = {};
|
|
6456
|
-
if (!
|
|
6935
|
+
if (!existsSync3(path))
|
|
6457
6936
|
return out;
|
|
6458
6937
|
const text2 = readFileSync(path, "utf8");
|
|
6459
6938
|
for (const raw of text2.split("\n")) {
|
|
@@ -6694,7 +7173,7 @@ import { tmpdir } from "node:os";
|
|
|
6694
7173
|
import { resolve as resolve4 } from "node:path";
|
|
6695
7174
|
|
|
6696
7175
|
// apps/body/dist/acp.js
|
|
6697
|
-
import { spawn } from "node:child_process";
|
|
7176
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
6698
7177
|
import { EventEmitter } from "node:events";
|
|
6699
7178
|
|
|
6700
7179
|
// apps/body/dist/harness-capabilities.js
|
|
@@ -6775,10 +7254,10 @@ var PROFILES = [
|
|
|
6775
7254
|
}
|
|
6776
7255
|
},
|
|
6777
7256
|
{
|
|
6778
|
-
match:
|
|
7257
|
+
match: CURSOR_HARNESS_COMMAND,
|
|
6779
7258
|
profile: {
|
|
6780
7259
|
enforcement: "config-isolated",
|
|
6781
|
-
note: "cursor-
|
|
7260
|
+
note: "cursor-acp-bridge drives cursor-agent; cursor-agent loads MCP servers from ~/.cursor/mcp.json, so an isolated CURSOR_HOME scopes the session"
|
|
6782
7261
|
}
|
|
6783
7262
|
}
|
|
6784
7263
|
];
|
|
@@ -6800,7 +7279,7 @@ function matchProfile(agentCommand) {
|
|
|
6800
7279
|
}
|
|
6801
7280
|
|
|
6802
7281
|
// apps/body/dist/acp.js
|
|
6803
|
-
var
|
|
7282
|
+
var STDERR_TAIL_MAX_CHARS2 = 2e3;
|
|
6804
7283
|
function braceDelta(line) {
|
|
6805
7284
|
let delta = 0;
|
|
6806
7285
|
for (const char of line) {
|
|
@@ -7015,7 +7494,7 @@ function agentStreamSnapshot(updates, agentLabel) {
|
|
|
7015
7494
|
const completedMessages = [];
|
|
7016
7495
|
let messageText2 = "";
|
|
7017
7496
|
let lastWasMessage = false;
|
|
7018
|
-
let
|
|
7497
|
+
let thoughtText2 = "";
|
|
7019
7498
|
let thoughtRunOpen = false;
|
|
7020
7499
|
for (const { update } of updates) {
|
|
7021
7500
|
const kind = typeof update.sessionUpdate === "string" ? update.sessionUpdate : "";
|
|
@@ -7044,8 +7523,8 @@ function agentStreamSnapshot(updates, agentLabel) {
|
|
|
7044
7523
|
if (!delta)
|
|
7045
7524
|
continue;
|
|
7046
7525
|
if (!thoughtRunOpen)
|
|
7047
|
-
|
|
7048
|
-
|
|
7526
|
+
thoughtText2 = "";
|
|
7527
|
+
thoughtText2 += delta;
|
|
7049
7528
|
thoughtRunOpen = true;
|
|
7050
7529
|
} else {
|
|
7051
7530
|
thoughtRunOpen = false;
|
|
@@ -7053,7 +7532,7 @@ function agentStreamSnapshot(updates, agentLabel) {
|
|
|
7053
7532
|
}
|
|
7054
7533
|
return {
|
|
7055
7534
|
messageText: messageText2,
|
|
7056
|
-
...
|
|
7535
|
+
...thoughtText2 || completedMessages.length ? { thoughtText: thoughtText2 || completedMessages.at(-1) } : {}
|
|
7057
7536
|
};
|
|
7058
7537
|
}
|
|
7059
7538
|
function toolCallEntries(updates) {
|
|
@@ -7139,7 +7618,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
7139
7618
|
async start(timeoutMs = 6e4) {
|
|
7140
7619
|
if (this.alive)
|
|
7141
7620
|
return;
|
|
7142
|
-
this.child =
|
|
7621
|
+
this.child = spawn3(this.agentCommand, this.agentArgs, {
|
|
7143
7622
|
// agentEnv is the child's whole environment: buildAgentEnv's allowlist is
|
|
7144
7623
|
// a real boundary, not a decorative one layered over a full inherit.
|
|
7145
7624
|
env: this.inheritProcessEnv ? { ...process.env, ...this.agentEnv } : this.agentEnv,
|
|
@@ -7154,7 +7633,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
7154
7633
|
this.stderrTail = "";
|
|
7155
7634
|
this.child.stderr.setEncoding("utf8");
|
|
7156
7635
|
this.child.stderr.on("data", (chunk) => {
|
|
7157
|
-
this.stderrTail = (this.stderrTail + chunk).slice(-
|
|
7636
|
+
this.stderrTail = (this.stderrTail + chunk).slice(-STDERR_TAIL_MAX_CHARS2);
|
|
7158
7637
|
this.emit("stderr", chunk);
|
|
7159
7638
|
});
|
|
7160
7639
|
this.child.stdout.setEncoding("utf8");
|
|
@@ -7553,7 +8032,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
7553
8032
|
const current = this.activeRunIds.get(sessionId);
|
|
7554
8033
|
if (current)
|
|
7555
8034
|
return Promise.resolve(current);
|
|
7556
|
-
return new Promise((
|
|
8035
|
+
return new Promise((resolve32, reject) => {
|
|
7557
8036
|
const onUpdate = (update) => {
|
|
7558
8037
|
if (update.sessionId !== sessionId)
|
|
7559
8038
|
return;
|
|
@@ -7561,7 +8040,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
7561
8040
|
if (!runId)
|
|
7562
8041
|
return;
|
|
7563
8042
|
cleanup();
|
|
7564
|
-
|
|
8043
|
+
resolve32(runId);
|
|
7565
8044
|
};
|
|
7566
8045
|
const timer = setTimeout(() => {
|
|
7567
8046
|
cleanup();
|
|
@@ -7645,13 +8124,13 @@ var AcpClient = class extends EventEmitter {
|
|
|
7645
8124
|
}
|
|
7646
8125
|
const id = this.nextId++;
|
|
7647
8126
|
const payload = { jsonrpc: "2.0", id, method, params };
|
|
7648
|
-
return new Promise((
|
|
8127
|
+
return new Promise((resolve32, reject) => {
|
|
7649
8128
|
const timer = setTimeout(() => {
|
|
7650
8129
|
this.pending.delete(id);
|
|
7651
8130
|
reject(new AcpRequestTimeoutError(method, timeoutMs, this.stderrTail, Boolean(onStart), detail));
|
|
7652
8131
|
}, timeoutMs);
|
|
7653
8132
|
this.pending.set(id, {
|
|
7654
|
-
resolve:
|
|
8133
|
+
resolve: resolve32,
|
|
7655
8134
|
reject,
|
|
7656
8135
|
timer,
|
|
7657
8136
|
method,
|
|
@@ -8170,8 +8649,8 @@ async function syncAgentModelCatalog(input) {
|
|
|
8170
8649
|
}
|
|
8171
8650
|
|
|
8172
8651
|
// apps/body/dist/connector-google.js
|
|
8173
|
-
import { readFileSync as
|
|
8174
|
-
import { join as
|
|
8652
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
8653
|
+
import { join as join3 } from "node:path";
|
|
8175
8654
|
|
|
8176
8655
|
// apps/body/dist/google-workspace-client.js
|
|
8177
8656
|
function credentialsTokenSource(credentials) {
|
|
@@ -8391,182 +8870,164 @@ function googleWorkspaceClient(tokenSource, transport = defaultGoogleApiTranspor
|
|
|
8391
8870
|
};
|
|
8392
8871
|
}
|
|
8393
8872
|
|
|
8394
|
-
// apps/body/dist/connector-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
function isGoogleToolConnectorType(type) {
|
|
8406
|
-
return type in GOOGLE_TOOL_SCOPES;
|
|
8873
|
+
// apps/body/dist/connector-squire.js
|
|
8874
|
+
import { execFile, spawn as spawn4 } from "node:child_process";
|
|
8875
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
8876
|
+
import { lstatSync as lstatSync2, readFileSync as readFileSync3, realpathSync, rmSync } from "node:fs";
|
|
8877
|
+
import { homedir as homedir2, hostname, tmpdir as tmpdir2 } from "node:os";
|
|
8878
|
+
import { basename as basename3, dirname as dirname2, join as join2, resolve as resolve6 } from "node:path";
|
|
8879
|
+
var SQUIRE_MCP_NAME = "@trusty-squire/mcp";
|
|
8880
|
+
var SQUIRE_CONNECT_PACKAGE = `${SQUIRE_MCP_NAME}@latest`;
|
|
8881
|
+
var activeConnectSession;
|
|
8882
|
+
function squireConnectSession() {
|
|
8883
|
+
return activeConnectSession;
|
|
8407
8884
|
}
|
|
8408
|
-
|
|
8409
|
-
if (
|
|
8410
|
-
return
|
|
8411
|
-
let raw;
|
|
8885
|
+
function isProcessAlive(pid) {
|
|
8886
|
+
if (pid === void 0 || pid <= 0)
|
|
8887
|
+
return false;
|
|
8412
8888
|
try {
|
|
8413
|
-
|
|
8889
|
+
process.kill(pid, 0);
|
|
8890
|
+
return true;
|
|
8414
8891
|
} catch (error) {
|
|
8415
|
-
return
|
|
8416
|
-
source: "unavailable",
|
|
8417
|
-
reason: `Squire has no Google OAuth grant on record yet (connect your Google account in Squire first: ${describe(error)})`
|
|
8418
|
-
};
|
|
8892
|
+
return error?.code === "EPERM";
|
|
8419
8893
|
}
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
const
|
|
8423
|
-
|
|
8424
|
-
|
|
8894
|
+
}
|
|
8895
|
+
function releaseSquireConnectSession(log2) {
|
|
8896
|
+
const claim = activeConnectSession;
|
|
8897
|
+
activeConnectSession = void 0;
|
|
8898
|
+
if (!claim)
|
|
8899
|
+
return;
|
|
8900
|
+
if (isProcessAlive(claim.pid)) {
|
|
8901
|
+
log2?.(`released trusty-squire connect session claim (pid ${String(claim.pid)} still live \u2014 a fresh connect owns the browser now)`);
|
|
8902
|
+
claim.abort();
|
|
8903
|
+
} else {
|
|
8904
|
+
log2?.("cleared dead trusty-squire connect session claim (owner process gone)");
|
|
8425
8905
|
}
|
|
8426
|
-
return {
|
|
8427
|
-
source: "squire",
|
|
8428
|
-
credentials: {
|
|
8429
|
-
accessToken,
|
|
8430
|
-
refreshToken: typeof record3.refreshToken === "string" ? record3.refreshToken : typeof record3.refresh_token === "string" ? record3.refresh_token : void 0,
|
|
8431
|
-
expiresAt: typeof record3.expiresAt === "number" ? record3.expiresAt : void 0,
|
|
8432
|
-
accountEmail: typeof record3.accountEmail === "string" ? record3.accountEmail : typeof record3.email === "string" ? record3.email : void 0
|
|
8433
|
-
}
|
|
8434
|
-
};
|
|
8435
8906
|
}
|
|
8436
|
-
function
|
|
8437
|
-
return
|
|
8907
|
+
function squireChromeProfileDir() {
|
|
8908
|
+
return process.env.TRUSTY_SQUIRE_PROFILE_DIR ?? join2(homedir2(), ".trusty-squire", "chrome-profile");
|
|
8438
8909
|
}
|
|
8439
|
-
function
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
};
|
|
8445
|
-
}
|
|
8446
|
-
for (const path of manualGoogleCredentialsSearchPaths(home)) {
|
|
8910
|
+
function squireProfilePathIdentity(profileDir) {
|
|
8911
|
+
const absolute = resolve6(profileDir);
|
|
8912
|
+
const suffix = [];
|
|
8913
|
+
let candidate = absolute;
|
|
8914
|
+
for (; ; ) {
|
|
8447
8915
|
try {
|
|
8448
|
-
|
|
8449
|
-
if (typeof parsed.accessToken === "string" || typeof parsed.access_token === "string") {
|
|
8450
|
-
return {
|
|
8451
|
-
source: "manual",
|
|
8452
|
-
credentials: {
|
|
8453
|
-
accessToken: parsed.accessToken ?? parsed.access_token,
|
|
8454
|
-
refreshToken: typeof parsed.refreshToken === "string" ? parsed.refreshToken : void 0,
|
|
8455
|
-
accountEmail: typeof parsed.accountEmail === "string" ? parsed.accountEmail : void 0
|
|
8456
|
-
}
|
|
8457
|
-
};
|
|
8458
|
-
}
|
|
8916
|
+
return join2(realpathSync.native(candidate), ...suffix.reverse());
|
|
8459
8917
|
} catch {
|
|
8918
|
+
const parent = dirname2(candidate);
|
|
8919
|
+
if (parent === candidate)
|
|
8920
|
+
return absolute;
|
|
8921
|
+
suffix.push(basename3(candidate));
|
|
8922
|
+
candidate = parent;
|
|
8460
8923
|
}
|
|
8461
8924
|
}
|
|
8462
|
-
return {
|
|
8463
|
-
source: "manual-missing",
|
|
8464
|
-
reason: `no Google credentials found. Put a google-credentials.json (OAuth access token) at ${manualGoogleCredentialsSearchPaths(home)[0]} or connect your Google account in Trusty Squire first.`
|
|
8465
|
-
};
|
|
8466
8925
|
}
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
...extra
|
|
8471
|
-
});
|
|
8472
|
-
function outputTail(text2, maxChars = 800) {
|
|
8473
|
-
const trimmed = text2.trim();
|
|
8474
|
-
return trimmed.length <= maxChars ? trimmed : `\u2026${trimmed.slice(-maxChars)}`;
|
|
8926
|
+
function squireProfileLockPath(profileDir = squireChromeProfileDir(), lockRoot = tmpdir2()) {
|
|
8927
|
+
const digest = createHash2("sha256").update(squireProfilePathIdentity(profileDir)).digest("hex").slice(0, 24);
|
|
8928
|
+
return join2(lockRoot, `trusty-squire-profile-${digest}.lock`);
|
|
8475
8929
|
}
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
emit();
|
|
8482
|
-
};
|
|
8483
|
-
const fail = (label, reason, output) => {
|
|
8484
|
-
push(step(label, "failed", { reason, ...output ? { output } : {} }));
|
|
8485
|
-
return { status: "error", steps, errorMessage: reason };
|
|
8486
|
-
};
|
|
8487
|
-
emit();
|
|
8488
|
-
if (!isGoogleToolConnectorType(options.connectorType)) {
|
|
8489
|
-
return fail("connector type", `${options.connectorType} is not a Google tool connector`);
|
|
8490
|
-
}
|
|
8491
|
-
push(step("Google credentials resolved", "running", { output: "resolving\u2026" }));
|
|
8492
|
-
const resolved = options.resolvedCredentials ? await options.resolvedCredentials : options.resolveCredentials ? await options.resolveCredentials() : await (async () => {
|
|
8493
|
-
const oneClick = await readGoogleCredentialsFromVault(options.squire);
|
|
8494
|
-
return oneClick.source === "squire" ? { ...oneClick } : { ...loadManualGoogleCredentials(options.home, options.env) };
|
|
8495
|
-
})();
|
|
8496
|
-
if (!("credentials" in resolved)) {
|
|
8497
|
-
const reason = resolved.reason;
|
|
8498
|
-
steps[1] = step("Google credentials resolved", "failed", { reason, output: outputTail(reason) });
|
|
8499
|
-
emit();
|
|
8500
|
-
return { status: "error", steps, errorMessage: reason };
|
|
8501
|
-
}
|
|
8502
|
-
steps[1] = step("Google credentials resolved", "done", {
|
|
8503
|
-
output: resolved.source === "squire" ? "one-click: read the Google grant from Trusty Squire" : "manual: local google-credentials.json"
|
|
8504
|
-
});
|
|
8505
|
-
emit();
|
|
8506
|
-
const client = options.client ?? googleWorkspaceClient(credentialsTokenSource(resolved.credentials));
|
|
8507
|
-
push(step("authorized with Google", "running", { output: "verifying the grant with Google\u2026" }));
|
|
8508
|
-
const verify = await client.verify();
|
|
8509
|
-
if (!verify.ok) {
|
|
8510
|
-
return fail("authorized with Google", verify.reason, outputTail(verify.reason));
|
|
8511
|
-
}
|
|
8512
|
-
steps[2] = step("authorized with Google", "done", {
|
|
8513
|
-
...verify.account ? { output: `signed in as ${verify.account}` } : {}
|
|
8514
|
-
});
|
|
8515
|
-
emit();
|
|
8516
|
-
push(step("tools enabled", "done", {
|
|
8517
|
-
output: `${GOOGLE_TOOL_SCOPES[options.connectorType].length} Google scopes granted`
|
|
8518
|
-
}));
|
|
8519
|
-
return {
|
|
8520
|
-
status: "connected",
|
|
8521
|
-
steps,
|
|
8522
|
-
...verify.account ? { signedInAs: verify.account } : {}
|
|
8523
|
-
};
|
|
8930
|
+
var SQUIRE_BROWSER_BUSY_GOOGLE_REASON = "Trusty Squire is still using the browser \u2014 connect Trusty Squire first";
|
|
8931
|
+
function isSquireBrowserSessionFailure(text2) {
|
|
8932
|
+
if (typeof text2 !== "string" || text2.length === 0)
|
|
8933
|
+
return false;
|
|
8934
|
+
return /Trusty Squire[\s\S]{0,80}browser/i.test(text2) || /browser[\s\S]{0,80}Trusty Squire/i.test(text2);
|
|
8524
8935
|
}
|
|
8525
|
-
function
|
|
8526
|
-
return
|
|
8936
|
+
function squireForeignClaimAction(owner) {
|
|
8937
|
+
return `Trusty Squire's browser is in use by another process (pid ${owner.pid}). Finish or close that Trusty Squire session, then press Connect again.`;
|
|
8527
8938
|
}
|
|
8528
|
-
|
|
8529
|
-
// apps/body/dist/connector-squire.js
|
|
8530
|
-
import { execFile, spawn as spawn2 } from "node:child_process";
|
|
8531
|
-
var SQUIRE_MCP_NAME = "@trusty-squire/mcp";
|
|
8532
|
-
var SQUIRE_CONNECT_PACKAGE = `${SQUIRE_MCP_NAME}@latest`;
|
|
8533
|
-
var activeConnectSession;
|
|
8534
|
-
function isProcessAlive(pid) {
|
|
8535
|
-
if (pid === void 0 || pid <= 0)
|
|
8536
|
-
return false;
|
|
8939
|
+
function readLinuxStartTime(pid) {
|
|
8537
8940
|
try {
|
|
8538
|
-
|
|
8941
|
+
const stat4 = readFileSync3(`/proc/${pid}/stat`, "utf8");
|
|
8942
|
+
const close = stat4.lastIndexOf(")");
|
|
8943
|
+
return close < 0 ? void 0 : stat4.slice(close + 2).split(" ")[19];
|
|
8944
|
+
} catch {
|
|
8945
|
+
return void 0;
|
|
8946
|
+
}
|
|
8947
|
+
}
|
|
8948
|
+
function lockOwnerIsAlive(owner) {
|
|
8949
|
+
if (!isProcessAlive(owner.pid))
|
|
8950
|
+
return false;
|
|
8951
|
+
if (owner.startTime === null || owner.startTime === "unknown")
|
|
8539
8952
|
return true;
|
|
8540
|
-
|
|
8541
|
-
|
|
8953
|
+
const actual = readLinuxStartTime(owner.pid);
|
|
8954
|
+
if (actual === void 0)
|
|
8955
|
+
return true;
|
|
8956
|
+
return actual === owner.startTime;
|
|
8957
|
+
}
|
|
8958
|
+
function readLockFileOwner(lockPath) {
|
|
8959
|
+
try {
|
|
8960
|
+
const target = lstatSync2(lockPath).isDirectory() ? join2(lockPath, "owner.json") : lockPath;
|
|
8961
|
+
const parsed = JSON.parse(readFileSync3(target, "utf8"));
|
|
8962
|
+
if (typeof parsed.host !== "string" || typeof parsed.pid !== "number")
|
|
8963
|
+
return void 0;
|
|
8964
|
+
return {
|
|
8965
|
+
host: parsed.host,
|
|
8966
|
+
pid: parsed.pid,
|
|
8967
|
+
startTime: typeof parsed.start_time === "string" ? parsed.start_time : null
|
|
8968
|
+
};
|
|
8969
|
+
} catch {
|
|
8970
|
+
return void 0;
|
|
8542
8971
|
}
|
|
8543
8972
|
}
|
|
8544
|
-
function
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8973
|
+
function removeProfileLock(lockPath) {
|
|
8974
|
+
rmSync(lockPath, { recursive: true, force: true });
|
|
8975
|
+
}
|
|
8976
|
+
function reclaimSquireProfileClaim(options) {
|
|
8977
|
+
const profileDir = options?.profileDir ?? squireChromeProfileDir();
|
|
8978
|
+
const lockRoot = options?.lockRoot ?? tmpdir2();
|
|
8979
|
+
const lockPath = squireProfileLockPath(profileDir, lockRoot);
|
|
8980
|
+
const owner = readLockFileOwner(lockPath);
|
|
8981
|
+
if (!owner) {
|
|
8982
|
+
return { kind: "free" };
|
|
8983
|
+
}
|
|
8984
|
+
const ours = (options?.ourPids ?? []).includes(owner.pid);
|
|
8985
|
+
if (ours) {
|
|
8986
|
+
removeProfileLock(lockPath);
|
|
8987
|
+
options?.log?.(`released our trusty-squire on-disk browser claim (pid ${owner.pid})`);
|
|
8988
|
+
return { kind: "released-ours", owner };
|
|
8989
|
+
}
|
|
8990
|
+
if (owner.host !== hostname() || lockOwnerIsAlive(owner)) {
|
|
8991
|
+
const action = squireForeignClaimAction(owner);
|
|
8992
|
+
options?.log?.(`trusty-squire browser claim blocked by live pid ${owner.pid} \u2014 not superseding a foreign session`);
|
|
8993
|
+
return { kind: "blocked-foreign", owner, action };
|
|
8554
8994
|
}
|
|
8995
|
+
removeProfileLock(lockPath);
|
|
8996
|
+
options?.log?.(`cleared dead trusty-squire on-disk browser claim (pid ${owner.pid} gone)`);
|
|
8997
|
+
return { kind: "reclaimed-dead", owner };
|
|
8555
8998
|
}
|
|
8556
|
-
var defaultShellRunner = (command, args) => new Promise((
|
|
8999
|
+
var defaultShellRunner = (command, args) => new Promise((resolve32) => {
|
|
8557
9000
|
execFile(command, [...args], { timeout: 12e4, maxBuffer: 4 * 1024 * 1024, encoding: "utf8" }, (error, stdout6, stderr) => {
|
|
8558
9001
|
const code = error?.code;
|
|
8559
|
-
|
|
9002
|
+
resolve32({
|
|
8560
9003
|
code: typeof code === "number" ? code : error ? 1 : 0,
|
|
8561
9004
|
stdout: String(stdout6 ?? ""),
|
|
8562
9005
|
stderr: String(stderr ?? "")
|
|
8563
9006
|
});
|
|
8564
9007
|
});
|
|
8565
9008
|
});
|
|
9009
|
+
function squireConnectProcessEnv(profileDir = squireChromeProfileDir()) {
|
|
9010
|
+
return {
|
|
9011
|
+
...process.env,
|
|
9012
|
+
TRUSTY_SQUIRE_PROFILE_DIR: profileDir
|
|
9013
|
+
};
|
|
9014
|
+
}
|
|
8566
9015
|
var CONNECT_TIMEOUT_MS = 3e5;
|
|
8567
|
-
|
|
8568
|
-
const
|
|
8569
|
-
|
|
9016
|
+
function killConnectTree(child) {
|
|
9017
|
+
const pid = child.pid;
|
|
9018
|
+
if (pid !== void 0) {
|
|
9019
|
+
try {
|
|
9020
|
+
process.kill(-pid, "SIGTERM");
|
|
9021
|
+
} catch {
|
|
9022
|
+
}
|
|
9023
|
+
}
|
|
9024
|
+
child.kill();
|
|
9025
|
+
}
|
|
9026
|
+
var defaultStreamedRunner = (command, args, env) => new Promise((resolve32) => {
|
|
9027
|
+
const child = spawn4(command, args, {
|
|
9028
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
9029
|
+
env: env ?? squireConnectProcessEnv(),
|
|
9030
|
+
detached: true
|
|
8570
9031
|
});
|
|
8571
9032
|
let stdout6 = "";
|
|
8572
9033
|
let stderr = "";
|
|
@@ -8574,14 +9035,14 @@ var defaultStreamedRunner = (command, args) => new Promise((resolve31) => {
|
|
|
8574
9035
|
const safetyTimer = setTimeout(() => {
|
|
8575
9036
|
if (!resolved) {
|
|
8576
9037
|
resolved = true;
|
|
8577
|
-
|
|
9038
|
+
resolve32({ stdout: stdout6, stderr, pid: child.pid ?? void 0, signIn: void 0, abort: () => {
|
|
8578
9039
|
} });
|
|
8579
9040
|
}
|
|
8580
|
-
child
|
|
9041
|
+
killConnectTree(child);
|
|
8581
9042
|
}, CONNECT_TIMEOUT_MS);
|
|
8582
9043
|
const abort = () => {
|
|
8583
9044
|
clearTimeout(safetyTimer);
|
|
8584
|
-
child
|
|
9045
|
+
killConnectTree(child);
|
|
8585
9046
|
};
|
|
8586
9047
|
const claim = {
|
|
8587
9048
|
pid: child.pid ?? void 0,
|
|
@@ -8593,7 +9054,7 @@ var defaultStreamedRunner = (command, args) => new Promise((resolve31) => {
|
|
|
8593
9054
|
if (!resolved) {
|
|
8594
9055
|
resolved = true;
|
|
8595
9056
|
clearTimeout(safetyTimer);
|
|
8596
|
-
|
|
9057
|
+
resolve32(result);
|
|
8597
9058
|
}
|
|
8598
9059
|
};
|
|
8599
9060
|
const checkOutput = () => {
|
|
@@ -8621,7 +9082,7 @@ ${stderr}`;
|
|
|
8621
9082
|
} });
|
|
8622
9083
|
});
|
|
8623
9084
|
});
|
|
8624
|
-
var
|
|
9085
|
+
var step = (label, status, reason) => ({
|
|
8625
9086
|
label,
|
|
8626
9087
|
status,
|
|
8627
9088
|
...reason ? { reason } : {}
|
|
@@ -8685,142 +9146,311 @@ function parseSignedInAs(output) {
|
|
|
8685
9146
|
return output.match(/signed in as ([^\s,;]+)/i)?.[1];
|
|
8686
9147
|
}
|
|
8687
9148
|
async function installSquire(options) {
|
|
9149
|
+
const profileDir = options.profileDir ?? squireChromeProfileDir();
|
|
9150
|
+
const lockRoot = options.lockRoot ?? tmpdir2();
|
|
8688
9151
|
const run2 = options.run ?? defaultShellRunner;
|
|
8689
9152
|
const streamRun = options.streamRun ?? defaultStreamedRunner;
|
|
8690
9153
|
const log2 = options.log ?? (() => {
|
|
8691
9154
|
});
|
|
9155
|
+
const steps = [step("helper reached", "done")];
|
|
9156
|
+
const emit = () => options.onProgress?.([...steps]);
|
|
9157
|
+
const push = (next) => {
|
|
9158
|
+
steps.push(next);
|
|
9159
|
+
emit();
|
|
9160
|
+
};
|
|
9161
|
+
const fail = (reason) => {
|
|
9162
|
+
steps.push(step("waiting for sign-in", "pending"));
|
|
9163
|
+
emit();
|
|
9164
|
+
return { status: "error", steps, errorMessage: reason };
|
|
9165
|
+
};
|
|
9166
|
+
emit();
|
|
9167
|
+
const previousPid = squireConnectSession()?.pid;
|
|
9168
|
+
releaseSquireConnectSession(log2);
|
|
9169
|
+
const claim = reclaimSquireProfileClaim({
|
|
9170
|
+
log: log2,
|
|
9171
|
+
profileDir,
|
|
9172
|
+
lockRoot,
|
|
9173
|
+
...previousPid !== void 0 ? { ourPids: [previousPid] } : {}
|
|
9174
|
+
});
|
|
9175
|
+
if (claim.kind === "blocked-foreign") {
|
|
9176
|
+
push(step("trusty-squire installed", "failed", claim.action));
|
|
9177
|
+
return fail(claim.action);
|
|
9178
|
+
}
|
|
9179
|
+
const resolution = await resolveSquireConnectSpec(run2);
|
|
9180
|
+
if (resolution.reResolved) {
|
|
9181
|
+
log2(`trusty-squire stale copy ${resolution.resolvedVersion ?? "unknown"} re-resolved against current release ${resolution.currentRelease}`);
|
|
9182
|
+
}
|
|
9183
|
+
const install = await streamRun("npx", [
|
|
9184
|
+
...resolution.npxArgs,
|
|
9185
|
+
"connect",
|
|
9186
|
+
"--force-relogin=google",
|
|
9187
|
+
"--target=codex",
|
|
9188
|
+
"--skip-browser"
|
|
9189
|
+
], squireConnectProcessEnv(profileDir));
|
|
9190
|
+
if (!install.signIn) {
|
|
9191
|
+
const stderr = install.stderr.trim();
|
|
9192
|
+
let stepReason = stderr || "connect printed no sign-in URL";
|
|
9193
|
+
let failReason = stderr || "the trusty-squire connect command printed no sign-in surface";
|
|
9194
|
+
if (isSquireBrowserSessionFailure(stderr)) {
|
|
9195
|
+
const again = reclaimSquireProfileClaim({ log: log2, profileDir, lockRoot });
|
|
9196
|
+
if (again.kind === "blocked-foreign") {
|
|
9197
|
+
stepReason = again.action;
|
|
9198
|
+
failReason = again.action;
|
|
9199
|
+
}
|
|
9200
|
+
}
|
|
9201
|
+
push(step("trusty-squire installed", "failed", stepReason));
|
|
9202
|
+
return fail(failReason);
|
|
9203
|
+
}
|
|
9204
|
+
const version = resolution.resolvedVersion;
|
|
9205
|
+
push(step(`trusty-squire${version ? ` ${version}` : ""} installed`, "done"));
|
|
9206
|
+
const signIn = install.signIn;
|
|
9207
|
+
const signedInAs = parseSignedInAs(`${install.stdout}
|
|
9208
|
+
${install.stderr}`);
|
|
9209
|
+
push(step("waiting for sign-in", "done"));
|
|
9210
|
+
const pair = await pairSquire(options.mcp, options.workspaceId);
|
|
9211
|
+
if (!pair.ok) {
|
|
9212
|
+
push(step("paired to workspace", "failed", pair.reason));
|
|
9213
|
+
return {
|
|
9214
|
+
status: "installing",
|
|
9215
|
+
steps,
|
|
9216
|
+
signIn,
|
|
9217
|
+
...version ? { squireVersion: version } : {},
|
|
9218
|
+
...signedInAs ? { signedInAs } : {}
|
|
9219
|
+
};
|
|
9220
|
+
}
|
|
9221
|
+
push(step("paired to workspace", "done"));
|
|
9222
|
+
return {
|
|
9223
|
+
status: "connected",
|
|
9224
|
+
steps,
|
|
9225
|
+
signIn,
|
|
9226
|
+
...version ? { squireVersion: version } : {},
|
|
9227
|
+
...signedInAs ? { signedInAs } : {}
|
|
9228
|
+
};
|
|
9229
|
+
}
|
|
9230
|
+
async function pairSquire(mcp, _workspaceId) {
|
|
9231
|
+
if (!mcp)
|
|
9232
|
+
return { ok: false, reason: "the Squire MCP surface is not mounted on this helper" };
|
|
9233
|
+
try {
|
|
9234
|
+
await mcp.call("list_credentials", { fields: "summary" });
|
|
9235
|
+
return { ok: true };
|
|
9236
|
+
} catch (error) {
|
|
9237
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
9238
|
+
}
|
|
9239
|
+
}
|
|
9240
|
+
function asRecord2(value) {
|
|
9241
|
+
return value && typeof value === "object" ? value : {};
|
|
9242
|
+
}
|
|
9243
|
+
function asArray(value) {
|
|
9244
|
+
return Array.isArray(value) ? value : [];
|
|
9245
|
+
}
|
|
9246
|
+
function stringList(value) {
|
|
9247
|
+
return asArray(value).filter((entry) => typeof entry === "string");
|
|
9248
|
+
}
|
|
9249
|
+
function numberOrNull(value) {
|
|
9250
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
9251
|
+
}
|
|
9252
|
+
function vaultConnectionMeta(raw) {
|
|
9253
|
+
const record3 = asRecord2(raw);
|
|
9254
|
+
const reference = String(record3.reference ?? record3.id ?? "");
|
|
9255
|
+
return {
|
|
9256
|
+
reference,
|
|
9257
|
+
service: typeof record3.service === "string" ? record3.service : null,
|
|
9258
|
+
label: String(record3.label ?? record3.service ?? reference),
|
|
9259
|
+
fieldNames: stringList(record3.field_names ?? record3.fieldNames),
|
|
9260
|
+
allowedHosts: stringList(record3.allowed_hosts ?? record3.allowedHosts ?? record3.login_hosts),
|
|
9261
|
+
createdAt: numberOrNull(record3.created_at ?? record3.createdAt) ?? 0,
|
|
9262
|
+
stale: record3.stale === true,
|
|
9263
|
+
state: record3.state === "error" ? "error" : "active"
|
|
9264
|
+
};
|
|
9265
|
+
}
|
|
9266
|
+
async function readVault(mcp) {
|
|
9267
|
+
const result = asRecord2(await mcp.call("list_credentials"));
|
|
9268
|
+
return asArray(result.credentials ?? result.items ?? result).map(vaultConnectionMeta);
|
|
9269
|
+
}
|
|
9270
|
+
function connectionGrant(raw) {
|
|
9271
|
+
const record3 = asRecord2(raw);
|
|
9272
|
+
return {
|
|
9273
|
+
grantId: String(record3.grant_id ?? record3.grantId ?? record3.id ?? ""),
|
|
9274
|
+
credentialRef: String(record3.credential_ref ?? record3.credentialRef ?? record3.reference ?? ""),
|
|
9275
|
+
createdAt: numberOrNull(record3.created_at ?? record3.createdAt) ?? 0,
|
|
9276
|
+
...numberOrNull(record3.revoked_at ?? record3.revokedAt) !== null ? { revokedAt: numberOrNull(record3.revoked_at ?? record3.revokedAt) } : {},
|
|
9277
|
+
...numberOrNull(record3.rate_limit_per_hour) !== null ? { rateLimitPerHour: numberOrNull(record3.rate_limit_per_hour) } : {},
|
|
9278
|
+
...numberOrNull(record3.spend_cap_usd) !== null ? { spendCapUsd: numberOrNull(record3.spend_cap_usd) } : {}
|
|
9279
|
+
};
|
|
9280
|
+
}
|
|
9281
|
+
async function readGrants(mcp, ref) {
|
|
9282
|
+
const result = asRecord2(await mcp.call("list_app_access", {}));
|
|
9283
|
+
return asArray(result.grants ?? result.items ?? result).map(connectionGrant).filter((grant) => grant.credentialRef === ref && grant.revokedAt === void 0);
|
|
9284
|
+
}
|
|
9285
|
+
async function revokeGrants(mcp, ref) {
|
|
9286
|
+
const grants = await readGrants(mcp, ref);
|
|
9287
|
+
let revoked = 0;
|
|
9288
|
+
let failed = 0;
|
|
9289
|
+
for (const grant of grants) {
|
|
9290
|
+
try {
|
|
9291
|
+
const result = asRecord2(await mcp.call("revoke_app_access", { grant_id: grant.grantId }));
|
|
9292
|
+
if (result.revoked === false)
|
|
9293
|
+
failed += 1;
|
|
9294
|
+
else
|
|
9295
|
+
revoked += 1;
|
|
9296
|
+
} catch {
|
|
9297
|
+
failed += 1;
|
|
9298
|
+
}
|
|
9299
|
+
}
|
|
9300
|
+
return { revoked, failed };
|
|
9301
|
+
}
|
|
9302
|
+
|
|
9303
|
+
// apps/body/dist/connector-google.js
|
|
9304
|
+
var GOOGLE_TOOL_SCOPES = {
|
|
9305
|
+
"google-gmail": [
|
|
9306
|
+
"https://www.googleapis.com/auth/gmail.send",
|
|
9307
|
+
"https://www.googleapis.com/auth/gmail.readonly",
|
|
9308
|
+
"https://www.googleapis.com/auth/gmail.compose"
|
|
9309
|
+
],
|
|
9310
|
+
"google-calendar": ["https://www.googleapis.com/auth/calendar.events", "https://www.googleapis.com/auth/calendar.readonly"],
|
|
9311
|
+
"google-drive": ["https://www.googleapis.com/auth/drive.readonly"],
|
|
9312
|
+
"google-youtube": ["https://www.googleapis.com/auth/youtube.readonly"]
|
|
9313
|
+
};
|
|
9314
|
+
function isGoogleToolConnectorType(type) {
|
|
9315
|
+
return type in GOOGLE_TOOL_SCOPES;
|
|
9316
|
+
}
|
|
9317
|
+
async function readGoogleCredentialsFromVault(mcp) {
|
|
9318
|
+
if (!mcp)
|
|
9319
|
+
return { source: "unavailable", reason: "no Trusty Squire connector is paired" };
|
|
9320
|
+
let raw;
|
|
9321
|
+
try {
|
|
9322
|
+
raw = await mcp.call("google_oauth_credentials", {});
|
|
9323
|
+
} catch (error) {
|
|
9324
|
+
const detail = describe(error);
|
|
9325
|
+
if (isSquireBrowserSessionFailure(detail)) {
|
|
9326
|
+
return {
|
|
9327
|
+
source: "unavailable",
|
|
9328
|
+
reason: SQUIRE_BROWSER_BUSY_GOOGLE_REASON
|
|
9329
|
+
};
|
|
9330
|
+
}
|
|
9331
|
+
return {
|
|
9332
|
+
source: "unavailable",
|
|
9333
|
+
reason: `Squire has no Google OAuth grant on record yet (connect your Google account in Squire first: ${detail})`
|
|
9334
|
+
};
|
|
9335
|
+
}
|
|
9336
|
+
const record3 = raw && typeof raw === "object" ? raw : {};
|
|
9337
|
+
const inner = record3.credentials && typeof record3.credentials === "object" ? record3.credentials : record3;
|
|
9338
|
+
const accessToken = inner.accessToken ?? inner.access_token;
|
|
9339
|
+
if (!accessToken || typeof accessToken !== "string") {
|
|
9340
|
+
return { source: "unavailable", reason: "Squire returned a Google grant without an access token" };
|
|
9341
|
+
}
|
|
9342
|
+
return {
|
|
9343
|
+
source: "squire",
|
|
9344
|
+
credentials: {
|
|
9345
|
+
accessToken,
|
|
9346
|
+
refreshToken: typeof record3.refreshToken === "string" ? record3.refreshToken : typeof record3.refresh_token === "string" ? record3.refresh_token : void 0,
|
|
9347
|
+
expiresAt: typeof record3.expiresAt === "number" ? record3.expiresAt : void 0,
|
|
9348
|
+
accountEmail: typeof record3.accountEmail === "string" ? record3.accountEmail : typeof record3.email === "string" ? record3.email : void 0
|
|
9349
|
+
}
|
|
9350
|
+
};
|
|
9351
|
+
}
|
|
9352
|
+
function manualGoogleCredentialsSearchPaths(home) {
|
|
9353
|
+
return [join3(home, "google-credentials.json")];
|
|
9354
|
+
}
|
|
9355
|
+
function loadManualGoogleCredentials(home, env = process.env) {
|
|
9356
|
+
if (env.BEELINE_GOOGLE_ACCESS_TOKEN) {
|
|
9357
|
+
return {
|
|
9358
|
+
source: "manual",
|
|
9359
|
+
credentials: { accessToken: env.BEELINE_GOOGLE_ACCESS_TOKEN }
|
|
9360
|
+
};
|
|
9361
|
+
}
|
|
9362
|
+
for (const path of manualGoogleCredentialsSearchPaths(home)) {
|
|
9363
|
+
try {
|
|
9364
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
9365
|
+
if (typeof parsed.accessToken === "string" || typeof parsed.access_token === "string") {
|
|
9366
|
+
return {
|
|
9367
|
+
source: "manual",
|
|
9368
|
+
credentials: {
|
|
9369
|
+
accessToken: parsed.accessToken ?? parsed.access_token,
|
|
9370
|
+
refreshToken: typeof parsed.refreshToken === "string" ? parsed.refreshToken : void 0,
|
|
9371
|
+
accountEmail: typeof parsed.accountEmail === "string" ? parsed.accountEmail : void 0
|
|
9372
|
+
}
|
|
9373
|
+
};
|
|
9374
|
+
}
|
|
9375
|
+
} catch {
|
|
9376
|
+
}
|
|
9377
|
+
}
|
|
9378
|
+
return {
|
|
9379
|
+
source: "manual-missing",
|
|
9380
|
+
reason: `no Google credentials found. Put a google-credentials.json (OAuth access token) at ${manualGoogleCredentialsSearchPaths(home)[0]} or connect your Google account in Trusty Squire first.`
|
|
9381
|
+
};
|
|
9382
|
+
}
|
|
9383
|
+
var step2 = (label, status, extra) => ({
|
|
9384
|
+
label,
|
|
9385
|
+
status,
|
|
9386
|
+
...extra
|
|
9387
|
+
});
|
|
9388
|
+
function outputTail(text2, maxChars = 800) {
|
|
9389
|
+
const trimmed = text2.trim();
|
|
9390
|
+
return trimmed.length <= maxChars ? trimmed : `\u2026${trimmed.slice(-maxChars)}`;
|
|
9391
|
+
}
|
|
9392
|
+
async function installGoogleTool(options) {
|
|
8692
9393
|
const steps = [step2("helper reached", "done")];
|
|
8693
9394
|
const emit = () => options.onProgress?.([...steps]);
|
|
8694
9395
|
const push = (next) => {
|
|
8695
9396
|
steps.push(next);
|
|
8696
9397
|
emit();
|
|
8697
9398
|
};
|
|
8698
|
-
const fail = (reason) => {
|
|
8699
|
-
|
|
8700
|
-
emit();
|
|
9399
|
+
const fail = (label, reason, output) => {
|
|
9400
|
+
push(step2(label, "failed", { reason, ...output ? { output } : {} }));
|
|
8701
9401
|
return { status: "error", steps, errorMessage: reason };
|
|
8702
9402
|
};
|
|
8703
9403
|
emit();
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
if (resolution.reResolved) {
|
|
8707
|
-
log2(`trusty-squire stale copy ${resolution.resolvedVersion ?? "unknown"} re-resolved against current release ${resolution.currentRelease}`);
|
|
9404
|
+
if (!isGoogleToolConnectorType(options.connectorType)) {
|
|
9405
|
+
return fail("connector type", `${options.connectorType} is not a Google tool connector`);
|
|
8708
9406
|
}
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
"
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
9407
|
+
push(step2("Google credentials resolved", "running", { output: "resolving\u2026" }));
|
|
9408
|
+
const resolved = options.resolvedCredentials ? await options.resolvedCredentials : options.resolveCredentials ? await options.resolveCredentials() : await (async () => {
|
|
9409
|
+
const oneClick = await readGoogleCredentialsFromVault(options.squire);
|
|
9410
|
+
if (oneClick.source === "squire")
|
|
9411
|
+
return oneClick;
|
|
9412
|
+
if (isSquireBrowserSessionFailure(oneClick.reason))
|
|
9413
|
+
return oneClick;
|
|
9414
|
+
return loadManualGoogleCredentials(options.home, options.env);
|
|
9415
|
+
})();
|
|
9416
|
+
if (!("credentials" in resolved)) {
|
|
9417
|
+
const reason = resolved.reason;
|
|
9418
|
+
steps[1] = step2("Google credentials resolved", "failed", { reason, output: outputTail(reason) });
|
|
9419
|
+
emit();
|
|
9420
|
+
return { status: "error", steps, errorMessage: reason };
|
|
8720
9421
|
}
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
push(step2("
|
|
8727
|
-
const
|
|
8728
|
-
if (!
|
|
8729
|
-
|
|
8730
|
-
return {
|
|
8731
|
-
status: "installing",
|
|
8732
|
-
steps,
|
|
8733
|
-
signIn,
|
|
8734
|
-
...version ? { squireVersion: version } : {},
|
|
8735
|
-
...signedInAs ? { signedInAs } : {}
|
|
8736
|
-
};
|
|
9422
|
+
steps[1] = step2("Google credentials resolved", "done", {
|
|
9423
|
+
output: resolved.source === "squire" ? "one-click: read the Google grant from Trusty Squire" : "manual: local google-credentials.json"
|
|
9424
|
+
});
|
|
9425
|
+
emit();
|
|
9426
|
+
const client = options.client ?? googleWorkspaceClient(credentialsTokenSource(resolved.credentials));
|
|
9427
|
+
push(step2("authorized with Google", "running", { output: "verifying the grant with Google\u2026" }));
|
|
9428
|
+
const verify = await client.verify();
|
|
9429
|
+
if (!verify.ok) {
|
|
9430
|
+
return fail("authorized with Google", verify.reason, outputTail(verify.reason));
|
|
8737
9431
|
}
|
|
8738
|
-
|
|
9432
|
+
steps[2] = step2("authorized with Google", "done", {
|
|
9433
|
+
...verify.account ? { output: `signed in as ${verify.account}` } : {}
|
|
9434
|
+
});
|
|
9435
|
+
emit();
|
|
9436
|
+
push(step2("tools enabled", "done", {
|
|
9437
|
+
output: `${GOOGLE_TOOL_SCOPES[options.connectorType].length} Google scopes granted`
|
|
9438
|
+
}));
|
|
8739
9439
|
return {
|
|
8740
9440
|
status: "connected",
|
|
8741
9441
|
steps,
|
|
8742
|
-
|
|
8743
|
-
...version ? { squireVersion: version } : {},
|
|
8744
|
-
...signedInAs ? { signedInAs } : {}
|
|
8745
|
-
};
|
|
8746
|
-
}
|
|
8747
|
-
async function pairSquire(mcp, _workspaceId) {
|
|
8748
|
-
if (!mcp)
|
|
8749
|
-
return { ok: false, reason: "the Squire MCP surface is not mounted on this helper" };
|
|
8750
|
-
try {
|
|
8751
|
-
await mcp.call("list_credentials", { fields: "summary" });
|
|
8752
|
-
return { ok: true };
|
|
8753
|
-
} catch (error) {
|
|
8754
|
-
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
8755
|
-
}
|
|
8756
|
-
}
|
|
8757
|
-
function asRecord(value) {
|
|
8758
|
-
return value && typeof value === "object" ? value : {};
|
|
8759
|
-
}
|
|
8760
|
-
function asArray(value) {
|
|
8761
|
-
return Array.isArray(value) ? value : [];
|
|
8762
|
-
}
|
|
8763
|
-
function stringList(value) {
|
|
8764
|
-
return asArray(value).filter((entry) => typeof entry === "string");
|
|
8765
|
-
}
|
|
8766
|
-
function numberOrNull(value) {
|
|
8767
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
8768
|
-
}
|
|
8769
|
-
function vaultConnectionMeta(raw) {
|
|
8770
|
-
const record3 = asRecord(raw);
|
|
8771
|
-
const reference = String(record3.reference ?? record3.id ?? "");
|
|
8772
|
-
return {
|
|
8773
|
-
reference,
|
|
8774
|
-
service: typeof record3.service === "string" ? record3.service : null,
|
|
8775
|
-
label: String(record3.label ?? record3.service ?? reference),
|
|
8776
|
-
fieldNames: stringList(record3.field_names ?? record3.fieldNames),
|
|
8777
|
-
allowedHosts: stringList(record3.allowed_hosts ?? record3.allowedHosts ?? record3.login_hosts),
|
|
8778
|
-
createdAt: numberOrNull(record3.created_at ?? record3.createdAt) ?? 0,
|
|
8779
|
-
stale: record3.stale === true,
|
|
8780
|
-
state: record3.state === "error" ? "error" : "active"
|
|
8781
|
-
};
|
|
8782
|
-
}
|
|
8783
|
-
async function readVault(mcp) {
|
|
8784
|
-
const result = asRecord(await mcp.call("list_credentials"));
|
|
8785
|
-
return asArray(result.credentials ?? result.items ?? result).map(vaultConnectionMeta);
|
|
8786
|
-
}
|
|
8787
|
-
function connectionGrant(raw) {
|
|
8788
|
-
const record3 = asRecord(raw);
|
|
8789
|
-
return {
|
|
8790
|
-
grantId: String(record3.grant_id ?? record3.grantId ?? record3.id ?? ""),
|
|
8791
|
-
credentialRef: String(record3.credential_ref ?? record3.credentialRef ?? record3.reference ?? ""),
|
|
8792
|
-
createdAt: numberOrNull(record3.created_at ?? record3.createdAt) ?? 0,
|
|
8793
|
-
...numberOrNull(record3.revoked_at ?? record3.revokedAt) !== null ? { revokedAt: numberOrNull(record3.revoked_at ?? record3.revokedAt) } : {},
|
|
8794
|
-
...numberOrNull(record3.rate_limit_per_hour) !== null ? { rateLimitPerHour: numberOrNull(record3.rate_limit_per_hour) } : {},
|
|
8795
|
-
...numberOrNull(record3.spend_cap_usd) !== null ? { spendCapUsd: numberOrNull(record3.spend_cap_usd) } : {}
|
|
9442
|
+
...verify.account ? { signedInAs: verify.account } : {}
|
|
8796
9443
|
};
|
|
8797
9444
|
}
|
|
8798
|
-
|
|
8799
|
-
|
|
8800
|
-
return asArray(result.grants ?? result.items ?? result).map(connectionGrant).filter((grant) => grant.credentialRef === ref && grant.revokedAt === void 0);
|
|
8801
|
-
}
|
|
8802
|
-
async function revokeGrants(mcp, ref) {
|
|
8803
|
-
const grants = await readGrants(mcp, ref);
|
|
8804
|
-
let revoked = 0;
|
|
8805
|
-
let failed = 0;
|
|
8806
|
-
for (const grant of grants) {
|
|
8807
|
-
try {
|
|
8808
|
-
const result = asRecord(await mcp.call("revoke_app_access", { grant_id: grant.grantId }));
|
|
8809
|
-
if (result.revoked === false)
|
|
8810
|
-
failed += 1;
|
|
8811
|
-
else
|
|
8812
|
-
revoked += 1;
|
|
8813
|
-
} catch {
|
|
8814
|
-
failed += 1;
|
|
8815
|
-
}
|
|
8816
|
-
}
|
|
8817
|
-
return { revoked, failed };
|
|
9445
|
+
function describe(error) {
|
|
9446
|
+
return error instanceof Error ? error.message : String(error);
|
|
8818
9447
|
}
|
|
8819
9448
|
|
|
8820
9449
|
// apps/body/dist/squire-mcp-client.js
|
|
8821
|
-
import { spawn as
|
|
9450
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
8822
9451
|
var INITIALIZE_TIMEOUT_MS = 3e4;
|
|
8823
9452
|
var CALL_TIMEOUT_MS = 12e4;
|
|
9453
|
+
var SQUIRE_MCP_SERVER_ARGS = ["-y", "@trusty-squire/mcp@latest", "server"];
|
|
8824
9454
|
var StdioSquireMcpClient = class {
|
|
8825
9455
|
options;
|
|
8826
9456
|
child;
|
|
@@ -8874,12 +9504,7 @@ var StdioSquireMcpClient = class {
|
|
|
8874
9504
|
return this.initialized;
|
|
8875
9505
|
}
|
|
8876
9506
|
initialize() {
|
|
8877
|
-
const child = (this.options.spawn ??
|
|
8878
|
-
// `@latest`: the current release, never a source-level version pin
|
|
8879
|
-
// (captain). Only the vault MCP server the agent spawns; the connect
|
|
8880
|
-
// install path verifies freshness itself (connector-squire.ts).
|
|
8881
|
-
...this.options.args ?? ["-y", "@trusty-squire/mcp@latest"]
|
|
8882
|
-
]);
|
|
9507
|
+
const child = (this.options.spawn ?? spawn5)(this.options.command ?? "npx", [...this.options.args ?? [...SQUIRE_MCP_SERVER_ARGS]], { env: this.options.env ?? squireConnectProcessEnv() });
|
|
8883
9508
|
this.child = child;
|
|
8884
9509
|
this.buffer = "";
|
|
8885
9510
|
child.stdout.setEncoding("utf8");
|
|
@@ -8913,12 +9538,12 @@ var StdioSquireMcpClient = class {
|
|
|
8913
9538
|
const child = this.child;
|
|
8914
9539
|
if (!child)
|
|
8915
9540
|
return Promise.reject(new Error("Squire MCP session is not running"));
|
|
8916
|
-
return new Promise((
|
|
9541
|
+
return new Promise((resolve32, reject) => {
|
|
8917
9542
|
const timer = setTimeout(() => {
|
|
8918
9543
|
this.pending.delete(id);
|
|
8919
9544
|
reject(new Error(`${method} timed out`));
|
|
8920
9545
|
}, method === "initialize" ? INITIALIZE_TIMEOUT_MS : CALL_TIMEOUT_MS);
|
|
8921
|
-
this.pending.set(id, { resolve:
|
|
9546
|
+
this.pending.set(id, { resolve: resolve32, reject, timer });
|
|
8922
9547
|
child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}
|
|
8923
9548
|
`);
|
|
8924
9549
|
});
|
|
@@ -9034,6 +9659,7 @@ var ConnectorAssignmentLoop = class {
|
|
|
9034
9659
|
this.log(`connector assignments unavailable: ${describe2(error)}`);
|
|
9035
9660
|
return;
|
|
9036
9661
|
}
|
|
9662
|
+
const squireWork = [];
|
|
9037
9663
|
let googleBatch;
|
|
9038
9664
|
for (const assignment of assignments) {
|
|
9039
9665
|
const key = `${assignment.kind}:${assignment.connectorId}`;
|
|
@@ -9049,17 +9675,15 @@ var ConnectorAssignmentLoop = class {
|
|
|
9049
9675
|
if (this.inFlight.has(key))
|
|
9050
9676
|
continue;
|
|
9051
9677
|
this.inFlight.add(key);
|
|
9052
|
-
|
|
9678
|
+
squireWork.push(this.handle(assignment).catch((error) => this.log(`connector assignment ${key} failed: ${describe2(error)}`)).finally(() => this.inFlight.delete(key)));
|
|
9679
|
+
}
|
|
9680
|
+
if (googleBatch) {
|
|
9681
|
+
const keys = googleBatch.map((assignment) => `${assignment.kind}:${assignment.connectorId}`);
|
|
9682
|
+
void Promise.all(squireWork).then(() => this.runGoogleBatch(googleBatch)).catch((error) => this.log(`google connector installs failed: ${describe2(error)}`)).finally(() => {
|
|
9683
|
+
for (const key of keys)
|
|
9684
|
+
this.inFlight.delete(key);
|
|
9685
|
+
});
|
|
9053
9686
|
}
|
|
9054
|
-
if (googleBatch)
|
|
9055
|
-
this.flushGoogleBatch(googleBatch);
|
|
9056
|
-
}
|
|
9057
|
-
flushGoogleBatch(batch) {
|
|
9058
|
-
const keys = batch.map((a2) => `${a2.kind}:${a2.connectorId}`);
|
|
9059
|
-
void this.runGoogleBatch(batch).catch((error) => this.log(`google connector installs failed: ${describe2(error)}`)).finally(() => {
|
|
9060
|
-
for (const key of keys)
|
|
9061
|
-
this.inFlight.delete(key);
|
|
9062
|
-
});
|
|
9063
9687
|
}
|
|
9064
9688
|
/** The Google tool connectors ride ONE grant: every install in the batch
|
|
9065
9689
|
* shares one credential resolution (the single Google consent) and the
|
|
@@ -9083,6 +9707,8 @@ var ConnectorAssignmentLoop = class {
|
|
|
9083
9707
|
const oneClick = await readGoogleCredentialsFromVault(this.squire());
|
|
9084
9708
|
if (oneClick.source === "squire")
|
|
9085
9709
|
return oneClick;
|
|
9710
|
+
if (isSquireBrowserSessionFailure(oneClick.reason))
|
|
9711
|
+
return oneClick;
|
|
9086
9712
|
} catch (error) {
|
|
9087
9713
|
this.log(`google one-click grant lookup failed: ${describe2(error)}`);
|
|
9088
9714
|
}
|
|
@@ -9227,12 +9853,13 @@ var SERVER_EVENT_KINDS = [
|
|
|
9227
9853
|
"check-failed",
|
|
9228
9854
|
"merged",
|
|
9229
9855
|
"grant-decided",
|
|
9856
|
+
"connector-offer-decided",
|
|
9230
9857
|
"turn-cancelled"
|
|
9231
9858
|
];
|
|
9232
9859
|
|
|
9233
9860
|
// apps/body/dist/daemon-api-client.js
|
|
9234
|
-
import { resolve as
|
|
9235
|
-
import { randomUUID } from "node:crypto";
|
|
9861
|
+
import { resolve as resolve8 } from "node:path";
|
|
9862
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
9236
9863
|
|
|
9237
9864
|
// node_modules/ws/wrapper.mjs
|
|
9238
9865
|
var import_stream = __toESM(require_stream(), 1);
|
|
@@ -9250,9 +9877,9 @@ import { randomBytes as randomBytes5 } from "node:crypto";
|
|
|
9250
9877
|
import { execFile as execFile2 } from "node:child_process";
|
|
9251
9878
|
import { closeSync, openSync } from "node:fs";
|
|
9252
9879
|
import { mkdir, readFile as readFile2, readdir, rename, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
9253
|
-
import { homedir as
|
|
9254
|
-
import { dirname as
|
|
9255
|
-
import { spawn as
|
|
9880
|
+
import { homedir as homedir3 } from "node:os";
|
|
9881
|
+
import { dirname as dirname3, resolve as resolve7 } from "node:path";
|
|
9882
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
9256
9883
|
import { promisify } from "node:util";
|
|
9257
9884
|
|
|
9258
9885
|
// node_modules/@noble/hashes/_u64.js
|
|
@@ -13639,7 +14266,7 @@ function alphabet(letters) {
|
|
|
13639
14266
|
};
|
|
13640
14267
|
}
|
|
13641
14268
|
// @__NO_SIDE_EFFECTS__
|
|
13642
|
-
function
|
|
14269
|
+
function join4(separator = "") {
|
|
13643
14270
|
astr("join", separator);
|
|
13644
14271
|
return {
|
|
13645
14272
|
encode: (from) => {
|
|
@@ -13769,8 +14396,8 @@ var base64 = hasBase64Builtin ? {
|
|
|
13769
14396
|
decode(s) {
|
|
13770
14397
|
return decodeBase64Builtin(s, false);
|
|
13771
14398
|
}
|
|
13772
|
-
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */
|
|
13773
|
-
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */
|
|
14399
|
+
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join4(""));
|
|
14400
|
+
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join4(""));
|
|
13774
14401
|
var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
13775
14402
|
function bech32Polymod(pre) {
|
|
13776
14403
|
const b = pre >> 25;
|
|
@@ -17788,15 +18415,15 @@ var DEFAULT_AGENT_IDENTITY_NAME = "beeline-agent";
|
|
|
17788
18415
|
var DEFAULT_BODY_IDENTITY_NAME = "beeline-body";
|
|
17789
18416
|
var DEFAULT_DAEMON_MONOLITH_BASE_URL = "https://server.usebeeline.app";
|
|
17790
18417
|
function defaultSupervisorRoot(env = process.env) {
|
|
17791
|
-
return
|
|
18418
|
+
return resolve7(env.XDG_STATE_HOME ?? resolve7(homedir3(), ".local", "state"));
|
|
17792
18419
|
}
|
|
17793
18420
|
function runtimeDirectory(supervisorRoot, publicKey) {
|
|
17794
18421
|
if (!/^[0-9a-f]{64}$/i.test(publicKey))
|
|
17795
18422
|
throw new Error("invalid agent public key");
|
|
17796
|
-
return
|
|
18423
|
+
return resolve7(supervisorRoot, "beeline", "agents", publicKey.toLowerCase());
|
|
17797
18424
|
}
|
|
17798
18425
|
function runtimeConfigPath(supervisorRoot, publicKey) {
|
|
17799
|
-
return
|
|
18426
|
+
return resolve7(runtimeDirectory(supervisorRoot, publicKey), "runtime.json");
|
|
17800
18427
|
}
|
|
17801
18428
|
function identityFromKey(value, name) {
|
|
17802
18429
|
const secretKey = value ? value.startsWith("nsec1") ? decodeNsec(value) : Uint8Array.from(Buffer.from(value, "hex")) : randomBytes5(32);
|
|
@@ -17817,7 +18444,13 @@ function runtimeIdentity(identity) {
|
|
|
17817
18444
|
throw new Error("stored identity public key mismatch");
|
|
17818
18445
|
return restored;
|
|
17819
18446
|
}
|
|
17820
|
-
function runtimeAgentCommand(runtime) {
|
|
18447
|
+
function runtimeAgentCommand(runtime, env = process.env) {
|
|
18448
|
+
if (runtime.agentKind === "cursor") {
|
|
18449
|
+
try {
|
|
18450
|
+
return resolveAgentCommand({ kind: "cursor", env });
|
|
18451
|
+
} catch {
|
|
18452
|
+
}
|
|
18453
|
+
}
|
|
17821
18454
|
return {
|
|
17822
18455
|
kind: runtime.agentKind ?? "reference",
|
|
17823
18456
|
command: runtime.agentCommand ?? runtime.agentBinary,
|
|
@@ -17826,7 +18459,7 @@ function runtimeAgentCommand(runtime) {
|
|
|
17826
18459
|
}
|
|
17827
18460
|
async function writeRuntimeRecord(runtime) {
|
|
17828
18461
|
const path = runtimeConfigPath(runtime.supervisorRoot, runtime.agent.publicKey);
|
|
17829
|
-
await mkdir(
|
|
18462
|
+
await mkdir(dirname3(path), { recursive: true, mode: 448 });
|
|
17830
18463
|
const staged = `${path}.${process.pid}.tmp`;
|
|
17831
18464
|
await writeFile2(staged, `${JSON.stringify(runtime, null, 2)}
|
|
17832
18465
|
`, { mode: 384 });
|
|
@@ -17852,7 +18485,7 @@ async function migrateRuntimeRecordAccessPolicy(path) {
|
|
|
17852
18485
|
return { runtime, migrated: true };
|
|
17853
18486
|
}
|
|
17854
18487
|
async function stageMonolithAgentRuntime(input) {
|
|
17855
|
-
const supervisorRoot = input.supervisorRoot ?
|
|
18488
|
+
const supervisorRoot = input.supervisorRoot ? resolve7(input.supervisorRoot) : defaultSupervisorRoot();
|
|
17856
18489
|
const configPath = runtimeConfigPath(supervisorRoot, input.agentIdentity.publicKey);
|
|
17857
18490
|
const configuredBaseUrl = input.monolithBaseUrl ?? DEFAULT_DAEMON_MONOLITH_BASE_URL;
|
|
17858
18491
|
const baseUrl = new URL(configuredBaseUrl).origin;
|
|
@@ -17897,9 +18530,9 @@ async function stageMonolithAgentRuntime(input) {
|
|
|
17897
18530
|
return { runtime, configPath };
|
|
17898
18531
|
}
|
|
17899
18532
|
async function runtimePaths(root) {
|
|
17900
|
-
const agents =
|
|
18533
|
+
const agents = resolve7(root, "beeline", "agents");
|
|
17901
18534
|
const entries = await readdir(agents, { withFileTypes: true }).catch(() => []);
|
|
17902
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) =>
|
|
18535
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => resolve7(agents, entry.name, "runtime.json"));
|
|
17903
18536
|
}
|
|
17904
18537
|
async function findAgentRuntimeConfigPaths(env = process.env, _cwd = process.cwd()) {
|
|
17905
18538
|
return runtimePaths(defaultSupervisorRoot(env));
|
|
@@ -17908,13 +18541,13 @@ async function findRuntimeConfigPaths(cwd = process.cwd(), env = process.env) {
|
|
|
17908
18541
|
return findAgentRuntimeConfigPaths(env, cwd);
|
|
17909
18542
|
}
|
|
17910
18543
|
async function resolveRuntimeConfigPath(path) {
|
|
17911
|
-
return
|
|
18544
|
+
return resolve7(path);
|
|
17912
18545
|
}
|
|
17913
18546
|
async function selectRuntimeConfigPaths(options) {
|
|
17914
18547
|
const hostScope = true;
|
|
17915
18548
|
const configs = await options.findHostRuntimes(options.cwd);
|
|
17916
18549
|
const requestedPubkey = options.requestedPubkey;
|
|
17917
|
-
const paths = requestedPubkey ? configs.filter((path) =>
|
|
18550
|
+
const paths = requestedPubkey ? configs.filter((path) => dirname3(path).endsWith(requestedPubkey)) : [...new Set(configs)];
|
|
17918
18551
|
if (!paths.length)
|
|
17919
18552
|
throw new Error(options.noRuntimeMessage(hostScope));
|
|
17920
18553
|
if (options.requestedPubkey && paths.length > 1)
|
|
@@ -17923,7 +18556,7 @@ async function selectRuntimeConfigPaths(options) {
|
|
|
17923
18556
|
}
|
|
17924
18557
|
async function runtimeDaemonPid(configPath) {
|
|
17925
18558
|
try {
|
|
17926
|
-
const pid = Number((await readFile2(
|
|
18559
|
+
const pid = Number((await readFile2(resolve7(dirname3(configPath), "daemon.pid"), "utf8")).trim());
|
|
17927
18560
|
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
17928
18561
|
return null;
|
|
17929
18562
|
process.kill(pid, 0);
|
|
@@ -17936,11 +18569,11 @@ async function daemonIsThisRuntime(pid, configPath) {
|
|
|
17936
18569
|
try {
|
|
17937
18570
|
const argv = (await readFile2(`/proc/${pid}/cmdline`, "utf8")).split("\0").filter(Boolean);
|
|
17938
18571
|
const flag = argv.lastIndexOf("--config");
|
|
17939
|
-
return flag > 0 && argv[flag - 1] === "daemon" &&
|
|
18572
|
+
return flag > 0 && argv[flag - 1] === "daemon" && resolve7(argv[flag + 1]) === resolve7(configPath);
|
|
17940
18573
|
} catch {
|
|
17941
18574
|
try {
|
|
17942
18575
|
const { stdout: stdout6 } = await execFileAsync("ps", ["-p", String(pid), "-o", "command="]);
|
|
17943
|
-
return stdout6.includes(" daemon ") && stdout6.includes(
|
|
18576
|
+
return stdout6.includes(" daemon ") && stdout6.includes(resolve7(configPath));
|
|
17944
18577
|
} catch {
|
|
17945
18578
|
return false;
|
|
17946
18579
|
}
|
|
@@ -17966,14 +18599,14 @@ async function stopRuntimeDaemon(path, opts = {}) {
|
|
|
17966
18599
|
throw new Error(`agent daemon ${pid} did not stop after ${timeout}ms`);
|
|
17967
18600
|
}
|
|
17968
18601
|
async function launchRuntimeDaemon(configPath, opts = {}) {
|
|
17969
|
-
const directory =
|
|
18602
|
+
const directory = dirname3(configPath);
|
|
17970
18603
|
await mkdir(directory, { recursive: true, mode: 448 });
|
|
17971
18604
|
const foreground = opts.foreground === true;
|
|
17972
|
-
const output = foreground ? "inherit" : openSync(
|
|
18605
|
+
const output = foreground ? "inherit" : openSync(resolve7(directory, "daemon.log"), "a", 384);
|
|
17973
18606
|
const entrypoint = opts.entrypoint ?? process.argv[1];
|
|
17974
18607
|
if (!entrypoint)
|
|
17975
18608
|
throw new Error("cannot resolve daemon CLI entrypoint");
|
|
17976
|
-
const child =
|
|
18609
|
+
const child = spawn6(process.execPath, [...opts.execArgv ?? [], entrypoint, "daemon", "--config", resolve7(configPath)], {
|
|
17977
18610
|
cwd: directory,
|
|
17978
18611
|
env: opts.env ?? process.env,
|
|
17979
18612
|
detached: !foreground,
|
|
@@ -17990,9 +18623,9 @@ async function launchRuntimeDaemon(configPath, opts = {}) {
|
|
|
17990
18623
|
}
|
|
17991
18624
|
async function removeAgentRuntime(runtime) {
|
|
17992
18625
|
const source = runtimeDirectory(runtime.supervisorRoot, runtime.agent.publicKey);
|
|
17993
|
-
const deletedRoot =
|
|
18626
|
+
const deletedRoot = resolve7(runtime.supervisorRoot, "beeline", "deleted-runtimes");
|
|
17994
18627
|
await mkdir(deletedRoot, { recursive: true, mode: 448 });
|
|
17995
|
-
const target =
|
|
18628
|
+
const target = resolve7(deletedRoot, `${runtime.agent.publicKey}-${Date.now()}`);
|
|
17996
18629
|
await rename(source, target);
|
|
17997
18630
|
return target;
|
|
17998
18631
|
}
|
|
@@ -18033,7 +18666,7 @@ var DaemonApiClient = class {
|
|
|
18033
18666
|
agentId;
|
|
18034
18667
|
fetchImpl;
|
|
18035
18668
|
webSocketFactory;
|
|
18036
|
-
presenceLifecycleId =
|
|
18669
|
+
presenceLifecycleId = randomUUID2();
|
|
18037
18670
|
liveSocket;
|
|
18038
18671
|
liveReconnect;
|
|
18039
18672
|
liveReconnectDelayMs = 1e3;
|
|
@@ -18227,8 +18860,8 @@ var DaemonApiClient = class {
|
|
|
18227
18860
|
};
|
|
18228
18861
|
async function activateDaemonTransport(path, fetchImpl = fetch) {
|
|
18229
18862
|
const runtime = await readRuntimeRecord(path);
|
|
18230
|
-
const expectedPath =
|
|
18231
|
-
if (
|
|
18863
|
+
const expectedPath = resolve8(runtimeDirectory(runtime.supervisorRoot, runtime.agent.publicKey), "runtime.json");
|
|
18864
|
+
if (resolve8(path) !== expectedPath) {
|
|
18232
18865
|
throw new Error(`refusing daemon token exchange outside canonical runtime path: ${path}`);
|
|
18233
18866
|
}
|
|
18234
18867
|
const transport = runtime.transport;
|
|
@@ -18268,18 +18901,18 @@ async function activateDaemonTransport(path, fetchImpl = fetch) {
|
|
|
18268
18901
|
|
|
18269
18902
|
// apps/body/dist/room-runtime.js
|
|
18270
18903
|
import { execFile as execFile6 } from "node:child_process";
|
|
18271
|
-
import { createHash as
|
|
18272
|
-
import { existsSync as
|
|
18904
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
18905
|
+
import { existsSync as existsSync5, mkdirSync } from "node:fs";
|
|
18273
18906
|
import { mkdir as mkdir13, rm as rm5 } from "node:fs/promises";
|
|
18274
|
-
import { dirname as
|
|
18907
|
+
import { dirname as dirname9, resolve as resolve21 } from "node:path";
|
|
18275
18908
|
import { promisify as promisify4 } from "node:util";
|
|
18276
18909
|
|
|
18277
18910
|
// apps/body/dist/grant-runner.js
|
|
18278
18911
|
import { execFile as execFile3 } from "node:child_process";
|
|
18279
|
-
import { createHash as
|
|
18912
|
+
import { createHash as createHash3, randomBytes as randomBytes6 } from "node:crypto";
|
|
18280
18913
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
18281
18914
|
import { createServer } from "node:http";
|
|
18282
|
-
import { dirname as
|
|
18915
|
+
import { dirname as dirname5, resolve as resolve11 } from "node:path";
|
|
18283
18916
|
|
|
18284
18917
|
// packages/api-contract/dist/agent-grants.js
|
|
18285
18918
|
var AGENT_GRANT_KINDS = ["path", "host", "secret", "device", "budget", "command"];
|
|
@@ -18502,9 +19135,9 @@ function surfaceAllows(surface, capability) {
|
|
|
18502
19135
|
|
|
18503
19136
|
// apps/body/dist/bwrap-sandbox.js
|
|
18504
19137
|
import { spawnSync } from "node:child_process";
|
|
18505
|
-
import { lstatSync as
|
|
18506
|
-
import { homedir as
|
|
18507
|
-
import { isAbsolute as isAbsolute2, relative, resolve as
|
|
19138
|
+
import { lstatSync as lstatSync3 } from "node:fs";
|
|
19139
|
+
import { homedir as homedir4 } from "node:os";
|
|
19140
|
+
import { isAbsolute as isAbsolute2, relative, resolve as resolve9 } from "node:path";
|
|
18508
19141
|
var DEFAULT_SANDBOX_POLICY = "bwrap";
|
|
18509
19142
|
function isSandboxPolicy(value) {
|
|
18510
19143
|
return value === "bwrap" || value === "off";
|
|
@@ -18536,16 +19169,16 @@ var HARNESS_HOME_STATE_DIRS = [
|
|
|
18536
19169
|
dirs: [".grok"]
|
|
18537
19170
|
},
|
|
18538
19171
|
{
|
|
18539
|
-
match:
|
|
19172
|
+
match: CURSOR_HARNESS_COMMAND,
|
|
18540
19173
|
dirs: [".cursor"]
|
|
18541
19174
|
}
|
|
18542
19175
|
];
|
|
18543
|
-
function harnessHomeStateDirs(agentCommand, home =
|
|
19176
|
+
function harnessHomeStateDirs(agentCommand, home = homedir4()) {
|
|
18544
19177
|
if (!agentCommand)
|
|
18545
19178
|
return [];
|
|
18546
19179
|
for (const { match, dirs } of HARNESS_HOME_STATE_DIRS) {
|
|
18547
19180
|
if (match.test(agentCommand))
|
|
18548
|
-
return dirs.map((dir) =>
|
|
19181
|
+
return dirs.map((dir) => resolve9(home, dir));
|
|
18549
19182
|
}
|
|
18550
19183
|
return [];
|
|
18551
19184
|
}
|
|
@@ -18557,18 +19190,18 @@ var KNOWN_CREDENTIAL_MASK_PATHS = [
|
|
|
18557
19190
|
".git-credentials",
|
|
18558
19191
|
".secrets.env"
|
|
18559
19192
|
];
|
|
18560
|
-
function credentialMaskPaths(extraPaths, home =
|
|
19193
|
+
function credentialMaskPaths(extraPaths, home = homedir4(), stat4 = (path) => {
|
|
18561
19194
|
try {
|
|
18562
|
-
const info =
|
|
19195
|
+
const info = lstatSync3(path);
|
|
18563
19196
|
return { isDirectory: info.isDirectory() };
|
|
18564
19197
|
} catch {
|
|
18565
19198
|
return void 0;
|
|
18566
19199
|
}
|
|
18567
19200
|
}, requiredPaths = []) {
|
|
18568
|
-
const required = new Set(requiredPaths.map((path) =>
|
|
19201
|
+
const required = new Set(requiredPaths.map((path) => resolve9(path)));
|
|
18569
19202
|
const candidates = [
|
|
18570
|
-
...KNOWN_CREDENTIAL_MASK_PATHS.map((entry) =>
|
|
18571
|
-
...(extraPaths ?? []).map((entry) =>
|
|
19203
|
+
...KNOWN_CREDENTIAL_MASK_PATHS.map((entry) => resolve9(home, entry)),
|
|
19204
|
+
...(extraPaths ?? []).map((entry) => resolve9(entry))
|
|
18572
19205
|
];
|
|
18573
19206
|
const seen = /* @__PURE__ */ new Set();
|
|
18574
19207
|
const masks = [];
|
|
@@ -18595,7 +19228,7 @@ function normalize(paths) {
|
|
|
18595
19228
|
for (const path of paths) {
|
|
18596
19229
|
if (!path)
|
|
18597
19230
|
continue;
|
|
18598
|
-
seen.add(
|
|
19231
|
+
seen.add(resolve9(path));
|
|
18599
19232
|
}
|
|
18600
19233
|
return Array.from(seen).sort();
|
|
18601
19234
|
}
|
|
@@ -18633,7 +19266,7 @@ function sandboxMountPlan(spec) {
|
|
|
18633
19266
|
writable,
|
|
18634
19267
|
quotaTmpfs: spec.workbench ? [
|
|
18635
19268
|
{
|
|
18636
|
-
target:
|
|
19269
|
+
target: resolve9(spec.workbench.dir),
|
|
18637
19270
|
maxBytes: spec.workbench.maxBytes,
|
|
18638
19271
|
maxInodes: spec.workbench.maxInodes,
|
|
18639
19272
|
blockGit: true
|
|
@@ -18688,7 +19321,7 @@ function buildBwrapArgv(input) {
|
|
|
18688
19321
|
for (const binding of quotaTmpfs) {
|
|
18689
19322
|
args.push("--dir", binding.target, "--size", String(binding.maxBytes), "--tmpfs", binding.target);
|
|
18690
19323
|
if (binding.blockGit)
|
|
18691
|
-
args.push("--ro-bind", "/dev/null",
|
|
19324
|
+
args.push("--ro-bind", "/dev/null", resolve9(binding.target, ".git"));
|
|
18692
19325
|
}
|
|
18693
19326
|
args.push("--chdir", input.cwd);
|
|
18694
19327
|
args.push("--die-with-parent");
|
|
@@ -18754,8 +19387,8 @@ function detectBwrapSandbox(options = {}) {
|
|
|
18754
19387
|
|
|
18755
19388
|
// apps/body/dist/provider-key-store.js
|
|
18756
19389
|
import { chmod, mkdir as mkdir2, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
18757
|
-
import { homedir as
|
|
18758
|
-
import { dirname as
|
|
19390
|
+
import { homedir as homedir5 } from "node:os";
|
|
19391
|
+
import { dirname as dirname4, resolve as resolve10 } from "node:path";
|
|
18759
19392
|
var PROVIDER_KEY_ENV_VARS = {
|
|
18760
19393
|
openrouter: "OPENROUTER_API_KEY",
|
|
18761
19394
|
openai: "OPENAI_API_KEY",
|
|
@@ -18765,8 +19398,8 @@ var PROVIDER_KEY_ENV_VARS = {
|
|
|
18765
19398
|
};
|
|
18766
19399
|
var GOOGLE_ENV_ALIAS = "GEMINI_API_KEY";
|
|
18767
19400
|
function providerKeyStorePath(env = process.env) {
|
|
18768
|
-
const configRoot = env.XDG_CONFIG_HOME?.trim() ||
|
|
18769
|
-
return
|
|
19401
|
+
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve10(homedir5(), ".config");
|
|
19402
|
+
return resolve10(configRoot, "beeline", "providers.json");
|
|
18770
19403
|
}
|
|
18771
19404
|
async function readProviderKeyStore(env = process.env) {
|
|
18772
19405
|
const path = providerKeyStorePath(env);
|
|
@@ -18789,7 +19422,7 @@ async function readSavedProviderKey(provider, env = process.env) {
|
|
|
18789
19422
|
async function saveProviderKey(provider, key, env = process.env) {
|
|
18790
19423
|
const path = providerKeyStorePath(env);
|
|
18791
19424
|
const store = { ...await readProviderKeyStore(env), [provider]: key };
|
|
18792
|
-
await mkdir2(
|
|
19425
|
+
await mkdir2(dirname4(path), { recursive: true, mode: 448 });
|
|
18793
19426
|
await writeFile3(path, `${JSON.stringify(store, null, 2)}
|
|
18794
19427
|
`, { mode: 384 });
|
|
18795
19428
|
await chmod(path, 384);
|
|
@@ -18826,7 +19459,7 @@ function operatorSecretResolver(env = process.env) {
|
|
|
18826
19459
|
if (saved)
|
|
18827
19460
|
return saved;
|
|
18828
19461
|
}
|
|
18829
|
-
const raw = await readFile4(
|
|
19462
|
+
const raw = await readFile4(resolve11(dirname5(providerKeyStorePath(env)), "secrets.json"), "utf8").catch(() => void 0);
|
|
18830
19463
|
if (!raw)
|
|
18831
19464
|
return void 0;
|
|
18832
19465
|
try {
|
|
@@ -18938,9 +19571,9 @@ var GrantCommandRunner = class {
|
|
|
18938
19571
|
...Object.fromEntries(secrets)
|
|
18939
19572
|
};
|
|
18940
19573
|
const cap = this.options.outputCapBytes ?? GRANT_COMMAND_OUTPUT_CAP_BYTES;
|
|
18941
|
-
const
|
|
19574
|
+
const spawn12 = surfaceAllows(policy.surface, "run-host-command") ? { command: argv[0], args: argv.slice(1) } : roomSandboxCommand(policy, room.cwd, argv);
|
|
18942
19575
|
const outcome = await new Promise((resolveRun) => {
|
|
18943
|
-
const child = execFile3(
|
|
19576
|
+
const child = execFile3(spawn12.command, spawn12.args, {
|
|
18944
19577
|
cwd: room.cwd,
|
|
18945
19578
|
env,
|
|
18946
19579
|
timeout: this.options.timeoutMs ?? GRANT_COMMAND_TIMEOUT_MS,
|
|
@@ -19018,7 +19651,7 @@ ${ROOM_WRITE_REFUSED_NOTE}` : outcome.output, secrets), cap);
|
|
|
19018
19651
|
if (!script || script.path !== argument.path) {
|
|
19019
19652
|
throw new Error(`${argument.path} is a script no human has read: this grant was approved without it. Ask with request_grant kind=command so the card carries what the command runs.`);
|
|
19020
19653
|
}
|
|
19021
|
-
if (
|
|
19654
|
+
if (createHash3("sha256").update(bytes).digest("hex") !== script.sha256) {
|
|
19022
19655
|
throw new Error(`${argument.path} changed after it was approved, so the approval no longer covers it. Ask with request_grant kind=command again so a human reads what runs now.`);
|
|
19023
19656
|
}
|
|
19024
19657
|
}
|
|
@@ -19028,8 +19661,8 @@ function scriptCandidates(cwd, scratch, argv) {
|
|
|
19028
19661
|
if (!argument)
|
|
19029
19662
|
return [];
|
|
19030
19663
|
const paths = [
|
|
19031
|
-
|
|
19032
|
-
...scratch ? [
|
|
19664
|
+
resolve11(cwd, argument.path),
|
|
19665
|
+
...scratch ? [resolve11(scratch, argument.path)] : []
|
|
19033
19666
|
];
|
|
19034
19667
|
return [...new Set(paths)];
|
|
19035
19668
|
}
|
|
@@ -19210,20 +19843,20 @@ function captureConnectionUsage(recorder, turn, calls) {
|
|
|
19210
19843
|
}
|
|
19211
19844
|
|
|
19212
19845
|
// apps/body/dist/server-command-intake.js
|
|
19213
|
-
import { randomUUID as
|
|
19846
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
19214
19847
|
import { mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
|
|
19215
|
-
import { tmpdir as
|
|
19216
|
-
import { dirname as
|
|
19848
|
+
import { tmpdir as tmpdir3 } from "node:os";
|
|
19849
|
+
import { dirname as dirname6, join as join5 } from "node:path";
|
|
19217
19850
|
var CommandExecutionContext = class {
|
|
19218
|
-
generationId =
|
|
19851
|
+
generationId = randomUUID3();
|
|
19219
19852
|
path;
|
|
19220
19853
|
current;
|
|
19221
19854
|
constructor(root) {
|
|
19222
|
-
this.path =
|
|
19855
|
+
this.path = join5(root ?? tmpdir3(), `beeline-command-${this.generationId}.json`);
|
|
19223
19856
|
}
|
|
19224
19857
|
async enter(command) {
|
|
19225
19858
|
this.current = command;
|
|
19226
|
-
await mkdir3(
|
|
19859
|
+
await mkdir3(dirname6(this.path), { recursive: true });
|
|
19227
19860
|
await writeFile4(this.path, JSON.stringify({
|
|
19228
19861
|
roomId: command.roomId,
|
|
19229
19862
|
requestId: command.turnRequestId,
|
|
@@ -19345,13 +19978,13 @@ async function runServerCommandIntake(options) {
|
|
|
19345
19978
|
}
|
|
19346
19979
|
}
|
|
19347
19980
|
options.onPoll?.();
|
|
19348
|
-
const reconcile = await new Promise((
|
|
19981
|
+
const reconcile = await new Promise((resolve32) => {
|
|
19349
19982
|
const done = (needed) => {
|
|
19350
19983
|
if (timer)
|
|
19351
19984
|
clearTimeout(timer);
|
|
19352
19985
|
signal?.removeEventListener("abort", aborted);
|
|
19353
19986
|
wake = void 0;
|
|
19354
|
-
|
|
19987
|
+
resolve32(needed);
|
|
19355
19988
|
};
|
|
19356
19989
|
const aborted = () => done(false);
|
|
19357
19990
|
wake = done;
|
|
@@ -19377,22 +20010,35 @@ async function runServerCommandIntake(options) {
|
|
|
19377
20010
|
|
|
19378
20011
|
// apps/body/dist/monolith-corner-turn.js
|
|
19379
20012
|
import { execFile as execFile5 } from "node:child_process";
|
|
19380
|
-
import { createHash as
|
|
20013
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
19381
20014
|
import { mkdir as mkdir12 } from "node:fs/promises";
|
|
19382
|
-
import { homedir as
|
|
19383
|
-
import { join as
|
|
20015
|
+
import { homedir as homedir8 } from "node:os";
|
|
20016
|
+
import { join as join10 } from "node:path";
|
|
19384
20017
|
import { promisify as promisify3 } from "node:util";
|
|
19385
20018
|
|
|
19386
20019
|
// apps/body/dist/agent-home.js
|
|
19387
|
-
import { existsSync as
|
|
19388
|
-
import { createHash as
|
|
20020
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "node:fs";
|
|
20021
|
+
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
19389
20022
|
import { chmod as chmod2, copyFile, lstat, mkdir as mkdir5, readFile as readFile6, readdir as readdir2, realpath, rename as rename2, rm as rm2, symlink, unlink, writeFile as writeFile6 } from "node:fs/promises";
|
|
19390
|
-
import { homedir as
|
|
19391
|
-
import { basename as
|
|
20023
|
+
import { homedir as homedir6 } from "node:os";
|
|
20024
|
+
import { basename as basename4, dirname as dirname7, join as join6, relative as relative2, resolve as resolve14, sep } from "node:path";
|
|
19392
20025
|
|
|
19393
20026
|
// apps/body/dist/beeline-skill.js
|
|
19394
|
-
import { readFileSync as
|
|
19395
|
-
import { resolve as
|
|
20027
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
20028
|
+
import { resolve as resolve12 } from "node:path";
|
|
20029
|
+
|
|
20030
|
+
// packages/api-contract/dist/workbench.js
|
|
20031
|
+
var CONNECTABLE_CONNECTOR_KINDS = [
|
|
20032
|
+
"trusty-squire",
|
|
20033
|
+
"google-gmail",
|
|
20034
|
+
"google-calendar",
|
|
20035
|
+
"google-drive",
|
|
20036
|
+
"google-youtube"
|
|
20037
|
+
];
|
|
20038
|
+
|
|
20039
|
+
// packages/api-contract/dist/connector-offers.js
|
|
20040
|
+
var CONNECTOR_OFFER_WINDOW_MS = 2 * 6e4;
|
|
20041
|
+
var OFFERABLE_CONNECTOR_KINDS = CONNECTABLE_CONNECTOR_KINDS.filter((kind) => kind !== "wallet");
|
|
19396
20042
|
|
|
19397
20043
|
// packages/api-contract/dist/agent-pairing-code.js
|
|
19398
20044
|
var CURRENT_AGENT_PAIRING_CODE = /^[0-9A-F]{8}-[0-9A-F]{8}$/;
|
|
@@ -19457,12 +20103,12 @@ function beelineCapabilityContextForHarness(agentCommand, repository, directMess
|
|
|
19457
20103
|
...harnessHonorsSessionSystemPrompt(agentCommand) ? {} : { compatibilityTurnPrefix: primer }
|
|
19458
20104
|
};
|
|
19459
20105
|
}
|
|
19460
|
-
function runningBeelineReleaseId(env = process.env, read = (path) =>
|
|
20106
|
+
function runningBeelineReleaseId(env = process.env, read = (path) => readFileSync5(path, "utf8")) {
|
|
19461
20107
|
try {
|
|
19462
20108
|
const lib = env.BEELINE_LIB_DIR;
|
|
19463
20109
|
if (!lib)
|
|
19464
20110
|
return "source";
|
|
19465
|
-
const manifest = JSON.parse(read(
|
|
20111
|
+
const manifest = JSON.parse(read(resolve12(lib, "bundle.json")));
|
|
19466
20112
|
return [manifest.version, manifest.commit].filter(Boolean).join("-") || "source";
|
|
19467
20113
|
} catch {
|
|
19468
20114
|
return "source";
|
|
@@ -19484,13 +20130,17 @@ When your corner's pull request is ready, merging is your step: once the configu
|
|
|
19484
20130
|
|
|
19485
20131
|
## Tools and the Workbench
|
|
19486
20132
|
|
|
19487
|
-
A **tool** is something you can use once a human
|
|
20133
|
+
A **tool** is something you can use once a human adds it; a **key** is the credential that tool holds for that human. You spend a key through the mounted connector and never see the credential itself.
|
|
19488
20134
|
|
|
19489
|
-
|
|
20135
|
+
The tools this build knows, what each is for, and which the person you are answering already has are one call away: beeline-agent workbench_status. Trusty Squire is vaulted credentials plus a browser that signs up and signs in for you; the Google tools (Gmail, Calendar, Drive, YouTube) work through the person's own Google sign-in. The wallet is created only from the Workbench page, and Tailscale is not available yet.
|
|
19490
20136
|
|
|
19491
|
-
|
|
20137
|
+
**Offer the tool at the moment you need it.** When the work in front of you needs a tool the person does not have, do not send them to a settings page and do not stop at naming it. Call workbench_status first - a tool they already have is used, not offered. Then call offer_connector with the connectorType and one short reason: a card appears in this Room, spoken by you, addressed to the person you are answering, with one action. Only that person or a Workspace admin can accept it; accepting adds the tool on your machine, and the sign-in or keys stay theirs. Your turn pauses on the card - say in prose what you are waiting for and end the turn; you are woken when it is added, and then you carry on.
|
|
19492
20138
|
|
|
19493
|
-
|
|
20139
|
+
**Research before you offer, and say so.** Never offer a tool you cannot describe. If someone asks you to install or add something you do not already know - by name, by purpose, or by what it will hold - say plainly that you are looking it up first, find out what it is and what it does with credentials, and state what you learned in your reply BEFORE the card appears. A person reading "Add X?" must already have read, in your own words, what X is. Refusing to act blind is part of being trusted with keys.
|
|
20140
|
+
|
|
20141
|
+
An offer is setup, never authority: it does not replace a grant, write permission, target-branch confirmation, or the merge gate, and it never needs a raw credential in chat. You never pair a tool yourself and never ask anyone for a key value; once a tool is added, provisioning happens inside it and receipts reach the person through the tool's own status message.
|
|
20142
|
+
|
|
20143
|
+
Keys are sovereign: they belong to the human who provisioned them. You cannot use another member's key and must not ask a member to share one. The Workbench page remains the place a person manages tools and keys by hand (Settings \u2192 Workbench); you point there to MANAGE what exists, not to add what you need.
|
|
19494
20144
|
|
|
19495
20145
|
## Showing a mock
|
|
19496
20146
|
|
|
@@ -19644,7 +20294,7 @@ var SQUIRE_GOVERNED_TOOL_SET = new Set(SQUIRE_GOVERNED_TOOLS);
|
|
|
19644
20294
|
|
|
19645
20295
|
// apps/body/dist/openrouter-routing.js
|
|
19646
20296
|
import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
|
|
19647
|
-
import { resolve as
|
|
20297
|
+
import { resolve as resolve13 } from "node:path";
|
|
19648
20298
|
var OPENROUTER_ENDPOINTS_BASE_URL = "https://openrouter.ai/api/v1/models";
|
|
19649
20299
|
var OPENROUTER_COMPLETIONS_URL = "https://openrouter.ai/api/v1/chat/completions";
|
|
19650
20300
|
var OPENROUTER_ROUTING_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -19746,10 +20396,10 @@ function openRouterRoutingFor(providers, allowFallbacks = true) {
|
|
|
19746
20396
|
};
|
|
19747
20397
|
}
|
|
19748
20398
|
function openRouterRoutingCacheDir(runtimeDir) {
|
|
19749
|
-
return
|
|
20399
|
+
return resolve13(runtimeDir, "openrouter-routing");
|
|
19750
20400
|
}
|
|
19751
20401
|
function cachePath(cacheDir, model) {
|
|
19752
|
-
return
|
|
20402
|
+
return resolve13(cacheDir, `${model.replace(/[^A-Za-z0-9._-]+/g, "_")}.json`);
|
|
19753
20403
|
}
|
|
19754
20404
|
async function readCache(cacheDir, model) {
|
|
19755
20405
|
try {
|
|
@@ -19780,7 +20430,7 @@ async function writeCache(cacheDir, value) {
|
|
|
19780
20430
|
});
|
|
19781
20431
|
}
|
|
19782
20432
|
function probeCachePath(cacheDir, model) {
|
|
19783
|
-
return
|
|
20433
|
+
return resolve13(cacheDir, `${model.replace(/[^A-Za-z0-9._-]+/g, "_")}.probe.json`);
|
|
19784
20434
|
}
|
|
19785
20435
|
async function readProbeCache(cacheDir, model) {
|
|
19786
20436
|
try {
|
|
@@ -20220,8 +20870,8 @@ var SHARED_CREDENTIALS = [
|
|
|
20220
20870
|
// shape as codex).
|
|
20221
20871
|
{ dir: "grok", source: ".grok/auth.json", target: "auth.json" },
|
|
20222
20872
|
{ dir: "pi", source: ".pi/agent/auth.json", target: "auth.json" },
|
|
20223
|
-
// Cursor CLI stores auth state under ~/.cursor/; cursor-agent
|
|
20224
|
-
//
|
|
20873
|
+
// Cursor CLI stores auth state under ~/.cursor/; cursor-agent reads
|
|
20874
|
+
// CURSOR_HOME to relocate the data directory.
|
|
20225
20875
|
{ dir: "cursor", source: ".cursor/agent-cli-state.json", target: "agent-cli-state.json" }
|
|
20226
20876
|
];
|
|
20227
20877
|
var GOOSE_SHARED_CONFIG_FILES = ["config.yaml", "secrets.yaml"];
|
|
@@ -20270,8 +20920,8 @@ var HOME_SUBDIRS = [
|
|
|
20270
20920
|
"tmp"
|
|
20271
20921
|
];
|
|
20272
20922
|
async function prepareRoomAgentHome(input) {
|
|
20273
|
-
const root =
|
|
20274
|
-
const operatorHome = input.operatorHome ??
|
|
20923
|
+
const root = resolve14(input.root);
|
|
20924
|
+
const operatorHome = input.operatorHome ?? homedir6();
|
|
20275
20925
|
try {
|
|
20276
20926
|
await mkdir5(root, { recursive: true, mode: 448 });
|
|
20277
20927
|
const rootStats = await lstat(root);
|
|
@@ -20279,7 +20929,7 @@ async function prepareRoomAgentHome(input) {
|
|
|
20279
20929
|
throw new AgentHomeSecurityError(`agent home root is not an ordinary directory: ${root}`);
|
|
20280
20930
|
}
|
|
20281
20931
|
for (const subdir of HOME_SUBDIRS) {
|
|
20282
|
-
const path =
|
|
20932
|
+
const path = resolve14(root, subdir);
|
|
20283
20933
|
await mkdir5(path, { recursive: true, mode: 448 });
|
|
20284
20934
|
await assertRealContainedDirectory(path, root);
|
|
20285
20935
|
}
|
|
@@ -20290,9 +20940,9 @@ async function prepareRoomAgentHome(input) {
|
|
|
20290
20940
|
return {};
|
|
20291
20941
|
}
|
|
20292
20942
|
for (const credential of SHARED_CREDENTIALS) {
|
|
20293
|
-
const source =
|
|
20294
|
-
const target =
|
|
20295
|
-
if (!
|
|
20943
|
+
const source = resolve14(operatorHome, credential.source);
|
|
20944
|
+
const target = resolve14(root, credential.dir, credential.target);
|
|
20945
|
+
if (!existsSync4(source) || existsSync4(target))
|
|
20296
20946
|
continue;
|
|
20297
20947
|
await symlink(source, target).catch(() => void 0);
|
|
20298
20948
|
}
|
|
@@ -20314,12 +20964,12 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
20314
20964
|
...isReviewer ? [{ name: BEELINE_REVIEW_SKILL_NAME, content: beelineReviewSkillMarkdown(skillReleaseId) }] : []
|
|
20315
20965
|
];
|
|
20316
20966
|
const shared = await resolveSharedSkillSources(operatorHome, sharedSkills);
|
|
20317
|
-
await provisionManagedSkillsDir(
|
|
20967
|
+
await provisionManagedSkillsDir(resolve14(root, skillDir, "skills"), managedSkills, shared, sharedSkills.length === 0);
|
|
20318
20968
|
for (const config of HARNESS_MCP_CONFIGS) {
|
|
20319
20969
|
try {
|
|
20320
|
-
const source =
|
|
20321
|
-
const target =
|
|
20322
|
-
const mcpSection =
|
|
20970
|
+
const source = resolve14(operatorHome, config.toml);
|
|
20971
|
+
const target = resolve14(root, config.dir, "config.toml");
|
|
20972
|
+
const mcpSection = existsSync4(source) ? filteredHarnessMcpToml(readFileSync6(source, "utf8")) : void 0;
|
|
20323
20973
|
const section = config.dir === "codex" ? [CODEX_ROOM_AGENT_LOCKDOWN_TOML, CODEX_ROOM_WEB_SEARCH_TOML, mcpSection].filter(Boolean).join("\n") : mcpSection;
|
|
20324
20974
|
if (!section) {
|
|
20325
20975
|
await unlink(target).catch(() => void 0);
|
|
@@ -20333,13 +20983,13 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
20333
20983
|
}
|
|
20334
20984
|
}
|
|
20335
20985
|
try {
|
|
20336
|
-
const gooseConfigDir =
|
|
20986
|
+
const gooseConfigDir = resolve14(root, "goose", "config");
|
|
20337
20987
|
await mkdir5(gooseConfigDir, { recursive: true, mode: 448 });
|
|
20338
20988
|
for (const name of GOOSE_SHARED_CONFIG_FILES) {
|
|
20339
|
-
const source =
|
|
20340
|
-
const target =
|
|
20341
|
-
if (
|
|
20342
|
-
await writeIsolatedHarnessFile(target,
|
|
20989
|
+
const source = resolve14(operatorHome, ".config", "goose", name);
|
|
20990
|
+
const target = resolve14(gooseConfigDir, name);
|
|
20991
|
+
if (existsSync4(source)) {
|
|
20992
|
+
await writeIsolatedHarnessFile(target, readFileSync6(source, "utf8"));
|
|
20343
20993
|
} else {
|
|
20344
20994
|
await unlink(target).catch(() => void 0);
|
|
20345
20995
|
}
|
|
@@ -20350,9 +21000,9 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
20350
21000
|
console.warn("[body] operator Goose configuration passthrough failed:", error);
|
|
20351
21001
|
}
|
|
20352
21002
|
try {
|
|
20353
|
-
const claudeJson =
|
|
20354
|
-
const claudeTarget =
|
|
20355
|
-
const mcpServers =
|
|
21003
|
+
const claudeJson = resolve14(operatorHome, ".claude.json");
|
|
21004
|
+
const claudeTarget = resolve14(root, "claude", ".claude.json");
|
|
21005
|
+
const mcpServers = existsSync4(claudeJson) ? readClaudeUserScopeMcpServers(claudeJson) : void 0;
|
|
20356
21006
|
if (mcpServers && Object.keys(mcpServers).length > 0) {
|
|
20357
21007
|
await writeIsolatedHarnessFile(claudeTarget, `${JSON.stringify({ mcpServers }, null, 2)}
|
|
20358
21008
|
`);
|
|
@@ -20366,7 +21016,7 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
20366
21016
|
}
|
|
20367
21017
|
try {
|
|
20368
21018
|
const settings2 = { permissions: { allow: ["WebSearch", "WebFetch"] } };
|
|
20369
|
-
await writeIsolatedHarnessFile(
|
|
21019
|
+
await writeIsolatedHarnessFile(resolve14(root, "claude", "settings.json"), `${JSON.stringify(settings2, null, 2)}
|
|
20370
21020
|
`);
|
|
20371
21021
|
} catch (error) {
|
|
20372
21022
|
if (failClosed)
|
|
@@ -20376,8 +21026,8 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
20376
21026
|
await provisionPiCustomModelConfig(root, operatorHome, failClosed, openRouterRouting);
|
|
20377
21027
|
}
|
|
20378
21028
|
async function provisionPiCustomModelConfig(root, operatorHome, failClosed, openRouterRouting) {
|
|
20379
|
-
const source =
|
|
20380
|
-
const target =
|
|
21029
|
+
const source = resolve14(operatorHome, PI_CUSTOM_MODEL_CONFIG.source);
|
|
21030
|
+
const target = resolve14(root, "pi", PI_CUSTOM_MODEL_CONFIG.target);
|
|
20381
21031
|
let decision2;
|
|
20382
21032
|
if (openRouterRouting) {
|
|
20383
21033
|
decision2 = await resolveOpenRouterRouting(openRouterRouting);
|
|
@@ -20410,7 +21060,7 @@ async function provisionPiCustomModelConfig(root, operatorHome, failClosed, open
|
|
|
20410
21060
|
if (resolvedSource !== source) {
|
|
20411
21061
|
throw new AgentHomeSecurityError(`Pi custom model config resolves through a link: ${source}`);
|
|
20412
21062
|
}
|
|
20413
|
-
const sourceValue = JSON.parse(
|
|
21063
|
+
const sourceValue = JSON.parse(readFileSync6(resolvedSource, "utf8"));
|
|
20414
21064
|
await writeIsolatedHarnessFile(target, `${JSON.stringify(withOpenRouterModelRouting(sourceValue, pin), null, 2)}
|
|
20415
21065
|
`);
|
|
20416
21066
|
} catch (error) {
|
|
@@ -20422,7 +21072,7 @@ async function provisionPiCustomModelConfig(root, operatorHome, failClosed, open
|
|
|
20422
21072
|
}
|
|
20423
21073
|
function readClaudeUserScopeMcpServers(path) {
|
|
20424
21074
|
try {
|
|
20425
|
-
const parsed = JSON.parse(
|
|
21075
|
+
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
20426
21076
|
if (parsed && typeof parsed.mcpServers === "object" && parsed.mcpServers !== null) {
|
|
20427
21077
|
return Object.fromEntries(Object.entries(parsed.mcpServers).filter(([name, value]) => {
|
|
20428
21078
|
if (name === "squire")
|
|
@@ -20446,21 +21096,21 @@ function filteredHarnessMcpToml(source) {
|
|
|
20446
21096
|
return extractTomlSections(source, ["mcp_servers"], excluded);
|
|
20447
21097
|
}
|
|
20448
21098
|
async function provisionManagedSkillsDir(target, managedSkills, sharedSkills, optionalShares) {
|
|
20449
|
-
const parent =
|
|
20450
|
-
await assertRealContainedDirectory(parent,
|
|
21099
|
+
const parent = dirname7(target);
|
|
21100
|
+
await assertRealContainedDirectory(parent, dirname7(parent));
|
|
20451
21101
|
const plan = await planManagedSkills(managedSkills, sharedSkills, optionalShares);
|
|
20452
21102
|
if (await materializedSkillManifest(target) === plan.manifest)
|
|
20453
21103
|
return;
|
|
20454
|
-
const staged =
|
|
21104
|
+
const staged = resolve14(parent, `.skills.${process.pid}.${randomUUID4()}.tmp`);
|
|
20455
21105
|
await mkdir5(staged, { mode: 448 });
|
|
20456
21106
|
try {
|
|
20457
21107
|
for (const entry of plan.entries) {
|
|
20458
21108
|
if (entry.kind === "managed") {
|
|
20459
|
-
const skillDir =
|
|
21109
|
+
const skillDir = resolve14(staged, entry.name);
|
|
20460
21110
|
await mkdir5(skillDir, { recursive: true });
|
|
20461
|
-
await writeIsolatedHarnessFile(
|
|
21111
|
+
await writeIsolatedHarnessFile(resolve14(skillDir, "SKILL.md"), entry.content);
|
|
20462
21112
|
} else {
|
|
20463
|
-
await copySafeSkillTree(entry.source,
|
|
21113
|
+
await copySafeSkillTree(entry.source, resolve14(staged, entry.name), entry.source);
|
|
20464
21114
|
}
|
|
20465
21115
|
}
|
|
20466
21116
|
const existing = await lstat(target).catch(() => void 0);
|
|
@@ -20487,8 +21137,8 @@ async function planManagedSkills(managedSkills, sharedSkills, optionalShares) {
|
|
|
20487
21137
|
try {
|
|
20488
21138
|
const tree = [];
|
|
20489
21139
|
await walkSafeSkillTree(shared.source, shared.source, {
|
|
20490
|
-
directory: async (rel) => void tree.push(`d ${
|
|
20491
|
-
file: async (rel, realPath) => void tree.push(`f ${
|
|
21140
|
+
directory: async (rel) => void tree.push(`d ${join6(shared.name, rel)}`),
|
|
21141
|
+
file: async (rel, realPath) => void tree.push(`f ${join6(shared.name, rel)} ${sha2563(await readFile6(realPath))}`)
|
|
20492
21142
|
});
|
|
20493
21143
|
entries.push({ kind: "shared", name: shared.name, source: shared.source });
|
|
20494
21144
|
lines.push(...tree);
|
|
@@ -20507,8 +21157,8 @@ async function materializedSkillManifest(target) {
|
|
|
20507
21157
|
const lines = [];
|
|
20508
21158
|
const visit = async (directory, prefix) => {
|
|
20509
21159
|
for (const entry of await readdir2(directory)) {
|
|
20510
|
-
const path =
|
|
20511
|
-
const rel = prefix ?
|
|
21160
|
+
const path = resolve14(directory, entry);
|
|
21161
|
+
const rel = prefix ? join6(prefix, entry) : entry;
|
|
20512
21162
|
const entryStats = await lstat(path);
|
|
20513
21163
|
if (entryStats.isSymbolicLink())
|
|
20514
21164
|
return false;
|
|
@@ -20533,7 +21183,7 @@ async function materializedSkillManifest(target) {
|
|
|
20533
21183
|
return lines.sort().join("\n");
|
|
20534
21184
|
}
|
|
20535
21185
|
function sha2563(value) {
|
|
20536
|
-
return
|
|
21186
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
20537
21187
|
}
|
|
20538
21188
|
async function resolveSharedSkillSources(operatorHome, names) {
|
|
20539
21189
|
if (names.length > 0)
|
|
@@ -20542,14 +21192,14 @@ async function resolveSharedSkillSources(operatorHome, names) {
|
|
|
20542
21192
|
const resolved = [];
|
|
20543
21193
|
const skipped = [];
|
|
20544
21194
|
for (const relativeRoot of OPERATOR_SKILL_SOURCE_DIRS) {
|
|
20545
|
-
const sourceRoot =
|
|
21195
|
+
const sourceRoot = resolve14(operatorHome, relativeRoot);
|
|
20546
21196
|
const rootStats = await lstat(sourceRoot).catch(() => void 0);
|
|
20547
21197
|
if (!rootStats?.isDirectory() || rootStats.isSymbolicLink())
|
|
20548
21198
|
continue;
|
|
20549
21199
|
for (const entry of await readdir2(sourceRoot)) {
|
|
20550
21200
|
if (!isSharedSkillName(entry) || seen.has(entry))
|
|
20551
21201
|
continue;
|
|
20552
|
-
const candidate =
|
|
21202
|
+
const candidate = resolve14(sourceRoot, entry);
|
|
20553
21203
|
try {
|
|
20554
21204
|
const candidateStats = await lstat(candidate);
|
|
20555
21205
|
if (candidateStats.isSymbolicLink()) {
|
|
@@ -20565,7 +21215,7 @@ async function resolveSharedSkillSources(operatorHome, names) {
|
|
|
20565
21215
|
continue;
|
|
20566
21216
|
}
|
|
20567
21217
|
assertContained(sourceRoot, candidate);
|
|
20568
|
-
const skillMd =
|
|
21218
|
+
const skillMd = resolve14(candidate, "SKILL.md");
|
|
20569
21219
|
const skillStats = await lstat(skillMd).catch((error) => {
|
|
20570
21220
|
if (isMissingPathError(error)) {
|
|
20571
21221
|
skipped.push({ path: candidate, reason: "missing SKILL.md" });
|
|
@@ -20617,8 +21267,8 @@ async function resolveExplicitSkillSources(operatorHome, names) {
|
|
|
20617
21267
|
for (const name of unique) {
|
|
20618
21268
|
const matches = [];
|
|
20619
21269
|
for (const relativeRoot of OPERATOR_SKILL_SOURCE_DIRS) {
|
|
20620
|
-
const sourceRoot =
|
|
20621
|
-
const candidate =
|
|
21270
|
+
const sourceRoot = resolve14(operatorHome, relativeRoot);
|
|
21271
|
+
const candidate = resolve14(sourceRoot, name);
|
|
20622
21272
|
const rootStats = await lstat(sourceRoot).catch(() => void 0);
|
|
20623
21273
|
const candidateStats = await lstat(candidate).catch(() => void 0);
|
|
20624
21274
|
if (!candidateStats)
|
|
@@ -20635,7 +21285,7 @@ async function resolveExplicitSkillSources(operatorHome, names) {
|
|
|
20635
21285
|
if (matches.length !== 1) {
|
|
20636
21286
|
throw new Error(matches.length === 0 ? `shared skill is unavailable: ${name}` : `shared skill source is ambiguous: ${name}`);
|
|
20637
21287
|
}
|
|
20638
|
-
const skillMd =
|
|
21288
|
+
const skillMd = resolve14(matches[0], "SKILL.md");
|
|
20639
21289
|
const skillStats = await lstat(skillMd).catch(() => void 0);
|
|
20640
21290
|
if (!skillStats?.isFile() || skillStats.isSymbolicLink() || skillStats.nlink !== 1) {
|
|
20641
21291
|
throw new Error(`shared skill requires an ordinary SKILL.md: ${name}`);
|
|
@@ -20646,7 +21296,7 @@ async function resolveExplicitSkillSources(operatorHome, names) {
|
|
|
20646
21296
|
}
|
|
20647
21297
|
function assertContained(root, candidate) {
|
|
20648
21298
|
const rel = relative2(root, candidate);
|
|
20649
|
-
if (rel === ".." || rel.startsWith(`..${sep}`) ||
|
|
21299
|
+
if (rel === ".." || rel.startsWith(`..${sep}`) || resolve14(root, rel) !== resolve14(candidate)) {
|
|
20650
21300
|
throw new Error(`path escapes the agent skill boundary: ${candidate}`);
|
|
20651
21301
|
}
|
|
20652
21302
|
}
|
|
@@ -20661,14 +21311,14 @@ var BLOCKED_SHARED_FILENAMES = /^(?:\.env(?:\..*)?|auth\.json|\.credentials\.jso
|
|
|
20661
21311
|
async function walkSafeSkillTree(source, sourceRoot, visitor, rel = "") {
|
|
20662
21312
|
assertContained(sourceRoot, source);
|
|
20663
21313
|
const resolvedSource = await realpath(source);
|
|
20664
|
-
if (resolvedSource !==
|
|
21314
|
+
if (resolvedSource !== resolve14(source)) {
|
|
20665
21315
|
throw new Error(`shared skill path resolves through a link: ${source}`);
|
|
20666
21316
|
}
|
|
20667
21317
|
assertContained(sourceRoot, resolvedSource);
|
|
20668
21318
|
const stats = await lstat(resolvedSource);
|
|
20669
21319
|
if (stats.isSymbolicLink())
|
|
20670
21320
|
throw new Error(`shared skill contains a symlink: ${source}`);
|
|
20671
|
-
if (BLOCKED_SHARED_FILENAMES.test(
|
|
21321
|
+
if (BLOCKED_SHARED_FILENAMES.test(basename4(source))) {
|
|
20672
21322
|
throw new Error(`shared skill contains credential or configuration material: ${source}`);
|
|
20673
21323
|
}
|
|
20674
21324
|
if (stats.isDirectory()) {
|
|
@@ -20676,7 +21326,7 @@ async function walkSafeSkillTree(source, sourceRoot, visitor, rel = "") {
|
|
|
20676
21326
|
for (const entry of await readdir2(resolvedSource)) {
|
|
20677
21327
|
if (entry === "." || entry === "..")
|
|
20678
21328
|
throw new Error("invalid shared skill entry");
|
|
20679
|
-
await walkSafeSkillTree(
|
|
21329
|
+
await walkSafeSkillTree(resolve14(source, entry), sourceRoot, visitor, rel ? join6(rel, entry) : entry);
|
|
20680
21330
|
}
|
|
20681
21331
|
return;
|
|
20682
21332
|
}
|
|
@@ -20688,22 +21338,22 @@ async function walkSafeSkillTree(source, sourceRoot, visitor, rel = "") {
|
|
|
20688
21338
|
async function copySafeSkillTree(source, target, sourceRoot) {
|
|
20689
21339
|
await walkSafeSkillTree(source, sourceRoot, {
|
|
20690
21340
|
directory: async (rel) => {
|
|
20691
|
-
await mkdir5(
|
|
21341
|
+
await mkdir5(resolve14(target, rel), { mode: 448 });
|
|
20692
21342
|
},
|
|
20693
21343
|
file: async (rel, realPath) => {
|
|
20694
|
-
const destination =
|
|
21344
|
+
const destination = resolve14(target, rel);
|
|
20695
21345
|
await copyFile(realPath, destination);
|
|
20696
21346
|
await chmod2(destination, 384);
|
|
20697
21347
|
}
|
|
20698
21348
|
});
|
|
20699
21349
|
}
|
|
20700
21350
|
async function writeIsolatedHarnessFile(path, content) {
|
|
20701
|
-
const parent =
|
|
21351
|
+
const parent = dirname7(path);
|
|
20702
21352
|
const parentStats = await lstat(parent);
|
|
20703
21353
|
if (!parentStats.isDirectory() || parentStats.isSymbolicLink()) {
|
|
20704
21354
|
throw new Error(`isolated harness parent is not a real directory: ${parent}`);
|
|
20705
21355
|
}
|
|
20706
|
-
const temporary =
|
|
21356
|
+
const temporary = resolve14(parent, `.${basename4(path)}.${process.pid}.${randomUUID4()}.tmp`);
|
|
20707
21357
|
try {
|
|
20708
21358
|
await writeFile6(temporary, content, { mode: 384, flag: "wx" });
|
|
20709
21359
|
await chmod2(temporary, 384);
|
|
@@ -20713,18 +21363,18 @@ async function writeIsolatedHarnessFile(path, content) {
|
|
|
20713
21363
|
}
|
|
20714
21364
|
}
|
|
20715
21365
|
function roomAgentHomeEnv(root) {
|
|
20716
|
-
const resolved =
|
|
21366
|
+
const resolved = resolve14(root);
|
|
20717
21367
|
return {
|
|
20718
|
-
HOME:
|
|
20719
|
-
CLAUDE_CONFIG_DIR:
|
|
20720
|
-
CODEX_HOME:
|
|
20721
|
-
GOOSE_PATH_ROOT:
|
|
20722
|
-
GROK_HOME:
|
|
20723
|
-
CURSOR_HOME:
|
|
20724
|
-
PI_CODING_AGENT_DIR:
|
|
20725
|
-
XDG_STATE_HOME:
|
|
20726
|
-
XDG_CACHE_HOME:
|
|
20727
|
-
TMPDIR:
|
|
21368
|
+
HOME: resolve14(resolved, "user"),
|
|
21369
|
+
CLAUDE_CONFIG_DIR: resolve14(resolved, "claude"),
|
|
21370
|
+
CODEX_HOME: resolve14(resolved, "codex"),
|
|
21371
|
+
GOOSE_PATH_ROOT: resolve14(resolved, "goose"),
|
|
21372
|
+
GROK_HOME: resolve14(resolved, "grok"),
|
|
21373
|
+
CURSOR_HOME: resolve14(resolved, "cursor"),
|
|
21374
|
+
PI_CODING_AGENT_DIR: resolve14(resolved, "pi"),
|
|
21375
|
+
XDG_STATE_HOME: resolve14(resolved, "state"),
|
|
21376
|
+
XDG_CACHE_HOME: resolve14(resolved, "cache"),
|
|
21377
|
+
TMPDIR: resolve14(resolved, "tmp")
|
|
20728
21378
|
};
|
|
20729
21379
|
}
|
|
20730
21380
|
var HARNESS_STATE_ENV_VARS = [
|
|
@@ -20743,22 +21393,22 @@ function harnessStateDirsFromEnv(env) {
|
|
|
20743
21393
|
for (const name of HARNESS_STATE_ENV_VARS) {
|
|
20744
21394
|
const value = env[name];
|
|
20745
21395
|
if (value)
|
|
20746
|
-
stateDirs.push(
|
|
21396
|
+
stateDirs.push(resolve14(value));
|
|
20747
21397
|
}
|
|
20748
21398
|
const tmp = env.TMPDIR;
|
|
20749
|
-
return { stateDirs, ...tmp ? { tmpDir:
|
|
21399
|
+
return { stateDirs, ...tmp ? { tmpDir: resolve14(tmp) } : {} };
|
|
20750
21400
|
}
|
|
20751
21401
|
|
|
20752
21402
|
// apps/body/dist/attachment-delivery.js
|
|
20753
21403
|
import { mkdir as mkdir6, writeFile as writeFile7 } from "node:fs/promises";
|
|
20754
|
-
import { basename as
|
|
21404
|
+
import { basename as basename5, extname, join as join7 } from "node:path";
|
|
20755
21405
|
var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
20756
21406
|
var MEDIA_TTL_HOURS = 24;
|
|
20757
21407
|
var EXPIRED_REASON = `expired: attachments are kept for ${MEDIA_TTL_HOURS} hours and these bytes are past that window`;
|
|
20758
21408
|
var FETCH_TIMEOUT_MS = 3e4;
|
|
20759
21409
|
var MAX_INLINE_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
20760
21410
|
function safeFileName(attachment, index, taken) {
|
|
20761
|
-
const raw =
|
|
21411
|
+
const raw = basename5(attachment.name ?? "").replace(/[^\w.-]+/g, "_").replace(/^\.+/, "");
|
|
20762
21412
|
let name = raw || `attachment-${index + 1}`;
|
|
20763
21413
|
if (taken.has(name)) {
|
|
20764
21414
|
const ext = extname(name);
|
|
@@ -20795,7 +21445,7 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
|
|
|
20795
21445
|
const bytes = Buffer.from(await response.arrayBuffer());
|
|
20796
21446
|
if (bytes.length > MAX_ATTACHMENT_BYTES)
|
|
20797
21447
|
return tooLarge(bytes.length);
|
|
20798
|
-
const path =
|
|
21448
|
+
const path = join7(dir, safeFileName(attachment, index, taken));
|
|
20799
21449
|
await writeFile7(path, bytes);
|
|
20800
21450
|
const mimeType = attachment.mimeType ?? response.headers.get("content-type") ?? "";
|
|
20801
21451
|
if (!mimeType.startsWith("image/"))
|
|
@@ -21186,7 +21836,7 @@ function sessionConfigFingerprint(input) {
|
|
|
21186
21836
|
|
|
21187
21837
|
// apps/body/dist/pi-mcp-bridge.js
|
|
21188
21838
|
import { mkdir as mkdir7 } from "node:fs/promises";
|
|
21189
|
-
import { resolve as
|
|
21839
|
+
import { resolve as resolve15 } from "node:path";
|
|
21190
21840
|
var PI_MCP_BRIDGE_FILENAME = "beeline-mcp-bridge.js";
|
|
21191
21841
|
function harnessMountsSessionMcpServers(agentCommand) {
|
|
21192
21842
|
return !(agentCommand && /(^|[/\\])pi-acp(\.[a-z]+)?$/i.test(agentCommand));
|
|
@@ -21206,8 +21856,8 @@ async function installPiMcpBridge(input) {
|
|
|
21206
21856
|
return void 0;
|
|
21207
21857
|
if (!input.piHome || !input.servers.length)
|
|
21208
21858
|
return void 0;
|
|
21209
|
-
const directory =
|
|
21210
|
-
const path =
|
|
21859
|
+
const directory = resolve15(input.piHome, "extensions");
|
|
21860
|
+
const path = resolve15(directory, PI_MCP_BRIDGE_FILENAME);
|
|
21211
21861
|
try {
|
|
21212
21862
|
await mkdir7(directory, { recursive: true, mode: 448 });
|
|
21213
21863
|
await writeIsolatedHarnessFile(path, piMcpBridgeSource(input.servers));
|
|
@@ -21407,7 +22057,7 @@ async function contains(git, head, ancestor) {
|
|
|
21407
22057
|
}
|
|
21408
22058
|
|
|
21409
22059
|
// apps/body/dist/room-session.js
|
|
21410
|
-
import { resolve as
|
|
22060
|
+
import { resolve as resolve16 } from "node:path";
|
|
21411
22061
|
|
|
21412
22062
|
// apps/body/dist/read-only-policy.js
|
|
21413
22063
|
var READ_ONLY_MCP_SERVER_NAME = "beeline-readonly-mcp";
|
|
@@ -21632,21 +22282,21 @@ function readOnlyMcpServer(config, cwd, agentMemoryDir) {
|
|
|
21632
22282
|
command: config.readonlyMcpCommand,
|
|
21633
22283
|
args: [...config.readonlyMcpArgs ?? []],
|
|
21634
22284
|
env: [
|
|
21635
|
-
{ name: "BEELINE_READONLY_ROOT", value:
|
|
22285
|
+
{ name: "BEELINE_READONLY_ROOT", value: resolve16(cwd) },
|
|
21636
22286
|
...config.agentHomeRoot ? [
|
|
21637
22287
|
{
|
|
21638
22288
|
name: "BEELINE_READONLY_AGENT_SKILLS_ROOT",
|
|
21639
|
-
value:
|
|
22289
|
+
value: resolve16(config.agentHomeRoot, skillDir, "skills")
|
|
21640
22290
|
}
|
|
21641
22291
|
] : [],
|
|
21642
|
-
...agentMemoryDir ? [{ name: "BEELINE_READONLY_AGENT_MEMORY_ROOT", value:
|
|
22292
|
+
...agentMemoryDir ? [{ name: "BEELINE_READONLY_AGENT_MEMORY_ROOT", value: resolve16(agentMemoryDir) }] : []
|
|
21643
22293
|
]
|
|
21644
22294
|
};
|
|
21645
22295
|
}
|
|
21646
22296
|
|
|
21647
22297
|
// apps/body/dist/pi-turn-record.js
|
|
21648
22298
|
import { readdir as readdir3, readFile as readFile7 } from "node:fs/promises";
|
|
21649
|
-
import { resolve as
|
|
22299
|
+
import { resolve as resolve17 } from "node:path";
|
|
21650
22300
|
function summarizeProviderError(errorMessage2) {
|
|
21651
22301
|
const trimmed = errorMessage2.trim();
|
|
21652
22302
|
const statusMatch = /^(\d{3}):\s*([\s\S]*)$/.exec(trimmed);
|
|
@@ -21667,7 +22317,7 @@ function summarizeProviderError(errorMessage2) {
|
|
|
21667
22317
|
}
|
|
21668
22318
|
async function sessionFileFromMap(home, sessionId) {
|
|
21669
22319
|
try {
|
|
21670
|
-
const raw = await readFile7(
|
|
22320
|
+
const raw = await readFile7(resolve17(home, ".pi", "pi-acp", "session-map.json"), "utf8");
|
|
21671
22321
|
const map = JSON.parse(raw);
|
|
21672
22322
|
const file = map.sessions?.[sessionId]?.sessionFile;
|
|
21673
22323
|
return typeof file === "string" && file ? file : void 0;
|
|
@@ -21676,7 +22326,7 @@ async function sessionFileFromMap(home, sessionId) {
|
|
|
21676
22326
|
}
|
|
21677
22327
|
}
|
|
21678
22328
|
async function sessionFileFromLayout(piDir, sessionId) {
|
|
21679
|
-
const sessionsRoot =
|
|
22329
|
+
const sessionsRoot = resolve17(piDir, "sessions");
|
|
21680
22330
|
const suffix = `_${sessionId}.jsonl`;
|
|
21681
22331
|
let projects;
|
|
21682
22332
|
try {
|
|
@@ -21685,7 +22335,7 @@ async function sessionFileFromLayout(piDir, sessionId) {
|
|
|
21685
22335
|
return void 0;
|
|
21686
22336
|
}
|
|
21687
22337
|
for (const project of projects) {
|
|
21688
|
-
const dir =
|
|
22338
|
+
const dir = resolve17(sessionsRoot, project);
|
|
21689
22339
|
let files;
|
|
21690
22340
|
try {
|
|
21691
22341
|
files = await readdir3(dir);
|
|
@@ -21694,7 +22344,7 @@ async function sessionFileFromLayout(piDir, sessionId) {
|
|
|
21694
22344
|
}
|
|
21695
22345
|
const match = files.find((file) => file.endsWith(suffix));
|
|
21696
22346
|
if (match)
|
|
21697
|
-
return
|
|
22347
|
+
return resolve17(dir, match);
|
|
21698
22348
|
}
|
|
21699
22349
|
return void 0;
|
|
21700
22350
|
}
|
|
@@ -21869,7 +22519,7 @@ async function withTurnReceiptHeartbeat(api, receipt, task, onHeartbeatError) {
|
|
|
21869
22519
|
|
|
21870
22520
|
// apps/body/dist/turn-trace.js
|
|
21871
22521
|
import { appendFile, mkdir as mkdir8, readdir as readdir4, rm as rm3 } from "node:fs/promises";
|
|
21872
|
-
import { resolve as
|
|
22522
|
+
import { resolve as resolve18 } from "node:path";
|
|
21873
22523
|
import { performance as performance2 } from "node:perf_hooks";
|
|
21874
22524
|
var TURN_PHASES = [
|
|
21875
22525
|
/** Enqueued on `SessionScheduler` until this turn holds a slot. A capacity wait lives here. */
|
|
@@ -22099,7 +22749,7 @@ function formatTurnTraceLine(record3) {
|
|
|
22099
22749
|
return [head, ...record3.attempts.map((attempt) => formatTurnAttempt(attempt))].join("\n ");
|
|
22100
22750
|
}
|
|
22101
22751
|
function turnTraceDirectory(runtimeDir) {
|
|
22102
|
-
return
|
|
22752
|
+
return resolve18(runtimeDir, "turn-traces");
|
|
22103
22753
|
}
|
|
22104
22754
|
var TURN_TRACE_RETENTION_DAYS = 7;
|
|
22105
22755
|
function traceFileName(date) {
|
|
@@ -22116,7 +22766,7 @@ var TurnTraceFile = class {
|
|
|
22116
22766
|
this.options = options;
|
|
22117
22767
|
}
|
|
22118
22768
|
path(now2 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))()) {
|
|
22119
|
-
return
|
|
22769
|
+
return resolve18(this.directory, traceFileName(now2));
|
|
22120
22770
|
}
|
|
22121
22771
|
write(record3) {
|
|
22122
22772
|
this.tail = this.tail.catch(() => void 0).then(async () => {
|
|
@@ -22140,15 +22790,15 @@ var TurnTraceFile = class {
|
|
|
22140
22790
|
this.prunedDay = day;
|
|
22141
22791
|
const cutoff = traceFileName(new Date(now2.getTime() - TURN_TRACE_RETENTION_DAYS * 864e5));
|
|
22142
22792
|
const names = await readdir4(this.directory).catch(() => []);
|
|
22143
|
-
await Promise.all(names.filter((name) => /^turns-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name) && name < cutoff).map((name) => rm3(
|
|
22793
|
+
await Promise.all(names.filter((name) => /^turns-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name) && name < cutoff).map((name) => rm3(resolve18(this.directory, name), { force: true })));
|
|
22144
22794
|
}
|
|
22145
22795
|
};
|
|
22146
22796
|
|
|
22147
22797
|
// apps/body/dist/corner-github-auth.js
|
|
22148
22798
|
import { chmod as chmod3, mkdir as mkdir9, writeFile as writeFile8 } from "node:fs/promises";
|
|
22149
|
-
import { delimiter as delimiter2, resolve as
|
|
22799
|
+
import { delimiter as delimiter2, resolve as resolve19 } from "node:path";
|
|
22150
22800
|
async function installCornerGitHubWrappers(input) {
|
|
22151
|
-
const bin =
|
|
22801
|
+
const bin = resolve19(input.root, "beeline-github-bin");
|
|
22152
22802
|
await mkdir9(bin, { recursive: true, mode: 448 });
|
|
22153
22803
|
const common = {
|
|
22154
22804
|
node: process.execPath,
|
|
@@ -22158,13 +22808,13 @@ async function installCornerGitHubWrappers(input) {
|
|
|
22158
22808
|
featureBranch: input.featureBranch,
|
|
22159
22809
|
targetBranch: input.targetBranch
|
|
22160
22810
|
};
|
|
22161
|
-
await writeLauncher(
|
|
22811
|
+
await writeLauncher(resolve19(bin, "git"), {
|
|
22162
22812
|
...common,
|
|
22163
22813
|
command: input.gitBinary,
|
|
22164
22814
|
launcher: "git"
|
|
22165
22815
|
});
|
|
22166
22816
|
if (input.ghBinary)
|
|
22167
|
-
await writeLauncher(
|
|
22817
|
+
await writeLauncher(resolve19(bin, "gh"), {
|
|
22168
22818
|
...common,
|
|
22169
22819
|
command: input.ghBinary,
|
|
22170
22820
|
launcher: "gh"
|
|
@@ -22299,25 +22949,25 @@ process.exit(result.status ?? 1);
|
|
|
22299
22949
|
}
|
|
22300
22950
|
|
|
22301
22951
|
// apps/body/dist/warm-node-modules.js
|
|
22302
|
-
import { createHash as
|
|
22952
|
+
import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
|
|
22303
22953
|
import { constants as fsConstants } from "node:fs";
|
|
22304
22954
|
import { chmod as chmod4, copyFile as copyFile2, link, lstat as lstat2, mkdir as mkdir10, readdir as readdir5, readFile as readFile8, readlink, rename as rename3, rm as rm4, stat as stat2, symlink as symlink2, utimes } from "node:fs/promises";
|
|
22305
|
-
import { dirname as
|
|
22955
|
+
import { dirname as dirname8, join as join8, resolve as resolve20 } from "node:path";
|
|
22306
22956
|
var STORE_FORMAT = "v1";
|
|
22307
22957
|
var STAGING_PREFIX = ".beeline-warm-";
|
|
22308
22958
|
var STAGING_SWEEP_MS = 24 * 60 * 60 * 1e3;
|
|
22309
22959
|
var WARM_STORE_MAX_ENTRIES = 3;
|
|
22310
22960
|
function sharedNpmCacheDir(supervisorRoot) {
|
|
22311
|
-
return
|
|
22961
|
+
return resolve20(supervisorRoot, "beeline", "npm-cache");
|
|
22312
22962
|
}
|
|
22313
22963
|
function warmNodeModulesStoreDir(supervisorRoot) {
|
|
22314
|
-
return
|
|
22964
|
+
return resolve20(supervisorRoot, "beeline", "node-modules");
|
|
22315
22965
|
}
|
|
22316
22966
|
function isPlanRefusal(value) {
|
|
22317
22967
|
return "failure" in value;
|
|
22318
22968
|
}
|
|
22319
22969
|
async function readWarmPlan(worktreePath) {
|
|
22320
|
-
const lockfile = await readFile8(
|
|
22970
|
+
const lockfile = await readFile8(resolve20(worktreePath, "package-lock.json")).catch(() => void 0);
|
|
22321
22971
|
if (!lockfile)
|
|
22322
22972
|
return { failure: "no-lockfile" };
|
|
22323
22973
|
const packages = parseLockfilePackages(lockfile);
|
|
@@ -22332,7 +22982,7 @@ async function readWarmPlan(worktreePath) {
|
|
|
22332
22982
|
const unsafe = trees.find((tree) => !isContainedTreePath(tree));
|
|
22333
22983
|
if (unsafe)
|
|
22334
22984
|
return { failure: "unsafe-lockfile", detail: unsafe };
|
|
22335
|
-
const key =
|
|
22985
|
+
const key = createHash5("sha256").update(`${STORE_FORMAT}\0${process.platform}\0${process.arch}\0${process.versions.modules}\0`).update(lockfile).digest("hex").slice(0, 32);
|
|
22336
22986
|
return { key, trees };
|
|
22337
22987
|
}
|
|
22338
22988
|
function nodeModulesTreePaths(packages) {
|
|
@@ -22356,11 +23006,11 @@ async function seedWarmNodeModules(input) {
|
|
|
22356
23006
|
return { reason: plan.failure, ...plan.detail ? { detail: plan.detail } : {} };
|
|
22357
23007
|
}
|
|
22358
23008
|
for (const tree of plan.trees) {
|
|
22359
|
-
if (await pathExists(
|
|
23009
|
+
if (await pathExists(resolve20(input.worktreePath, tree))) {
|
|
22360
23010
|
return { reason: "present", key: plan.key };
|
|
22361
23011
|
}
|
|
22362
23012
|
}
|
|
22363
|
-
const entry =
|
|
23013
|
+
const entry = resolve20(input.storeRoot, plan.key);
|
|
22364
23014
|
if (!await isDirectory(entry))
|
|
22365
23015
|
return { reason: "cold", key: plan.key };
|
|
22366
23016
|
const [storeDevice, checkoutDevice] = await Promise.all([
|
|
@@ -22370,19 +23020,19 @@ async function seedWarmNodeModules(input) {
|
|
|
22370
23020
|
if (storeDevice === void 0 || storeDevice !== checkoutDevice) {
|
|
22371
23021
|
return { reason: "cross-device", key: plan.key };
|
|
22372
23022
|
}
|
|
22373
|
-
const staging =
|
|
23023
|
+
const staging = resolve20(input.storeRoot, `${STAGING_PREFIX}${process.pid}.${randomUUID5()}`);
|
|
22374
23024
|
const placed = [];
|
|
22375
23025
|
const now2 = (input.now ?? Date.now)();
|
|
22376
23026
|
try {
|
|
22377
23027
|
await sweepStaleStaging(input.storeRoot, now2);
|
|
22378
23028
|
await utimes(entry, now2 / 1e3, now2 / 1e3).catch(() => void 0);
|
|
22379
23029
|
for (const tree of plan.trees) {
|
|
22380
|
-
await cloneTree(
|
|
23030
|
+
await cloneTree(resolve20(entry, tree), resolve20(staging, tree), seedFile);
|
|
22381
23031
|
}
|
|
22382
23032
|
for (const tree of plan.trees) {
|
|
22383
|
-
const target =
|
|
22384
|
-
await mkdir10(
|
|
22385
|
-
await rename3(
|
|
23033
|
+
const target = resolve20(input.worktreePath, tree);
|
|
23034
|
+
await mkdir10(dirname8(target), { recursive: true });
|
|
23035
|
+
await rename3(resolve20(staging, tree), target);
|
|
22386
23036
|
placed.push(target);
|
|
22387
23037
|
}
|
|
22388
23038
|
return { reason: "seeded", key: plan.key };
|
|
@@ -22400,11 +23050,11 @@ async function harvestWarmNodeModules(input) {
|
|
|
22400
23050
|
if (isPlanRefusal(plan)) {
|
|
22401
23051
|
return { reason: plan.failure, ...plan.detail ? { detail: plan.detail } : {} };
|
|
22402
23052
|
}
|
|
22403
|
-
const entry =
|
|
23053
|
+
const entry = resolve20(input.storeRoot, plan.key);
|
|
22404
23054
|
if (await pathExists(entry))
|
|
22405
23055
|
return { reason: "already-warm", key: plan.key };
|
|
22406
23056
|
for (const tree of plan.trees) {
|
|
22407
|
-
if (!await isDirectory(
|
|
23057
|
+
if (!await isDirectory(resolve20(input.worktreePath, tree))) {
|
|
22408
23058
|
return { reason: "no-node-modules", key: plan.key, detail: tree };
|
|
22409
23059
|
}
|
|
22410
23060
|
}
|
|
@@ -22416,12 +23066,12 @@ async function harvestWarmNodeModules(input) {
|
|
|
22416
23066
|
detail: `${missing.length} absent, e.g. ${missing.slice(0, 3).join(", ")}`
|
|
22417
23067
|
};
|
|
22418
23068
|
}
|
|
22419
|
-
const staging =
|
|
23069
|
+
const staging = resolve20(input.storeRoot, `${STAGING_PREFIX}${process.pid}.${randomUUID5()}`);
|
|
22420
23070
|
try {
|
|
22421
23071
|
await mkdir10(input.storeRoot, { recursive: true, mode: 493 });
|
|
22422
23072
|
await sweepStaleStaging(input.storeRoot, (input.now ?? Date.now)());
|
|
22423
23073
|
for (const tree of plan.trees) {
|
|
22424
|
-
await cloneTree(
|
|
23074
|
+
await cloneTree(resolve20(input.worktreePath, tree), resolve20(staging, tree), harvestFile);
|
|
22425
23075
|
}
|
|
22426
23076
|
await input.onCopied?.();
|
|
22427
23077
|
if (!await stagedTreeIsPublishable(input.worktreePath, staging, plan.key)) {
|
|
@@ -22442,18 +23092,18 @@ async function stagedTreeIsPublishable(worktreePath, staging, key) {
|
|
|
22442
23092
|
const settled = await readWarmPlan(worktreePath);
|
|
22443
23093
|
if (isPlanRefusal(settled) || settled.key !== key)
|
|
22444
23094
|
return false;
|
|
22445
|
-
const hidden =
|
|
23095
|
+
const hidden = join8("node_modules", ".package-lock.json");
|
|
22446
23096
|
const [copied, current] = await Promise.all([
|
|
22447
|
-
readFile8(
|
|
22448
|
-
readFile8(
|
|
23097
|
+
readFile8(resolve20(staging, hidden)).catch(() => void 0),
|
|
23098
|
+
readFile8(resolve20(worktreePath, hidden)).catch(() => void 0)
|
|
22449
23099
|
]);
|
|
22450
23100
|
if (!copied || !current || !copied.equals(current))
|
|
22451
23101
|
return false;
|
|
22452
23102
|
return (await missingInstalledPackages(worktreePath, staging)).length === 0;
|
|
22453
23103
|
}
|
|
22454
23104
|
async function missingInstalledPackages(worktreePath, treeRoot = worktreePath) {
|
|
22455
|
-
const wanted = parseLockfilePackages(await readFile8(
|
|
22456
|
-
const installed = parseLockfilePackages(await readFile8(
|
|
23105
|
+
const wanted = parseLockfilePackages(await readFile8(resolve20(worktreePath, "package-lock.json")).catch(() => void 0));
|
|
23106
|
+
const installed = parseLockfilePackages(await readFile8(resolve20(treeRoot, "node_modules", ".package-lock.json")).catch(() => void 0));
|
|
22457
23107
|
if (!wanted)
|
|
22458
23108
|
return ["package-lock.json is unreadable"];
|
|
22459
23109
|
if (!installed)
|
|
@@ -22473,14 +23123,14 @@ async function missingInstalledPackages(worktreePath, treeRoot = worktreePath) {
|
|
|
22473
23123
|
required.push(path);
|
|
22474
23124
|
}
|
|
22475
23125
|
await mapWithLimit(required, INTEGRITY_READ_CONCURRENCY, async (path) => {
|
|
22476
|
-
if (!(path in installed) || !await isInstalledPackage(
|
|
23126
|
+
if (!(path in installed) || !await isInstalledPackage(resolve20(treeRoot, path))) {
|
|
22477
23127
|
missing.push(path);
|
|
22478
23128
|
}
|
|
22479
23129
|
});
|
|
22480
23130
|
return missing.sort();
|
|
22481
23131
|
}
|
|
22482
23132
|
async function isInstalledPackage(path) {
|
|
22483
|
-
return stat2(
|
|
23133
|
+
return stat2(join8(path, "package.json")).then((info) => info.isFile(), () => false);
|
|
22484
23134
|
}
|
|
22485
23135
|
var INTEGRITY_READ_CONCURRENCY = 64;
|
|
22486
23136
|
async function mapWithLimit(values, limit, visit) {
|
|
@@ -22514,8 +23164,8 @@ function isContainedTreePath(value) {
|
|
|
22514
23164
|
async function cloneTree(source, target, file, topLevel = true) {
|
|
22515
23165
|
await mkdir10(target, { recursive: true, mode: 493 });
|
|
22516
23166
|
for (const entry of await readdir5(source, { withFileTypes: true })) {
|
|
22517
|
-
const from =
|
|
22518
|
-
const to =
|
|
23167
|
+
const from = join8(source, entry.name);
|
|
23168
|
+
const to = join8(target, entry.name);
|
|
22519
23169
|
if (entry.isSymbolicLink()) {
|
|
22520
23170
|
await symlink2(await readlink(from), to);
|
|
22521
23171
|
continue;
|
|
@@ -22545,13 +23195,13 @@ async function pruneWarmStore(storeRoot, keep) {
|
|
|
22545
23195
|
const names = (await readdir5(storeRoot).catch(() => [])).filter((name) => !name.startsWith(STAGING_PREFIX));
|
|
22546
23196
|
const entries = [];
|
|
22547
23197
|
for (const name of names) {
|
|
22548
|
-
const info = await lstat2(
|
|
23198
|
+
const info = await lstat2(join8(storeRoot, name)).catch(() => void 0);
|
|
22549
23199
|
if (info?.isDirectory())
|
|
22550
23200
|
entries.push({ name, usedAt: info.mtimeMs });
|
|
22551
23201
|
}
|
|
22552
23202
|
const dropped = entries.sort((a2, b) => b.usedAt - a2.usedAt || a2.name.localeCompare(b.name)).slice(keep);
|
|
22553
23203
|
for (const entry of dropped) {
|
|
22554
|
-
await rm4(
|
|
23204
|
+
await rm4(join8(storeRoot, entry.name), { recursive: true, force: true }).catch(() => void 0);
|
|
22555
23205
|
}
|
|
22556
23206
|
return dropped.map((entry) => entry.name);
|
|
22557
23207
|
}
|
|
@@ -22560,7 +23210,7 @@ async function sweepStaleStaging(storeRoot, now2) {
|
|
|
22560
23210
|
for (const name of entries) {
|
|
22561
23211
|
if (!name.startsWith(STAGING_PREFIX))
|
|
22562
23212
|
continue;
|
|
22563
|
-
const path =
|
|
23213
|
+
const path = join8(storeRoot, name);
|
|
22564
23214
|
const info = await lstat2(path).catch(() => void 0);
|
|
22565
23215
|
if (!info || now2 - info.mtimeMs < STAGING_SWEEP_MS)
|
|
22566
23216
|
continue;
|
|
@@ -22582,8 +23232,8 @@ function describe3(error) {
|
|
|
22582
23232
|
|
|
22583
23233
|
// apps/body/dist/monolith-room-turn.js
|
|
22584
23234
|
import { mkdir as mkdir11 } from "node:fs/promises";
|
|
22585
|
-
import { homedir as
|
|
22586
|
-
import { join as
|
|
23235
|
+
import { homedir as homedir7 } from "node:os";
|
|
23236
|
+
import { join as join9 } from "node:path";
|
|
22587
23237
|
|
|
22588
23238
|
// packages/api-contract/dist/scheduled-prompts.js
|
|
22589
23239
|
var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
|
|
@@ -22615,9 +23265,23 @@ function inboxItemPromptBody(item) {
|
|
|
22615
23265
|
return isScheduledPrompt(item) ? item.systemEvent?.consequence ?? item.body : item.body;
|
|
22616
23266
|
}
|
|
22617
23267
|
function pendingGrantToolCall(call) {
|
|
22618
|
-
if (!/(?:^|[._:/-])request_grant$/i.test(call.title ?? ""))
|
|
23268
|
+
if (!/(?:^|[._:/-])(?:request_grant|offer_connector)$/i.test(call.title ?? ""))
|
|
22619
23269
|
return false;
|
|
22620
|
-
return /pending, card posted/i.test(typeof call.content === "string" ? call.content : JSON.stringify(call.content ?? ""));
|
|
23270
|
+
return /(?:pending|already offered), card (?:posted|still open)/i.test(typeof call.content === "string" ? call.content : JSON.stringify(call.content ?? ""));
|
|
23271
|
+
}
|
|
23272
|
+
function resumePrompt(item) {
|
|
23273
|
+
if (item.systemEvent?.kind === "connector-offer-decided") {
|
|
23274
|
+
return [
|
|
23275
|
+
`This is the answer to your connector offer: ${item.body}.`,
|
|
23276
|
+
"Your paused work resumes now. The tool is being installed on your machine; its sign-in and status reach the person through the tool\u2019s own status message, not through you.",
|
|
23277
|
+
'Acknowledge in one short line (for example "Adding Trusty Squire now.") and continue the work that needed it, or say plainly what still has to happen before you can.'
|
|
23278
|
+
].join(" ");
|
|
23279
|
+
}
|
|
23280
|
+
return [
|
|
23281
|
+
"This is the answer to your grant request; your paused work resumes now.",
|
|
23282
|
+
"If it was approved and it is a command grant, run it with run_granted_command and the exact argv.",
|
|
23283
|
+
"If it was declined, try another way or say plainly what you cannot do."
|
|
23284
|
+
].join(" ");
|
|
22621
23285
|
}
|
|
22622
23286
|
function roomMentionDirectory(roster, selfId) {
|
|
22623
23287
|
const rows = [];
|
|
@@ -22719,7 +23383,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
22719
23383
|
...this.options.config.bwrapPath ? { bwrapPath: this.options.config.bwrapPath } : {},
|
|
22720
23384
|
...this.sessionScratchDir ? { scratch: this.sessionScratchDir } : {},
|
|
22721
23385
|
...this.sessionStateDirs.length ? { harnessStateDirs: this.sessionStateDirs } : {},
|
|
22722
|
-
maskPaths: credentialMaskPaths(this.options.config.sandboxMaskPaths, this.options.config.operatorHome ??
|
|
23386
|
+
maskPaths: credentialMaskPaths(this.options.config.sandboxMaskPaths, this.options.config.operatorHome ?? homedir7())
|
|
22723
23387
|
};
|
|
22724
23388
|
}
|
|
22725
23389
|
/**
|
|
@@ -22786,7 +23450,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
22786
23450
|
const cached = this.deliveredAttachments.get(item.id);
|
|
22787
23451
|
if (cached)
|
|
22788
23452
|
return cached;
|
|
22789
|
-
const delivered = await deliverAttachments(item.attachments,
|
|
23453
|
+
const delivered = await deliverAttachments(item.attachments, join9(this.attachmentDir, item.id.replace(/[^\w-]/g, "_")), this.options.fetchImpl);
|
|
22790
23454
|
this.deliveredAttachments.set(item.id, withoutImageData(delivered));
|
|
22791
23455
|
return delivered;
|
|
22792
23456
|
}
|
|
@@ -22873,6 +23537,10 @@ var MonolithRoomTurnLoop = class {
|
|
|
22873
23537
|
})
|
|
22874
23538
|
}) : {};
|
|
22875
23539
|
const command = this.options.config.agentCommand ?? this.options.config.agentBinary;
|
|
23540
|
+
const harnessLabel = harnessIdentityLabel({
|
|
23541
|
+
kind: this.options.config.agentKind,
|
|
23542
|
+
command
|
|
23543
|
+
});
|
|
22876
23544
|
const agentEnv = { ...this.options.config.agentEnv, ...homeOverlay };
|
|
22877
23545
|
this.agentEnv = agentEnv;
|
|
22878
23546
|
const agentArgs = agentArgsWithModelSelection({
|
|
@@ -22880,12 +23548,12 @@ var MonolithRoomTurnLoop = class {
|
|
|
22880
23548
|
command,
|
|
22881
23549
|
args: this.options.config.agentArgs ?? []
|
|
22882
23550
|
}, selection);
|
|
22883
|
-
const operatorHome = this.options.config.operatorHome ??
|
|
23551
|
+
const operatorHome = this.options.config.operatorHome ?? homedir7();
|
|
22884
23552
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
22885
|
-
this.attachmentDir = tmpDir ?
|
|
23553
|
+
this.attachmentDir = tmpDir ? join9(tmpDir, "beeline-attachments") : void 0;
|
|
22886
23554
|
this.sessionScratchDir = tmpDir;
|
|
22887
23555
|
this.sessionStateDirs = stateDirs;
|
|
22888
|
-
const homeStateDirs = harnessHomeStateDirs(
|
|
23556
|
+
const homeStateDirs = harnessHomeStateDirs(harnessLabel, agentEnv.HOME ?? operatorHome);
|
|
22889
23557
|
await Promise.all(homeStateDirs.map((dir) => mkdir11(dir, { recursive: true })));
|
|
22890
23558
|
const attachScratchRoot = this.options.config.agentHomeRoot ?? tmpDir;
|
|
22891
23559
|
if (attachScratchRoot)
|
|
@@ -22921,7 +23589,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
22921
23589
|
})
|
|
22922
23590
|
];
|
|
22923
23591
|
await installPiMcpBridge({
|
|
22924
|
-
agentCommand:
|
|
23592
|
+
agentCommand: harnessLabel,
|
|
22925
23593
|
piHome: agentEnv.PI_CODING_AGENT_DIR,
|
|
22926
23594
|
servers
|
|
22927
23595
|
});
|
|
@@ -22931,7 +23599,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
22931
23599
|
agentArgs: spawnCommand.args,
|
|
22932
23600
|
agentEnv,
|
|
22933
23601
|
agentCwd: this.options.cwd,
|
|
22934
|
-
agentLabel:
|
|
23602
|
+
agentLabel: harnessLabel,
|
|
22935
23603
|
// `bwrapPath` is set only when `detectBwrapSandbox` passed its self-test
|
|
22936
23604
|
// (`config.ts`), which is exactly when `wrapAgentCommand` above wraps.
|
|
22937
23605
|
osSandbox: Boolean(this.options.config.bwrapPath),
|
|
@@ -23007,7 +23675,10 @@ var MonolithRoomTurnLoop = class {
|
|
|
23007
23675
|
if (durableReplyText(result.agentText))
|
|
23008
23676
|
return void 0;
|
|
23009
23677
|
return explainEmptyAgentTurn({
|
|
23010
|
-
agentLabel:
|
|
23678
|
+
agentLabel: harnessIdentityLabel({
|
|
23679
|
+
kind: this.options.config.agentKind,
|
|
23680
|
+
command: this.options.config.agentCommand ?? this.options.config.agentBinary
|
|
23681
|
+
}),
|
|
23011
23682
|
agentEnv: this.agentEnv,
|
|
23012
23683
|
sessionId: this.sessionId,
|
|
23013
23684
|
result
|
|
@@ -23129,11 +23800,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
23129
23800
|
const buildPrompt = () => [
|
|
23130
23801
|
this.turnInstructionPrefix,
|
|
23131
23802
|
WarmTranscript.render(this.warmTranscript.select(this.sessionId, transcriptRows), "Room conversation so far:", "New in the Room since your last turn (the earlier conversation is already in this session):"),
|
|
23132
|
-
grantDecision ?
|
|
23133
|
-
"This is the answer to your grant request; your paused work resumes now.",
|
|
23134
|
-
"If it was approved and it is a command grant, run it with run_granted_command and the exact argv.",
|
|
23135
|
-
"If it was declined, try another way or say plainly what you cannot do."
|
|
23136
|
-
].join(" ") : "",
|
|
23803
|
+
grantDecision ? resumePrompt(item) : "",
|
|
23137
23804
|
roomMentionDirectory(roster, this.agent.publicKey),
|
|
23138
23805
|
(corners.corners ?? []).some((corner) => !corner.archived) ? `Current corners you belong to (use the exact cornerId with steer_corner):
|
|
23139
23806
|
${JSON.stringify((corners.corners ?? []).filter((corner) => !corner.archived))}` : "",
|
|
@@ -23219,7 +23886,7 @@ ${JSON.stringify((corners.corners ?? []).filter((corner) => !corner.archived))}`
|
|
|
23219
23886
|
this.pausedOnGrantRequestId = item.id;
|
|
23220
23887
|
console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${item.id} paused on a grant card`);
|
|
23221
23888
|
} else if (resumedRequestId) {
|
|
23222
|
-
console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${resumedRequestId} resumed by
|
|
23889
|
+
console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${resumedRequestId} resumed by card decision ${item.id}`);
|
|
23223
23890
|
}
|
|
23224
23891
|
if (openCornerCall) {
|
|
23225
23892
|
console.log(`[thin-core] monolith Room ${this.options.roomId} tool call: ${openCornerCall.title} (${openCornerCall.status ?? "no status"})`);
|
|
@@ -23323,7 +23990,7 @@ ${JSON.stringify((corners.corners ?? []).filter((corner) => !corner.archived))}`
|
|
|
23323
23990
|
const item = {
|
|
23324
23991
|
...command.source,
|
|
23325
23992
|
id: command.turnRequestId,
|
|
23326
|
-
body: command.action === "resume" ? `Resume the paused turn. The server supplied this
|
|
23993
|
+
body: command.action === "resume" ? `Resume the paused turn. The server supplied this answer: ${command.source.body}` : command.source.body
|
|
23327
23994
|
};
|
|
23328
23995
|
this.startPrompt(item);
|
|
23329
23996
|
await this.activeTurn?.promise;
|
|
@@ -23502,7 +24169,7 @@ function toolArguments(call) {
|
|
|
23502
24169
|
return input ? { input: clampBytes(redactToolDetail(input), TOOL_ARGUMENT_MAX_BYTES) } : {};
|
|
23503
24170
|
}
|
|
23504
24171
|
function toolCallKey(call, index) {
|
|
23505
|
-
return call.id ? `id-${
|
|
24172
|
+
return call.id ? `id-${createHash6("sha256").update(call.id).digest("hex")}` : `tool-${index}`;
|
|
23506
24173
|
}
|
|
23507
24174
|
function toolCallSettled(call) {
|
|
23508
24175
|
if (call.resultReceived)
|
|
@@ -23752,6 +24419,10 @@ var MonolithCornerTurnLoop = class {
|
|
|
23752
24419
|
})
|
|
23753
24420
|
}) : {};
|
|
23754
24421
|
const command = this.options.config.agentCommand ?? this.options.config.agentBinary;
|
|
24422
|
+
const harnessLabel = harnessIdentityLabel({
|
|
24423
|
+
kind: this.options.config.agentKind,
|
|
24424
|
+
command
|
|
24425
|
+
});
|
|
23755
24426
|
const repository = this.options.repository;
|
|
23756
24427
|
let githubEnv = repository ? { GH_TOKEN: repository.githubToken, GITHUB_TOKEN: repository.githubToken } : {};
|
|
23757
24428
|
if (repository && this.options.config.runtimeConfigPath && this.options.config.agentHomeRoot) {
|
|
@@ -23783,11 +24454,11 @@ var MonolithCornerTurnLoop = class {
|
|
|
23783
24454
|
command,
|
|
23784
24455
|
args: this.options.config.agentArgs ?? []
|
|
23785
24456
|
}, selection);
|
|
23786
|
-
const operatorHome = this.options.config.operatorHome ??
|
|
24457
|
+
const operatorHome = this.options.config.operatorHome ?? homedir8();
|
|
23787
24458
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
23788
|
-
this.attachmentDir = tmpDir ?
|
|
24459
|
+
this.attachmentDir = tmpDir ? join10(tmpDir, "beeline-attachments") : void 0;
|
|
23789
24460
|
this.sessionScratchDir = tmpDir;
|
|
23790
|
-
const homeStateDirs = harnessHomeStateDirs(
|
|
24461
|
+
const homeStateDirs = harnessHomeStateDirs(harnessLabel, agentEnv.HOME ?? operatorHome);
|
|
23791
24462
|
await Promise.all(homeStateDirs.map((dir) => mkdir12(dir, { recursive: true })));
|
|
23792
24463
|
const attachScratchRoot = this.options.config.agentHomeRoot ?? tmpDir;
|
|
23793
24464
|
if (attachScratchRoot)
|
|
@@ -23820,7 +24491,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
23820
24491
|
agentArgs: spawnCommand.args,
|
|
23821
24492
|
agentEnv,
|
|
23822
24493
|
agentCwd: this.options.worktreePath,
|
|
23823
|
-
agentLabel:
|
|
24494
|
+
agentLabel: harnessLabel,
|
|
23824
24495
|
autoApprovePermissions: true,
|
|
23825
24496
|
permissionHandler: () => Promise.resolve("allow")
|
|
23826
24497
|
};
|
|
@@ -23860,7 +24531,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
23860
24531
|
})
|
|
23861
24532
|
];
|
|
23862
24533
|
await installPiMcpBridge({
|
|
23863
|
-
agentCommand:
|
|
24534
|
+
agentCommand: harnessLabel,
|
|
23864
24535
|
piHome: agentEnv.PI_CODING_AGENT_DIR,
|
|
23865
24536
|
servers
|
|
23866
24537
|
});
|
|
@@ -23887,7 +24558,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
23887
24558
|
selfReviewerInstruction ?? cornerMergeInstruction(configuration.yoloMode, configuration.reviewerHandle)
|
|
23888
24559
|
],
|
|
23889
24560
|
"Do not tag the user when a corner turn finishes: the server posts the merge summary card and its push already cover completion. Tag a human only mid-turn, and only when you need a decision or input.",
|
|
23890
|
-
"Never restate server check or merge notes. On a checks turn, say nothing unless you merge or push a fix, then use one short line. Never merge while approvalPending is true. When approval is pending, wait for the reviewer to tag you. Never merge another pull request. Never create a schedule to poll pr_checks_status or the merge gate: the green transition wakes the reviewer and the reviewer's approval tag wakes you, and tagging any agent other than the configured reviewer cannot clear the gate. If a schedule wakes you in this corner anyway, follow the same rule as a checks turn: say nothing unless you merge, push a fix, or report a genuinely new blocker."
|
|
24561
|
+
"Never restate server check or merge notes. On a checks turn, say nothing unless you merge or push a fix, then use one short line. When asked whether the reviewer was woken, call pr_checks_status and report reviewerWake; do not invent a cause. Never merge while approvalPending is true. When approval is pending, wait for the reviewer to tag you. Never merge another pull request. Never create a schedule to poll pr_checks_status or the merge gate: the green transition wakes the reviewer and the reviewer's approval tag wakes you, and tagging any agent other than the configured reviewer cannot clear the gate. If a schedule wakes you in this corner anyway, follow the same rule as a checks turn: say nothing unless you merge, push a fix, or report a genuinely new blocker."
|
|
23891
24562
|
] : [
|
|
23892
24563
|
"This is a chat-only corner with no repository or GitHub workflow.",
|
|
23893
24564
|
"Work in this corner's writable workspace. Use write_scratch_file or ordinary tools to create files, then post_artifact with the path to send them back to the corner.",
|
|
@@ -23937,7 +24608,10 @@ var MonolithCornerTurnLoop = class {
|
|
|
23937
24608
|
if (durableReplyText(result.agentText))
|
|
23938
24609
|
return void 0;
|
|
23939
24610
|
return explainEmptyAgentTurn({
|
|
23940
|
-
agentLabel:
|
|
24611
|
+
agentLabel: harnessIdentityLabel({
|
|
24612
|
+
kind: this.options.config.agentKind,
|
|
24613
|
+
command: this.options.config.agentCommand ?? this.options.config.agentBinary
|
|
24614
|
+
}),
|
|
23941
24615
|
agentEnv: this.agentEnv,
|
|
23942
24616
|
sessionId: this.sessionId,
|
|
23943
24617
|
result
|
|
@@ -24006,7 +24680,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
24006
24680
|
const [conversation, roster, delivered] = await trace.measure("context-fetch", () => Promise.all([
|
|
24007
24681
|
api.execute("getRoomConversation", { roomId: cornerId, limit: 200 }),
|
|
24008
24682
|
this.roster(),
|
|
24009
|
-
this.attachmentDir && attachments.length ? deliverAttachments(attachments,
|
|
24683
|
+
this.attachmentDir && attachments.length ? deliverAttachments(attachments, join10(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : Promise.resolve([])
|
|
24010
24684
|
]));
|
|
24011
24685
|
const names = new Map(roster.members.map((member) => [member.identityId, member.name]));
|
|
24012
24686
|
const requestedBy = requester && !requester.name && names.get(requester.pubkey) ? { ...requester, name: names.get(requester.pubkey) } : requester;
|
|
@@ -24773,13 +25447,13 @@ function shouldPostInitialCornerWorkingState(restore, isOpener = true) {
|
|
|
24773
25447
|
}
|
|
24774
25448
|
async function materializeCornerWorktree(input) {
|
|
24775
25449
|
const remote = roomCheckoutRemote(input.remote);
|
|
24776
|
-
const repositoryHash =
|
|
24777
|
-
const gitCommonDir =
|
|
24778
|
-
const path =
|
|
24779
|
-
await mkdir13(
|
|
24780
|
-
await mkdir13(
|
|
25450
|
+
const repositoryHash = createHash7("sha256").update(remote).digest("hex").slice(0, 24);
|
|
25451
|
+
const gitCommonDir = resolve21(input.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
|
|
25452
|
+
const path = resolve21(input.supervisorRoot, "beeline", "corners", input.cornerId);
|
|
25453
|
+
await mkdir13(dirname9(gitCommonDir), { recursive: true, mode: 448 });
|
|
25454
|
+
await mkdir13(dirname9(path), { recursive: true, mode: 448 });
|
|
24781
25455
|
const authEnv = githubGitEnv(input.token);
|
|
24782
|
-
if (!
|
|
25456
|
+
if (!existsSync5(resolve21(gitCommonDir, "HEAD"))) {
|
|
24783
25457
|
await execFileAsync4("git", ["clone", "--bare", remote, gitCommonDir], {
|
|
24784
25458
|
env: authEnv,
|
|
24785
25459
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -24798,7 +25472,7 @@ async function materializeCornerWorktree(input) {
|
|
|
24798
25472
|
"origin",
|
|
24799
25473
|
`+refs/heads/${input.featureBranch}:refs/remotes/origin/${input.featureBranch}`
|
|
24800
25474
|
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 }).then(() => true, () => false);
|
|
24801
|
-
if (!
|
|
25475
|
+
if (!existsSync5(resolve21(path, ".git"))) {
|
|
24802
25476
|
await rm5(path, { recursive: true, force: true });
|
|
24803
25477
|
await execFileAsync4("git", [
|
|
24804
25478
|
`--git-dir=${gitCommonDir}`,
|
|
@@ -24849,7 +25523,7 @@ async function materializeCornerWorktree(input) {
|
|
|
24849
25523
|
`${input.committer.publicKey.slice(0, 16)}@users.noreply.github.com`
|
|
24850
25524
|
]);
|
|
24851
25525
|
const top = await execFileAsync4("git", ["-C", path, "rev-parse", "--show-toplevel"]);
|
|
24852
|
-
if (
|
|
25526
|
+
if (resolve21(top.stdout.trim()) !== resolve21(path)) {
|
|
24853
25527
|
throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
|
|
24854
25528
|
}
|
|
24855
25529
|
return { path, gitCommonDir };
|
|
@@ -24870,7 +25544,7 @@ async function mapWithConcurrency(values, limit, visit) {
|
|
|
24870
25544
|
async function removeCornerWorktreeAndBranches(worktree) {
|
|
24871
25545
|
const localRef = `refs/heads/${worktree.branch}`;
|
|
24872
25546
|
const remoteRef = `refs/heads/${worktree.branch}`;
|
|
24873
|
-
const worktreeExists =
|
|
25547
|
+
const worktreeExists = existsSync5(worktree.path);
|
|
24874
25548
|
const localExists = await gitRefExists(worktree.gitCommonDir, localRef);
|
|
24875
25549
|
if (worktreeExists) {
|
|
24876
25550
|
const checkedOut = await execFileAsync4("git", [
|
|
@@ -24915,8 +25589,8 @@ async function removeCornerWorktreeAndBranches(worktree) {
|
|
|
24915
25589
|
}
|
|
24916
25590
|
var execFileAsync4 = promisify4(execFile6);
|
|
24917
25591
|
async function removeCornerScratchWorkspace(input) {
|
|
24918
|
-
const expected =
|
|
24919
|
-
if (
|
|
25592
|
+
const expected = resolve21(input.roomRoot, "scratch");
|
|
25593
|
+
if (resolve21(input.scratchPath) !== expected) {
|
|
24920
25594
|
throw new Error(`refusing to remove scratch outside corner ${input.cornerId}`);
|
|
24921
25595
|
}
|
|
24922
25596
|
await rm5(expected, { recursive: true, force: true });
|
|
@@ -25130,14 +25804,14 @@ var RoomRuntimeCoordinator = class {
|
|
|
25130
25804
|
return this.runtime.rooms.find((room) => room.channelId === roomId);
|
|
25131
25805
|
}
|
|
25132
25806
|
roomRoot(roomId) {
|
|
25133
|
-
return this.roomRecord(roomId)?.root ??
|
|
25807
|
+
return this.roomRecord(roomId)?.root ?? resolve21(dirname9(this.configPath), "rooms", roomId);
|
|
25134
25808
|
}
|
|
25135
25809
|
roomAgentHomeRoot(workspaceRoot, required = false) {
|
|
25136
25810
|
const flag = process.env.BUZZY_BODY_ROOM_HOME;
|
|
25137
25811
|
if (!required && flag === "0")
|
|
25138
25812
|
return void 0;
|
|
25139
|
-
const home =
|
|
25140
|
-
if (!required && flag !== "1" && !
|
|
25813
|
+
const home = resolve21(workspaceRoot, "agent-home");
|
|
25814
|
+
if (!required && flag !== "1" && !existsSync5(home) && existsSync5(workspaceRoot))
|
|
25141
25815
|
return void 0;
|
|
25142
25816
|
try {
|
|
25143
25817
|
mkdirSync(home, { recursive: true, mode: 448 });
|
|
@@ -25152,10 +25826,10 @@ var RoomRuntimeCoordinator = class {
|
|
|
25152
25826
|
return {
|
|
25153
25827
|
...this.baseConfig,
|
|
25154
25828
|
workspaceRoot,
|
|
25155
|
-
agentPrivateRoot:
|
|
25156
|
-
agentMemoryRoot:
|
|
25157
|
-
openRouterRoutingCacheDir: openRouterRoutingCacheDir(
|
|
25158
|
-
turnTraceDir: turnTraceDirectory(
|
|
25829
|
+
agentPrivateRoot: resolve21(workspaceRoot, "agent-private"),
|
|
25830
|
+
agentMemoryRoot: resolve21(dirname9(this.configPath), "memory"),
|
|
25831
|
+
openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname9(this.configPath)),
|
|
25832
|
+
turnTraceDir: turnTraceDirectory(dirname9(this.configPath)),
|
|
25159
25833
|
...agentHomeRoot ? { agentHomeRoot } : {}
|
|
25160
25834
|
};
|
|
25161
25835
|
}
|
|
@@ -25221,12 +25895,12 @@ var RoomRuntimeCoordinator = class {
|
|
|
25221
25895
|
return this.roomRoot(roomId);
|
|
25222
25896
|
const remote = roomCheckoutRemote(repository.remote);
|
|
25223
25897
|
const targetBranch = repository.targetBranch || "main";
|
|
25224
|
-
const checkoutId =
|
|
25225
|
-
const path =
|
|
25226
|
-
await mkdir13(
|
|
25898
|
+
const checkoutId = createHash7("sha256").update(`${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
|
|
25899
|
+
const path = resolve21(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
|
|
25900
|
+
await mkdir13(dirname9(path), { recursive: true, mode: 448 });
|
|
25227
25901
|
const token = remote.startsWith("https://github.com/") ? await this.options.daemonApi.execute("getRoomGitHubToken", { roomId }) : void 0;
|
|
25228
25902
|
const env = token ? githubGitEnv(token.token) : process.env;
|
|
25229
|
-
if (!
|
|
25903
|
+
if (!existsSync5(resolve21(path, ".git"))) {
|
|
25230
25904
|
await execFileAsync4("git", ["clone", "--no-checkout", remote, path], {
|
|
25231
25905
|
env,
|
|
25232
25906
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -25279,7 +25953,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
25279
25953
|
featureBranch,
|
|
25280
25954
|
token: granted.token
|
|
25281
25955
|
}) : void 0;
|
|
25282
|
-
const workspacePath = worktree?.path ??
|
|
25956
|
+
const workspacePath = worktree?.path ?? resolve21(this.roomRoot(corner.cornerId), "scratch");
|
|
25283
25957
|
if (!worktree)
|
|
25284
25958
|
await mkdir13(workspacePath, { recursive: true, mode: 448 });
|
|
25285
25959
|
const isOpener = !corner.openedBy || corner.openedBy === this.agent.publicKey;
|
|
@@ -25668,8 +26342,8 @@ var ThinDaemonCore = class {
|
|
|
25668
26342
|
// apps/body/dist/systemd.js
|
|
25669
26343
|
import { execFile as execFile7 } from "node:child_process";
|
|
25670
26344
|
import { mkdir as mkdir14, readFile as readFile9, writeFile as writeFile9 } from "node:fs/promises";
|
|
25671
|
-
import { homedir as
|
|
25672
|
-
import { dirname as
|
|
26345
|
+
import { homedir as homedir9 } from "node:os";
|
|
26346
|
+
import { dirname as dirname10, resolve as resolve22 } from "node:path";
|
|
25673
26347
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
25674
26348
|
import { promisify as promisify5 } from "node:util";
|
|
25675
26349
|
var execFileAsync5 = promisify5(execFile7);
|
|
@@ -25710,10 +26384,10 @@ WantedBy=default.target
|
|
|
25710
26384
|
`;
|
|
25711
26385
|
}
|
|
25712
26386
|
function isCanonicalInstalledLauncher(env = process.env, invocationPath = process.argv[1]) {
|
|
25713
|
-
const home = env.HOME?.trim() ||
|
|
25714
|
-
const expectedLibDir =
|
|
26387
|
+
const home = env.HOME?.trim() || homedir9();
|
|
26388
|
+
const expectedLibDir = resolve22(home, ".local", "lib", "beeline");
|
|
25715
26389
|
const expectedPrefix = `${expectedLibDir}/`;
|
|
25716
|
-
return
|
|
26390
|
+
return resolve22(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve22(invocationPath).startsWith(expectedPrefix);
|
|
25717
26391
|
}
|
|
25718
26392
|
function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
25719
26393
|
if (isCanonicalInstalledLauncher(env, invocationPath))
|
|
@@ -25721,8 +26395,8 @@ function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
|
25721
26395
|
throw new Error("refusing to modify the shared Beeline systemd unit outside the canonical ~/.local/bin/beeline launcher");
|
|
25722
26396
|
}
|
|
25723
26397
|
function systemdUserUnitPath(env = process.env) {
|
|
25724
|
-
const configRoot = env.XDG_CONFIG_HOME?.trim() ||
|
|
25725
|
-
return
|
|
26398
|
+
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve22(homedir9(), ".config");
|
|
26399
|
+
return resolve22(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
|
|
25726
26400
|
}
|
|
25727
26401
|
var runSystemctl = async (args) => {
|
|
25728
26402
|
const result = await execFileAsync5("systemctl", ["--user", ...args], {
|
|
@@ -25740,7 +26414,7 @@ async function installAgentService(publicKey, options = {}) {
|
|
|
25740
26414
|
const content = agentServiceUnit();
|
|
25741
26415
|
const existing = await readFile9(path, "utf8").catch(() => "");
|
|
25742
26416
|
if (existing !== content) {
|
|
25743
|
-
await mkdir14(
|
|
26417
|
+
await mkdir14(dirname10(path), { recursive: true, mode: 448 });
|
|
25744
26418
|
await writeFile9(path, content, { mode: 384 });
|
|
25745
26419
|
}
|
|
25746
26420
|
const run2 = options.run ?? runSystemctl;
|
|
@@ -25821,7 +26495,7 @@ async function retireRemovedAgent(runtime, options = {}) {
|
|
|
25821
26495
|
}
|
|
25822
26496
|
|
|
25823
26497
|
// apps/body/dist/start-command.js
|
|
25824
|
-
import { dirname as
|
|
26498
|
+
import { dirname as dirname11 } from "node:path";
|
|
25825
26499
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
25826
26500
|
var DEFAULT_RESTART_DRAIN_TIMEOUT_MS = 30 * 6e4;
|
|
25827
26501
|
var RESTART_WAIT_REPORT_INTERVAL_MS = 3e4;
|
|
@@ -25896,7 +26570,7 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
25896
26570
|
continue;
|
|
25897
26571
|
}
|
|
25898
26572
|
const spinnerHandle = spinner();
|
|
25899
|
-
spinnerHandle.start(`Starting ${
|
|
26573
|
+
spinnerHandle.start(`Starting ${dirname11(path)}\u2026`);
|
|
25900
26574
|
try {
|
|
25901
26575
|
await startRuntime(path, spinnerHandle);
|
|
25902
26576
|
spinnerHandle.stop(import_picocolors.default.green("Started."));
|
|
@@ -25911,11 +26585,11 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
25911
26585
|
}
|
|
25912
26586
|
|
|
25913
26587
|
// apps/body/dist/connect-command.js
|
|
25914
|
-
import { spawn as
|
|
25915
|
-
import { createHash as
|
|
26588
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
26589
|
+
import { createHash as createHash9, randomUUID as randomUUID6 } from "node:crypto";
|
|
25916
26590
|
import { chmod as chmod6, mkdir as mkdir16, readFile as readFile11, unlink as unlink2, writeFile as writeFile11 } from "node:fs/promises";
|
|
25917
|
-
import { homedir as
|
|
25918
|
-
import { dirname as
|
|
26591
|
+
import { homedir as homedir11, hostname as hostname2 } from "node:os";
|
|
26592
|
+
import { dirname as dirname13, resolve as resolve24 } from "node:path";
|
|
25919
26593
|
import { stdin as stdin3, stdout as stdout4 } from "node:process";
|
|
25920
26594
|
|
|
25921
26595
|
// apps/body/dist/clack-support.js
|
|
@@ -25939,50 +26613,6 @@ function unwrapPrompt(value, cancelMessage = "Cancelled.") {
|
|
|
25939
26613
|
return value;
|
|
25940
26614
|
}
|
|
25941
26615
|
|
|
25942
|
-
// apps/body/dist/cursor-models.js
|
|
25943
|
-
import { spawn as spawn5 } from "node:child_process";
|
|
25944
|
-
var CURSOR_MODELS_TIMEOUT_MS = 1e4;
|
|
25945
|
-
function parseCursorModelsOutput(output) {
|
|
25946
|
-
const options = [];
|
|
25947
|
-
for (const line of output.split(/\r?\n/)) {
|
|
25948
|
-
const match = /^\s*([A-Za-z0-9][A-Za-z0-9._-]*)\s+-\s+(\S.*?)\s*$/.exec(line);
|
|
25949
|
-
if (!match)
|
|
25950
|
-
continue;
|
|
25951
|
-
const id = match[1];
|
|
25952
|
-
const name = match[2].replace(/\s*\(current, default\)\s*$/i, "").trim();
|
|
25953
|
-
options.push({ id, ...name && name !== id ? { name } : {} });
|
|
25954
|
-
}
|
|
25955
|
-
if (!options.length)
|
|
25956
|
-
return void 0;
|
|
25957
|
-
return {
|
|
25958
|
-
currentValue: options.some((option) => option.id === "auto") ? "auto" : options[0].id,
|
|
25959
|
-
options
|
|
25960
|
-
};
|
|
25961
|
-
}
|
|
25962
|
-
async function enumerateCursorModels(env = process.env) {
|
|
25963
|
-
return new Promise((resolve31) => {
|
|
25964
|
-
const child = spawn5("cursor-agent", ["models"], {
|
|
25965
|
-
env,
|
|
25966
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
25967
|
-
});
|
|
25968
|
-
let output = "";
|
|
25969
|
-
const timer = setTimeout(() => {
|
|
25970
|
-
child.kill("SIGKILL");
|
|
25971
|
-
}, CURSOR_MODELS_TIMEOUT_MS);
|
|
25972
|
-
child.stdout?.on("data", (chunk) => {
|
|
25973
|
-
output += chunk.toString();
|
|
25974
|
-
});
|
|
25975
|
-
child.on("error", () => {
|
|
25976
|
-
clearTimeout(timer);
|
|
25977
|
-
resolve31(void 0);
|
|
25978
|
-
});
|
|
25979
|
-
child.on("close", (code) => {
|
|
25980
|
-
clearTimeout(timer);
|
|
25981
|
-
resolve31(code === 0 ? parseCursorModelsOutput(output) : void 0);
|
|
25982
|
-
});
|
|
25983
|
-
});
|
|
25984
|
-
}
|
|
25985
|
-
|
|
25986
26616
|
// apps/body/dist/provider-key-check.js
|
|
25987
26617
|
var PROVIDER_LABELS = {
|
|
25988
26618
|
openrouter: "OpenRouter",
|
|
@@ -26043,7 +26673,7 @@ async function verifyProviderKey(input) {
|
|
|
26043
26673
|
}
|
|
26044
26674
|
|
|
26045
26675
|
// apps/body/dist/pair-agent-selection.js
|
|
26046
|
-
import { spawn as
|
|
26676
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
26047
26677
|
import { stdin as stdin2, stdout as stdout3 } from "node:process";
|
|
26048
26678
|
var NO_AGENT_MESSAGE = `No supported ACP-capable coding agent was detected.
|
|
26049
26679
|
Install one of these supported agents:
|
|
@@ -26052,7 +26682,7 @@ Install one of these supported agents:
|
|
|
26052
26682
|
goose https://block.github.io/goose/docs/getting-started/installation/
|
|
26053
26683
|
pi npm install -g @mariozechner/pi-coding-agent pi-acp
|
|
26054
26684
|
grok curl -fsSL https://x.ai/cli/install.sh | bash
|
|
26055
|
-
cursor
|
|
26685
|
+
cursor Install Cursor Agent CLI from https://cursor.com/docs/cli
|
|
26056
26686
|
Then retry, or explicitly use \`--agent reference\` with an LLM key.
|
|
26057
26687
|
For another ACP server, use \`--agent custom --agent-command "<cmd> [args...]"\`.`;
|
|
26058
26688
|
async function clackConfirmInstall(message) {
|
|
@@ -26072,7 +26702,7 @@ async function clackSelectAgent(candidates) {
|
|
|
26072
26702
|
}
|
|
26073
26703
|
async function installAdapter(install, opts) {
|
|
26074
26704
|
await new Promise((resolveInstall, rejectInstall) => {
|
|
26075
|
-
const child =
|
|
26705
|
+
const child = spawn7(install.command, install.args, {
|
|
26076
26706
|
cwd: opts.cwd,
|
|
26077
26707
|
env: opts.env ?? process.env,
|
|
26078
26708
|
stdio: "inherit"
|
|
@@ -26583,23 +27213,23 @@ function parseConnectSubscriptions(value) {
|
|
|
26583
27213
|
];
|
|
26584
27214
|
}
|
|
26585
27215
|
async function readMachineId(env = process.env) {
|
|
26586
|
-
const configDir =
|
|
26587
|
-
const machineIdPath =
|
|
27216
|
+
const configDir = resolve24(env.XDG_CONFIG_HOME ?? resolve24(homedir11(), ".config"), "beeline");
|
|
27217
|
+
const machineIdPath = resolve24(configDir, "machine-id");
|
|
26588
27218
|
let machineId;
|
|
26589
|
-
let machineName =
|
|
27219
|
+
let machineName = hostname2();
|
|
26590
27220
|
try {
|
|
26591
27221
|
const existing = await readFile11(machineIdPath, "utf8");
|
|
26592
27222
|
machineId = existing.trim();
|
|
26593
27223
|
if (!/^[0-9a-f-]{32,}$/.test(machineId))
|
|
26594
27224
|
throw new Error("invalid persisted machine id");
|
|
26595
27225
|
} catch {
|
|
26596
|
-
machineId =
|
|
27226
|
+
machineId = randomUUID6();
|
|
26597
27227
|
try {
|
|
26598
27228
|
await mkdir16(configDir, { recursive: true, mode: 448 });
|
|
26599
27229
|
await writeFile11(machineIdPath, `${machineId}
|
|
26600
27230
|
`, { mode: 384 });
|
|
26601
27231
|
} catch {
|
|
26602
|
-
machineId =
|
|
27232
|
+
machineId = createHash9("sha256").update(machineName).digest("hex").slice(0, 36);
|
|
26603
27233
|
}
|
|
26604
27234
|
}
|
|
26605
27235
|
return { machineId, machineName };
|
|
@@ -26608,7 +27238,7 @@ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl, machine
|
|
|
26608
27238
|
const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
|
|
26609
27239
|
if (!normalizedPairingCode)
|
|
26610
27240
|
throw new Error("invalid pairing code");
|
|
26611
|
-
const avatarSeed =
|
|
27241
|
+
const avatarSeed = createHash9("sha256").update(normalizedPairingCode.toUpperCase()).digest("hex").slice(0, 32);
|
|
26612
27242
|
return jsonRequest(`${baseUrl}/auth/agent/connect`, {
|
|
26613
27243
|
pairing_code: normalizedPairingCode,
|
|
26614
27244
|
harness: selection.harness,
|
|
@@ -26657,7 +27287,7 @@ async function installCurrentRelease(fetchImpl) {
|
|
|
26657
27287
|
});
|
|
26658
27288
|
await activateRelease(layout, releaseId);
|
|
26659
27289
|
return {
|
|
26660
|
-
binary:
|
|
27290
|
+
binary: resolve24(layout.binDir, "beeline"),
|
|
26661
27291
|
version: published.version ?? releaseId
|
|
26662
27292
|
};
|
|
26663
27293
|
}
|
|
@@ -26680,7 +27310,7 @@ function providerEnvironment(selection) {
|
|
|
26680
27310
|
};
|
|
26681
27311
|
}
|
|
26682
27312
|
async function writePrivateJson(path, value) {
|
|
26683
|
-
await mkdir16(
|
|
27313
|
+
await mkdir16(dirname13(path), { recursive: true, mode: 448 });
|
|
26684
27314
|
await writeFile11(path, `${JSON.stringify(value, null, 2)}
|
|
26685
27315
|
`, { mode: 384 });
|
|
26686
27316
|
await chmod6(path, 384);
|
|
@@ -26689,8 +27319,8 @@ async function writeProviderEnv(selection, agentPubkey) {
|
|
|
26689
27319
|
const values = providerEnvironment(selection);
|
|
26690
27320
|
if (Object.keys(values).length === 0)
|
|
26691
27321
|
return void 0;
|
|
26692
|
-
const path =
|
|
26693
|
-
await mkdir16(
|
|
27322
|
+
const path = resolve24(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
|
|
27323
|
+
await mkdir16(dirname13(path), { recursive: true, mode: 448 });
|
|
26694
27324
|
const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
|
|
26695
27325
|
await writeFile11(path, `${contents}
|
|
26696
27326
|
`, { mode: 384 });
|
|
@@ -26699,7 +27329,7 @@ async function writeProviderEnv(selection, agentPubkey) {
|
|
|
26699
27329
|
}
|
|
26700
27330
|
async function runInstalledFinish(binary, grantPath) {
|
|
26701
27331
|
await new Promise((resolveRun, rejectRun) => {
|
|
26702
|
-
const child =
|
|
27332
|
+
const child = spawn9(binary, ["connect-finish", grantPath], {
|
|
26703
27333
|
stdio: ["ignore", "pipe", "pipe"]
|
|
26704
27334
|
});
|
|
26705
27335
|
let diagnostic = "";
|
|
@@ -26756,7 +27386,7 @@ async function runConnectWizard(code, fetchImpl, eventSubscriptions, accessPolic
|
|
|
26756
27386
|
await finishConnectedAgentPairing(baseUrl, pairingCode, grant.workspace_joined, eventSubscriptions, fetchImpl);
|
|
26757
27387
|
const installedRelease = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl), (release) => `Installed Beeline helper ${release.version}`);
|
|
26758
27388
|
const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
|
|
26759
|
-
const grantPath =
|
|
27389
|
+
const grantPath = resolve24(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
|
|
26760
27390
|
await writePrivateJson(grantPath, {
|
|
26761
27391
|
agentSecretKey: grant.agent_secret_key,
|
|
26762
27392
|
bodySecretKey: grant.body_secret_key,
|
|
@@ -26841,18 +27471,18 @@ async function runConnectFinishCommand(path) {
|
|
|
26841
27471
|
throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
|
|
26842
27472
|
}
|
|
26843
27473
|
try {
|
|
26844
|
-
const grant = JSON.parse(await readFile11(
|
|
27474
|
+
const grant = JSON.parse(await readFile11(resolve24(path), "utf8"));
|
|
26845
27475
|
if (!isDevicePairingGrant(grant))
|
|
26846
27476
|
throw new Error("device connection grant is invalid");
|
|
26847
27477
|
const connected = await completeDevicePairing(grant);
|
|
26848
|
-
await unlink2(
|
|
27478
|
+
await unlink2(resolve24(path));
|
|
26849
27479
|
const providerEnv = grant.llmEnvFile ? await readFile11(grant.llmEnvFile, "utf8").catch(() => "") : "";
|
|
26850
27480
|
const apiKey = (/^OPENROUTER_API_KEY=(\S+)/m.exec(providerEnv)?.[1] ?? "").replace(/^["']|["']$/g, "");
|
|
26851
27481
|
const model = openRouterModelId(grant.model, { OPENROUTER_API_KEY: apiKey });
|
|
26852
27482
|
if (model) {
|
|
26853
27483
|
const decision2 = await resolveOpenRouterRouting({
|
|
26854
27484
|
model,
|
|
26855
|
-
cacheDir: openRouterRoutingCacheDir(
|
|
27485
|
+
cacheDir: openRouterRoutingCacheDir(dirname13(connected.configPath)),
|
|
26856
27486
|
...apiKey ? { apiKey } : {},
|
|
26857
27487
|
probeTimeoutMs: 1e4
|
|
26858
27488
|
});
|
|
@@ -26873,22 +27503,22 @@ init_self_update_manifest();
|
|
|
26873
27503
|
|
|
26874
27504
|
// apps/body/dist/managed-update.js
|
|
26875
27505
|
init_self_update();
|
|
26876
|
-
import { spawn as
|
|
27506
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
26877
27507
|
import { mkdir as mkdir18, rm as rm7, stat as stat3, writeFile as writeFile13 } from "node:fs/promises";
|
|
26878
|
-
import { dirname as
|
|
27508
|
+
import { dirname as dirname15, resolve as resolve26 } from "node:path";
|
|
26879
27509
|
|
|
26880
27510
|
// apps/body/dist/update-rollback-alert.js
|
|
26881
27511
|
import { mkdir as mkdir17, readFile as readFile12, rename as rename5, unlink as unlink3, writeFile as writeFile12 } from "node:fs/promises";
|
|
26882
|
-
import { dirname as
|
|
27512
|
+
import { dirname as dirname14, resolve as resolve25 } from "node:path";
|
|
26883
27513
|
var REPORT_INTERVAL_MS = 60 * 60 * 1e3;
|
|
26884
27514
|
var lastLogged = /* @__PURE__ */ new Map();
|
|
26885
27515
|
function updateRollbackAlertPath(runtimeDir) {
|
|
26886
|
-
return
|
|
27516
|
+
return resolve25(runtimeDir, "update-rollback-alert.json");
|
|
26887
27517
|
}
|
|
26888
27518
|
async function writeAlert(runtimeDir, alert) {
|
|
26889
27519
|
const path = updateRollbackAlertPath(runtimeDir);
|
|
26890
27520
|
const staged = `${path}.${process.pid}.tmp`;
|
|
26891
|
-
await mkdir17(
|
|
27521
|
+
await mkdir17(dirname14(path), { recursive: true });
|
|
26892
27522
|
await writeFile12(staged, `${JSON.stringify(alert, null, 2)}
|
|
26893
27523
|
`, { mode: 384 });
|
|
26894
27524
|
await rename5(staged, path);
|
|
@@ -26952,13 +27582,13 @@ var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
|
|
|
26952
27582
|
var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
|
|
26953
27583
|
async function withInstallLock(layout, work, options = {}) {
|
|
26954
27584
|
const now2 = options.now ?? Date.now;
|
|
26955
|
-
const lock =
|
|
27585
|
+
const lock = resolve26(layout.releasesRoot, ".state", "install.lock");
|
|
26956
27586
|
const deadline = now2() + (options.waitMs ?? 1e4);
|
|
26957
|
-
await mkdir18(
|
|
27587
|
+
await mkdir18(dirname15(lock), { recursive: true });
|
|
26958
27588
|
for (; ; ) {
|
|
26959
27589
|
try {
|
|
26960
27590
|
await mkdir18(lock);
|
|
26961
|
-
await writeFile13(
|
|
27591
|
+
await writeFile13(resolve26(lock, "owner"), `${process.pid}
|
|
26962
27592
|
${now2()}
|
|
26963
27593
|
`, "utf8");
|
|
26964
27594
|
break;
|
|
@@ -27081,7 +27711,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
27081
27711
|
if (!attempt || attempt.releaseId !== desiredRelease || attempt.status !== "pending") {
|
|
27082
27712
|
const from = await readInstalledBundleIdentity({
|
|
27083
27713
|
...this.#layout,
|
|
27084
|
-
libDir:
|
|
27714
|
+
libDir: resolve26(this.#layout.releasesRoot, this.#loadedRelease)
|
|
27085
27715
|
}).catch(() => void 0) ?? {};
|
|
27086
27716
|
const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
|
|
27087
27717
|
const record3 = {
|
|
@@ -27287,7 +27917,7 @@ async function runManagedUpdateWorkerProcess() {
|
|
|
27287
27917
|
if (!entrypoint)
|
|
27288
27918
|
throw new Error("cannot resolve the current Beeline entrypoint");
|
|
27289
27919
|
await new Promise((resolveWorker, rejectWorker) => {
|
|
27290
|
-
const child =
|
|
27920
|
+
const child = spawn10(process.execPath, [entrypoint, "managed-update-worker"], {
|
|
27291
27921
|
detached: true,
|
|
27292
27922
|
env: { ...process.env, BEELINE_INTERNAL_UPDATE_WORKER: "1" },
|
|
27293
27923
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -27368,7 +27998,7 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
|
|
|
27368
27998
|
});
|
|
27369
27999
|
if (!accepted)
|
|
27370
28000
|
return false;
|
|
27371
|
-
await writeFile13(
|
|
28001
|
+
await writeFile13(resolve26(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
|
|
27372
28002
|
readyAt: (options.now ?? Date.now)(),
|
|
27373
28003
|
loadedRelease,
|
|
27374
28004
|
functionalProof: options.functionalProof
|
|
@@ -27597,11 +28227,11 @@ init_self_update();
|
|
|
27597
28227
|
|
|
27598
28228
|
// apps/body/dist/daemon-failure.js
|
|
27599
28229
|
import { mkdir as mkdir19, readFile as readFile13, rename as rename6, rm as rm8, writeFile as writeFile14 } from "node:fs/promises";
|
|
27600
|
-
import { dirname as
|
|
28230
|
+
import { dirname as dirname16, resolve as resolve27 } from "node:path";
|
|
27601
28231
|
var DAEMON_FAILURE_LIMIT = 3;
|
|
27602
28232
|
var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
27603
28233
|
function daemonFailurePath(runtimeDir) {
|
|
27604
|
-
return
|
|
28234
|
+
return resolve27(runtimeDir, "daemon-distress.json");
|
|
27605
28235
|
}
|
|
27606
28236
|
async function readFailureRecord(runtimeDir) {
|
|
27607
28237
|
try {
|
|
@@ -27617,7 +28247,7 @@ async function readFailureRecord(runtimeDir) {
|
|
|
27617
28247
|
async function writeFailureRecord(runtimeDir, record3) {
|
|
27618
28248
|
const path = daemonFailurePath(runtimeDir);
|
|
27619
28249
|
const staged = `${path}.${process.pid}.tmp`;
|
|
27620
|
-
await mkdir19(
|
|
28250
|
+
await mkdir19(dirname16(path), { recursive: true, mode: 448 });
|
|
27621
28251
|
await writeFile14(staged, `${JSON.stringify(record3, null, 2)}
|
|
27622
28252
|
`, { mode: 384 });
|
|
27623
28253
|
await rename6(staged, path);
|
|
@@ -27641,8 +28271,8 @@ async function clearDaemonStartFailures(runtimeDir) {
|
|
|
27641
28271
|
|
|
27642
28272
|
// apps/body/dist/update-functional-probe.js
|
|
27643
28273
|
import { mkdir as mkdir20, rm as rm9 } from "node:fs/promises";
|
|
27644
|
-
import { homedir as
|
|
27645
|
-
import { resolve as
|
|
28274
|
+
import { homedir as homedir12 } from "node:os";
|
|
28275
|
+
import { resolve as resolve28 } from "node:path";
|
|
27646
28276
|
var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
|
|
27647
28277
|
var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
|
|
27648
28278
|
var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
|
|
@@ -27709,6 +28339,10 @@ function describeCurrentReleaseOutcome(outcome) {
|
|
|
27709
28339
|
}
|
|
27710
28340
|
async function runUpdateFunctionalProbe(input) {
|
|
27711
28341
|
const command = input.config.agentCommand ?? input.config.agentBinary;
|
|
28342
|
+
const harnessLabel = harnessIdentityLabel({
|
|
28343
|
+
kind: input.config.agentKind,
|
|
28344
|
+
command
|
|
28345
|
+
});
|
|
27712
28346
|
const harness = input.config.agentKind ?? command;
|
|
27713
28347
|
if (input.config.modelUnavailable) {
|
|
27714
28348
|
throw new UpdateFunctionalProbeError("model-unavailable", input.config.modelUnavailable.detail);
|
|
@@ -27736,9 +28370,9 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
27736
28370
|
modelAnswerReason: `${detail} (the current release has the same host sandbox failure)`
|
|
27737
28371
|
};
|
|
27738
28372
|
}
|
|
27739
|
-
const root = input.probeRoot ??
|
|
27740
|
-
const cwd =
|
|
27741
|
-
const homeRoot =
|
|
28373
|
+
const root = input.probeRoot ?? resolve28(input.runtimeDir, "update-functional-probe");
|
|
28374
|
+
const cwd = resolve28(root, "checkout");
|
|
28375
|
+
const homeRoot = resolve28(root, "agent-home");
|
|
27742
28376
|
await rm9(root, { recursive: true, force: true });
|
|
27743
28377
|
await mkdir20(cwd, { recursive: true, mode: 448 });
|
|
27744
28378
|
let client;
|
|
@@ -27747,7 +28381,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
27747
28381
|
...input.config.agentEnv,
|
|
27748
28382
|
...await prepareRoomAgentHome({
|
|
27749
28383
|
root: homeRoot,
|
|
27750
|
-
operatorHome: input.config.operatorHome ??
|
|
28384
|
+
operatorHome: input.config.operatorHome ?? homedir12(),
|
|
27751
28385
|
sharedSkills: input.config.sharedSkills ?? [],
|
|
27752
28386
|
...input.config.agentKind ? { agentKind: input.config.agentKind } : {},
|
|
27753
28387
|
skillReleaseId: input.releaseId,
|
|
@@ -27768,8 +28402,8 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
27768
28402
|
let turnCompleted = true;
|
|
27769
28403
|
if (input.config.bwrapPath) {
|
|
27770
28404
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
27771
|
-
const operatorHome = input.config.operatorHome ??
|
|
27772
|
-
const homeStateDirs = harnessHomeStateDirs(
|
|
28405
|
+
const operatorHome = input.config.operatorHome ?? homedir12();
|
|
28406
|
+
const homeStateDirs = harnessHomeStateDirs(harnessLabel, agentEnv.HOME ?? operatorHome);
|
|
27773
28407
|
await Promise.all(homeStateDirs.map((dir) => mkdir20(dir, { recursive: true })));
|
|
27774
28408
|
spawnCommand = wrapAgentCommand({
|
|
27775
28409
|
bwrapPath: input.config.bwrapPath,
|
|
@@ -27788,7 +28422,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
27788
28422
|
client = new AcpClient({
|
|
27789
28423
|
agentCommand: spawnCommand.command,
|
|
27790
28424
|
agentArgs: spawnCommand.args,
|
|
27791
|
-
agentLabel:
|
|
28425
|
+
agentLabel: harnessLabel,
|
|
27792
28426
|
agentEnv,
|
|
27793
28427
|
agentCwd: cwd,
|
|
27794
28428
|
autoApprovePermissions: true
|
|
@@ -27819,7 +28453,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
27819
28453
|
modelAnswer = { modelAnswer: "served" };
|
|
27820
28454
|
} else {
|
|
27821
28455
|
const explained = await explainEmptyAgentTurn({
|
|
27822
|
-
agentLabel:
|
|
28456
|
+
agentLabel: harnessLabel,
|
|
27823
28457
|
agentEnv,
|
|
27824
28458
|
sessionId,
|
|
27825
28459
|
result: served
|
|
@@ -27919,8 +28553,8 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
27919
28553
|
}
|
|
27920
28554
|
|
|
27921
28555
|
// apps/body/dist/current-release-probe.js
|
|
27922
|
-
import { spawn as
|
|
27923
|
-
import { dirname as
|
|
28556
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
28557
|
+
import { dirname as dirname17, join as join12 } from "node:path";
|
|
27924
28558
|
init_self_update();
|
|
27925
28559
|
var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
|
|
27926
28560
|
var UPDATE_PROBE_COMMAND = "update-probe";
|
|
@@ -27963,14 +28597,14 @@ function outcomeFromReport(report) {
|
|
|
27963
28597
|
}
|
|
27964
28598
|
}
|
|
27965
28599
|
async function probeReleaseInSubprocess(input) {
|
|
27966
|
-
const bundleDir =
|
|
28600
|
+
const bundleDir = join12(input.layout.releasesRoot, input.releaseId);
|
|
27967
28601
|
const entrypoint = await resolveBundleEntrypoint(bundleDir);
|
|
27968
28602
|
if (!entrypoint) {
|
|
27969
28603
|
return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
|
|
27970
28604
|
}
|
|
27971
28605
|
const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
|
|
27972
|
-
return new Promise((
|
|
27973
|
-
const child =
|
|
28606
|
+
return new Promise((resolve32) => {
|
|
28607
|
+
const child = spawn11(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
27974
28608
|
let stdout6 = "";
|
|
27975
28609
|
let stderr = "";
|
|
27976
28610
|
let settled = false;
|
|
@@ -27979,7 +28613,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
27979
28613
|
return;
|
|
27980
28614
|
settled = true;
|
|
27981
28615
|
clearTimeout(timer);
|
|
27982
|
-
|
|
28616
|
+
resolve32(outcome);
|
|
27983
28617
|
};
|
|
27984
28618
|
const timer = setTimeout(() => {
|
|
27985
28619
|
child.kill("SIGKILL");
|
|
@@ -28026,7 +28660,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
28026
28660
|
const runtime = await readRuntimeRecord(configPath);
|
|
28027
28661
|
const agent = runtimeAgentCommand(runtime);
|
|
28028
28662
|
const config = loadBodyConfig({
|
|
28029
|
-
workspaceRoot:
|
|
28663
|
+
workspaceRoot: join12(dirname17(configPath), "workspace"),
|
|
28030
28664
|
llmEnvFile: runtime.llmEnvFile,
|
|
28031
28665
|
env: { ...env, BUZZ_AGENT_BIN: agent.command, BUZZ_DEV_MCP_BIN: runtime.mcpBinary },
|
|
28032
28666
|
agent
|
|
@@ -28044,7 +28678,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
28044
28678
|
}
|
|
28045
28679
|
const layout = beelineInstallLayout(env);
|
|
28046
28680
|
const releaseId = (layout && await activeReleaseId(layout).catch(() => void 0)) ?? "unknown";
|
|
28047
|
-
const runtimeDir =
|
|
28681
|
+
const runtimeDir = dirname17(configPath);
|
|
28048
28682
|
const outcome = await probeOutcome(() => (options.probe ?? runUpdateFunctionalProbe)({
|
|
28049
28683
|
config,
|
|
28050
28684
|
runtimeDir,
|
|
@@ -28052,7 +28686,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
28052
28686
|
sandboxRequired: runtime.sandbox !== "off",
|
|
28053
28687
|
sandboxUnavailableDetail: sandbox.advisory,
|
|
28054
28688
|
// The successor's probe still holds `<runtimeDir>/update-functional-probe`.
|
|
28055
|
-
probeRoot:
|
|
28689
|
+
probeRoot: join12(runtimeDir, "current-release-probe")
|
|
28056
28690
|
}));
|
|
28057
28691
|
const report = outcome.kind === "served" ? { probe: "served" } : outcome.kind === "refused" ? { probe: "refused", status: outcome.status, reason: outcome.reason } : outcome.kind === "sandbox-unavailable" ? { probe: "sandbox-unavailable", reason: outcome.reason } : { probe: "failed", reason: outcome.reason };
|
|
28058
28692
|
write(JSON.stringify(report));
|
|
@@ -28060,7 +28694,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
28060
28694
|
|
|
28061
28695
|
// apps/body/dist/release-status.js
|
|
28062
28696
|
import { readFile as readFile14, readdir as readdir6, rename as rename7, writeFile as writeFile15 } from "node:fs/promises";
|
|
28063
|
-
import { resolve as
|
|
28697
|
+
import { resolve as resolve29 } from "node:path";
|
|
28064
28698
|
var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
|
|
28065
28699
|
var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
|
|
28066
28700
|
var SOURCE_SHA = /^[0-9a-f]{7,64}$/;
|
|
@@ -28077,7 +28711,7 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
28077
28711
|
pid: options.pid ?? process.pid,
|
|
28078
28712
|
readyAt: (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
|
|
28079
28713
|
};
|
|
28080
|
-
const target =
|
|
28714
|
+
const target = resolve29(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
|
|
28081
28715
|
const temporary = `${target}.${status.pid}.tmp`;
|
|
28082
28716
|
await writeFile15(temporary, `${JSON.stringify(status, null, 2)}
|
|
28083
28717
|
`, { mode: 384 });
|
|
@@ -28087,7 +28721,7 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
28087
28721
|
|
|
28088
28722
|
// apps/body/dist/scratch-sweep.js
|
|
28089
28723
|
import { lstat as lstat4, readdir as readdir7, rmdir, unlink as unlink4 } from "node:fs/promises";
|
|
28090
|
-
import { resolve as
|
|
28724
|
+
import { resolve as resolve30 } from "node:path";
|
|
28091
28725
|
var DEFAULT_SCRATCH_TTL_HOURS = 72;
|
|
28092
28726
|
var NEVER_SWEEP_SUBDIR_NAMES = new Set(HOME_SUBDIRS.filter((name) => name !== "tmp"));
|
|
28093
28727
|
function scratchTtlMs(env = process.env) {
|
|
@@ -28096,7 +28730,7 @@ function scratchTtlMs(env = process.env) {
|
|
|
28096
28730
|
return (Number.isFinite(hours) && hours > 0 ? hours : DEFAULT_SCRATCH_TTL_HOURS) * 60 * 60 * 1e3;
|
|
28097
28731
|
}
|
|
28098
28732
|
async function discoverAttachScratchRoots(runtimeDir) {
|
|
28099
|
-
const roomsDir =
|
|
28733
|
+
const roomsDir = resolve30(runtimeDir, "rooms");
|
|
28100
28734
|
let entries;
|
|
28101
28735
|
try {
|
|
28102
28736
|
entries = await readdir7(roomsDir, { withFileTypes: true });
|
|
@@ -28107,7 +28741,7 @@ async function discoverAttachScratchRoots(runtimeDir) {
|
|
|
28107
28741
|
for (const entry of entries) {
|
|
28108
28742
|
if (!entry.isDirectory())
|
|
28109
28743
|
continue;
|
|
28110
|
-
const home =
|
|
28744
|
+
const home = resolve30(roomsDir, entry.name, "agent-home");
|
|
28111
28745
|
const stats = await lstat4(home).catch(() => void 0);
|
|
28112
28746
|
if (stats?.isDirectory())
|
|
28113
28747
|
roots.push(home);
|
|
@@ -28126,7 +28760,7 @@ async function removeStaleFiles(dir, cutoffMs, protectNamesHere) {
|
|
|
28126
28760
|
for (const entry of entries) {
|
|
28127
28761
|
if (protectNamesHere && NEVER_SWEEP_SUBDIR_NAMES.has(entry.name))
|
|
28128
28762
|
continue;
|
|
28129
|
-
const path =
|
|
28763
|
+
const path = resolve30(dir, entry.name);
|
|
28130
28764
|
const stats = await lstat4(path).catch(() => void 0);
|
|
28131
28765
|
if (!stats || stats.isSymbolicLink())
|
|
28132
28766
|
continue;
|
|
@@ -28213,7 +28847,7 @@ var DaemonExitError = class extends Error {
|
|
|
28213
28847
|
};
|
|
28214
28848
|
async function runStoredDaemon(pathOrPointer) {
|
|
28215
28849
|
const configPath = await resolveRuntimeConfigPath(pathOrPointer);
|
|
28216
|
-
daemonFailureRuntimeDir =
|
|
28850
|
+
daemonFailureRuntimeDir = dirname18(configPath);
|
|
28217
28851
|
const accessMigration = await migrateRuntimeRecordAccessPolicy(configPath);
|
|
28218
28852
|
let runtime = accessMigration.runtime;
|
|
28219
28853
|
if (!runtime.transport) {
|
|
@@ -28225,7 +28859,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
28225
28859
|
runtime = activated.runtime;
|
|
28226
28860
|
const daemonApi = activated.client;
|
|
28227
28861
|
const agent = runtimeAgentCommand(runtime);
|
|
28228
|
-
await writeFile16(
|
|
28862
|
+
await writeFile16(resolve31(dirname18(configPath), "daemon.pid"), `${process.pid}
|
|
28229
28863
|
`, { mode: 384 });
|
|
28230
28864
|
const env = {
|
|
28231
28865
|
...process.env,
|
|
@@ -28233,7 +28867,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
28233
28867
|
BUZZ_DEV_MCP_BIN: runtime.mcpBinary
|
|
28234
28868
|
};
|
|
28235
28869
|
const config = loadBodyConfig({
|
|
28236
|
-
workspaceRoot:
|
|
28870
|
+
workspaceRoot: resolve31(dirname18(configPath), "workspace"),
|
|
28237
28871
|
llmEnvFile: runtime.llmEnvFile,
|
|
28238
28872
|
env,
|
|
28239
28873
|
agent
|
|
@@ -28268,7 +28902,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
28268
28902
|
const stop = () => controller.abort();
|
|
28269
28903
|
process.once("SIGINT", stop);
|
|
28270
28904
|
process.once("SIGTERM", stop);
|
|
28271
|
-
const runtimeDir =
|
|
28905
|
+
const runtimeDir = dirname18(configPath);
|
|
28272
28906
|
const layout = beelineInstallLayout(process.env);
|
|
28273
28907
|
const notifier = new SystemdNotifier();
|
|
28274
28908
|
let rollbackAlertDrain;
|
|
@@ -28424,7 +29058,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
28424
29058
|
} finally {
|
|
28425
29059
|
clearInterval(scratchSweepTimer);
|
|
28426
29060
|
await notifier.stopping(stoppingStatus).catch(() => void 0);
|
|
28427
|
-
const pidPath =
|
|
29061
|
+
const pidPath = resolve31(dirname18(configPath), "daemon.pid");
|
|
28428
29062
|
const recorded = Number((await readFile15(pidPath, "utf8").catch(() => "")).trim());
|
|
28429
29063
|
if (recorded === process.pid) {
|
|
28430
29064
|
await unlink5(pidPath).catch(() => void 0);
|
|
@@ -28436,6 +29070,10 @@ async function main() {
|
|
|
28436
29070
|
if (args.length === 0)
|
|
28437
29071
|
usage();
|
|
28438
29072
|
const command = args[0];
|
|
29073
|
+
if (command === CURSOR_ACP_BRIDGE_FLAG) {
|
|
29074
|
+
await runCursorAcpStdioServer();
|
|
29075
|
+
return;
|
|
29076
|
+
}
|
|
28439
29077
|
if (command === "--help" || command === "-h")
|
|
28440
29078
|
usage(0);
|
|
28441
29079
|
if (command === "managed-update-worker") {
|
|
@@ -28452,7 +29090,7 @@ async function main() {
|
|
|
28452
29090
|
const roomId = roomFlag >= 0 ? args[roomFlag + 1] : void 0;
|
|
28453
29091
|
if (!configPath || !roomId)
|
|
28454
29092
|
throw new Error("corner-read-token requires --config and --room");
|
|
28455
|
-
const activated = await activateDaemonTransport(
|
|
29093
|
+
const activated = await activateDaemonTransport(resolve31(configPath));
|
|
28456
29094
|
if (!activated)
|
|
28457
29095
|
throw new Error("corner-read-token requires monolith transport");
|
|
28458
29096
|
const credential = await activated.client.execute("getRoomGitHubToken", { roomId });
|
|
@@ -28501,14 +29139,14 @@ async function main() {
|
|
|
28501
29139
|
const agentPubkey = agentFlag >= 0 ? args[agentFlag + 1] : void 0;
|
|
28502
29140
|
if (!configPath && agentPubkey) {
|
|
28503
29141
|
const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
|
|
28504
|
-
configPath = configs.find((candidate) =>
|
|
29142
|
+
configPath = configs.find((candidate) => dirname18(candidate).endsWith(agentPubkey));
|
|
28505
29143
|
}
|
|
28506
29144
|
if (!configPath && agentPubkey) {
|
|
28507
29145
|
throw new DaemonExitError(`unknown agent ${agentPubkey}: no durable runtime exists; refusing systemd restart loop`, UNKNOWN_AGENT_EXIT_STATUS);
|
|
28508
29146
|
}
|
|
28509
29147
|
if (!configPath)
|
|
28510
29148
|
throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
|
|
28511
|
-
await runStoredDaemon(
|
|
29149
|
+
await runStoredDaemon(resolve31(configPath));
|
|
28512
29150
|
return;
|
|
28513
29151
|
}
|
|
28514
29152
|
if (command === "update") {
|
|
@@ -28529,7 +29167,7 @@ async function main() {
|
|
|
28529
29167
|
if (!agentPubkey)
|
|
28530
29168
|
throw new Error("stop requires --agent <pubkey>");
|
|
28531
29169
|
const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
|
|
28532
|
-
const configPath = configs.find((candidate) =>
|
|
29170
|
+
const configPath = configs.find((candidate) => dirname18(candidate).endsWith(agentPubkey));
|
|
28533
29171
|
if (!configPath)
|
|
28534
29172
|
throw new Error(`no stored runtime found for agent ${agentPubkey}`);
|
|
28535
29173
|
const runtime = await readRuntimeRecord(configPath);
|