usebeeline 0.0.90 → 0.0.92
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/README.md +6 -3
- package/dist/usebeeline.mjs +677 -298
- 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 net = __require("net");
|
|
2417
2417
|
var tls = __require("tls");
|
|
2418
|
-
var { randomBytes: randomBytes7, createHash:
|
|
2418
|
+
var { randomBytes: randomBytes7, createHash: createHash9 } = __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 = createHash9("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: createHash9 } = __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 = createHash9("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
|
|
3988
|
-
import { constants as
|
|
3989
|
-
import { access, chmod as
|
|
3987
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
3988
|
+
import { constants as fsConstants2 } from "node:fs";
|
|
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
3990
|
import { spawn as spawn4 } from "node:child_process";
|
|
3991
3991
|
import { homedir as homedir9 } from "node:os";
|
|
3992
|
-
import { dirname as
|
|
3992
|
+
import { dirname as dirname11, join as join9, resolve as resolve22 } from "node:path";
|
|
3993
3993
|
function anchorLayout(rawLibDir) {
|
|
3994
|
-
const libDir =
|
|
3994
|
+
const libDir = resolve22(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: resolve22(libDir, "../../bin"),
|
|
4011
4011
|
libDir,
|
|
4012
|
-
releasesRoot:
|
|
4012
|
+
releasesRoot: resolve22(libDir, `../${RELEASES_SEGMENT}`)
|
|
4013
4013
|
};
|
|
4014
4014
|
}
|
|
4015
4015
|
function beelineInstallLayout(env = process.env) {
|
|
@@ -4020,7 +4020,7 @@ function beelineInstallLayout(env = process.env) {
|
|
|
4020
4020
|
}
|
|
4021
4021
|
function defaultBeelineInstallLayout(env = process.env) {
|
|
4022
4022
|
const home = env.HOME?.trim() || homedir9();
|
|
4023
|
-
return anchorLayout(
|
|
4023
|
+
return anchorLayout(resolve22(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(resolve22(dirname11(resolve22(explicitBinDir)), "lib", "beeline"));
|
|
4032
4032
|
return defaultBeelineInstallLayout(env);
|
|
4033
4033
|
}
|
|
4034
4034
|
function hostPlatformKey() {
|
|
@@ -4039,13 +4039,13 @@ function hostPlatformKey() {
|
|
|
4039
4039
|
return `${os}-${arch}`;
|
|
4040
4040
|
}
|
|
4041
4041
|
function bundleJsonCandidates(bundleDir) {
|
|
4042
|
-
return [
|
|
4042
|
+
return [join9(bundleDir, "lib", "beeline", "bundle.json"), join9(bundleDir, "bundle.json")];
|
|
4043
4043
|
}
|
|
4044
4044
|
async function readBundleJson(bundleDir) {
|
|
4045
4045
|
let raw;
|
|
4046
4046
|
for (const candidate of bundleJsonCandidates(bundleDir)) {
|
|
4047
4047
|
try {
|
|
4048
|
-
raw = await
|
|
4048
|
+
raw = await readFile10(candidate, "utf8");
|
|
4049
4049
|
break;
|
|
4050
4050
|
} catch {
|
|
4051
4051
|
}
|
|
@@ -4063,17 +4063,17 @@ async function readBundleJson(bundleDir) {
|
|
|
4063
4063
|
}
|
|
4064
4064
|
}
|
|
4065
4065
|
function updateStatePath(layout) {
|
|
4066
|
-
return
|
|
4066
|
+
return join9(layout.releasesRoot, ".state", "update-state.json");
|
|
4067
4067
|
}
|
|
4068
4068
|
async function readUpdateState(layout) {
|
|
4069
4069
|
try {
|
|
4070
|
-
return JSON.parse(await
|
|
4070
|
+
return JSON.parse(await readFile10(updateStatePath(layout), "utf8"));
|
|
4071
4071
|
} catch {
|
|
4072
4072
|
return {};
|
|
4073
4073
|
}
|
|
4074
4074
|
}
|
|
4075
4075
|
async function writeUpdateState(layout, state) {
|
|
4076
|
-
await
|
|
4076
|
+
await mkdir15(join9(layout.releasesRoot, ".state"), { recursive: true });
|
|
4077
4077
|
await writeFile10(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
|
|
4078
4078
|
`, "utf8");
|
|
4079
4079
|
}
|
|
@@ -4089,7 +4089,7 @@ function sanitizeReleaseId(id) {
|
|
|
4089
4089
|
}
|
|
4090
4090
|
async function pathKind(path) {
|
|
4091
4091
|
try {
|
|
4092
|
-
const info = await
|
|
4092
|
+
const info = await lstat3(path);
|
|
4093
4093
|
if (info.isSymbolicLink())
|
|
4094
4094
|
return "symlink";
|
|
4095
4095
|
return info.isDirectory() ? "directory" : "missing";
|
|
@@ -4103,9 +4103,9 @@ async function activeReleaseId(layout) {
|
|
|
4103
4103
|
return "legacy";
|
|
4104
4104
|
if (kind === "missing")
|
|
4105
4105
|
return void 0;
|
|
4106
|
-
const { readlink } = await import("node:fs/promises");
|
|
4106
|
+
const { readlink: readlink2 } = await import("node:fs/promises");
|
|
4107
4107
|
try {
|
|
4108
|
-
const target = await
|
|
4108
|
+
const target = await readlink2(layout.libDir);
|
|
4109
4109
|
return sanitizeReleaseId(target.split("/").pop() ?? target);
|
|
4110
4110
|
} catch {
|
|
4111
4111
|
return void 0;
|
|
@@ -4155,12 +4155,12 @@ function run(command, args, timeoutMs) {
|
|
|
4155
4155
|
});
|
|
4156
4156
|
}
|
|
4157
4157
|
function entrypointCandidates(bundleDir) {
|
|
4158
|
-
return [
|
|
4158
|
+
return [join9(bundleDir, BUNDLE_ENTRYPOINT), join9(bundleDir, "beeline-cli.mjs")];
|
|
4159
4159
|
}
|
|
4160
4160
|
async function resolveBundleEntrypoint(bundleDir) {
|
|
4161
4161
|
for (const candidate of entrypointCandidates(bundleDir)) {
|
|
4162
4162
|
try {
|
|
4163
|
-
await access(candidate,
|
|
4163
|
+
await access(candidate, fsConstants2.F_OK);
|
|
4164
4164
|
return candidate;
|
|
4165
4165
|
} catch {
|
|
4166
4166
|
}
|
|
@@ -4177,18 +4177,18 @@ 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 = join9(layout.releasesRoot, releaseId);
|
|
4181
|
+
const okMarker = join9(releaseDir, ".stage-ok");
|
|
4182
4182
|
let previouslyVerified = false;
|
|
4183
4183
|
try {
|
|
4184
|
-
const recorded = await
|
|
4184
|
+
const recorded = await readFile10(okMarker, "utf8");
|
|
4185
4185
|
if (recorded.trim() === published.sha256)
|
|
4186
4186
|
return releaseId;
|
|
4187
4187
|
previouslyVerified = true;
|
|
4188
4188
|
} catch {
|
|
4189
4189
|
}
|
|
4190
|
-
await
|
|
4191
|
-
const tempArchive =
|
|
4190
|
+
await mkdir15(releaseDir, { recursive: true });
|
|
4191
|
+
const tempArchive = join9(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 = createHash7("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);
|
|
@@ -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(join9(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, [join9(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
|
}
|
|
@@ -4245,10 +4245,10 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
4245
4245
|
return releaseId;
|
|
4246
4246
|
} catch (error) {
|
|
4247
4247
|
if (!previouslyVerified)
|
|
4248
|
-
await
|
|
4248
|
+
await rm6(releaseDir, { recursive: true, force: true });
|
|
4249
4249
|
throw error;
|
|
4250
4250
|
} finally {
|
|
4251
|
-
await
|
|
4251
|
+
await rm6(tempArchive, { force: true });
|
|
4252
4252
|
}
|
|
4253
4253
|
}
|
|
4254
4254
|
function forwarderScript(tool) {
|
|
@@ -4268,45 +4268,45 @@ function forwarderScript(tool) {
|
|
|
4268
4268
|
async function replaceFile(path, contents, mode) {
|
|
4269
4269
|
const temp = `${path}.new-${process.pid}`;
|
|
4270
4270
|
await writeFile10(temp, contents, { mode });
|
|
4271
|
-
await
|
|
4272
|
-
await
|
|
4271
|
+
await chmod5(temp, mode);
|
|
4272
|
+
await rename4(temp, path);
|
|
4273
4273
|
}
|
|
4274
4274
|
async function activateRelease(layout, releaseId) {
|
|
4275
|
-
const releaseDir =
|
|
4276
|
-
await access(
|
|
4277
|
-
await
|
|
4278
|
-
await
|
|
4275
|
+
const releaseDir = join9(layout.releasesRoot, releaseId);
|
|
4276
|
+
await access(join9(releaseDir, BUNDLE_ENTRYPOINT), fsConstants2.F_OK);
|
|
4277
|
+
await mkdir15(layout.releasesRoot, { recursive: true });
|
|
4278
|
+
await mkdir15(layout.binDir, { recursive: true });
|
|
4279
4279
|
let previousReleaseId = await activeReleaseId(layout);
|
|
4280
4280
|
const kind = await pathKind(layout.libDir);
|
|
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 = join9(layout.releasesRoot, legacyId);
|
|
4285
4285
|
try {
|
|
4286
|
-
await access(legacyDir,
|
|
4286
|
+
await access(legacyDir, fsConstants2.F_OK);
|
|
4287
4287
|
previousReleaseId = `${legacyId}-${Date.now()}`;
|
|
4288
|
-
await
|
|
4289
|
-
await normalizeLegacyBundleShape(
|
|
4288
|
+
await rename4(layout.libDir, join9(layout.releasesRoot, previousReleaseId));
|
|
4289
|
+
await normalizeLegacyBundleShape(join9(layout.releasesRoot, previousReleaseId));
|
|
4290
4290
|
} catch {
|
|
4291
|
-
await
|
|
4291
|
+
await rename4(layout.libDir, legacyDir);
|
|
4292
4292
|
await normalizeLegacyBundleShape(legacyDir);
|
|
4293
4293
|
previousReleaseId = legacyId;
|
|
4294
4294
|
}
|
|
4295
4295
|
}
|
|
4296
4296
|
const tempLink = `${layout.libDir}.new-${process.pid}`;
|
|
4297
|
-
await
|
|
4298
|
-
await
|
|
4299
|
-
await
|
|
4300
|
-
await fsyncDir(
|
|
4297
|
+
await rm6(tempLink, { force: true });
|
|
4298
|
+
await symlink3(join9("beeline-releases", releaseId), tempLink);
|
|
4299
|
+
await rename4(tempLink, layout.libDir);
|
|
4300
|
+
await fsyncDir(dirname11(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 = join9(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(join9(bundleDir, name), fsConstants2.F_OK);
|
|
4310
4310
|
anyFlat = true;
|
|
4311
4311
|
break;
|
|
4312
4312
|
} catch {
|
|
@@ -4314,14 +4314,14 @@ async function normalizeLegacyBundleShape(bundleDir) {
|
|
|
4314
4314
|
}
|
|
4315
4315
|
if (!anyFlat)
|
|
4316
4316
|
return;
|
|
4317
|
-
await
|
|
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(join9(innerLib, name), fsConstants2.F_OK);
|
|
4321
4321
|
continue;
|
|
4322
4322
|
} catch {
|
|
4323
4323
|
}
|
|
4324
|
-
await
|
|
4324
|
+
await rename4(join9(bundleDir, name), join9(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 = join9(activeBundleRoot, "bin", tool);
|
|
4334
4334
|
try {
|
|
4335
|
-
await access(target,
|
|
4335
|
+
await access(target, fsConstants2.X_OK);
|
|
4336
4336
|
} catch {
|
|
4337
4337
|
continue;
|
|
4338
4338
|
}
|
|
4339
|
-
await replaceFile(
|
|
4339
|
+
await replaceFile(join9(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
|
|
4348
|
+
current = await readFile10(join9(layout.binDir, name), "utf8");
|
|
4349
4349
|
} catch {
|
|
4350
4350
|
current = void 0;
|
|
4351
4351
|
}
|
|
@@ -4358,29 +4358,29 @@ async function repairInstallForwarders(layout, opts = {}) {
|
|
|
4358
4358
|
}
|
|
4359
4359
|
if (healthy)
|
|
4360
4360
|
return false;
|
|
4361
|
-
await
|
|
4361
|
+
await mkdir15(layout.binDir, { recursive: true });
|
|
4362
4362
|
await writeBinForwarders(layout, layout.libDir);
|
|
4363
4363
|
opts.logger?.(`[body] self-update: repaired <prefix>/bin forwarders to follow the active-bundle anchor (${layout.libDir})`);
|
|
4364
4364
|
return true;
|
|
4365
4365
|
}
|
|
4366
4366
|
async function rollbackToPreviousRelease(layout, previousReleaseId) {
|
|
4367
|
-
const releaseDir =
|
|
4367
|
+
const releaseDir = join9(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
|
-
await
|
|
4374
|
-
await
|
|
4375
|
-
await
|
|
4376
|
-
await fsyncDir(
|
|
4373
|
+
await rm6(tempLink, { force: true });
|
|
4374
|
+
await symlink3(join9("beeline-releases", previousReleaseId), tempLink);
|
|
4375
|
+
await rename4(tempLink, layout.libDir);
|
|
4376
|
+
await fsyncDir(dirname11(layout.libDir));
|
|
4377
4377
|
}
|
|
4378
4378
|
function updateAttemptPath(layout) {
|
|
4379
|
-
return
|
|
4379
|
+
return join9(layout.releasesRoot, ".state", "update-attempt.json");
|
|
4380
4380
|
}
|
|
4381
4381
|
async function readUpdateAttempt(layout) {
|
|
4382
4382
|
try {
|
|
4383
|
-
const raw = JSON.parse(await
|
|
4383
|
+
const raw = JSON.parse(await readFile10(updateAttemptPath(layout), "utf8"));
|
|
4384
4384
|
if (raw.version !== 1 || typeof raw.appliedAt !== "number" || typeof raw.confirmBy !== "number" || typeof raw.releaseId !== "string" || !["pending", "confirmed", "reverted"].includes(raw.status)) {
|
|
4385
4385
|
return void 0;
|
|
4386
4386
|
}
|
|
@@ -4390,12 +4390,12 @@ async function readUpdateAttempt(layout) {
|
|
|
4390
4390
|
}
|
|
4391
4391
|
}
|
|
4392
4392
|
async function writeUpdateAttempt(layout, record2) {
|
|
4393
|
-
await
|
|
4393
|
+
await mkdir15(join9(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(record2, null, 2)}
|
|
4397
4397
|
`, { mode: 384 });
|
|
4398
|
-
await
|
|
4398
|
+
await rename4(staged, path);
|
|
4399
4399
|
}
|
|
4400
4400
|
async function replaceUpdateAttempt(layout, record2) {
|
|
4401
4401
|
await writeUpdateAttempt(layout, record2);
|
|
@@ -4655,8 +4655,8 @@ var init_self_update = __esm({
|
|
|
4655
4655
|
});
|
|
4656
4656
|
|
|
4657
4657
|
// apps/body/dist/cli.js
|
|
4658
|
-
import { dirname as
|
|
4659
|
-
import { readFile as
|
|
4658
|
+
import { dirname as dirname17, resolve as resolve30 } from "node:path";
|
|
4659
|
+
import { readFile as readFile15, unlink as unlink5, writeFile as writeFile16 } from "node:fs/promises";
|
|
4660
4660
|
import { stdin as stdin4, stdout as stdout5 } from "node:process";
|
|
4661
4661
|
|
|
4662
4662
|
// node_modules/@clack/core/dist/index.mjs
|
|
@@ -7527,7 +7527,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
7527
7527
|
const current = this.activeRunIds.get(sessionId);
|
|
7528
7528
|
if (current)
|
|
7529
7529
|
return Promise.resolve(current);
|
|
7530
|
-
return new Promise((
|
|
7530
|
+
return new Promise((resolve31, reject) => {
|
|
7531
7531
|
const onUpdate = (update) => {
|
|
7532
7532
|
if (update.sessionId !== sessionId)
|
|
7533
7533
|
return;
|
|
@@ -7535,7 +7535,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
7535
7535
|
if (!runId)
|
|
7536
7536
|
return;
|
|
7537
7537
|
cleanup();
|
|
7538
|
-
|
|
7538
|
+
resolve31(runId);
|
|
7539
7539
|
};
|
|
7540
7540
|
const timer = setTimeout(() => {
|
|
7541
7541
|
cleanup();
|
|
@@ -7619,13 +7619,13 @@ var AcpClient = class extends EventEmitter {
|
|
|
7619
7619
|
}
|
|
7620
7620
|
const id = this.nextId++;
|
|
7621
7621
|
const payload = { jsonrpc: "2.0", id, method, params };
|
|
7622
|
-
return new Promise((
|
|
7622
|
+
return new Promise((resolve31, reject) => {
|
|
7623
7623
|
const timer = setTimeout(() => {
|
|
7624
7624
|
this.pending.delete(id);
|
|
7625
7625
|
reject(new AcpRequestTimeoutError(method, timeoutMs, this.stderrTail, Boolean(onStart), detail));
|
|
7626
7626
|
}, timeoutMs);
|
|
7627
7627
|
this.pending.set(id, {
|
|
7628
|
-
resolve:
|
|
7628
|
+
resolve: resolve31,
|
|
7629
7629
|
reject,
|
|
7630
7630
|
timer,
|
|
7631
7631
|
method,
|
|
@@ -17164,10 +17164,10 @@ async function activateDaemonTransport(path, fetchImpl = fetch) {
|
|
|
17164
17164
|
|
|
17165
17165
|
// apps/body/dist/room-runtime.js
|
|
17166
17166
|
import { execFile as execFile5 } from "node:child_process";
|
|
17167
|
-
import { createHash as
|
|
17167
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
17168
17168
|
import { existsSync as existsSync4, mkdirSync } from "node:fs";
|
|
17169
|
-
import { mkdir as
|
|
17170
|
-
import { dirname as
|
|
17169
|
+
import { mkdir as mkdir13, rm as rm5 } from "node:fs/promises";
|
|
17170
|
+
import { dirname as dirname8, resolve as resolve20 } from "node:path";
|
|
17171
17171
|
import { promisify as promisify4 } from "node:util";
|
|
17172
17172
|
|
|
17173
17173
|
// apps/body/dist/grant-runner.js
|
|
@@ -17449,7 +17449,7 @@ var KNOWN_CREDENTIAL_MASK_PATHS = [
|
|
|
17449
17449
|
".git-credentials",
|
|
17450
17450
|
".secrets.env"
|
|
17451
17451
|
];
|
|
17452
|
-
function credentialMaskPaths(extraPaths, home = homedir3(),
|
|
17452
|
+
function credentialMaskPaths(extraPaths, home = homedir3(), stat4 = (path) => {
|
|
17453
17453
|
try {
|
|
17454
17454
|
const info = lstatSync2(path);
|
|
17455
17455
|
return { isDirectory: info.isDirectory() };
|
|
@@ -17468,7 +17468,7 @@ function credentialMaskPaths(extraPaths, home = homedir3(), stat3 = (path) => {
|
|
|
17468
17468
|
if (seen.has(path))
|
|
17469
17469
|
continue;
|
|
17470
17470
|
seen.add(path);
|
|
17471
|
-
const info =
|
|
17471
|
+
const info = stat4(path);
|
|
17472
17472
|
if (!info) {
|
|
17473
17473
|
if (required.has(path))
|
|
17474
17474
|
masks.push({ path, kind: "dir", create: true });
|
|
@@ -18137,13 +18137,13 @@ async function runServerCommandIntake(options) {
|
|
|
18137
18137
|
}
|
|
18138
18138
|
}
|
|
18139
18139
|
options.onPoll?.();
|
|
18140
|
-
const reconcile = await new Promise((
|
|
18140
|
+
const reconcile = await new Promise((resolve31) => {
|
|
18141
18141
|
const done = (needed) => {
|
|
18142
18142
|
if (timer)
|
|
18143
18143
|
clearTimeout(timer);
|
|
18144
18144
|
signal?.removeEventListener("abort", aborted);
|
|
18145
18145
|
wake = void 0;
|
|
18146
|
-
|
|
18146
|
+
resolve31(needed);
|
|
18147
18147
|
};
|
|
18148
18148
|
const aborted = () => done(false);
|
|
18149
18149
|
wake = done;
|
|
@@ -18169,10 +18169,10 @@ async function runServerCommandIntake(options) {
|
|
|
18169
18169
|
|
|
18170
18170
|
// apps/body/dist/monolith-corner-turn.js
|
|
18171
18171
|
import { execFile as execFile4 } from "node:child_process";
|
|
18172
|
-
import { createHash as
|
|
18173
|
-
import { mkdir as
|
|
18172
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
18173
|
+
import { mkdir as mkdir12 } from "node:fs/promises";
|
|
18174
18174
|
import { homedir as homedir7 } from "node:os";
|
|
18175
|
-
import { join as
|
|
18175
|
+
import { join as join8 } from "node:path";
|
|
18176
18176
|
import { promisify as promisify3 } from "node:util";
|
|
18177
18177
|
|
|
18178
18178
|
// apps/body/dist/agent-home.js
|
|
@@ -18995,7 +18995,7 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
18995
18995
|
console.warn("[body] operator MCP passthrough failed for claude:", error);
|
|
18996
18996
|
}
|
|
18997
18997
|
try {
|
|
18998
|
-
const settings2 = { permissions: { allow: ["WebSearch"] } };
|
|
18998
|
+
const settings2 = { permissions: { allow: ["WebSearch", "WebFetch"] } };
|
|
18999
18999
|
await writeIsolatedHarnessFile(resolve13(root, "claude", "settings.json"), `${JSON.stringify(settings2, null, 2)}
|
|
19000
19000
|
`);
|
|
19001
19001
|
} catch (error) {
|
|
@@ -19559,18 +19559,6 @@ function sanitizeAgentReply(message) {
|
|
|
19559
19559
|
}
|
|
19560
19560
|
return lines.slice(1).join("\n").trim();
|
|
19561
19561
|
}
|
|
19562
|
-
var CORNER_OPEN_ECHO = /^(?:(?:ok(?:ay)?|done|sure|great|alright)[,.!:]?\s+)?(?:i(?:'ve| have|'ll| will|'m| am)?\s+)?(?:just\s+)?open(?:ed|ing)?\s+(?:up\s+)?(?:a\s+|the\s+|your\s+)?(?:new\s+|write(?:-enabled)?\s+|repository\s+)*corner\b/iu;
|
|
19563
|
-
var CORNER_OPEN_ECHO_MAX_CHARS = 320;
|
|
19564
|
-
function stripCornerOpenEcho(message) {
|
|
19565
|
-
const visible = message.trim();
|
|
19566
|
-
if (!visible)
|
|
19567
|
-
return "";
|
|
19568
|
-
const paragraphs = visible.split(/\n\s*\n/);
|
|
19569
|
-
const first = paragraphs[0].trim();
|
|
19570
|
-
if (first.length > CORNER_OPEN_ECHO_MAX_CHARS || !CORNER_OPEN_ECHO.test(first))
|
|
19571
|
-
return visible;
|
|
19572
|
-
return paragraphs.slice(1).join("\n\n").trim();
|
|
19573
|
-
}
|
|
19574
19562
|
var STATUS_FILLER = new Set("a an the this that it its is are was were be been being has have had do does did now still remains remain remaining ready for review reviewing pr pull request all every both and or so to of in on at as with by no not nothing new further more else needed needs need required action actions change changes changed status state update updates updated waiting wait awaiting pending running progress idle done ok okay good great well fine confirmed confirm already again yet just currently right i we will can should would github remote upstream branch head latest current report reported noted note see looks look like everything nothing appears appear seems seem there here which what from without any".split(/\s+/));
|
|
19575
19563
|
var STATUS_SYNONYMS = {
|
|
19576
19564
|
passed: ["pass", "passed", "passing", "passes", "green", "succeeded", "success", "successful", "successfully"],
|
|
@@ -20792,16 +20780,299 @@ process.exit(result.status ?? 1);
|
|
|
20792
20780
|
await chmod3(path, 448);
|
|
20793
20781
|
}
|
|
20794
20782
|
|
|
20783
|
+
// apps/body/dist/warm-node-modules.js
|
|
20784
|
+
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
20785
|
+
import { constants as fsConstants } from "node:fs";
|
|
20786
|
+
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";
|
|
20787
|
+
import { dirname as dirname7, join as join6, resolve as resolve19 } from "node:path";
|
|
20788
|
+
var STORE_FORMAT = "v1";
|
|
20789
|
+
var STAGING_PREFIX = ".beeline-warm-";
|
|
20790
|
+
var STAGING_SWEEP_MS = 24 * 60 * 60 * 1e3;
|
|
20791
|
+
var WARM_STORE_MAX_ENTRIES = 3;
|
|
20792
|
+
function sharedNpmCacheDir(supervisorRoot) {
|
|
20793
|
+
return resolve19(supervisorRoot, "beeline", "npm-cache");
|
|
20794
|
+
}
|
|
20795
|
+
function warmNodeModulesStoreDir(supervisorRoot) {
|
|
20796
|
+
return resolve19(supervisorRoot, "beeline", "node-modules");
|
|
20797
|
+
}
|
|
20798
|
+
function isPlanRefusal(value) {
|
|
20799
|
+
return "failure" in value;
|
|
20800
|
+
}
|
|
20801
|
+
async function readWarmPlan(worktreePath) {
|
|
20802
|
+
const lockfile = await readFile8(resolve19(worktreePath, "package-lock.json")).catch(() => void 0);
|
|
20803
|
+
if (!lockfile)
|
|
20804
|
+
return { failure: "no-lockfile" };
|
|
20805
|
+
const packages = parseLockfilePackages(lockfile);
|
|
20806
|
+
if (!packages)
|
|
20807
|
+
return { failure: "no-lockfile" };
|
|
20808
|
+
const escaping = Object.keys(packages).find((path) => namesInstalledPackage(path) && !isContainedPath(path));
|
|
20809
|
+
if (escaping)
|
|
20810
|
+
return { failure: "unsafe-lockfile", detail: escaping };
|
|
20811
|
+
const trees = nodeModulesTreePaths(packages);
|
|
20812
|
+
if (trees.length === 0)
|
|
20813
|
+
return { failure: "no-lockfile" };
|
|
20814
|
+
const unsafe = trees.find((tree) => !isContainedTreePath(tree));
|
|
20815
|
+
if (unsafe)
|
|
20816
|
+
return { failure: "unsafe-lockfile", detail: unsafe };
|
|
20817
|
+
const key = createHash4("sha256").update(`${STORE_FORMAT}\0${process.platform}\0${process.arch}\0${process.versions.modules}\0`).update(lockfile).digest("hex").slice(0, 32);
|
|
20818
|
+
return { key, trees };
|
|
20819
|
+
}
|
|
20820
|
+
function nodeModulesTreePaths(packages) {
|
|
20821
|
+
const trees = /* @__PURE__ */ new Set();
|
|
20822
|
+
for (const path of Object.keys(packages)) {
|
|
20823
|
+
if (!namesInstalledPackage(path))
|
|
20824
|
+
continue;
|
|
20825
|
+
const segments = path.split("/");
|
|
20826
|
+
trees.add(segments.slice(0, segments.indexOf("node_modules") + 1).join("/"));
|
|
20827
|
+
}
|
|
20828
|
+
return [...trees].sort();
|
|
20829
|
+
}
|
|
20830
|
+
function namesInstalledPackage(path) {
|
|
20831
|
+
const segments = path.split("/");
|
|
20832
|
+
const index = segments.indexOf("node_modules");
|
|
20833
|
+
return index >= 0 && index < segments.length - 1;
|
|
20834
|
+
}
|
|
20835
|
+
async function seedWarmNodeModules(input) {
|
|
20836
|
+
const plan = await readWarmPlan(input.worktreePath);
|
|
20837
|
+
if (isPlanRefusal(plan)) {
|
|
20838
|
+
return { reason: plan.failure, ...plan.detail ? { detail: plan.detail } : {} };
|
|
20839
|
+
}
|
|
20840
|
+
for (const tree of plan.trees) {
|
|
20841
|
+
if (await pathExists(resolve19(input.worktreePath, tree))) {
|
|
20842
|
+
return { reason: "present", key: plan.key };
|
|
20843
|
+
}
|
|
20844
|
+
}
|
|
20845
|
+
const entry = resolve19(input.storeRoot, plan.key);
|
|
20846
|
+
if (!await isDirectory(entry))
|
|
20847
|
+
return { reason: "cold", key: plan.key };
|
|
20848
|
+
const [storeDevice, checkoutDevice] = await Promise.all([
|
|
20849
|
+
deviceOf(entry),
|
|
20850
|
+
deviceOf(input.worktreePath)
|
|
20851
|
+
]);
|
|
20852
|
+
if (storeDevice === void 0 || storeDevice !== checkoutDevice) {
|
|
20853
|
+
return { reason: "cross-device", key: plan.key };
|
|
20854
|
+
}
|
|
20855
|
+
const staging = resolve19(input.storeRoot, `${STAGING_PREFIX}${process.pid}.${randomUUID4()}`);
|
|
20856
|
+
const placed = [];
|
|
20857
|
+
const now2 = (input.now ?? Date.now)();
|
|
20858
|
+
try {
|
|
20859
|
+
await sweepStaleStaging(input.storeRoot, now2);
|
|
20860
|
+
await utimes(entry, now2 / 1e3, now2 / 1e3).catch(() => void 0);
|
|
20861
|
+
for (const tree of plan.trees) {
|
|
20862
|
+
await cloneTree(resolve19(entry, tree), resolve19(staging, tree), seedFile);
|
|
20863
|
+
}
|
|
20864
|
+
for (const tree of plan.trees) {
|
|
20865
|
+
const target = resolve19(input.worktreePath, tree);
|
|
20866
|
+
await mkdir10(dirname7(target), { recursive: true });
|
|
20867
|
+
await rename3(resolve19(staging, tree), target);
|
|
20868
|
+
placed.push(target);
|
|
20869
|
+
}
|
|
20870
|
+
return { reason: "seeded", key: plan.key };
|
|
20871
|
+
} catch (error) {
|
|
20872
|
+
for (const target of placed) {
|
|
20873
|
+
await rm4(target, { recursive: true, force: true }).catch(() => void 0);
|
|
20874
|
+
}
|
|
20875
|
+
return { reason: "failed", key: plan.key, detail: describe(error) };
|
|
20876
|
+
} finally {
|
|
20877
|
+
await rm4(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
20878
|
+
}
|
|
20879
|
+
}
|
|
20880
|
+
async function harvestWarmNodeModules(input) {
|
|
20881
|
+
const plan = await readWarmPlan(input.worktreePath);
|
|
20882
|
+
if (isPlanRefusal(plan)) {
|
|
20883
|
+
return { reason: plan.failure, ...plan.detail ? { detail: plan.detail } : {} };
|
|
20884
|
+
}
|
|
20885
|
+
const entry = resolve19(input.storeRoot, plan.key);
|
|
20886
|
+
if (await pathExists(entry))
|
|
20887
|
+
return { reason: "already-warm", key: plan.key };
|
|
20888
|
+
for (const tree of plan.trees) {
|
|
20889
|
+
if (!await isDirectory(resolve19(input.worktreePath, tree))) {
|
|
20890
|
+
return { reason: "no-node-modules", key: plan.key, detail: tree };
|
|
20891
|
+
}
|
|
20892
|
+
}
|
|
20893
|
+
const missing = await missingInstalledPackages(input.worktreePath);
|
|
20894
|
+
if (missing.length > 0) {
|
|
20895
|
+
return {
|
|
20896
|
+
reason: "incomplete",
|
|
20897
|
+
key: plan.key,
|
|
20898
|
+
detail: `${missing.length} absent, e.g. ${missing.slice(0, 3).join(", ")}`
|
|
20899
|
+
};
|
|
20900
|
+
}
|
|
20901
|
+
const staging = resolve19(input.storeRoot, `${STAGING_PREFIX}${process.pid}.${randomUUID4()}`);
|
|
20902
|
+
try {
|
|
20903
|
+
await mkdir10(input.storeRoot, { recursive: true, mode: 493 });
|
|
20904
|
+
await sweepStaleStaging(input.storeRoot, (input.now ?? Date.now)());
|
|
20905
|
+
for (const tree of plan.trees) {
|
|
20906
|
+
await cloneTree(resolve19(input.worktreePath, tree), resolve19(staging, tree), harvestFile);
|
|
20907
|
+
}
|
|
20908
|
+
await input.onCopied?.();
|
|
20909
|
+
if (!await stagedTreeIsPublishable(input.worktreePath, staging, plan.key)) {
|
|
20910
|
+
return { reason: "changed", key: plan.key };
|
|
20911
|
+
}
|
|
20912
|
+
await rename3(staging, entry);
|
|
20913
|
+
await pruneWarmStore(input.storeRoot, WARM_STORE_MAX_ENTRIES);
|
|
20914
|
+
return { reason: "stored", key: plan.key };
|
|
20915
|
+
} catch (error) {
|
|
20916
|
+
if (await pathExists(entry))
|
|
20917
|
+
return { reason: "already-warm", key: plan.key };
|
|
20918
|
+
return { reason: "failed", key: plan.key, detail: describe(error) };
|
|
20919
|
+
} finally {
|
|
20920
|
+
await rm4(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
20921
|
+
}
|
|
20922
|
+
}
|
|
20923
|
+
async function stagedTreeIsPublishable(worktreePath, staging, key) {
|
|
20924
|
+
const settled = await readWarmPlan(worktreePath);
|
|
20925
|
+
if (isPlanRefusal(settled) || settled.key !== key)
|
|
20926
|
+
return false;
|
|
20927
|
+
const hidden = join6("node_modules", ".package-lock.json");
|
|
20928
|
+
const [copied, current] = await Promise.all([
|
|
20929
|
+
readFile8(resolve19(staging, hidden)).catch(() => void 0),
|
|
20930
|
+
readFile8(resolve19(worktreePath, hidden)).catch(() => void 0)
|
|
20931
|
+
]);
|
|
20932
|
+
if (!copied || !current || !copied.equals(current))
|
|
20933
|
+
return false;
|
|
20934
|
+
return (await missingInstalledPackages(worktreePath, staging)).length === 0;
|
|
20935
|
+
}
|
|
20936
|
+
async function missingInstalledPackages(worktreePath, treeRoot = worktreePath) {
|
|
20937
|
+
const wanted = parseLockfilePackages(await readFile8(resolve19(worktreePath, "package-lock.json")).catch(() => void 0));
|
|
20938
|
+
const installed = parseLockfilePackages(await readFile8(resolve19(treeRoot, "node_modules", ".package-lock.json")).catch(() => void 0));
|
|
20939
|
+
if (!wanted)
|
|
20940
|
+
return ["package-lock.json is unreadable"];
|
|
20941
|
+
if (!installed)
|
|
20942
|
+
return ["node_modules/.package-lock.json is absent"];
|
|
20943
|
+
const required = [];
|
|
20944
|
+
const missing = [];
|
|
20945
|
+
for (const [path, entry] of Object.entries(wanted)) {
|
|
20946
|
+
if (!namesInstalledPackage(path))
|
|
20947
|
+
continue;
|
|
20948
|
+
if (entry.link === true || entry.optional === true)
|
|
20949
|
+
continue;
|
|
20950
|
+
if (entry.os !== void 0 || entry.cpu !== void 0)
|
|
20951
|
+
continue;
|
|
20952
|
+
if (!isContainedPath(path))
|
|
20953
|
+
missing.push(path);
|
|
20954
|
+
else
|
|
20955
|
+
required.push(path);
|
|
20956
|
+
}
|
|
20957
|
+
await mapWithLimit(required, INTEGRITY_READ_CONCURRENCY, async (path) => {
|
|
20958
|
+
if (!(path in installed) || !await isInstalledPackage(resolve19(treeRoot, path))) {
|
|
20959
|
+
missing.push(path);
|
|
20960
|
+
}
|
|
20961
|
+
});
|
|
20962
|
+
return missing.sort();
|
|
20963
|
+
}
|
|
20964
|
+
async function isInstalledPackage(path) {
|
|
20965
|
+
return stat2(join6(path, "package.json")).then((info) => info.isFile(), () => false);
|
|
20966
|
+
}
|
|
20967
|
+
var INTEGRITY_READ_CONCURRENCY = 64;
|
|
20968
|
+
async function mapWithLimit(values, limit, visit) {
|
|
20969
|
+
let cursor3 = 0;
|
|
20970
|
+
await Promise.all(Array.from({ length: Math.min(limit, values.length) }, async () => {
|
|
20971
|
+
while (cursor3 < values.length)
|
|
20972
|
+
await visit(values[cursor3++]);
|
|
20973
|
+
}));
|
|
20974
|
+
}
|
|
20975
|
+
function parseLockfilePackages(source) {
|
|
20976
|
+
if (!source)
|
|
20977
|
+
return void 0;
|
|
20978
|
+
try {
|
|
20979
|
+
const parsed = JSON.parse(source.toString("utf8"));
|
|
20980
|
+
const packages = parsed.packages;
|
|
20981
|
+
if (!packages || typeof packages !== "object" || Array.isArray(packages))
|
|
20982
|
+
return void 0;
|
|
20983
|
+
return packages;
|
|
20984
|
+
} catch {
|
|
20985
|
+
return void 0;
|
|
20986
|
+
}
|
|
20987
|
+
}
|
|
20988
|
+
function isContainedPath(value) {
|
|
20989
|
+
if (!value)
|
|
20990
|
+
return false;
|
|
20991
|
+
return value.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== ".." && !segment.includes("\\"));
|
|
20992
|
+
}
|
|
20993
|
+
function isContainedTreePath(value) {
|
|
20994
|
+
return isContainedPath(value) && value.split("/").pop() === "node_modules";
|
|
20995
|
+
}
|
|
20996
|
+
async function cloneTree(source, target, file, topLevel = true) {
|
|
20997
|
+
await mkdir10(target, { recursive: true, mode: 493 });
|
|
20998
|
+
for (const entry of await readdir5(source, { withFileTypes: true })) {
|
|
20999
|
+
const from = join6(source, entry.name);
|
|
21000
|
+
const to = join6(target, entry.name);
|
|
21001
|
+
if (entry.isSymbolicLink()) {
|
|
21002
|
+
await symlink2(await readlink(from), to);
|
|
21003
|
+
continue;
|
|
21004
|
+
}
|
|
21005
|
+
if (entry.isDirectory()) {
|
|
21006
|
+
await cloneTree(from, to, file, false);
|
|
21007
|
+
continue;
|
|
21008
|
+
}
|
|
21009
|
+
if (entry.isFile())
|
|
21010
|
+
await file(from, to, topLevel);
|
|
21011
|
+
}
|
|
21012
|
+
}
|
|
21013
|
+
var harvestFile = async (source, target) => {
|
|
21014
|
+
await copyFile2(source, target, fsConstants.COPYFILE_FICLONE);
|
|
21015
|
+
const info = await stat2(source);
|
|
21016
|
+
await chmod4(target, info.mode & 4095 & ~146);
|
|
21017
|
+
};
|
|
21018
|
+
var seedFile = async (source, target, topLevel) => {
|
|
21019
|
+
if (!topLevel) {
|
|
21020
|
+
await link(source, target);
|
|
21021
|
+
return;
|
|
21022
|
+
}
|
|
21023
|
+
await copyFile2(source, target);
|
|
21024
|
+
await chmod4(target, 420);
|
|
21025
|
+
};
|
|
21026
|
+
async function pruneWarmStore(storeRoot, keep) {
|
|
21027
|
+
const names = (await readdir5(storeRoot).catch(() => [])).filter((name) => !name.startsWith(STAGING_PREFIX));
|
|
21028
|
+
const entries = [];
|
|
21029
|
+
for (const name of names) {
|
|
21030
|
+
const info = await lstat2(join6(storeRoot, name)).catch(() => void 0);
|
|
21031
|
+
if (info?.isDirectory())
|
|
21032
|
+
entries.push({ name, usedAt: info.mtimeMs });
|
|
21033
|
+
}
|
|
21034
|
+
const dropped = entries.sort((a2, b) => b.usedAt - a2.usedAt || a2.name.localeCompare(b.name)).slice(keep);
|
|
21035
|
+
for (const entry of dropped) {
|
|
21036
|
+
await rm4(join6(storeRoot, entry.name), { recursive: true, force: true }).catch(() => void 0);
|
|
21037
|
+
}
|
|
21038
|
+
return dropped.map((entry) => entry.name);
|
|
21039
|
+
}
|
|
21040
|
+
async function sweepStaleStaging(storeRoot, now2) {
|
|
21041
|
+
const entries = await readdir5(storeRoot).catch(() => []);
|
|
21042
|
+
for (const name of entries) {
|
|
21043
|
+
if (!name.startsWith(STAGING_PREFIX))
|
|
21044
|
+
continue;
|
|
21045
|
+
const path = join6(storeRoot, name);
|
|
21046
|
+
const info = await lstat2(path).catch(() => void 0);
|
|
21047
|
+
if (!info || now2 - info.mtimeMs < STAGING_SWEEP_MS)
|
|
21048
|
+
continue;
|
|
21049
|
+
await rm4(path, { recursive: true, force: true }).catch(() => void 0);
|
|
21050
|
+
}
|
|
21051
|
+
}
|
|
21052
|
+
async function pathExists(path) {
|
|
21053
|
+
return lstat2(path).then(() => true, () => false);
|
|
21054
|
+
}
|
|
21055
|
+
async function deviceOf(path) {
|
|
21056
|
+
return stat2(path).then((info) => info.dev, () => void 0);
|
|
21057
|
+
}
|
|
21058
|
+
async function isDirectory(path) {
|
|
21059
|
+
return stat2(path).then((info) => info.isDirectory(), () => false);
|
|
21060
|
+
}
|
|
21061
|
+
function describe(error) {
|
|
21062
|
+
return error instanceof Error ? error.message : String(error);
|
|
21063
|
+
}
|
|
21064
|
+
|
|
20795
21065
|
// apps/body/dist/monolith-room-turn.js
|
|
20796
|
-
import { mkdir as
|
|
21066
|
+
import { mkdir as mkdir11 } from "node:fs/promises";
|
|
20797
21067
|
import { homedir as homedir6 } from "node:os";
|
|
20798
|
-
import { join as
|
|
21068
|
+
import { join as join7 } from "node:path";
|
|
20799
21069
|
|
|
20800
21070
|
// packages/api-contract/dist/scheduled-prompts.js
|
|
20801
21071
|
var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
|
|
20802
21072
|
var SCHEDULE_RAN_VERB = "ran a schedule for";
|
|
20803
21073
|
|
|
20804
21074
|
// apps/body/dist/monolith-room-turn.js
|
|
21075
|
+
var ROOM_PROMPT_INACTIVITY_TIMEOUT_MS = 18e4;
|
|
20805
21076
|
function isRoomMcpPermissionRequest(request, mountedServers = ROOM_MOUNTED_MCP_SERVERS) {
|
|
20806
21077
|
if (isSquireMcpPermissionRequest(request))
|
|
20807
21078
|
return false;
|
|
@@ -20836,12 +21107,11 @@ function roomMentionDirectory(roster, selfId) {
|
|
|
20836
21107
|
if (member.identityId === selfId)
|
|
20837
21108
|
continue;
|
|
20838
21109
|
const handle = member.handle?.trim().replace(/^@/, "");
|
|
20839
|
-
|
|
20840
|
-
const alias = handle || name;
|
|
20841
|
-
if (!alias)
|
|
21110
|
+
if (!handle)
|
|
20842
21111
|
continue;
|
|
21112
|
+
const name = member.name?.trim() ?? "";
|
|
20843
21113
|
const kind = member.kind === "agent" ? "agent" : "person";
|
|
20844
|
-
rows.push(`- @${
|
|
21114
|
+
rows.push(`- @${handle}${name && name !== handle ? ` \u2014 ${name}` : ""} (${kind})`);
|
|
20845
21115
|
}
|
|
20846
21116
|
if (!rows.length)
|
|
20847
21117
|
return "";
|
|
@@ -20852,47 +21122,6 @@ function roomMentionDirectory(roster, selfId) {
|
|
|
20852
21122
|
"Write a tag exactly as spelled here. An @name spelled any other way is plain text: it reaches nobody, and nobody is told it was meant for them. Never invent a handle, shorten one, or copy an @name out of the conversation \u2014 old messages carry spellings that no longer exist."
|
|
20853
21123
|
].join("\n");
|
|
20854
21124
|
}
|
|
20855
|
-
function escapeRegExp(value) {
|
|
20856
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20857
|
-
}
|
|
20858
|
-
function agentReplyMentionIds(text2, roster, authorId) {
|
|
20859
|
-
const aliases = /* @__PURE__ */ new Map();
|
|
20860
|
-
for (const member of roster.members) {
|
|
20861
|
-
if (member.identityId === authorId)
|
|
20862
|
-
continue;
|
|
20863
|
-
const rawAliases = member.kind === "agent" ? [member.handle] : [member.name, member.handle, member.soul?.name];
|
|
20864
|
-
for (const raw of rawAliases) {
|
|
20865
|
-
const display = raw?.trim().replace(/^@/, "");
|
|
20866
|
-
if (!display)
|
|
20867
|
-
continue;
|
|
20868
|
-
const key = display.toLocaleLowerCase();
|
|
20869
|
-
const entry = aliases.get(key) ?? { display, ids: /* @__PURE__ */ new Set() };
|
|
20870
|
-
entry.ids.add(member.identityId);
|
|
20871
|
-
aliases.set(key, entry);
|
|
20872
|
-
}
|
|
20873
|
-
}
|
|
20874
|
-
for (const member of roster.members) {
|
|
20875
|
-
if (member.identityId === authorId || member.kind === "agent" || !member.handle)
|
|
20876
|
-
continue;
|
|
20877
|
-
const handle = member.handle.trim().replace(/^@/, "").toLocaleLowerCase();
|
|
20878
|
-
const canonical = aliases.get(handle);
|
|
20879
|
-
const legacy = `a_${handle}`;
|
|
20880
|
-
if (canonical && !aliases.has(legacy))
|
|
20881
|
-
aliases.set(legacy, { ...canonical, display: legacy });
|
|
20882
|
-
}
|
|
20883
|
-
const mentioned = [];
|
|
20884
|
-
for (const { display, ids } of [...aliases.values()].sort((left, right) => right.display.length - left.display.length)) {
|
|
20885
|
-
if (ids.size !== 1)
|
|
20886
|
-
continue;
|
|
20887
|
-
const pattern = new RegExp(`(^|[\\s([{])@${escapeRegExp(display)}(?=$|[\\s.,!?;:)\\]}])`, "iu");
|
|
20888
|
-
if (!pattern.test(text2))
|
|
20889
|
-
continue;
|
|
20890
|
-
const identityId = [...ids][0];
|
|
20891
|
-
if (!mentioned.includes(identityId))
|
|
20892
|
-
mentioned.push(identityId);
|
|
20893
|
-
}
|
|
20894
|
-
return mentioned;
|
|
20895
|
-
}
|
|
20896
21125
|
var MonolithRoomTurnLoop = class {
|
|
20897
21126
|
options;
|
|
20898
21127
|
commandContext;
|
|
@@ -21039,7 +21268,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
21039
21268
|
const cached = this.deliveredAttachments.get(item.id);
|
|
21040
21269
|
if (cached)
|
|
21041
21270
|
return cached;
|
|
21042
|
-
const delivered = await deliverAttachments(item.attachments,
|
|
21271
|
+
const delivered = await deliverAttachments(item.attachments, join7(this.attachmentDir, item.id.replace(/[^\w-]/g, "_")), this.options.fetchImpl);
|
|
21043
21272
|
this.deliveredAttachments.set(item.id, withoutImageData(delivered));
|
|
21044
21273
|
return delivered;
|
|
21045
21274
|
}
|
|
@@ -21106,7 +21335,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
21106
21335
|
agentName: self?.name ?? this.agent.name
|
|
21107
21336
|
});
|
|
21108
21337
|
const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
|
|
21109
|
-
await
|
|
21338
|
+
await mkdir11(this.options.cwd, { recursive: true });
|
|
21110
21339
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
21111
21340
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
21112
21341
|
root: this.options.config.agentHomeRoot,
|
|
@@ -21132,14 +21361,14 @@ var MonolithRoomTurnLoop = class {
|
|
|
21132
21361
|
}, selection);
|
|
21133
21362
|
const operatorHome = this.options.config.operatorHome ?? homedir6();
|
|
21134
21363
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
21135
|
-
this.attachmentDir = tmpDir ?
|
|
21364
|
+
this.attachmentDir = tmpDir ? join7(tmpDir, "beeline-attachments") : void 0;
|
|
21136
21365
|
this.sessionScratchDir = tmpDir;
|
|
21137
21366
|
this.sessionStateDirs = stateDirs;
|
|
21138
21367
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
21139
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
21368
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir11(dir, { recursive: true })));
|
|
21140
21369
|
const attachScratchRoot = this.options.config.agentHomeRoot ?? tmpDir;
|
|
21141
21370
|
if (attachScratchRoot)
|
|
21142
|
-
await
|
|
21371
|
+
await mkdir11(attachScratchRoot, { recursive: true });
|
|
21143
21372
|
const spawnCommand = wrapAgentCommand({
|
|
21144
21373
|
bwrapPath: this.options.config.bwrapPath,
|
|
21145
21374
|
spec: {
|
|
@@ -21403,7 +21632,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
21403
21632
|
try {
|
|
21404
21633
|
stream.beginRun();
|
|
21405
21634
|
trace.promptSent();
|
|
21406
|
-
result2 = await this.client.sessionPrompt(this.sessionId, nextPrompt,
|
|
21635
|
+
result2 = await this.client.sessionPrompt(this.sessionId, nextPrompt, ROOM_PROMPT_INACTIVITY_TIMEOUT_MS, (delta, full) => {
|
|
21407
21636
|
trace.firstModelOutput();
|
|
21408
21637
|
stream.onChunk(delta, full);
|
|
21409
21638
|
}, void 0, (calls) => trace.toolCalls(calls));
|
|
@@ -21476,12 +21705,10 @@ var MonolithRoomTurnLoop = class {
|
|
|
21476
21705
|
console.warn(`[thin-core] monolith Room ${this.options.roomId} turn ${item.id}: ${explained.reason}`);
|
|
21477
21706
|
}
|
|
21478
21707
|
if (openCornerCall && !isFailedToolCall(openCornerCall)) {
|
|
21479
|
-
reply =
|
|
21708
|
+
reply = "";
|
|
21480
21709
|
}
|
|
21481
|
-
const mentionIds = reply ? agentReplyMentionIds(reply, roster, this.agent.publicKey) : [];
|
|
21482
21710
|
await trace.measure("publish", () => stream.settle(reply, reply ? {
|
|
21483
|
-
triggerMessageId: item.id
|
|
21484
|
-
mentionIds
|
|
21711
|
+
triggerMessageId: item.id
|
|
21485
21712
|
} : {}));
|
|
21486
21713
|
}, { priority: "interactive", roomKey: this.options.roomId });
|
|
21487
21714
|
}, (error) => console.error(`[thin-core] monolith Room ${this.options.roomId} receipt heartbeat failed:`, error));
|
|
@@ -21563,7 +21790,42 @@ var TOOL_ARGUMENT_MAX_BYTES = 1200;
|
|
|
21563
21790
|
var TOOL_OUTPUT_MAX_BYTES = 3200;
|
|
21564
21791
|
var TOOL_PATH_LIMIT = 12;
|
|
21565
21792
|
function cornerMergeInstruction(yoloMode) {
|
|
21566
|
-
return yoloMode ? "Yolo
|
|
21793
|
+
return yoloMode ? "Yolo is on: when the gate passes, merge this pull request with gh." : "Yolo is off: never merge; wait for explicit human approval in the app.";
|
|
21794
|
+
}
|
|
21795
|
+
var CORNER_DELIVERY_NUDGE = "Before ending this turn, inspect the repository state and finish delivering the work: commit and push the intended changes and open the pull request if one does not exist. Decide yourself whether any remaining dirty work belongs to the objective; do not discard it merely to make the worktree clean.";
|
|
21796
|
+
var CORNER_YOLO_MERGE_NUDGE = 'Yolo is on. Check the server merge gate with pr_checks_status now and, if checks="passed", held=false, and approvalPending=false, merge this pull request with gh. Otherwise stop without merging.';
|
|
21797
|
+
function isCornerChecksTurn(trigger, restates) {
|
|
21798
|
+
return Boolean(restates) || /\b(?:passed|failed) a check\b/i.test(trigger);
|
|
21799
|
+
}
|
|
21800
|
+
async function cornerUndeliveredRepositoryState(worktreePath, featureBranch, targetBranch) {
|
|
21801
|
+
try {
|
|
21802
|
+
const [{ stdout: status }, ahead] = await Promise.all([
|
|
21803
|
+
execFileAsync3("git", ["-C", worktreePath, "status", "--porcelain=v1"]),
|
|
21804
|
+
featureBranch ? firstResolvedRemoteRef(worktreePath, [featureBranch, targetBranch]).then((remoteRef) => remoteRef ? execFileAsync3("git", [
|
|
21805
|
+
"-C",
|
|
21806
|
+
worktreePath,
|
|
21807
|
+
"rev-list",
|
|
21808
|
+
"--count",
|
|
21809
|
+
`${remoteRef}..HEAD`
|
|
21810
|
+
]).then(({ stdout: stdout6 }) => Number.parseInt(stdout6.trim(), 10) || 0) : 0).catch(() => 0) : Promise.resolve(0)
|
|
21811
|
+
]);
|
|
21812
|
+
const dirty = status.trimEnd();
|
|
21813
|
+
return dirty || ahead > 0 ? `${dirty}
|
|
21814
|
+
ahead:${ahead}` : void 0;
|
|
21815
|
+
} catch {
|
|
21816
|
+
return void 0;
|
|
21817
|
+
}
|
|
21818
|
+
}
|
|
21819
|
+
async function firstResolvedRemoteRef(worktreePath, branches) {
|
|
21820
|
+
for (const branch of branches) {
|
|
21821
|
+
if (!branch)
|
|
21822
|
+
continue;
|
|
21823
|
+
const ref = `refs/remotes/origin/${branch}`;
|
|
21824
|
+
const resolved = await execFileAsync3("git", ["-C", worktreePath, "rev-parse", "--verify", ref]).then(() => true).catch(() => false);
|
|
21825
|
+
if (resolved)
|
|
21826
|
+
return ref;
|
|
21827
|
+
}
|
|
21828
|
+
return void 0;
|
|
21567
21829
|
}
|
|
21568
21830
|
function oneLine(value) {
|
|
21569
21831
|
return value.replace(/\s+/g, " ").trim();
|
|
@@ -21650,7 +21912,7 @@ function toolArguments(call) {
|
|
|
21650
21912
|
return input ? { input: clampBytes(redactToolDetail(input), TOOL_ARGUMENT_MAX_BYTES) } : {};
|
|
21651
21913
|
}
|
|
21652
21914
|
function toolCallKey(call, index) {
|
|
21653
|
-
return call.id ? `id-${
|
|
21915
|
+
return call.id ? `id-${createHash5("sha256").update(call.id).digest("hex")}` : `tool-${index}`;
|
|
21654
21916
|
}
|
|
21655
21917
|
function toolCallSettled(call) {
|
|
21656
21918
|
if (call.resultReceived)
|
|
@@ -21713,6 +21975,10 @@ var MonolithCornerTurnLoop = class {
|
|
|
21713
21975
|
modelTakesImages;
|
|
21714
21976
|
/** The one provider re-pinned after an empty completion, until the session ends. */
|
|
21715
21977
|
pinnedProviderOverride;
|
|
21978
|
+
/** The merge authority baked into the current session. */
|
|
21979
|
+
yoloMode = false;
|
|
21980
|
+
/** Repository state already given a delivery reminder, until that state changes. */
|
|
21981
|
+
lastDeliveryNudgeState;
|
|
21716
21982
|
turnIdentityInstructions = "";
|
|
21717
21983
|
busy = false;
|
|
21718
21984
|
forcedStop = false;
|
|
@@ -21737,6 +22003,8 @@ var MonolithCornerTurnLoop = class {
|
|
|
21737
22003
|
* by the same replay window the inbox already de-duplicates over.
|
|
21738
22004
|
*/
|
|
21739
22005
|
stoppedTurns = /* @__PURE__ */ new Set();
|
|
22006
|
+
/** In-flight warm-store harvest, awaited at shutdown and never by a turn. */
|
|
22007
|
+
harvest;
|
|
21740
22008
|
constructor(options) {
|
|
21741
22009
|
this.options = options;
|
|
21742
22010
|
this.agent = runtimeIdentity(options.runtime.agent);
|
|
@@ -21848,7 +22116,8 @@ var MonolithCornerTurnLoop = class {
|
|
|
21848
22116
|
agentName: self?.name ?? this.agent.name,
|
|
21849
22117
|
yoloMode: configuration.yoloMode
|
|
21850
22118
|
});
|
|
21851
|
-
|
|
22119
|
+
this.yoloMode = configuration.yoloMode;
|
|
22120
|
+
await mkdir12(this.options.worktreePath, { recursive: true });
|
|
21852
22121
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
21853
22122
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
21854
22123
|
root: this.options.config.agentHomeRoot,
|
|
@@ -21880,10 +22149,13 @@ var MonolithCornerTurnLoop = class {
|
|
|
21880
22149
|
inheritedPath: this.options.config.agentEnv.PATH ?? process.env.PATH
|
|
21881
22150
|
});
|
|
21882
22151
|
}
|
|
22152
|
+
const npmCacheDir = sharedNpmCacheDir(this.options.runtime.supervisorRoot);
|
|
22153
|
+
await mkdir12(npmCacheDir, { recursive: true, mode: 448 });
|
|
21883
22154
|
const agentEnv = {
|
|
21884
22155
|
...this.options.config.agentEnv,
|
|
21885
22156
|
...homeOverlay,
|
|
21886
|
-
...githubEnv
|
|
22157
|
+
...githubEnv,
|
|
22158
|
+
npm_config_cache: npmCacheDir
|
|
21887
22159
|
};
|
|
21888
22160
|
this.agentEnv = agentEnv;
|
|
21889
22161
|
const agentArgs = agentArgsWithModelSelection({
|
|
@@ -21893,13 +22165,13 @@ var MonolithCornerTurnLoop = class {
|
|
|
21893
22165
|
}, selection);
|
|
21894
22166
|
const operatorHome = this.options.config.operatorHome ?? homedir7();
|
|
21895
22167
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
21896
|
-
this.attachmentDir = tmpDir ?
|
|
22168
|
+
this.attachmentDir = tmpDir ? join8(tmpDir, "beeline-attachments") : void 0;
|
|
21897
22169
|
this.sessionScratchDir = tmpDir;
|
|
21898
22170
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
21899
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
22171
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir12(dir, { recursive: true })));
|
|
21900
22172
|
const attachScratchRoot = this.options.config.agentHomeRoot ?? tmpDir;
|
|
21901
22173
|
if (attachScratchRoot)
|
|
21902
|
-
await
|
|
22174
|
+
await mkdir12(attachScratchRoot, { recursive: true });
|
|
21903
22175
|
const spawnCommand = wrapAgentCommand({
|
|
21904
22176
|
bwrapPath: this.options.config.bwrapPath,
|
|
21905
22177
|
spec: {
|
|
@@ -21911,7 +22183,13 @@ var MonolithCornerTurnLoop = class {
|
|
|
21911
22183
|
harnessStateDirs: stateDirs,
|
|
21912
22184
|
harnessHomeStateDirs: homeStateDirs,
|
|
21913
22185
|
...tmpDir ? { tmpDir } : {},
|
|
21914
|
-
|
|
22186
|
+
additionalWritablePaths: [
|
|
22187
|
+
...attachScratchRoot ? [attachScratchRoot] : [],
|
|
22188
|
+
// The shared npm cache. npm writes to its cache on every install,
|
|
22189
|
+
// and this one is deliberately outside the per-corner home so the
|
|
22190
|
+
// download is paid once per host rather than once per corner.
|
|
22191
|
+
npmCacheDir
|
|
22192
|
+
],
|
|
21915
22193
|
maskPaths: credentialMaskPaths(this.options.config.sandboxMaskPaths, operatorHome)
|
|
21916
22194
|
},
|
|
21917
22195
|
command,
|
|
@@ -21940,7 +22218,11 @@ var MonolithCornerTurnLoop = class {
|
|
|
21940
22218
|
// the corner harness without inheriting any host credentials.
|
|
21941
22219
|
env: [
|
|
21942
22220
|
{ name: "GH_TOKEN", value: repository.githubToken },
|
|
21943
|
-
{ name: "GITHUB_TOKEN", value: repository.githubToken }
|
|
22221
|
+
{ name: "GITHUB_TOKEN", value: repository.githubToken },
|
|
22222
|
+
// Its shell tool runs the same installs the harness does, and
|
|
22223
|
+
// a sanitized env would otherwise send them to npm's default
|
|
22224
|
+
// per-corner cache.
|
|
22225
|
+
{ name: "npm_config_cache", value: npmCacheDir }
|
|
21944
22226
|
]
|
|
21945
22227
|
}
|
|
21946
22228
|
] : [],
|
|
@@ -21977,13 +22259,11 @@ var MonolithCornerTurnLoop = class {
|
|
|
21977
22259
|
personaInstructions,
|
|
21978
22260
|
...repository ? [
|
|
21979
22261
|
`You are in an isolated git worktree on ${repository.featureBranch}, targeting ${repository.targetBranch}.`,
|
|
21980
|
-
`
|
|
21981
|
-
|
|
21982
|
-
'On a later server checks turn, call beeline-agent pr_checks_status. Never merge unless it returns checks="passed", held=false, and approvalPending=false; a human hold remains until a later human explicitly resumes.',
|
|
22262
|
+
`Commit and push only ${repository.featureBranch}; never force-push or write to ${repository.targetBranch}. Before pushing, rebase on origin/${repository.featureBranch}; resolve conflicts autonomously, realigning to that remote branch and redoing the objective if needed, then rerun affected tests. Open the pull request with gh.`,
|
|
22263
|
+
'Once the pull request exists, reply only with its full URL and end the turn; do not check or wait for CI. On a later checks turn, call pr_checks_status. Merge only when checks="passed", held=false, and approvalPending=false; only a later explicit human resume clears a hold.',
|
|
21983
22264
|
cornerMergeInstruction(configuration.yoloMode),
|
|
21984
22265
|
"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.",
|
|
21985
|
-
|
|
21986
|
-
"When approval is pending, wait for the server close request. Never merge a different pull request."
|
|
22266
|
+
"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 approval is pending, wait for the server close request. Never merge another pull request."
|
|
21987
22267
|
] : [
|
|
21988
22268
|
"This is a chat-only corner with no repository or GitHub workflow.",
|
|
21989
22269
|
"Work in this corner's writable workspace. Use write_scratch_file or ordinary tools to create files, then attach_file to send them back to the corner.",
|
|
@@ -22102,7 +22382,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
22102
22382
|
const [conversation, roster, delivered] = await trace.measure("context-fetch", () => Promise.all([
|
|
22103
22383
|
api.execute("getRoomConversation", { roomId: cornerId, limit: 200 }),
|
|
22104
22384
|
this.roster(),
|
|
22105
|
-
this.attachmentDir && attachments.length ? deliverAttachments(attachments,
|
|
22385
|
+
this.attachmentDir && attachments.length ? deliverAttachments(attachments, join8(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : Promise.resolve([])
|
|
22106
22386
|
]));
|
|
22107
22387
|
const names = new Map(roster.members.map((member) => [member.identityId, member.name]));
|
|
22108
22388
|
const requestedBy = requester && !requester.name && names.get(requester.pubkey) ? { ...requester, name: names.get(requester.pubkey) } : requester;
|
|
@@ -22204,7 +22484,7 @@ ${trigger}`,
|
|
|
22204
22484
|
publishToolCalls(calls, false);
|
|
22205
22485
|
await this.activityTail;
|
|
22206
22486
|
};
|
|
22207
|
-
const runPrompt = async () => {
|
|
22487
|
+
const runPrompt = async (prompt = buildPrompt()) => {
|
|
22208
22488
|
activityAttempt += 1;
|
|
22209
22489
|
publishedToolCalls.clear();
|
|
22210
22490
|
observedToolCalls.clear();
|
|
@@ -22216,7 +22496,7 @@ ${trigger}`,
|
|
|
22216
22496
|
narrationRunBoundary = 0;
|
|
22217
22497
|
currentNarrationRun = "";
|
|
22218
22498
|
trace.promptSent();
|
|
22219
|
-
return this.client.sessionPrompt(this.sessionId, promptWithImages(
|
|
22499
|
+
return this.client.sessionPrompt(this.sessionId, promptWithImages(prompt, attachmentImageBlocks(delivered, this.acceptsImages())), 12e4, (delta, full, currentRun, runs) => {
|
|
22220
22500
|
trace.firstModelOutput();
|
|
22221
22501
|
if (runs) {
|
|
22222
22502
|
completedNarrationRuns = runs.slice(narrationRunBoundary);
|
|
@@ -22248,6 +22528,19 @@ ${trigger}`,
|
|
|
22248
22528
|
explained = await this.explainEmpty(result);
|
|
22249
22529
|
}
|
|
22250
22530
|
}
|
|
22531
|
+
const checksTurn = isCornerChecksTurn(trigger, restates);
|
|
22532
|
+
const deliveryState = !checksTurn && this.options.repository ? await cornerUndeliveredRepositoryState(this.options.worktreePath, this.options.repository.featureBranch, this.options.repository.targetBranch) : void 0;
|
|
22533
|
+
const needsDeliveryNudge = deliveryState !== void 0 && deliveryState !== this.lastDeliveryNudgeState;
|
|
22534
|
+
let replyBeforeNudge = "";
|
|
22535
|
+
if (!explained && (needsDeliveryNudge || checksTurn && this.yoloMode)) {
|
|
22536
|
+
if (needsDeliveryNudge)
|
|
22537
|
+
this.lastDeliveryNudgeState = deliveryState;
|
|
22538
|
+
replyBeforeNudge = durableReplyText(result.agentText);
|
|
22539
|
+
await flushToolCalls(result.toolCalls, "");
|
|
22540
|
+
result = await runPrompt(checksTurn ? CORNER_YOLO_MERGE_NUDGE : CORNER_DELIVERY_NUDGE);
|
|
22541
|
+
trace.promptSettled();
|
|
22542
|
+
explained = await this.explainEmpty(result);
|
|
22543
|
+
}
|
|
22251
22544
|
if (this.stoppedTurns.has(requestId)) {
|
|
22252
22545
|
stream.close();
|
|
22253
22546
|
throw new TurnStoppedError("turn stopped by the requester");
|
|
@@ -22255,6 +22548,7 @@ ${trigger}`,
|
|
|
22255
22548
|
let reply = durableReplyText(result.agentText);
|
|
22256
22549
|
if (!reply && explained?.recoveredText)
|
|
22257
22550
|
reply = durableReplyText(explained.recoveredText);
|
|
22551
|
+
reply = [replyBeforeNudge, reply].filter(Boolean).join("\n\n");
|
|
22258
22552
|
await flushToolCalls(result.toolCalls, reply);
|
|
22259
22553
|
for (const call of result.toolCalls) {
|
|
22260
22554
|
const failure = toolCallFailureLine(call);
|
|
@@ -22269,10 +22563,8 @@ ${trigger}`,
|
|
|
22269
22563
|
console.warn(`[thin-core] corner ${cornerId} turn ${requestId}: ${explained.reason}`);
|
|
22270
22564
|
}
|
|
22271
22565
|
const durableReply = spoken(reply);
|
|
22272
|
-
const mentionIds = durableReply ? agentReplyMentionIds(durableReply, roster, this.agent.publicKey) : [];
|
|
22273
22566
|
await trace.measure("publish", () => stream.settle(durableReply, durableReply ? {
|
|
22274
|
-
...requestedById ? { triggerMessageId: requestId } : {}
|
|
22275
|
-
mentionIds
|
|
22567
|
+
...requestedById ? { triggerMessageId: requestId } : {}
|
|
22276
22568
|
} : {}));
|
|
22277
22569
|
}, { priority: "interactive", roomKey: cornerId });
|
|
22278
22570
|
}, (error) => console.error(`[thin-core] corner ${cornerId} receipt heartbeat failed:`, error));
|
|
@@ -22304,8 +22596,39 @@ ${trigger}`,
|
|
|
22304
22596
|
} finally {
|
|
22305
22597
|
this.busy = false;
|
|
22306
22598
|
this.currentTurn = void 0;
|
|
22599
|
+
this.harvestWarmNodeModules();
|
|
22307
22600
|
}
|
|
22308
22601
|
}
|
|
22602
|
+
/**
|
|
22603
|
+
* Offer this worktree's `node_modules` to the host-wide warm store.
|
|
22604
|
+
*
|
|
22605
|
+
* A turn's end is the moment the tree is most likely to be a finished
|
|
22606
|
+
* install, and the store keeps only the first complete tree per lockfile —
|
|
22607
|
+
* so after the first corner on a lockfile this is one `stat` that answers
|
|
22608
|
+
* `already-warm`. The copy that the first one does is deliberately NOT
|
|
22609
|
+
* awaited by the turn: nobody in the Room is waiting on a cache, and the
|
|
22610
|
+
* only thing that waits is shutdown, so a half-copied tree is never left
|
|
22611
|
+
* where a later corner could read it as complete.
|
|
22612
|
+
*/
|
|
22613
|
+
harvestWarmNodeModules() {
|
|
22614
|
+
if (this.harvest || !this.options.repository)
|
|
22615
|
+
return;
|
|
22616
|
+
const { cornerId, worktreePath, runtime } = this.options;
|
|
22617
|
+
const run2 = harvestWarmNodeModules({
|
|
22618
|
+
worktreePath,
|
|
22619
|
+
storeRoot: warmNodeModulesStoreDir(runtime.supervisorRoot)
|
|
22620
|
+
}).then((outcome) => {
|
|
22621
|
+
if (outcome.reason === "already-warm" || outcome.reason === "no-lockfile")
|
|
22622
|
+
return;
|
|
22623
|
+
console.log(`[thin-core] corner ${cornerId} warm node_modules harvest: ${outcome.reason}${outcome.detail ? ` (${outcome.detail})` : ""}`);
|
|
22624
|
+
}).catch((error) => {
|
|
22625
|
+
console.error(`[thin-core] corner ${cornerId} warm node_modules harvest failed:`, error);
|
|
22626
|
+
}).finally(() => {
|
|
22627
|
+
if (this.harvest === run2)
|
|
22628
|
+
this.harvest = void 0;
|
|
22629
|
+
});
|
|
22630
|
+
this.harvest = run2;
|
|
22631
|
+
}
|
|
22309
22632
|
/**
|
|
22310
22633
|
* Bring this worktree onto the corner's branch as GitHub currently has it,
|
|
22311
22634
|
* before any work is done on top of it.
|
|
@@ -22352,6 +22675,7 @@ ${trigger}`,
|
|
|
22352
22675
|
const state = await api.execute("getCornerRestoreState", { cornerId });
|
|
22353
22676
|
if (!state.closeRequested)
|
|
22354
22677
|
return false;
|
|
22678
|
+
await this.harvest;
|
|
22355
22679
|
await this.options.onCloseRequested();
|
|
22356
22680
|
return true;
|
|
22357
22681
|
},
|
|
@@ -22360,6 +22684,7 @@ ${trigger}`,
|
|
|
22360
22684
|
} finally {
|
|
22361
22685
|
this.options.grantRunner?.unregister(cornerId);
|
|
22362
22686
|
await this.options.scheduler.suspend(cornerId);
|
|
22687
|
+
await this.harvest;
|
|
22363
22688
|
}
|
|
22364
22689
|
}
|
|
22365
22690
|
};
|
|
@@ -22780,13 +23105,13 @@ function shouldPostInitialCornerWorkingState(restore, isOpener = true) {
|
|
|
22780
23105
|
}
|
|
22781
23106
|
async function materializeCornerWorktree(input) {
|
|
22782
23107
|
const remote = roomCheckoutRemote(input.remote);
|
|
22783
|
-
const repositoryHash =
|
|
22784
|
-
const gitCommonDir =
|
|
22785
|
-
const path =
|
|
22786
|
-
await
|
|
22787
|
-
await
|
|
23108
|
+
const repositoryHash = createHash6("sha256").update(remote).digest("hex").slice(0, 24);
|
|
23109
|
+
const gitCommonDir = resolve20(input.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
|
|
23110
|
+
const path = resolve20(input.supervisorRoot, "beeline", "corners", input.cornerId);
|
|
23111
|
+
await mkdir13(dirname8(gitCommonDir), { recursive: true, mode: 448 });
|
|
23112
|
+
await mkdir13(dirname8(path), { recursive: true, mode: 448 });
|
|
22788
23113
|
const authEnv = githubGitEnv(input.token);
|
|
22789
|
-
if (!existsSync4(
|
|
23114
|
+
if (!existsSync4(resolve20(gitCommonDir, "HEAD"))) {
|
|
22790
23115
|
await execFileAsync4("git", ["clone", "--bare", remote, gitCommonDir], {
|
|
22791
23116
|
env: authEnv,
|
|
22792
23117
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -22805,8 +23130,8 @@ async function materializeCornerWorktree(input) {
|
|
|
22805
23130
|
"origin",
|
|
22806
23131
|
`+refs/heads/${input.featureBranch}:refs/remotes/origin/${input.featureBranch}`
|
|
22807
23132
|
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 }).then(() => true, () => false);
|
|
22808
|
-
if (!existsSync4(
|
|
22809
|
-
await
|
|
23133
|
+
if (!existsSync4(resolve20(path, ".git"))) {
|
|
23134
|
+
await rm5(path, { recursive: true, force: true });
|
|
22810
23135
|
await execFileAsync4("git", [
|
|
22811
23136
|
`--git-dir=${gitCommonDir}`,
|
|
22812
23137
|
"worktree",
|
|
@@ -22816,6 +23141,13 @@ async function materializeCornerWorktree(input) {
|
|
|
22816
23141
|
path,
|
|
22817
23142
|
restored ? `refs/remotes/origin/${input.featureBranch}` : `refs/remotes/origin/${input.targetBranch}`
|
|
22818
23143
|
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
|
|
23144
|
+
const seed = await seedWarmNodeModules({
|
|
23145
|
+
worktreePath: path,
|
|
23146
|
+
storeRoot: warmNodeModulesStoreDir(input.supervisorRoot)
|
|
23147
|
+
});
|
|
23148
|
+
if (seed.reason !== "no-lockfile") {
|
|
23149
|
+
console.log(`[thin-core] corner ${input.cornerId} warm node_modules: ${seed.reason}${seed.detail ? ` (${seed.detail})` : ""}`);
|
|
23150
|
+
}
|
|
22819
23151
|
}
|
|
22820
23152
|
await execFileAsync4("git", [
|
|
22821
23153
|
`--git-dir=${gitCommonDir}`,
|
|
@@ -22849,7 +23181,7 @@ async function materializeCornerWorktree(input) {
|
|
|
22849
23181
|
`${input.committer.publicKey.slice(0, 16)}@users.noreply.github.com`
|
|
22850
23182
|
]);
|
|
22851
23183
|
const top = await execFileAsync4("git", ["-C", path, "rev-parse", "--show-toplevel"]);
|
|
22852
|
-
if (
|
|
23184
|
+
if (resolve20(top.stdout.trim()) !== resolve20(path)) {
|
|
22853
23185
|
throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
|
|
22854
23186
|
}
|
|
22855
23187
|
return { path, gitCommonDir };
|
|
@@ -22915,11 +23247,11 @@ async function removeCornerWorktreeAndBranches(worktree) {
|
|
|
22915
23247
|
}
|
|
22916
23248
|
var execFileAsync4 = promisify4(execFile5);
|
|
22917
23249
|
async function removeCornerScratchWorkspace(input) {
|
|
22918
|
-
const expected =
|
|
22919
|
-
if (
|
|
23250
|
+
const expected = resolve20(input.roomRoot, "scratch");
|
|
23251
|
+
if (resolve20(input.scratchPath) !== expected) {
|
|
22920
23252
|
throw new Error(`refusing to remove scratch outside corner ${input.cornerId}`);
|
|
22921
23253
|
}
|
|
22922
|
-
await
|
|
23254
|
+
await rm5(expected, { recursive: true, force: true });
|
|
22923
23255
|
}
|
|
22924
23256
|
var RoomRuntimeCoordinator = class {
|
|
22925
23257
|
configPath;
|
|
@@ -23109,13 +23441,13 @@ var RoomRuntimeCoordinator = class {
|
|
|
23109
23441
|
return this.runtime.rooms.find((room) => room.channelId === roomId);
|
|
23110
23442
|
}
|
|
23111
23443
|
roomRoot(roomId) {
|
|
23112
|
-
return this.roomRecord(roomId)?.root ??
|
|
23444
|
+
return this.roomRecord(roomId)?.root ?? resolve20(dirname8(this.configPath), "rooms", roomId);
|
|
23113
23445
|
}
|
|
23114
23446
|
roomAgentHomeRoot(workspaceRoot, required = false) {
|
|
23115
23447
|
const flag = process.env.BUZZY_BODY_ROOM_HOME;
|
|
23116
23448
|
if (!required && flag === "0")
|
|
23117
23449
|
return void 0;
|
|
23118
|
-
const home =
|
|
23450
|
+
const home = resolve20(workspaceRoot, "agent-home");
|
|
23119
23451
|
if (!required && flag !== "1" && !existsSync4(home) && existsSync4(workspaceRoot))
|
|
23120
23452
|
return void 0;
|
|
23121
23453
|
try {
|
|
@@ -23131,10 +23463,10 @@ var RoomRuntimeCoordinator = class {
|
|
|
23131
23463
|
return {
|
|
23132
23464
|
...this.baseConfig,
|
|
23133
23465
|
workspaceRoot,
|
|
23134
|
-
agentPrivateRoot:
|
|
23135
|
-
agentMemoryRoot:
|
|
23136
|
-
openRouterRoutingCacheDir: openRouterRoutingCacheDir(
|
|
23137
|
-
turnTraceDir: turnTraceDirectory(
|
|
23466
|
+
agentPrivateRoot: resolve20(workspaceRoot, "agent-private"),
|
|
23467
|
+
agentMemoryRoot: resolve20(dirname8(this.configPath), "memory"),
|
|
23468
|
+
openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname8(this.configPath)),
|
|
23469
|
+
turnTraceDir: turnTraceDirectory(dirname8(this.configPath)),
|
|
23138
23470
|
...agentHomeRoot ? { agentHomeRoot } : {}
|
|
23139
23471
|
};
|
|
23140
23472
|
}
|
|
@@ -23200,12 +23532,12 @@ var RoomRuntimeCoordinator = class {
|
|
|
23200
23532
|
return this.roomRoot(roomId);
|
|
23201
23533
|
const remote = roomCheckoutRemote(repository.remote);
|
|
23202
23534
|
const targetBranch = repository.targetBranch || "main";
|
|
23203
|
-
const checkoutId =
|
|
23204
|
-
const path =
|
|
23205
|
-
await
|
|
23535
|
+
const checkoutId = createHash6("sha256").update(`${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
|
|
23536
|
+
const path = resolve20(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
|
|
23537
|
+
await mkdir13(dirname8(path), { recursive: true, mode: 448 });
|
|
23206
23538
|
const token = remote.startsWith("https://github.com/") ? await this.options.daemonApi.execute("getRoomGitHubToken", { roomId }) : void 0;
|
|
23207
23539
|
const env = token ? githubGitEnv(token.token) : process.env;
|
|
23208
|
-
if (!existsSync4(
|
|
23540
|
+
if (!existsSync4(resolve20(path, ".git"))) {
|
|
23209
23541
|
await execFileAsync4("git", ["clone", "--no-checkout", remote, path], {
|
|
23210
23542
|
env,
|
|
23211
23543
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -23258,9 +23590,9 @@ var RoomRuntimeCoordinator = class {
|
|
|
23258
23590
|
featureBranch,
|
|
23259
23591
|
token: granted.token
|
|
23260
23592
|
}) : void 0;
|
|
23261
|
-
const workspacePath = worktree?.path ??
|
|
23593
|
+
const workspacePath = worktree?.path ?? resolve20(this.roomRoot(corner.cornerId), "scratch");
|
|
23262
23594
|
if (!worktree)
|
|
23263
|
-
await
|
|
23595
|
+
await mkdir13(workspacePath, { recursive: true, mode: 448 });
|
|
23264
23596
|
const isOpener = !corner.openedBy || corner.openedBy === this.agent.publicKey;
|
|
23265
23597
|
if (worktree && shouldPostInitialCornerWorkingState(restore, isOpener)) {
|
|
23266
23598
|
await this.options.daemonApi.execute("postCornerRemoteState", {
|
|
@@ -23643,9 +23975,9 @@ var ThinDaemonCore = class {
|
|
|
23643
23975
|
|
|
23644
23976
|
// apps/body/dist/systemd.js
|
|
23645
23977
|
import { execFile as execFile6 } from "node:child_process";
|
|
23646
|
-
import { mkdir as
|
|
23978
|
+
import { mkdir as mkdir14, readFile as readFile9, writeFile as writeFile9 } from "node:fs/promises";
|
|
23647
23979
|
import { homedir as homedir8 } from "node:os";
|
|
23648
|
-
import { dirname as
|
|
23980
|
+
import { dirname as dirname9, resolve as resolve21 } from "node:path";
|
|
23649
23981
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
23650
23982
|
import { promisify as promisify5 } from "node:util";
|
|
23651
23983
|
var execFileAsync5 = promisify5(execFile6);
|
|
@@ -23687,9 +24019,9 @@ WantedBy=default.target
|
|
|
23687
24019
|
}
|
|
23688
24020
|
function isCanonicalInstalledLauncher(env = process.env, invocationPath = process.argv[1]) {
|
|
23689
24021
|
const home = env.HOME?.trim() || homedir8();
|
|
23690
|
-
const expectedLibDir =
|
|
24022
|
+
const expectedLibDir = resolve21(home, ".local", "lib", "beeline");
|
|
23691
24023
|
const expectedPrefix = `${expectedLibDir}/`;
|
|
23692
|
-
return
|
|
24024
|
+
return resolve21(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve21(invocationPath).startsWith(expectedPrefix);
|
|
23693
24025
|
}
|
|
23694
24026
|
function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
23695
24027
|
if (isCanonicalInstalledLauncher(env, invocationPath))
|
|
@@ -23697,8 +24029,8 @@ function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
|
23697
24029
|
throw new Error("refusing to modify the shared Beeline systemd unit outside the canonical ~/.local/bin/beeline launcher");
|
|
23698
24030
|
}
|
|
23699
24031
|
function systemdUserUnitPath(env = process.env) {
|
|
23700
|
-
const configRoot = env.XDG_CONFIG_HOME?.trim() ||
|
|
23701
|
-
return
|
|
24032
|
+
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve21(homedir8(), ".config");
|
|
24033
|
+
return resolve21(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
|
|
23702
24034
|
}
|
|
23703
24035
|
var runSystemctl = async (args) => {
|
|
23704
24036
|
const result = await execFileAsync5("systemctl", ["--user", ...args], {
|
|
@@ -23714,9 +24046,9 @@ async function installAgentService(publicKey, options = {}) {
|
|
|
23714
24046
|
assertCanonicalInstalledLauncher(env, options.invocationPath);
|
|
23715
24047
|
const path = systemdUserUnitPath(env);
|
|
23716
24048
|
const content = agentServiceUnit();
|
|
23717
|
-
const existing = await
|
|
24049
|
+
const existing = await readFile9(path, "utf8").catch(() => "");
|
|
23718
24050
|
if (existing !== content) {
|
|
23719
|
-
await
|
|
24051
|
+
await mkdir14(dirname9(path), { recursive: true, mode: 448 });
|
|
23720
24052
|
await writeFile9(path, content, { mode: 384 });
|
|
23721
24053
|
}
|
|
23722
24054
|
const run2 = options.run ?? runSystemctl;
|
|
@@ -23797,7 +24129,7 @@ async function retireRemovedAgent(runtime, options = {}) {
|
|
|
23797
24129
|
}
|
|
23798
24130
|
|
|
23799
24131
|
// apps/body/dist/start-command.js
|
|
23800
|
-
import { dirname as
|
|
24132
|
+
import { dirname as dirname10 } from "node:path";
|
|
23801
24133
|
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
23802
24134
|
var DEFAULT_RESTART_DRAIN_TIMEOUT_MS = 30 * 6e4;
|
|
23803
24135
|
var RESTART_WAIT_REPORT_INTERVAL_MS = 3e4;
|
|
@@ -23872,7 +24204,7 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
23872
24204
|
continue;
|
|
23873
24205
|
}
|
|
23874
24206
|
const spinnerHandle = spinner();
|
|
23875
|
-
spinnerHandle.start(`Starting ${
|
|
24207
|
+
spinnerHandle.start(`Starting ${dirname10(path)}\u2026`);
|
|
23876
24208
|
try {
|
|
23877
24209
|
await startRuntime(path, spinnerHandle);
|
|
23878
24210
|
spinnerHandle.stop(import_picocolors.default.green("Started."));
|
|
@@ -23888,9 +24220,9 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
23888
24220
|
|
|
23889
24221
|
// apps/body/dist/connect-command.js
|
|
23890
24222
|
import { spawn as spawn5 } from "node:child_process";
|
|
23891
|
-
import { createHash as
|
|
23892
|
-
import { chmod as
|
|
23893
|
-
import { dirname as
|
|
24223
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
24224
|
+
import { chmod as chmod6, mkdir as mkdir16, readFile as readFile11, unlink as unlink2, writeFile as writeFile11 } from "node:fs/promises";
|
|
24225
|
+
import { dirname as dirname12, resolve as resolve23 } from "node:path";
|
|
23894
24226
|
import { stdin as stdin3, stdout as stdout4 } from "node:process";
|
|
23895
24227
|
|
|
23896
24228
|
// apps/body/dist/clack-support.js
|
|
@@ -24157,7 +24489,11 @@ async function pairDevice(grant, options = {}) {
|
|
|
24157
24489
|
...grant.llmEnvFile ? { llmEnvFile: grant.llmEnvFile } : {},
|
|
24158
24490
|
agent: selectedAgent
|
|
24159
24491
|
});
|
|
24160
|
-
|
|
24492
|
+
const modelSelection = {
|
|
24493
|
+
model: grant.model,
|
|
24494
|
+
...grant.effort ? { effort: grant.effort } : {}
|
|
24495
|
+
};
|
|
24496
|
+
await (options.validateSelection ?? validateAgentModelSelection)(selectedAgent, localConfig.agentEnv, modelSelection);
|
|
24161
24497
|
const agentIdentity = identityFromKey(grant.agentSecretKey, grant.agentName);
|
|
24162
24498
|
const staged = await stageMonolithAgentRuntime({
|
|
24163
24499
|
workspaceId: grant.workspaceId,
|
|
@@ -24169,7 +24505,7 @@ async function pairDevice(grant, options = {}) {
|
|
|
24169
24505
|
agentKind: selectedAgent.kind,
|
|
24170
24506
|
agentCommand: selectedAgent.command,
|
|
24171
24507
|
agentArgs: selectedAgent.args,
|
|
24172
|
-
modelSelection
|
|
24508
|
+
modelSelection,
|
|
24173
24509
|
...grant.accessPolicy ? { accessPolicy: grant.accessPolicy } : {},
|
|
24174
24510
|
mcpBinary: localConfig.mcpBinary,
|
|
24175
24511
|
agentIdentity,
|
|
@@ -24284,6 +24620,12 @@ var clackPrompts = {
|
|
|
24284
24620
|
}), "Connection cancelled.");
|
|
24285
24621
|
}
|
|
24286
24622
|
};
|
|
24623
|
+
var CONNECT_EFFORT_CATEGORIES = ["effort", "reasoning_effort", "thought_level"];
|
|
24624
|
+
function connectEffortPickerFromAxes(axes, rawAxes = axes) {
|
|
24625
|
+
const isEffort = (axis2) => CONNECT_EFFORT_CATEGORIES.includes(axis2.category) && axis2.options.length > 0;
|
|
24626
|
+
const axis = axes.find(isEffort) ?? rawAxes.find(isEffort);
|
|
24627
|
+
return axis ? { currentValue: axis.currentValue, options: axis.options } : void 0;
|
|
24628
|
+
}
|
|
24287
24629
|
function connectModelPickerFromAxes(axes, fallbackModel, harness, rawAxes = axes) {
|
|
24288
24630
|
const filtered = axes.find((axis) => axis.category === "model");
|
|
24289
24631
|
if (filtered?.options.length) {
|
|
@@ -24301,13 +24643,18 @@ function connectModelPickerFromAxes(axes, fallbackModel, harness, rawAxes = axes
|
|
|
24301
24643
|
}
|
|
24302
24644
|
async function loadConnectModelCatalog(input) {
|
|
24303
24645
|
const agent = resolveAgentCommand({ kind: input.harness });
|
|
24646
|
+
const model = input.model ?? defaultConnectModel(input.harness, input.provider);
|
|
24304
24647
|
const catalog = await fetchAgentModelCatalog(agent, providerEnvironment({
|
|
24305
24648
|
harness: input.harness,
|
|
24306
24649
|
...input.provider ? { provider: input.provider } : {},
|
|
24307
24650
|
...input.apiKey ? { apiKey: input.apiKey } : {},
|
|
24308
|
-
model
|
|
24309
|
-
}), void 0, input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs });
|
|
24310
|
-
|
|
24651
|
+
model
|
|
24652
|
+
}), input.model ? { model: input.model } : void 0, input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs });
|
|
24653
|
+
const effort = connectEffortPickerFromAxes(catalog.catalog, catalog.raw);
|
|
24654
|
+
return {
|
|
24655
|
+
...connectModelPickerFromAxes(catalog.catalog, defaultConnectModel(input.harness, input.provider), input.harness, catalog.raw),
|
|
24656
|
+
...effort ? { effort } : {}
|
|
24657
|
+
};
|
|
24311
24658
|
}
|
|
24312
24659
|
var CONNECT_PROBE_TIMEOUT_MS = 12e3;
|
|
24313
24660
|
function connectProbeFoundModels(catalog) {
|
|
@@ -24341,6 +24688,33 @@ async function collectConnectWizard(prompts = clackPrompts, loadModels = loadCon
|
|
|
24341
24688
|
});
|
|
24342
24689
|
return picked.trim();
|
|
24343
24690
|
};
|
|
24691
|
+
const askEffort = async (catalog2, forHarness, model2, forProvider, forKey) => {
|
|
24692
|
+
if (!catalog2.effort)
|
|
24693
|
+
return void 0;
|
|
24694
|
+
let axis = catalog2.effort;
|
|
24695
|
+
if (model2 !== catalog2.currentValue) {
|
|
24696
|
+
const reread = await loadModels({
|
|
24697
|
+
harness: forHarness,
|
|
24698
|
+
model: model2,
|
|
24699
|
+
...forProvider ? { provider: forProvider } : {},
|
|
24700
|
+
...forKey ? { apiKey: forKey } : {},
|
|
24701
|
+
timeoutMs: CONNECT_PROBE_TIMEOUT_MS
|
|
24702
|
+
}).catch(() => void 0);
|
|
24703
|
+
axis = reread?.effort ?? axis;
|
|
24704
|
+
}
|
|
24705
|
+
if (!axis.options.length)
|
|
24706
|
+
return void 0;
|
|
24707
|
+
const picked = await prompts.select({
|
|
24708
|
+
message: brass("Choose reasoning effort"),
|
|
24709
|
+
options: axis.options.map((choice) => ({
|
|
24710
|
+
value: choice.id,
|
|
24711
|
+
label: choice.name ?? choice.id,
|
|
24712
|
+
...choice.id === axis.currentValue ? { hint: "current" } : {}
|
|
24713
|
+
})),
|
|
24714
|
+
...axis.options.some((choice) => choice.id === axis.currentValue) ? { initialValue: axis.currentValue } : {}
|
|
24715
|
+
});
|
|
24716
|
+
return picked.trim();
|
|
24717
|
+
};
|
|
24344
24718
|
const probe = async (candidate) => {
|
|
24345
24719
|
try {
|
|
24346
24720
|
const catalog2 = await loadModels({
|
|
@@ -24373,10 +24747,9 @@ async function collectConnectWizard(prompts = clackPrompts, loadModels = loadCon
|
|
|
24373
24747
|
sole: harness === sole,
|
|
24374
24748
|
...configured.currentValue ? { model: configured.currentValue } : {}
|
|
24375
24749
|
}));
|
|
24376
|
-
|
|
24377
|
-
|
|
24378
|
-
|
|
24379
|
-
};
|
|
24750
|
+
const model2 = await askModel(configured, harness);
|
|
24751
|
+
const effort2 = await askEffort(configured, harness, model2);
|
|
24752
|
+
return { harness, model: model2, ...effort2 ? { effort: effort2 } : {} };
|
|
24380
24753
|
}
|
|
24381
24754
|
let provider;
|
|
24382
24755
|
let apiKey;
|
|
@@ -24435,11 +24808,13 @@ async function collectConnectWizard(prompts = clackPrompts, loadModels = loadCon
|
|
|
24435
24808
|
...apiKey ? { apiKey: apiKey.trim() } : {}
|
|
24436
24809
|
});
|
|
24437
24810
|
const model = await askModel(catalog, harness, provider);
|
|
24811
|
+
const effort = await askEffort(catalog, harness, model, provider, apiKey?.trim());
|
|
24438
24812
|
return {
|
|
24439
24813
|
harness,
|
|
24440
24814
|
...provider ? { provider } : {},
|
|
24441
24815
|
...apiKey ? { apiKey: apiKey.trim() } : {},
|
|
24442
|
-
model
|
|
24816
|
+
model,
|
|
24817
|
+
...effort ? { effort } : {}
|
|
24443
24818
|
};
|
|
24444
24819
|
}
|
|
24445
24820
|
async function jsonRequest(url, body, fetchImpl) {
|
|
@@ -24464,12 +24839,13 @@ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl) {
|
|
|
24464
24839
|
const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
|
|
24465
24840
|
if (!normalizedPairingCode)
|
|
24466
24841
|
throw new Error("invalid pairing code");
|
|
24467
|
-
const avatarSeed =
|
|
24842
|
+
const avatarSeed = createHash8("sha256").update(normalizedPairingCode.toUpperCase()).digest("hex").slice(0, 32);
|
|
24468
24843
|
return jsonRequest(`${baseUrl}/auth/agent/connect`, {
|
|
24469
24844
|
pairing_code: normalizedPairingCode,
|
|
24470
24845
|
harness: selection.harness,
|
|
24471
24846
|
...selection.provider ? { provider: selection.provider } : {},
|
|
24472
24847
|
model: selection.model,
|
|
24848
|
+
...selection.effort ? { effort: selection.effort } : {},
|
|
24473
24849
|
avatar_seed: avatarSeed,
|
|
24474
24850
|
// This wizard always finishes the join itself (`finishConnectedAgentPairing`,
|
|
24475
24851
|
// called once the rename prompt below settles), so the claim must not
|
|
@@ -24511,7 +24887,7 @@ async function installCurrentRelease(fetchImpl) {
|
|
|
24511
24887
|
});
|
|
24512
24888
|
await activateRelease(layout, releaseId);
|
|
24513
24889
|
return {
|
|
24514
|
-
binary:
|
|
24890
|
+
binary: resolve23(layout.binDir, "beeline"),
|
|
24515
24891
|
version: published.version ?? releaseId
|
|
24516
24892
|
};
|
|
24517
24893
|
}
|
|
@@ -24534,21 +24910,21 @@ function providerEnvironment(selection) {
|
|
|
24534
24910
|
};
|
|
24535
24911
|
}
|
|
24536
24912
|
async function writePrivateJson(path, value) {
|
|
24537
|
-
await
|
|
24913
|
+
await mkdir16(dirname12(path), { recursive: true, mode: 448 });
|
|
24538
24914
|
await writeFile11(path, `${JSON.stringify(value, null, 2)}
|
|
24539
24915
|
`, { mode: 384 });
|
|
24540
|
-
await
|
|
24916
|
+
await chmod6(path, 384);
|
|
24541
24917
|
}
|
|
24542
24918
|
async function writeProviderEnv(selection, agentPubkey) {
|
|
24543
24919
|
const values = providerEnvironment(selection);
|
|
24544
24920
|
if (Object.keys(values).length === 0)
|
|
24545
24921
|
return void 0;
|
|
24546
|
-
const path =
|
|
24547
|
-
await
|
|
24922
|
+
const path = resolve23(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
|
|
24923
|
+
await mkdir16(dirname12(path), { recursive: true, mode: 448 });
|
|
24548
24924
|
const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
|
|
24549
24925
|
await writeFile11(path, `${contents}
|
|
24550
24926
|
`, { mode: 384 });
|
|
24551
|
-
await
|
|
24927
|
+
await chmod6(path, 384);
|
|
24552
24928
|
return path;
|
|
24553
24929
|
}
|
|
24554
24930
|
async function runInstalledFinish(binary, grantPath) {
|
|
@@ -24609,13 +24985,16 @@ async function runConnectWizard(code, fetchImpl, eventSubscriptions, accessPolic
|
|
|
24609
24985
|
await finishConnectedAgentPairing(baseUrl, pairingCode, grant.workspace_joined, eventSubscriptions, fetchImpl);
|
|
24610
24986
|
const installedRelease = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl), (release) => `Installed Beeline helper ${release.version}`);
|
|
24611
24987
|
const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
|
|
24612
|
-
const grantPath =
|
|
24988
|
+
const grantPath = resolve23(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
|
|
24613
24989
|
await writePrivateJson(grantPath, {
|
|
24614
24990
|
agentSecretKey: grant.agent_secret_key,
|
|
24615
24991
|
bodySecretKey: grant.body_secret_key,
|
|
24616
24992
|
agentName: grant.agent_name,
|
|
24617
24993
|
harness: grant.harness,
|
|
24618
24994
|
model: grant.model,
|
|
24995
|
+
// The server echoes back what it stored; the wizard's own answer is the
|
|
24996
|
+
// fallback for a server too old to carry the effort through.
|
|
24997
|
+
...grant.effort ?? selection.effort ? { effort: grant.effort ?? selection.effort } : {},
|
|
24619
24998
|
soul: grant.soul,
|
|
24620
24999
|
workspaceId: grant.workspace_id,
|
|
24621
25000
|
workspaceName: grant.workspace_name,
|
|
@@ -24671,7 +25050,7 @@ function isDevicePairingGrant(value) {
|
|
|
24671
25050
|
} catch {
|
|
24672
25051
|
return false;
|
|
24673
25052
|
}
|
|
24674
|
-
return typeof grant.agentSecretKey === "string" && /^[0-9a-f]{64}$/.test(grant.agentSecretKey) && typeof grant.bodySecretKey === "string" && /^[0-9a-f]{64}$/.test(grant.bodySecretKey) && typeof grant.agentName === "string" && CONNECT_HARNESSES.includes(grant.harness) && typeof grant.model === "string" && typeof grant.soul === "string" && typeof grant.workspaceId === "string" && typeof grant.workspaceName === "string" && typeof grant.pairedBy === "string" && /^[0-9a-f]{64}$/.test(grant.pairedBy) && typeof grant.monolithBaseUrl === "string" && grant.monolithBaseUrl === monolithOrigin && /^https?:$/.test(new URL(monolithOrigin).protocol) && typeof grant.daemonExchangeToken === "string" && /^bde_[A-Za-z0-9_-]{43}$/.test(grant.daemonExchangeToken);
|
|
25053
|
+
return typeof grant.agentSecretKey === "string" && /^[0-9a-f]{64}$/.test(grant.agentSecretKey) && typeof grant.bodySecretKey === "string" && /^[0-9a-f]{64}$/.test(grant.bodySecretKey) && typeof grant.agentName === "string" && CONNECT_HARNESSES.includes(grant.harness) && typeof grant.model === "string" && (grant.effort === void 0 || typeof grant.effort === "string") && typeof grant.soul === "string" && typeof grant.workspaceId === "string" && typeof grant.workspaceName === "string" && typeof grant.pairedBy === "string" && /^[0-9a-f]{64}$/.test(grant.pairedBy) && typeof grant.monolithBaseUrl === "string" && grant.monolithBaseUrl === monolithOrigin && /^https?:$/.test(new URL(monolithOrigin).protocol) && typeof grant.daemonExchangeToken === "string" && /^bde_[A-Za-z0-9_-]{43}$/.test(grant.daemonExchangeToken);
|
|
24675
25054
|
}
|
|
24676
25055
|
function connectPlainFailure(error) {
|
|
24677
25056
|
const raw = error instanceof Error ? error.message : String(error);
|
|
@@ -24691,18 +25070,18 @@ async function runConnectFinishCommand(path) {
|
|
|
24691
25070
|
throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
|
|
24692
25071
|
}
|
|
24693
25072
|
try {
|
|
24694
|
-
const grant = JSON.parse(await
|
|
25073
|
+
const grant = JSON.parse(await readFile11(resolve23(path), "utf8"));
|
|
24695
25074
|
if (!isDevicePairingGrant(grant))
|
|
24696
25075
|
throw new Error("device connection grant is invalid");
|
|
24697
25076
|
const connected = await completeDevicePairing(grant);
|
|
24698
|
-
await unlink2(
|
|
24699
|
-
const providerEnv = grant.llmEnvFile ? await
|
|
25077
|
+
await unlink2(resolve23(path));
|
|
25078
|
+
const providerEnv = grant.llmEnvFile ? await readFile11(grant.llmEnvFile, "utf8").catch(() => "") : "";
|
|
24700
25079
|
const apiKey = (/^OPENROUTER_API_KEY=(\S+)/m.exec(providerEnv)?.[1] ?? "").replace(/^["']|["']$/g, "");
|
|
24701
25080
|
const model = openRouterModelId(grant.model, { OPENROUTER_API_KEY: apiKey });
|
|
24702
25081
|
if (model) {
|
|
24703
25082
|
const decision2 = await resolveOpenRouterRouting({
|
|
24704
25083
|
model,
|
|
24705
|
-
cacheDir: openRouterRoutingCacheDir(
|
|
25084
|
+
cacheDir: openRouterRoutingCacheDir(dirname12(connected.configPath)),
|
|
24706
25085
|
...apiKey ? { apiKey } : {},
|
|
24707
25086
|
probeTimeoutMs: 1e4
|
|
24708
25087
|
});
|
|
@@ -24724,24 +25103,24 @@ init_self_update_manifest();
|
|
|
24724
25103
|
// apps/body/dist/managed-update.js
|
|
24725
25104
|
init_self_update();
|
|
24726
25105
|
import { spawn as spawn6 } from "node:child_process";
|
|
24727
|
-
import { mkdir as
|
|
24728
|
-
import { dirname as
|
|
25106
|
+
import { mkdir as mkdir18, rm as rm7, stat as stat3, writeFile as writeFile13 } from "node:fs/promises";
|
|
25107
|
+
import { dirname as dirname14, resolve as resolve25 } from "node:path";
|
|
24729
25108
|
|
|
24730
25109
|
// apps/body/dist/update-rollback-alert.js
|
|
24731
|
-
import { mkdir as
|
|
24732
|
-
import { dirname as
|
|
25110
|
+
import { mkdir as mkdir17, readFile as readFile12, rename as rename5, unlink as unlink3, writeFile as writeFile12 } from "node:fs/promises";
|
|
25111
|
+
import { dirname as dirname13, resolve as resolve24 } from "node:path";
|
|
24733
25112
|
var REPORT_INTERVAL_MS = 60 * 60 * 1e3;
|
|
24734
25113
|
var lastLogged = /* @__PURE__ */ new Map();
|
|
24735
25114
|
function updateRollbackAlertPath(runtimeDir) {
|
|
24736
|
-
return
|
|
25115
|
+
return resolve24(runtimeDir, "update-rollback-alert.json");
|
|
24737
25116
|
}
|
|
24738
25117
|
async function writeAlert(runtimeDir, alert) {
|
|
24739
25118
|
const path = updateRollbackAlertPath(runtimeDir);
|
|
24740
25119
|
const staged = `${path}.${process.pid}.tmp`;
|
|
24741
|
-
await
|
|
25120
|
+
await mkdir17(dirname13(path), { recursive: true });
|
|
24742
25121
|
await writeFile12(staged, `${JSON.stringify(alert, null, 2)}
|
|
24743
25122
|
`, { mode: 384 });
|
|
24744
|
-
await
|
|
25123
|
+
await rename5(staged, path);
|
|
24745
25124
|
}
|
|
24746
25125
|
async function queueUpdateRollbackAlert(runtimeDir, releaseId, now2 = Date.now()) {
|
|
24747
25126
|
const existing = await readUpdateRollbackAlert(runtimeDir);
|
|
@@ -24751,7 +25130,7 @@ async function queueUpdateRollbackAlert(runtimeDir, releaseId, now2 = Date.now()
|
|
|
24751
25130
|
}
|
|
24752
25131
|
async function readUpdateRollbackAlert(runtimeDir) {
|
|
24753
25132
|
try {
|
|
24754
|
-
const value = JSON.parse(await
|
|
25133
|
+
const value = JSON.parse(await readFile12(updateRollbackAlertPath(runtimeDir), "utf8"));
|
|
24755
25134
|
if (value.version !== 1 || typeof value.releaseId !== "string")
|
|
24756
25135
|
return void 0;
|
|
24757
25136
|
return value;
|
|
@@ -24802,22 +25181,22 @@ var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
|
|
|
24802
25181
|
var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
|
|
24803
25182
|
async function withInstallLock(layout, work, options = {}) {
|
|
24804
25183
|
const now2 = options.now ?? Date.now;
|
|
24805
|
-
const lock =
|
|
25184
|
+
const lock = resolve25(layout.releasesRoot, ".state", "install.lock");
|
|
24806
25185
|
const deadline = now2() + (options.waitMs ?? 1e4);
|
|
24807
|
-
await
|
|
25186
|
+
await mkdir18(dirname14(lock), { recursive: true });
|
|
24808
25187
|
for (; ; ) {
|
|
24809
25188
|
try {
|
|
24810
|
-
await
|
|
24811
|
-
await writeFile13(
|
|
25189
|
+
await mkdir18(lock);
|
|
25190
|
+
await writeFile13(resolve25(lock, "owner"), `${process.pid}
|
|
24812
25191
|
${now2()}
|
|
24813
25192
|
`, "utf8");
|
|
24814
25193
|
break;
|
|
24815
25194
|
} catch (error) {
|
|
24816
25195
|
if (error.code !== "EEXIST")
|
|
24817
25196
|
throw error;
|
|
24818
|
-
const age = now2() - await
|
|
25197
|
+
const age = now2() - await stat3(lock).then((value) => value.mtimeMs).catch(() => now2());
|
|
24819
25198
|
if (age > LOCK_STALE_MS) {
|
|
24820
|
-
await
|
|
25199
|
+
await rm7(lock, { recursive: true, force: true });
|
|
24821
25200
|
continue;
|
|
24822
25201
|
}
|
|
24823
25202
|
if (now2() >= deadline)
|
|
@@ -24828,7 +25207,7 @@ ${now2()}
|
|
|
24828
25207
|
try {
|
|
24829
25208
|
return await work();
|
|
24830
25209
|
} finally {
|
|
24831
|
-
await
|
|
25210
|
+
await rm7(lock, { recursive: true, force: true });
|
|
24832
25211
|
}
|
|
24833
25212
|
}
|
|
24834
25213
|
var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
@@ -24931,7 +25310,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
24931
25310
|
if (!attempt || attempt.releaseId !== desiredRelease || attempt.status !== "pending") {
|
|
24932
25311
|
const from = await readInstalledBundleIdentity({
|
|
24933
25312
|
...this.#layout,
|
|
24934
|
-
libDir:
|
|
25313
|
+
libDir: resolve25(this.#layout.releasesRoot, this.#loadedRelease)
|
|
24935
25314
|
}).catch(() => void 0) ?? {};
|
|
24936
25315
|
const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
|
|
24937
25316
|
const record2 = {
|
|
@@ -25218,7 +25597,7 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
|
|
|
25218
25597
|
});
|
|
25219
25598
|
if (!accepted)
|
|
25220
25599
|
return false;
|
|
25221
|
-
await writeFile13(
|
|
25600
|
+
await writeFile13(resolve25(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
|
|
25222
25601
|
readyAt: (options.now ?? Date.now)(),
|
|
25223
25602
|
loadedRelease,
|
|
25224
25603
|
functionalProof: options.functionalProof
|
|
@@ -25446,16 +25825,16 @@ async function runUpdateCommand(args) {
|
|
|
25446
25825
|
init_self_update();
|
|
25447
25826
|
|
|
25448
25827
|
// apps/body/dist/daemon-failure.js
|
|
25449
|
-
import { mkdir as
|
|
25450
|
-
import { dirname as
|
|
25828
|
+
import { mkdir as mkdir19, readFile as readFile13, rename as rename6, rm as rm8, writeFile as writeFile14 } from "node:fs/promises";
|
|
25829
|
+
import { dirname as dirname15, resolve as resolve26 } from "node:path";
|
|
25451
25830
|
var DAEMON_FAILURE_LIMIT = 3;
|
|
25452
25831
|
var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
25453
25832
|
function daemonFailurePath(runtimeDir) {
|
|
25454
|
-
return
|
|
25833
|
+
return resolve26(runtimeDir, "daemon-distress.json");
|
|
25455
25834
|
}
|
|
25456
25835
|
async function readFailureRecord(runtimeDir) {
|
|
25457
25836
|
try {
|
|
25458
|
-
const value = JSON.parse(await
|
|
25837
|
+
const value = JSON.parse(await readFile13(daemonFailurePath(runtimeDir), "utf8"));
|
|
25459
25838
|
if (value.version !== 1 || !Array.isArray(value.failures) || value.failures.some((failure) => typeof failure !== "number") || typeof value.lastError !== "string") {
|
|
25460
25839
|
return void 0;
|
|
25461
25840
|
}
|
|
@@ -25467,10 +25846,10 @@ async function readFailureRecord(runtimeDir) {
|
|
|
25467
25846
|
async function writeFailureRecord(runtimeDir, record2) {
|
|
25468
25847
|
const path = daemonFailurePath(runtimeDir);
|
|
25469
25848
|
const staged = `${path}.${process.pid}.tmp`;
|
|
25470
|
-
await
|
|
25849
|
+
await mkdir19(dirname15(path), { recursive: true, mode: 448 });
|
|
25471
25850
|
await writeFile14(staged, `${JSON.stringify(record2, null, 2)}
|
|
25472
25851
|
`, { mode: 384 });
|
|
25473
|
-
await
|
|
25852
|
+
await rename6(staged, path);
|
|
25474
25853
|
}
|
|
25475
25854
|
async function recordDaemonStartFailure(runtimeDir, error, now2 = Date.now()) {
|
|
25476
25855
|
const prior = await readFailureRecord(runtimeDir);
|
|
@@ -25486,13 +25865,13 @@ async function recordDaemonStartFailure(runtimeDir, error, now2 = Date.now()) {
|
|
|
25486
25865
|
return { distressed, count: failures.length, path: daemonFailurePath(runtimeDir) };
|
|
25487
25866
|
}
|
|
25488
25867
|
async function clearDaemonStartFailures(runtimeDir) {
|
|
25489
|
-
await
|
|
25868
|
+
await rm8(daemonFailurePath(runtimeDir), { force: true });
|
|
25490
25869
|
}
|
|
25491
25870
|
|
|
25492
25871
|
// apps/body/dist/update-functional-probe.js
|
|
25493
|
-
import { mkdir as
|
|
25872
|
+
import { mkdir as mkdir20, rm as rm9 } from "node:fs/promises";
|
|
25494
25873
|
import { homedir as homedir10 } from "node:os";
|
|
25495
|
-
import { resolve as
|
|
25874
|
+
import { resolve as resolve27 } from "node:path";
|
|
25496
25875
|
var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
|
|
25497
25876
|
var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
|
|
25498
25877
|
var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
|
|
@@ -25586,11 +25965,11 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
25586
25965
|
modelAnswerReason: `${detail} (the current release has the same host sandbox failure)`
|
|
25587
25966
|
};
|
|
25588
25967
|
}
|
|
25589
|
-
const root = input.probeRoot ??
|
|
25590
|
-
const cwd =
|
|
25591
|
-
const homeRoot =
|
|
25592
|
-
await
|
|
25593
|
-
await
|
|
25968
|
+
const root = input.probeRoot ?? resolve27(input.runtimeDir, "update-functional-probe");
|
|
25969
|
+
const cwd = resolve27(root, "checkout");
|
|
25970
|
+
const homeRoot = resolve27(root, "agent-home");
|
|
25971
|
+
await rm9(root, { recursive: true, force: true });
|
|
25972
|
+
await mkdir20(cwd, { recursive: true, mode: 448 });
|
|
25594
25973
|
let client;
|
|
25595
25974
|
try {
|
|
25596
25975
|
const agentEnv = {
|
|
@@ -25620,7 +25999,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
25620
25999
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
25621
26000
|
const operatorHome = input.config.operatorHome ?? homedir10();
|
|
25622
26001
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
25623
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
26002
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir20(dir, { recursive: true })));
|
|
25624
26003
|
spawnCommand = wrapAgentCommand({
|
|
25625
26004
|
bwrapPath: input.config.bwrapPath,
|
|
25626
26005
|
spec: {
|
|
@@ -25764,13 +26143,13 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
25764
26143
|
};
|
|
25765
26144
|
} finally {
|
|
25766
26145
|
await client?.stop().catch(() => void 0);
|
|
25767
|
-
await
|
|
26146
|
+
await rm9(root, { recursive: true, force: true }).catch(() => void 0);
|
|
25768
26147
|
}
|
|
25769
26148
|
}
|
|
25770
26149
|
|
|
25771
26150
|
// apps/body/dist/current-release-probe.js
|
|
25772
26151
|
import { spawn as spawn7 } from "node:child_process";
|
|
25773
|
-
import { dirname as
|
|
26152
|
+
import { dirname as dirname16, join as join10 } from "node:path";
|
|
25774
26153
|
init_self_update();
|
|
25775
26154
|
var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
|
|
25776
26155
|
var UPDATE_PROBE_COMMAND = "update-probe";
|
|
@@ -25813,13 +26192,13 @@ function outcomeFromReport(report) {
|
|
|
25813
26192
|
}
|
|
25814
26193
|
}
|
|
25815
26194
|
async function probeReleaseInSubprocess(input) {
|
|
25816
|
-
const bundleDir =
|
|
26195
|
+
const bundleDir = join10(input.layout.releasesRoot, input.releaseId);
|
|
25817
26196
|
const entrypoint = await resolveBundleEntrypoint(bundleDir);
|
|
25818
26197
|
if (!entrypoint) {
|
|
25819
26198
|
return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
|
|
25820
26199
|
}
|
|
25821
26200
|
const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
|
|
25822
|
-
return new Promise((
|
|
26201
|
+
return new Promise((resolve31) => {
|
|
25823
26202
|
const child = spawn7(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
25824
26203
|
let stdout6 = "";
|
|
25825
26204
|
let stderr = "";
|
|
@@ -25829,7 +26208,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
25829
26208
|
return;
|
|
25830
26209
|
settled = true;
|
|
25831
26210
|
clearTimeout(timer);
|
|
25832
|
-
|
|
26211
|
+
resolve31(outcome);
|
|
25833
26212
|
};
|
|
25834
26213
|
const timer = setTimeout(() => {
|
|
25835
26214
|
child.kill("SIGKILL");
|
|
@@ -25876,7 +26255,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
25876
26255
|
const runtime = await readRuntimeRecord(configPath);
|
|
25877
26256
|
const agent = runtimeAgentCommand(runtime);
|
|
25878
26257
|
const config = loadBodyConfig({
|
|
25879
|
-
workspaceRoot:
|
|
26258
|
+
workspaceRoot: join10(dirname16(configPath), "workspace"),
|
|
25880
26259
|
llmEnvFile: runtime.llmEnvFile,
|
|
25881
26260
|
env: { ...env, BUZZ_AGENT_BIN: agent.command, BUZZ_DEV_MCP_BIN: runtime.mcpBinary },
|
|
25882
26261
|
agent
|
|
@@ -25894,7 +26273,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
25894
26273
|
}
|
|
25895
26274
|
const layout = beelineInstallLayout(env);
|
|
25896
26275
|
const releaseId = (layout && await activeReleaseId(layout).catch(() => void 0)) ?? "unknown";
|
|
25897
|
-
const runtimeDir =
|
|
26276
|
+
const runtimeDir = dirname16(configPath);
|
|
25898
26277
|
const outcome = await probeOutcome(() => (options.probe ?? runUpdateFunctionalProbe)({
|
|
25899
26278
|
config,
|
|
25900
26279
|
runtimeDir,
|
|
@@ -25902,15 +26281,15 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
25902
26281
|
sandboxRequired: runtime.sandbox !== "off",
|
|
25903
26282
|
sandboxUnavailableDetail: sandbox.advisory,
|
|
25904
26283
|
// The successor's probe still holds `<runtimeDir>/update-functional-probe`.
|
|
25905
|
-
probeRoot:
|
|
26284
|
+
probeRoot: join10(runtimeDir, "current-release-probe")
|
|
25906
26285
|
}));
|
|
25907
26286
|
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 };
|
|
25908
26287
|
write(JSON.stringify(report));
|
|
25909
26288
|
}
|
|
25910
26289
|
|
|
25911
26290
|
// apps/body/dist/release-status.js
|
|
25912
|
-
import { readFile as
|
|
25913
|
-
import { resolve as
|
|
26291
|
+
import { readFile as readFile14, readdir as readdir6, rename as rename7, writeFile as writeFile15 } from "node:fs/promises";
|
|
26292
|
+
import { resolve as resolve28 } from "node:path";
|
|
25914
26293
|
var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
|
|
25915
26294
|
var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
|
|
25916
26295
|
var SOURCE_SHA = /^[0-9a-f]{7,64}$/;
|
|
@@ -25927,17 +26306,17 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
25927
26306
|
pid: options.pid ?? process.pid,
|
|
25928
26307
|
readyAt: (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
|
|
25929
26308
|
};
|
|
25930
|
-
const target =
|
|
26309
|
+
const target = resolve28(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
|
|
25931
26310
|
const temporary = `${target}.${status.pid}.tmp`;
|
|
25932
26311
|
await writeFile15(temporary, `${JSON.stringify(status, null, 2)}
|
|
25933
26312
|
`, { mode: 384 });
|
|
25934
|
-
await
|
|
26313
|
+
await rename7(temporary, target);
|
|
25935
26314
|
return status;
|
|
25936
26315
|
}
|
|
25937
26316
|
|
|
25938
26317
|
// apps/body/dist/scratch-sweep.js
|
|
25939
|
-
import { lstat as
|
|
25940
|
-
import { resolve as
|
|
26318
|
+
import { lstat as lstat4, readdir as readdir7, rmdir, unlink as unlink4 } from "node:fs/promises";
|
|
26319
|
+
import { resolve as resolve29 } from "node:path";
|
|
25941
26320
|
var DEFAULT_SCRATCH_TTL_HOURS = 72;
|
|
25942
26321
|
var NEVER_SWEEP_SUBDIR_NAMES = new Set(HOME_SUBDIRS.filter((name) => name !== "tmp"));
|
|
25943
26322
|
function scratchTtlMs(env = process.env) {
|
|
@@ -25946,10 +26325,10 @@ function scratchTtlMs(env = process.env) {
|
|
|
25946
26325
|
return (Number.isFinite(hours) && hours > 0 ? hours : DEFAULT_SCRATCH_TTL_HOURS) * 60 * 60 * 1e3;
|
|
25947
26326
|
}
|
|
25948
26327
|
async function discoverAttachScratchRoots(runtimeDir) {
|
|
25949
|
-
const roomsDir =
|
|
26328
|
+
const roomsDir = resolve29(runtimeDir, "rooms");
|
|
25950
26329
|
let entries;
|
|
25951
26330
|
try {
|
|
25952
|
-
entries = await
|
|
26331
|
+
entries = await readdir7(roomsDir, { withFileTypes: true });
|
|
25953
26332
|
} catch {
|
|
25954
26333
|
return [];
|
|
25955
26334
|
}
|
|
@@ -25957,8 +26336,8 @@ async function discoverAttachScratchRoots(runtimeDir) {
|
|
|
25957
26336
|
for (const entry of entries) {
|
|
25958
26337
|
if (!entry.isDirectory())
|
|
25959
26338
|
continue;
|
|
25960
|
-
const home =
|
|
25961
|
-
const stats = await
|
|
26339
|
+
const home = resolve29(roomsDir, entry.name, "agent-home");
|
|
26340
|
+
const stats = await lstat4(home).catch(() => void 0);
|
|
25962
26341
|
if (stats?.isDirectory())
|
|
25963
26342
|
roots.push(home);
|
|
25964
26343
|
}
|
|
@@ -25967,7 +26346,7 @@ async function discoverAttachScratchRoots(runtimeDir) {
|
|
|
25967
26346
|
async function removeStaleFiles(dir, cutoffMs, protectNamesHere) {
|
|
25968
26347
|
let entries;
|
|
25969
26348
|
try {
|
|
25970
|
-
entries = await
|
|
26349
|
+
entries = await readdir7(dir, { withFileTypes: true });
|
|
25971
26350
|
} catch {
|
|
25972
26351
|
return { removedFiles: 0, removedBytes: 0 };
|
|
25973
26352
|
}
|
|
@@ -25976,15 +26355,15 @@ async function removeStaleFiles(dir, cutoffMs, protectNamesHere) {
|
|
|
25976
26355
|
for (const entry of entries) {
|
|
25977
26356
|
if (protectNamesHere && NEVER_SWEEP_SUBDIR_NAMES.has(entry.name))
|
|
25978
26357
|
continue;
|
|
25979
|
-
const path =
|
|
25980
|
-
const stats = await
|
|
26358
|
+
const path = resolve29(dir, entry.name);
|
|
26359
|
+
const stats = await lstat4(path).catch(() => void 0);
|
|
25981
26360
|
if (!stats || stats.isSymbolicLink())
|
|
25982
26361
|
continue;
|
|
25983
26362
|
if (stats.isDirectory()) {
|
|
25984
26363
|
const nested = await removeStaleFiles(path, cutoffMs, false);
|
|
25985
26364
|
removedFiles += nested.removedFiles;
|
|
25986
26365
|
removedBytes += nested.removedBytes;
|
|
25987
|
-
const remaining = await
|
|
26366
|
+
const remaining = await readdir7(path).catch(() => void 0);
|
|
25988
26367
|
if (remaining && remaining.length === 0)
|
|
25989
26368
|
await rmdir(path).catch(() => void 0);
|
|
25990
26369
|
continue;
|
|
@@ -26002,7 +26381,7 @@ async function sweepAttachScratchRoots(roots, ttlMs, now2 = Date.now()) {
|
|
|
26002
26381
|
let removedFiles = 0;
|
|
26003
26382
|
let removedBytes = 0;
|
|
26004
26383
|
for (const root of roots) {
|
|
26005
|
-
const stats = await
|
|
26384
|
+
const stats = await lstat4(root).catch(() => void 0);
|
|
26006
26385
|
if (!stats?.isDirectory())
|
|
26007
26386
|
continue;
|
|
26008
26387
|
const result = await removeStaleFiles(root, cutoffMs, true);
|
|
@@ -26063,7 +26442,7 @@ var DaemonExitError = class extends Error {
|
|
|
26063
26442
|
};
|
|
26064
26443
|
async function runStoredDaemon(pathOrPointer) {
|
|
26065
26444
|
const configPath = await resolveRuntimeConfigPath(pathOrPointer);
|
|
26066
|
-
daemonFailureRuntimeDir =
|
|
26445
|
+
daemonFailureRuntimeDir = dirname17(configPath);
|
|
26067
26446
|
const accessMigration = await migrateRuntimeRecordAccessPolicy(configPath);
|
|
26068
26447
|
let runtime = accessMigration.runtime;
|
|
26069
26448
|
if (!runtime.transport) {
|
|
@@ -26075,7 +26454,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
26075
26454
|
runtime = activated.runtime;
|
|
26076
26455
|
const daemonApi = activated.client;
|
|
26077
26456
|
const agent = runtimeAgentCommand(runtime);
|
|
26078
|
-
await writeFile16(
|
|
26457
|
+
await writeFile16(resolve30(dirname17(configPath), "daemon.pid"), `${process.pid}
|
|
26079
26458
|
`, { mode: 384 });
|
|
26080
26459
|
const env = {
|
|
26081
26460
|
...process.env,
|
|
@@ -26083,7 +26462,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
26083
26462
|
BUZZ_DEV_MCP_BIN: runtime.mcpBinary
|
|
26084
26463
|
};
|
|
26085
26464
|
const config = loadBodyConfig({
|
|
26086
|
-
workspaceRoot:
|
|
26465
|
+
workspaceRoot: resolve30(dirname17(configPath), "workspace"),
|
|
26087
26466
|
llmEnvFile: runtime.llmEnvFile,
|
|
26088
26467
|
env,
|
|
26089
26468
|
agent
|
|
@@ -26118,7 +26497,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
26118
26497
|
const stop = () => controller.abort();
|
|
26119
26498
|
process.once("SIGINT", stop);
|
|
26120
26499
|
process.once("SIGTERM", stop);
|
|
26121
|
-
const runtimeDir =
|
|
26500
|
+
const runtimeDir = dirname17(configPath);
|
|
26122
26501
|
const layout = beelineInstallLayout(process.env);
|
|
26123
26502
|
const notifier = new SystemdNotifier();
|
|
26124
26503
|
let rollbackAlertDrain;
|
|
@@ -26265,8 +26644,8 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
26265
26644
|
} finally {
|
|
26266
26645
|
clearInterval(scratchSweepTimer);
|
|
26267
26646
|
await notifier.stopping(stoppingStatus).catch(() => void 0);
|
|
26268
|
-
const pidPath =
|
|
26269
|
-
const recorded = Number((await
|
|
26647
|
+
const pidPath = resolve30(dirname17(configPath), "daemon.pid");
|
|
26648
|
+
const recorded = Number((await readFile15(pidPath, "utf8").catch(() => "")).trim());
|
|
26270
26649
|
if (recorded === process.pid) {
|
|
26271
26650
|
await unlink5(pidPath).catch(() => void 0);
|
|
26272
26651
|
}
|
|
@@ -26293,7 +26672,7 @@ async function main() {
|
|
|
26293
26672
|
const roomId = roomFlag >= 0 ? args[roomFlag + 1] : void 0;
|
|
26294
26673
|
if (!configPath || !roomId)
|
|
26295
26674
|
throw new Error("corner-read-token requires --config and --room");
|
|
26296
|
-
const activated = await activateDaemonTransport(
|
|
26675
|
+
const activated = await activateDaemonTransport(resolve30(configPath));
|
|
26297
26676
|
if (!activated)
|
|
26298
26677
|
throw new Error("corner-read-token requires monolith transport");
|
|
26299
26678
|
const credential = await activated.client.execute("getRoomGitHubToken", { roomId });
|
|
@@ -26342,14 +26721,14 @@ async function main() {
|
|
|
26342
26721
|
const agentPubkey = agentFlag >= 0 ? args[agentFlag + 1] : void 0;
|
|
26343
26722
|
if (!configPath && agentPubkey) {
|
|
26344
26723
|
const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
|
|
26345
|
-
configPath = configs.find((candidate) =>
|
|
26724
|
+
configPath = configs.find((candidate) => dirname17(candidate).endsWith(agentPubkey));
|
|
26346
26725
|
}
|
|
26347
26726
|
if (!configPath && agentPubkey) {
|
|
26348
26727
|
throw new DaemonExitError(`unknown agent ${agentPubkey}: no durable runtime exists; refusing systemd restart loop`, UNKNOWN_AGENT_EXIT_STATUS);
|
|
26349
26728
|
}
|
|
26350
26729
|
if (!configPath)
|
|
26351
26730
|
throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
|
|
26352
|
-
await runStoredDaemon(
|
|
26731
|
+
await runStoredDaemon(resolve30(configPath));
|
|
26353
26732
|
return;
|
|
26354
26733
|
}
|
|
26355
26734
|
if (command === "update") {
|
|
@@ -26370,7 +26749,7 @@ async function main() {
|
|
|
26370
26749
|
if (!agentPubkey)
|
|
26371
26750
|
throw new Error("stop requires --agent <pubkey>");
|
|
26372
26751
|
const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
|
|
26373
|
-
const configPath = configs.find((candidate) =>
|
|
26752
|
+
const configPath = configs.find((candidate) => dirname17(candidate).endsWith(agentPubkey));
|
|
26374
26753
|
if (!configPath)
|
|
26375
26754
|
throw new Error(`no stored runtime found for agent ${agentPubkey}`);
|
|
26376
26755
|
const runtime = await readRuntimeRecord(configPath);
|