usebeeline 0.0.33 → 0.0.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/usebeeline.mjs +584 -181
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -309,12 +309,12 @@ __export(self_update_exports, {
|
|
|
309
309
|
});
|
|
310
310
|
import { createHash as createHash2 } from "node:crypto";
|
|
311
311
|
import { constants as fsConstants } from "node:fs";
|
|
312
|
-
import { access, chmod as
|
|
312
|
+
import { access, chmod as chmod3, lstat as lstat2, mkdir as mkdir8, open, readFile as readFile4, rename as rename3, rm as rm4, symlink as symlink2, writeFile as writeFile5 } from "node:fs/promises";
|
|
313
313
|
import { spawn as spawn4 } from "node:child_process";
|
|
314
|
-
import { homedir as
|
|
315
|
-
import { dirname as
|
|
314
|
+
import { homedir as homedir9 } from "node:os";
|
|
315
|
+
import { dirname as dirname8, join as join3, resolve as resolve14 } from "node:path";
|
|
316
316
|
function anchorLayout(rawLibDir) {
|
|
317
|
-
const libDir =
|
|
317
|
+
const libDir = resolve14(rawLibDir);
|
|
318
318
|
const segments = libDir.split(/[/\\]/);
|
|
319
319
|
const idx = segments.lastIndexOf(RELEASES_SEGMENT);
|
|
320
320
|
if (idx >= 2 && segments[idx - 1] === "lib") {
|
|
@@ -330,9 +330,9 @@ function anchorLayout(rawLibDir) {
|
|
|
330
330
|
// prefix's bin, NOT <prefix>/lib/bin — deriving it one level up was the
|
|
331
331
|
// defect that made activateRelease write its stable forwarders where
|
|
332
332
|
// nothing executed them, leaving stale raw wrappers in <prefix>/bin.
|
|
333
|
-
binDir:
|
|
333
|
+
binDir: resolve14(libDir, "../../bin"),
|
|
334
334
|
libDir,
|
|
335
|
-
releasesRoot:
|
|
335
|
+
releasesRoot: resolve14(libDir, `../${RELEASES_SEGMENT}`)
|
|
336
336
|
};
|
|
337
337
|
}
|
|
338
338
|
function beelineInstallLayout(env = process.env) {
|
|
@@ -342,8 +342,8 @@ function beelineInstallLayout(env = process.env) {
|
|
|
342
342
|
return anchorLayout(raw);
|
|
343
343
|
}
|
|
344
344
|
function defaultBeelineInstallLayout(env = process.env) {
|
|
345
|
-
const home = env.HOME?.trim() ||
|
|
346
|
-
return anchorLayout(
|
|
345
|
+
const home = env.HOME?.trim() || homedir9();
|
|
346
|
+
return anchorLayout(resolve14(home, ".local", "lib", "beeline"));
|
|
347
347
|
}
|
|
348
348
|
function hostPlatformKey() {
|
|
349
349
|
const os = process.platform === "linux" ? "linux" : process.platform === "darwin" ? "darwin" : "";
|
|
@@ -353,13 +353,13 @@ function hostPlatformKey() {
|
|
|
353
353
|
return `${os}-${arch}`;
|
|
354
354
|
}
|
|
355
355
|
function bundleJsonCandidates(bundleDir) {
|
|
356
|
-
return [
|
|
356
|
+
return [join3(bundleDir, "lib", "beeline", "bundle.json"), join3(bundleDir, "bundle.json")];
|
|
357
357
|
}
|
|
358
358
|
async function readBundleJson(bundleDir) {
|
|
359
359
|
let raw;
|
|
360
360
|
for (const candidate of bundleJsonCandidates(bundleDir)) {
|
|
361
361
|
try {
|
|
362
|
-
raw = await
|
|
362
|
+
raw = await readFile4(candidate, "utf8");
|
|
363
363
|
break;
|
|
364
364
|
} catch {
|
|
365
365
|
}
|
|
@@ -377,18 +377,18 @@ async function readBundleJson(bundleDir) {
|
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
function updateStatePath(layout) {
|
|
380
|
-
return
|
|
380
|
+
return join3(layout.releasesRoot, ".state", "update-state.json");
|
|
381
381
|
}
|
|
382
382
|
async function readUpdateState(layout) {
|
|
383
383
|
try {
|
|
384
|
-
return JSON.parse(await
|
|
384
|
+
return JSON.parse(await readFile4(updateStatePath(layout), "utf8"));
|
|
385
385
|
} catch {
|
|
386
386
|
return {};
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
389
|
async function writeUpdateState(layout, state) {
|
|
390
|
-
await
|
|
391
|
-
await
|
|
390
|
+
await mkdir8(join3(layout.releasesRoot, ".state"), { recursive: true });
|
|
391
|
+
await writeFile5(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
|
|
392
392
|
`, "utf8");
|
|
393
393
|
}
|
|
394
394
|
async function readInstalledBundleIdentity(layout, _state = {}) {
|
|
@@ -469,7 +469,7 @@ function run(command, args, timeoutMs) {
|
|
|
469
469
|
});
|
|
470
470
|
}
|
|
471
471
|
function entrypointCandidates(bundleDir) {
|
|
472
|
-
return [
|
|
472
|
+
return [join3(bundleDir, BUNDLE_ENTRYPOINT), join3(bundleDir, "beeline-cli.mjs")];
|
|
473
473
|
}
|
|
474
474
|
async function resolveBundleEntrypoint(bundleDir) {
|
|
475
475
|
for (const candidate of entrypointCandidates(bundleDir)) {
|
|
@@ -491,18 +491,18 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
491
491
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
492
492
|
const log = opts.logger ?? ((line) => console.log(`[body] self-update: ${line}`));
|
|
493
493
|
const releaseId = sanitizeReleaseId(published.commit ?? published.version ?? `release-${Date.now()}`);
|
|
494
|
-
const releaseDir =
|
|
495
|
-
const okMarker =
|
|
494
|
+
const releaseDir = join3(layout.releasesRoot, releaseId);
|
|
495
|
+
const okMarker = join3(releaseDir, ".stage-ok");
|
|
496
496
|
let previouslyVerified = false;
|
|
497
497
|
try {
|
|
498
|
-
const recorded = await
|
|
498
|
+
const recorded = await readFile4(okMarker, "utf8");
|
|
499
499
|
if (recorded.trim() === published.sha256)
|
|
500
500
|
return releaseId;
|
|
501
501
|
previouslyVerified = true;
|
|
502
502
|
} catch {
|
|
503
503
|
}
|
|
504
|
-
await
|
|
505
|
-
const tempArchive =
|
|
504
|
+
await mkdir8(releaseDir, { recursive: true });
|
|
505
|
+
const tempArchive = join3(layout.releasesRoot, `.download-${releaseId}-${process.pid}.tar.gz`);
|
|
506
506
|
try {
|
|
507
507
|
log(`downloading ${published.file}`);
|
|
508
508
|
const response = await fetchImpl(archiveUrlFor(manifestUrl, published.file), {
|
|
@@ -522,7 +522,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
522
522
|
if (actual !== published.sha256.toLowerCase()) {
|
|
523
523
|
throw new Error(`checksum mismatch for ${published.file}: expected ${published.sha256}, got ${actual} \u2014 aborting without touching the installed bundle`);
|
|
524
524
|
}
|
|
525
|
-
await
|
|
525
|
+
await writeFile5(tempArchive, Buffer.concat(chunks), { mode: 384 });
|
|
526
526
|
const entries = (await new Promise((resolveList, rejectList) => {
|
|
527
527
|
const child = spawn4("tar", ["-tzf", tempArchive], { stdio: ["ignore", "pipe", "inherit"] });
|
|
528
528
|
let out = "";
|
|
@@ -542,18 +542,18 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
542
542
|
throw new Error(`extracting bundle failed: ${extract2.stderr}`);
|
|
543
543
|
for (const relative3 of requiredBundlePaths()) {
|
|
544
544
|
try {
|
|
545
|
-
await access(
|
|
545
|
+
await access(join3(releaseDir, relative3), fsConstants.F_OK);
|
|
546
546
|
} catch {
|
|
547
547
|
throw new Error(`staged bundle is missing ${relative3}`);
|
|
548
548
|
}
|
|
549
549
|
}
|
|
550
550
|
if (opts.smokeTestCli !== false) {
|
|
551
|
-
const probe = await run(process.execPath, [
|
|
551
|
+
const probe = await run(process.execPath, [join3(releaseDir, BUNDLE_ENTRYPOINT), "--version"], 6e4);
|
|
552
552
|
if (probe.status !== 0) {
|
|
553
553
|
throw new Error(`staged bundle failed its startup smoke test (--version exited ${probe.status})${probe.stderr ? `: ${probe.stderr.trim()}` : ""}`);
|
|
554
554
|
}
|
|
555
555
|
}
|
|
556
|
-
await
|
|
556
|
+
await writeFile5(okMarker, `${published.sha256}
|
|
557
557
|
`, "utf8");
|
|
558
558
|
log(`staged release ${releaseId} (sha256 verified)`);
|
|
559
559
|
return releaseId;
|
|
@@ -581,26 +581,26 @@ function forwarderScript(tool) {
|
|
|
581
581
|
}
|
|
582
582
|
async function replaceFile(path, contents, mode) {
|
|
583
583
|
const temp = `${path}.new-${process.pid}`;
|
|
584
|
-
await
|
|
585
|
-
await
|
|
584
|
+
await writeFile5(temp, contents, { mode });
|
|
585
|
+
await chmod3(temp, mode);
|
|
586
586
|
await rename3(temp, path);
|
|
587
587
|
}
|
|
588
588
|
async function activateRelease(layout, releaseId) {
|
|
589
|
-
const releaseDir =
|
|
590
|
-
await access(
|
|
591
|
-
await
|
|
592
|
-
await
|
|
589
|
+
const releaseDir = join3(layout.releasesRoot, releaseId);
|
|
590
|
+
await access(join3(releaseDir, BUNDLE_ENTRYPOINT), fsConstants.F_OK);
|
|
591
|
+
await mkdir8(layout.releasesRoot, { recursive: true });
|
|
592
|
+
await mkdir8(layout.binDir, { recursive: true });
|
|
593
593
|
let previousReleaseId = await activeReleaseId(layout);
|
|
594
594
|
const kind = await pathKind(layout.libDir);
|
|
595
595
|
if (kind === "directory") {
|
|
596
596
|
const legacyIdentity = await readBundleJson(layout.libDir);
|
|
597
597
|
const legacyId = sanitizeReleaseId(legacyIdentity?.commit ?? legacyIdentity?.version ?? `legacy-${Date.now()}`);
|
|
598
|
-
const legacyDir =
|
|
598
|
+
const legacyDir = join3(layout.releasesRoot, legacyId);
|
|
599
599
|
try {
|
|
600
600
|
await access(legacyDir, fsConstants.F_OK);
|
|
601
601
|
previousReleaseId = `${legacyId}-${Date.now()}`;
|
|
602
|
-
await rename3(layout.libDir,
|
|
603
|
-
await normalizeLegacyBundleShape(
|
|
602
|
+
await rename3(layout.libDir, join3(layout.releasesRoot, previousReleaseId));
|
|
603
|
+
await normalizeLegacyBundleShape(join3(layout.releasesRoot, previousReleaseId));
|
|
604
604
|
} catch {
|
|
605
605
|
await rename3(layout.libDir, legacyDir);
|
|
606
606
|
await normalizeLegacyBundleShape(legacyDir);
|
|
@@ -609,18 +609,18 @@ async function activateRelease(layout, releaseId) {
|
|
|
609
609
|
}
|
|
610
610
|
const tempLink = `${layout.libDir}.new-${process.pid}`;
|
|
611
611
|
await rm4(tempLink, { force: true });
|
|
612
|
-
await symlink2(
|
|
612
|
+
await symlink2(join3("beeline-releases", releaseId), tempLink);
|
|
613
613
|
await rename3(tempLink, layout.libDir);
|
|
614
|
-
await fsyncDir(
|
|
614
|
+
await fsyncDir(dirname8(layout.libDir));
|
|
615
615
|
await writeBinForwarders(layout, releaseDir);
|
|
616
616
|
return { previousReleaseId };
|
|
617
617
|
}
|
|
618
618
|
async function normalizeLegacyBundleShape(bundleDir) {
|
|
619
|
-
const innerLib =
|
|
619
|
+
const innerLib = join3(bundleDir, "lib", "beeline");
|
|
620
620
|
let anyFlat = false;
|
|
621
621
|
for (const name of LEGACY_FLAT_BUNDLE_FILES) {
|
|
622
622
|
try {
|
|
623
|
-
await access(
|
|
623
|
+
await access(join3(bundleDir, name), fsConstants.F_OK);
|
|
624
624
|
anyFlat = true;
|
|
625
625
|
break;
|
|
626
626
|
} catch {
|
|
@@ -628,62 +628,62 @@ async function normalizeLegacyBundleShape(bundleDir) {
|
|
|
628
628
|
}
|
|
629
629
|
if (!anyFlat)
|
|
630
630
|
return;
|
|
631
|
-
await
|
|
631
|
+
await mkdir8(innerLib, { recursive: true });
|
|
632
632
|
for (const name of LEGACY_FLAT_BUNDLE_FILES) {
|
|
633
633
|
try {
|
|
634
|
-
await access(
|
|
634
|
+
await access(join3(innerLib, name), fsConstants.F_OK);
|
|
635
635
|
continue;
|
|
636
636
|
} catch {
|
|
637
637
|
}
|
|
638
|
-
await rename3(
|
|
638
|
+
await rename3(join3(bundleDir, name), join3(innerLib, name)).catch(() => void 0);
|
|
639
639
|
}
|
|
640
640
|
}
|
|
641
641
|
async function writeBinForwarders(layout, activeBundleRoot) {
|
|
642
642
|
for (const tool of FORWARDER_TOOLS) {
|
|
643
|
-
const target =
|
|
643
|
+
const target = join3(activeBundleRoot, "bin", tool);
|
|
644
644
|
try {
|
|
645
645
|
await access(target, fsConstants.X_OK);
|
|
646
646
|
} catch {
|
|
647
647
|
continue;
|
|
648
648
|
}
|
|
649
|
-
await replaceFile(
|
|
649
|
+
await replaceFile(join3(layout.binDir, tool), forwarderScript(tool), 493);
|
|
650
650
|
}
|
|
651
651
|
}
|
|
652
652
|
async function repairInstallForwarders(layout, opts = {}) {
|
|
653
653
|
if (await pathKind(layout.libDir) !== "symlink")
|
|
654
654
|
return false;
|
|
655
|
-
const forwarderPath =
|
|
655
|
+
const forwarderPath = join3(layout.binDir, "beeline");
|
|
656
656
|
let current;
|
|
657
657
|
try {
|
|
658
|
-
current = await
|
|
658
|
+
current = await readFile4(forwarderPath, "utf8");
|
|
659
659
|
} catch {
|
|
660
660
|
current = void 0;
|
|
661
661
|
}
|
|
662
662
|
if (current === forwarderScript("beeline"))
|
|
663
663
|
return false;
|
|
664
|
-
await
|
|
664
|
+
await mkdir8(layout.binDir, { recursive: true });
|
|
665
665
|
await writeBinForwarders(layout, layout.libDir);
|
|
666
666
|
opts.logger?.(`[body] self-update: repaired <prefix>/bin forwarders to follow the active-bundle anchor (${layout.libDir})`);
|
|
667
667
|
return true;
|
|
668
668
|
}
|
|
669
669
|
async function rollbackToPreviousRelease(layout, previousReleaseId) {
|
|
670
|
-
const releaseDir =
|
|
670
|
+
const releaseDir = join3(layout.releasesRoot, previousReleaseId);
|
|
671
671
|
const entrypoint = await resolveBundleEntrypoint(releaseDir);
|
|
672
672
|
if (!entrypoint) {
|
|
673
673
|
throw new Error(`release ${previousReleaseId} has no runnable CLI entrypoint`);
|
|
674
674
|
}
|
|
675
675
|
const tempLink = `${layout.libDir}.rollback-${process.pid}`;
|
|
676
676
|
await rm4(tempLink, { force: true });
|
|
677
|
-
await symlink2(
|
|
677
|
+
await symlink2(join3("beeline-releases", previousReleaseId), tempLink);
|
|
678
678
|
await rename3(tempLink, layout.libDir);
|
|
679
|
-
await fsyncDir(
|
|
679
|
+
await fsyncDir(dirname8(layout.libDir));
|
|
680
680
|
}
|
|
681
681
|
function updateAttemptPath(layout) {
|
|
682
|
-
return
|
|
682
|
+
return join3(layout.releasesRoot, ".state", "update-attempt.json");
|
|
683
683
|
}
|
|
684
684
|
async function readUpdateAttempt(layout) {
|
|
685
685
|
try {
|
|
686
|
-
const raw = JSON.parse(await
|
|
686
|
+
const raw = JSON.parse(await readFile4(updateAttemptPath(layout), "utf8"));
|
|
687
687
|
if (raw.version !== 1 || typeof raw.appliedAt !== "number" || typeof raw.confirmBy !== "number" || typeof raw.releaseId !== "string" || !["pending", "confirmed", "reverted"].includes(raw.status)) {
|
|
688
688
|
return void 0;
|
|
689
689
|
}
|
|
@@ -693,10 +693,10 @@ async function readUpdateAttempt(layout) {
|
|
|
693
693
|
}
|
|
694
694
|
}
|
|
695
695
|
async function writeUpdateAttempt(layout, record2) {
|
|
696
|
-
await
|
|
696
|
+
await mkdir8(join3(layout.releasesRoot, ".state"), { recursive: true });
|
|
697
697
|
const path = updateAttemptPath(layout);
|
|
698
698
|
const staged = `${path}.${process.pid}.tmp`;
|
|
699
|
-
await
|
|
699
|
+
await writeFile5(staged, `${JSON.stringify(record2, null, 2)}
|
|
700
700
|
`, { mode: 384 });
|
|
701
701
|
await rename3(staged, path);
|
|
702
702
|
}
|
|
@@ -955,8 +955,8 @@ var init_self_update = __esm({
|
|
|
955
955
|
});
|
|
956
956
|
|
|
957
957
|
// apps/body/dist/cli.js
|
|
958
|
-
import { dirname as
|
|
959
|
-
import { readFile as
|
|
958
|
+
import { dirname as dirname13, resolve as resolve21 } from "node:path";
|
|
959
|
+
import { readFile as readFile9, unlink as unlink3, writeFile as writeFile11 } from "node:fs/promises";
|
|
960
960
|
import { stdin as stdin4, stdout as stdout5 } from "node:process";
|
|
961
961
|
|
|
962
962
|
// node_modules/@clack/core/dist/index.mjs
|
|
@@ -2327,8 +2327,9 @@ import { accessSync as accessSync2, constants as constants2, existsSync as exist
|
|
|
2327
2327
|
import { basename, dirname, resolve as resolve2 } from "node:path";
|
|
2328
2328
|
|
|
2329
2329
|
// apps/body/dist/agent-command.js
|
|
2330
|
-
import { accessSync, constants, existsSync } from "node:fs";
|
|
2331
|
-
import {
|
|
2330
|
+
import { accessSync, constants, existsSync, readdirSync } from "node:fs";
|
|
2331
|
+
import { homedir } from "node:os";
|
|
2332
|
+
import { delimiter, isAbsolute, join, resolve } from "node:path";
|
|
2332
2333
|
var AGENT_KINDS = [
|
|
2333
2334
|
"codex",
|
|
2334
2335
|
"claude",
|
|
@@ -2363,13 +2364,74 @@ var ADAPTER_INSTALL_COMMANDS = {
|
|
|
2363
2364
|
function adapterInstallHint(kind) {
|
|
2364
2365
|
return formatAdapterInstallCommand(ADAPTER_INSTALL_COMMANDS[kind]);
|
|
2365
2366
|
}
|
|
2367
|
+
function nodeVersionRank(name) {
|
|
2368
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(name);
|
|
2369
|
+
if (!match)
|
|
2370
|
+
return void 0;
|
|
2371
|
+
return [Number(match[1] ?? 0), Number(match[2] ?? 0), Number(match[3] ?? 0)];
|
|
2372
|
+
}
|
|
2373
|
+
function nodeVersionBins(versionsDir, binSuffix) {
|
|
2374
|
+
let entries;
|
|
2375
|
+
try {
|
|
2376
|
+
entries = readdirSync(versionsDir);
|
|
2377
|
+
} catch {
|
|
2378
|
+
return [];
|
|
2379
|
+
}
|
|
2380
|
+
return entries.map((name) => ({ name, rank: nodeVersionRank(name) })).filter((entry) => Boolean(entry.rank)).sort((a2, b) => {
|
|
2381
|
+
for (let i3 = 0; i3 < 3; i3 += 1) {
|
|
2382
|
+
const delta = (b.rank[i3] ?? 0) - (a2.rank[i3] ?? 0);
|
|
2383
|
+
if (delta !== 0)
|
|
2384
|
+
return delta;
|
|
2385
|
+
}
|
|
2386
|
+
return 0;
|
|
2387
|
+
}).map((entry) => join(versionsDir, entry.name, binSuffix));
|
|
2388
|
+
}
|
|
2389
|
+
function wellKnownExecutableDirs(env = process.env) {
|
|
2390
|
+
const home = env.HOME?.trim() || homedir();
|
|
2391
|
+
const xdgData = env.XDG_DATA_HOME?.trim() || resolve(home, ".local", "share");
|
|
2392
|
+
const fnmRoots = [
|
|
2393
|
+
env.FNM_DIR?.trim(),
|
|
2394
|
+
resolve(xdgData, "fnm"),
|
|
2395
|
+
resolve(home, ".fnm")
|
|
2396
|
+
].filter((root) => Boolean(root));
|
|
2397
|
+
const nvmRoots = [env.NVM_DIR?.trim(), resolve(home, ".nvm")].filter((root) => Boolean(root));
|
|
2398
|
+
const versioned = [];
|
|
2399
|
+
for (const root of fnmRoots) {
|
|
2400
|
+
versioned.push(...nodeVersionBins(join(root, "node-versions"), "installation/bin"));
|
|
2401
|
+
}
|
|
2402
|
+
for (const root of nvmRoots) {
|
|
2403
|
+
versioned.push(...nodeVersionBins(join(root, "versions", "node"), "bin"));
|
|
2404
|
+
}
|
|
2405
|
+
return [
|
|
2406
|
+
...versioned,
|
|
2407
|
+
resolve(home, ".local", "bin"),
|
|
2408
|
+
"/usr/local/bin",
|
|
2409
|
+
"/opt/homebrew/bin"
|
|
2410
|
+
];
|
|
2411
|
+
}
|
|
2412
|
+
function augmentedSearchDirectories(env = process.env) {
|
|
2413
|
+
const directories = [];
|
|
2414
|
+
const pushAll = (paths) => {
|
|
2415
|
+
for (const directory of paths) {
|
|
2416
|
+
if (directory && !directories.includes(directory))
|
|
2417
|
+
directories.push(directory);
|
|
2418
|
+
}
|
|
2419
|
+
};
|
|
2420
|
+
pushAll((env.PATH ?? "").split(delimiter));
|
|
2421
|
+
if (env.BEELINE_HARNESS_PATH_AUGMENT === "0")
|
|
2422
|
+
return directories;
|
|
2423
|
+
pushAll(wellKnownExecutableDirs(env));
|
|
2424
|
+
pushAll((env.BEELINE_LAUNCHER_PATH ?? "").split(delimiter));
|
|
2425
|
+
return directories;
|
|
2426
|
+
}
|
|
2427
|
+
function describeExecutableSearch(env = process.env) {
|
|
2428
|
+
return augmentedSearchDirectories(env).join(", ");
|
|
2429
|
+
}
|
|
2366
2430
|
function firstExisting(paths) {
|
|
2367
2431
|
return paths.find((path) => path && existsSync(path));
|
|
2368
2432
|
}
|
|
2369
2433
|
function executableOnPath(name, env = process.env) {
|
|
2370
|
-
for (const directory of (env
|
|
2371
|
-
if (!directory)
|
|
2372
|
-
continue;
|
|
2434
|
+
for (const directory of augmentedSearchDirectories(env)) {
|
|
2373
2435
|
const candidate = resolve(directory, name);
|
|
2374
2436
|
try {
|
|
2375
2437
|
accessSync(candidate, constants.X_OK);
|
|
@@ -2389,7 +2451,7 @@ function requireExecutable(command, env, cwd, missingMessage) {
|
|
|
2389
2451
|
} catch {
|
|
2390
2452
|
}
|
|
2391
2453
|
}
|
|
2392
|
-
throw new Error(missingMessage);
|
|
2454
|
+
throw new Error(`${missingMessage} Searched: ${describeExecutableSearch(env)}.`);
|
|
2393
2455
|
}
|
|
2394
2456
|
function parseAgentCommand(value) {
|
|
2395
2457
|
const words = [];
|
|
@@ -3644,7 +3706,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
3644
3706
|
const current = this.activeRunIds.get(sessionId);
|
|
3645
3707
|
if (current)
|
|
3646
3708
|
return Promise.resolve(current);
|
|
3647
|
-
return new Promise((
|
|
3709
|
+
return new Promise((resolve22, reject) => {
|
|
3648
3710
|
const onUpdate = (update) => {
|
|
3649
3711
|
if (update.sessionId !== sessionId)
|
|
3650
3712
|
return;
|
|
@@ -3652,7 +3714,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
3652
3714
|
if (!runId)
|
|
3653
3715
|
return;
|
|
3654
3716
|
cleanup();
|
|
3655
|
-
|
|
3717
|
+
resolve22(runId);
|
|
3656
3718
|
};
|
|
3657
3719
|
const timer = setTimeout(() => {
|
|
3658
3720
|
cleanup();
|
|
@@ -3736,13 +3798,13 @@ var AcpClient = class extends EventEmitter {
|
|
|
3736
3798
|
}
|
|
3737
3799
|
const id = this.nextId++;
|
|
3738
3800
|
const payload = { jsonrpc: "2.0", id, method, params };
|
|
3739
|
-
return new Promise((
|
|
3801
|
+
return new Promise((resolve22, reject) => {
|
|
3740
3802
|
const timer = setTimeout(() => {
|
|
3741
3803
|
this.pending.delete(id);
|
|
3742
3804
|
reject(new AcpRequestTimeoutError(method, timeoutMs, this.stderrTail, Boolean(onStart)));
|
|
3743
3805
|
}, timeoutMs);
|
|
3744
3806
|
this.pending.set(id, {
|
|
3745
|
-
resolve:
|
|
3807
|
+
resolve: resolve22,
|
|
3746
3808
|
reject,
|
|
3747
3809
|
timer,
|
|
3748
3810
|
method,
|
|
@@ -4075,7 +4137,13 @@ async function withAgentModelCatalog(agent, agentEnv, selection, inspect) {
|
|
|
4075
4137
|
agentCommand: agent.command,
|
|
4076
4138
|
agentArgs: agentArgsWithModelSelection(agent, selection),
|
|
4077
4139
|
agentEnv,
|
|
4078
|
-
agentCwd: scratchCwd
|
|
4140
|
+
agentCwd: scratchCwd,
|
|
4141
|
+
// The wizard probe runs on the human's own machine for a few seconds —
|
|
4142
|
+
// inherit the caller's environment so harness launchers resolve (`pi`,
|
|
4143
|
+
// `pi-acp`, `claude-agent-acp`'s `env node`) and fnm/homebrew toolchains
|
|
4144
|
+
// work. Daemon sessions keep the allowlisted-env boundary; only this
|
|
4145
|
+
// probe opts in.
|
|
4146
|
+
inheritProcessEnv: true
|
|
4079
4147
|
});
|
|
4080
4148
|
try {
|
|
4081
4149
|
await client.start();
|
|
@@ -4153,14 +4221,14 @@ import { promisify as promisify3 } from "node:util";
|
|
|
4153
4221
|
// apps/body/dist/monolith-corner-turn.js
|
|
4154
4222
|
import { execFile as execFile2 } from "node:child_process";
|
|
4155
4223
|
import { mkdir as mkdir3 } from "node:fs/promises";
|
|
4156
|
-
import { homedir as
|
|
4224
|
+
import { homedir as homedir5 } from "node:os";
|
|
4157
4225
|
import { promisify as promisify2 } from "node:util";
|
|
4158
4226
|
|
|
4159
4227
|
// apps/body/dist/agent-home.js
|
|
4160
4228
|
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
|
|
4161
4229
|
import { randomUUID } from "node:crypto";
|
|
4162
4230
|
import { chmod, copyFile, lstat, mkdir, readdir, realpath, rename, rm as rm2, symlink, unlink, writeFile } from "node:fs/promises";
|
|
4163
|
-
import { homedir } from "node:os";
|
|
4231
|
+
import { homedir as homedir2 } from "node:os";
|
|
4164
4232
|
import { basename as basename3, dirname as dirname2, relative, resolve as resolve6, sep } from "node:path";
|
|
4165
4233
|
|
|
4166
4234
|
// apps/body/dist/beeline-skill.js
|
|
@@ -4172,18 +4240,31 @@ var BEELINE_ROOM_CAPABILITIES = [
|
|
|
4172
4240
|
"You may address any Room member, including another agent, by writing @name in your reply; the server routes that mention to them.",
|
|
4173
4241
|
"Tag another agent only when you need something from them: a question, a handoff, a task. Never tag to acknowledge, agree, or say you are ready. If nothing is actionable, do not reply.",
|
|
4174
4242
|
"Tag the user only when you need a decision or input, or when the task they asked for is finished. Never tag for progress, acknowledgement, or questions the transcript already answers.",
|
|
4175
|
-
"
|
|
4243
|
+
"Every MCP server mounted into this session is approved tool by tool - use operator and host tools freely; the read-only filesystem sandbox is the boundary, not a tool list. Network web search is enabled.",
|
|
4176
4244
|
"To send a file, call beeline-agent attach_file with a path inside your checkout; it is attached to your reply.",
|
|
4245
|
+
"To run something later or repeatedly, call beeline-agent create_schedule (interval in minutes or a 5-field cron, optional maxRuns); list_schedules / delete_schedule manage them.",
|
|
4177
4246
|
"When repository work is needed, you MUST call beeline-agent open_corner with a one-paragraph summary of the complete objective. The host-governed call is the only way to start write work.",
|
|
4178
4247
|
"Never claim an action or reply happened unless the prompt or a tool result proves it."
|
|
4179
4248
|
].join(" ");
|
|
4180
|
-
|
|
4249
|
+
var BEELINE_DM_CAPABILITIES = [
|
|
4250
|
+
"This is a private direct-message conversation with one person. Every message they send is addressed to you; reply without tagging.",
|
|
4251
|
+
"This Room is strictly conversational: there is no repository binding and no corner can be opened from here.",
|
|
4252
|
+
"The repository filesystem is read-only in this session.",
|
|
4253
|
+
"Every MCP server mounted into this session is approved tool by tool - use operator and host tools freely; the read-only filesystem sandbox is the boundary, not a tool list. Network web search is enabled.",
|
|
4254
|
+
"To send a file, call beeline-agent attach_file with a path inside your checkout; it is attached to your reply.",
|
|
4255
|
+
"Tag the person only when you need a decision or input, or when the task they asked for is finished.",
|
|
4256
|
+
"Never claim an action or reply happened unless the prompt or a tool result proves it."
|
|
4257
|
+
].join(" ");
|
|
4258
|
+
function beelinePrimer(repository, directMessage) {
|
|
4259
|
+
if (directMessage) {
|
|
4260
|
+
return `Consult the release-versioned using-beeline skill (SKILL.md) when you need the managed Room mechanics. ${BEELINE_DM_CAPABILITIES}`;
|
|
4261
|
+
}
|
|
4181
4262
|
const repositoryLine = repository ? ` This Room is bound to ${repository.name} (branch ${repository.branch}); you have a read-only checkout at the session root.` : "";
|
|
4182
4263
|
return `Consult the release-versioned using-beeline skill (SKILL.md) when you need the managed Room mechanics. ${BEELINE_ROOM_CAPABILITIES}${repositoryLine}`;
|
|
4183
4264
|
}
|
|
4184
4265
|
var BEELINE_CAPABILITIES_PRIMER = beelinePrimer();
|
|
4185
|
-
function beelineCapabilityContextForHarness(agentCommand, repository) {
|
|
4186
|
-
const primer = beelinePrimer(repository);
|
|
4266
|
+
function beelineCapabilityContextForHarness(agentCommand, repository, directMessage) {
|
|
4267
|
+
const primer = beelinePrimer(repository, directMessage);
|
|
4187
4268
|
return {
|
|
4188
4269
|
sessionPrompt: primer,
|
|
4189
4270
|
...harnessHonorsSessionSystemPrompt(agentCommand) ? {} : { compatibilityTurnPrefix: primer }
|
|
@@ -4210,7 +4291,7 @@ description: How to answer inside a Beeline Room.
|
|
|
4210
4291
|
|
|
4211
4292
|
# Using Beeline
|
|
4212
4293
|
|
|
4213
|
-
You are answering inside a read-only
|
|
4294
|
+
You are answering inside a Room whose filesystem is read-only. ${BEELINE_ROOM_CAPABILITIES}
|
|
4214
4295
|
`;
|
|
4215
4296
|
}
|
|
4216
4297
|
|
|
@@ -4391,7 +4472,12 @@ var SHARED_CREDENTIALS = [
|
|
|
4391
4472
|
var BEELINE_DEFAULT_SKILL_NAMES = [
|
|
4392
4473
|
USING_BEELINE_SKILL_NAME
|
|
4393
4474
|
];
|
|
4394
|
-
var
|
|
4475
|
+
var OPERATOR_SKILL_SOURCE_DIRS = [
|
|
4476
|
+
".agents/skills",
|
|
4477
|
+
".claude/skills",
|
|
4478
|
+
".codex/skills",
|
|
4479
|
+
".pi/agent/skills"
|
|
4480
|
+
];
|
|
4395
4481
|
var AGENT_SKILL_DIRS = ["claude", "codex", "grok", "pi"];
|
|
4396
4482
|
var SHARED_SKILL_NAME_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
4397
4483
|
function isSharedSkillName(value) {
|
|
@@ -4409,10 +4495,11 @@ var PI_CUSTOM_MODEL_CONFIG = {
|
|
|
4409
4495
|
target: "models.json"
|
|
4410
4496
|
};
|
|
4411
4497
|
var CODEX_ROOM_AGENT_LOCKDOWN_TOML = "[agents]\nenabled = false\n";
|
|
4498
|
+
var CODEX_ROOM_WEB_SEARCH_TOML = "[features]\nstandalone_web_search = true\n";
|
|
4412
4499
|
var HOME_SUBDIRS = ["user", "claude", "codex", "grok", "pi", "state", "cache", "tmp"];
|
|
4413
4500
|
async function prepareRoomAgentHome(input) {
|
|
4414
4501
|
const root = resolve6(input.root);
|
|
4415
|
-
const operatorHome = input.operatorHome ??
|
|
4502
|
+
const operatorHome = input.operatorHome ?? homedir2();
|
|
4416
4503
|
try {
|
|
4417
4504
|
await mkdir(root, { recursive: true, mode: 448 });
|
|
4418
4505
|
const rootStats = await lstat(root);
|
|
@@ -4452,17 +4539,17 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
4452
4539
|
const managedSkills = [
|
|
4453
4540
|
{ name: USING_BEELINE_SKILL_NAME, content: usingBeelineSkillMarkdown(skillReleaseId) }
|
|
4454
4541
|
];
|
|
4455
|
-
const shared = await
|
|
4542
|
+
const shared = await resolveSharedSkillSources(operatorHome, sharedSkills);
|
|
4456
4543
|
for (const dir of AGENT_SKILL_DIRS) {
|
|
4457
4544
|
const target = resolve6(root, dir, "skills");
|
|
4458
|
-
await provisionManagedSkillsDir(target, managedSkills, shared);
|
|
4545
|
+
await provisionManagedSkillsDir(target, managedSkills, shared, sharedSkills.length === 0);
|
|
4459
4546
|
}
|
|
4460
4547
|
for (const config of HARNESS_MCP_CONFIGS) {
|
|
4461
4548
|
try {
|
|
4462
4549
|
const source = resolve6(operatorHome, config.toml);
|
|
4463
4550
|
const target = resolve6(root, config.dir, "config.toml");
|
|
4464
4551
|
const mcpSection = existsSync3(source) ? filteredHarnessMcpToml(readFileSync4(source, "utf8")) : void 0;
|
|
4465
|
-
const section = config.dir === "codex" ? [CODEX_ROOM_AGENT_LOCKDOWN_TOML, mcpSection].filter(Boolean).join("\n") : mcpSection;
|
|
4552
|
+
const section = config.dir === "codex" ? [CODEX_ROOM_AGENT_LOCKDOWN_TOML, CODEX_ROOM_WEB_SEARCH_TOML, mcpSection].filter(Boolean).join("\n") : mcpSection;
|
|
4466
4553
|
if (!section) {
|
|
4467
4554
|
await unlink(target).catch(() => void 0);
|
|
4468
4555
|
continue;
|
|
@@ -4489,6 +4576,15 @@ async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, fa
|
|
|
4489
4576
|
throw error;
|
|
4490
4577
|
console.warn("[body] operator MCP passthrough failed for claude:", error);
|
|
4491
4578
|
}
|
|
4579
|
+
try {
|
|
4580
|
+
const settings2 = { permissions: { allow: ["WebSearch"] } };
|
|
4581
|
+
await writeIsolatedHarnessFile(resolve6(root, "claude", "settings.json"), `${JSON.stringify(settings2, null, 2)}
|
|
4582
|
+
`);
|
|
4583
|
+
} catch (error) {
|
|
4584
|
+
if (failClosed)
|
|
4585
|
+
throw error;
|
|
4586
|
+
console.warn("[body] claude web-search settings provisioning failed:", error);
|
|
4587
|
+
}
|
|
4492
4588
|
await provisionPiCustomModelConfig(root, operatorHome, failClosed);
|
|
4493
4589
|
}
|
|
4494
4590
|
async function provisionPiCustomModelConfig(root, operatorHome, failClosed) {
|
|
@@ -4540,7 +4636,7 @@ function filteredHarnessMcpToml(source) {
|
|
|
4540
4636
|
});
|
|
4541
4637
|
return extractTomlSections(source, ["mcp_servers"], excluded);
|
|
4542
4638
|
}
|
|
4543
|
-
async function provisionManagedSkillsDir(target, managedSkills, sharedSkills) {
|
|
4639
|
+
async function provisionManagedSkillsDir(target, managedSkills, sharedSkills, optionalShares) {
|
|
4544
4640
|
const parent = dirname2(target);
|
|
4545
4641
|
await assertRealContainedDirectory(parent, dirname2(parent));
|
|
4546
4642
|
const staged = resolve6(parent, `.skills.${process.pid}.${randomUUID()}.tmp`);
|
|
@@ -4557,7 +4653,13 @@ async function provisionManagedSkillsDir(target, managedSkills, sharedSkills) {
|
|
|
4557
4653
|
throw new Error(`shared skill collides with Beeline-owned skill: ${shared.name}`);
|
|
4558
4654
|
}
|
|
4559
4655
|
names.add(shared.name);
|
|
4560
|
-
|
|
4656
|
+
try {
|
|
4657
|
+
await copySafeSkillTree(shared.source, resolve6(staged, shared.name), shared.source);
|
|
4658
|
+
} catch (error) {
|
|
4659
|
+
if (!optionalShares)
|
|
4660
|
+
throw error;
|
|
4661
|
+
console.warn(`[body] skipping shared skill ${shared.name}:`, error);
|
|
4662
|
+
}
|
|
4561
4663
|
}
|
|
4562
4664
|
const existing = await lstat(target).catch(() => void 0);
|
|
4563
4665
|
if (existing)
|
|
@@ -4567,6 +4669,39 @@ async function provisionManagedSkillsDir(target, managedSkills, sharedSkills) {
|
|
|
4567
4669
|
await rm2(staged, { recursive: true, force: true });
|
|
4568
4670
|
}
|
|
4569
4671
|
}
|
|
4672
|
+
async function resolveSharedSkillSources(operatorHome, names) {
|
|
4673
|
+
if (names.length > 0)
|
|
4674
|
+
return resolveExplicitSkillSources(operatorHome, names);
|
|
4675
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4676
|
+
const resolved = [];
|
|
4677
|
+
for (const relativeRoot of OPERATOR_SKILL_SOURCE_DIRS) {
|
|
4678
|
+
const sourceRoot = resolve6(operatorHome, relativeRoot);
|
|
4679
|
+
const rootStats = await lstat(sourceRoot).catch(() => void 0);
|
|
4680
|
+
if (!rootStats?.isDirectory() || rootStats.isSymbolicLink())
|
|
4681
|
+
continue;
|
|
4682
|
+
for (const entry of await readdir(sourceRoot)) {
|
|
4683
|
+
if (!isSharedSkillName(entry) || seen.has(entry))
|
|
4684
|
+
continue;
|
|
4685
|
+
const candidate = resolve6(sourceRoot, entry);
|
|
4686
|
+
try {
|
|
4687
|
+
const candidateStats = await lstat(candidate);
|
|
4688
|
+
if (!candidateStats.isDirectory() || candidateStats.isSymbolicLink())
|
|
4689
|
+
continue;
|
|
4690
|
+
assertContained(sourceRoot, candidate);
|
|
4691
|
+
const skillMd = resolve6(candidate, "SKILL.md");
|
|
4692
|
+
const skillStats = await lstat(skillMd);
|
|
4693
|
+
if (!skillStats.isFile() || skillStats.isSymbolicLink() || skillStats.nlink !== 1) {
|
|
4694
|
+
throw new Error(`shared skill requires an ordinary SKILL.md: ${entry}`);
|
|
4695
|
+
}
|
|
4696
|
+
seen.add(entry);
|
|
4697
|
+
resolved.push({ name: entry, source: candidate });
|
|
4698
|
+
} catch (error) {
|
|
4699
|
+
console.warn(`[body] skipping operator skill ${entry}:`, error);
|
|
4700
|
+
}
|
|
4701
|
+
}
|
|
4702
|
+
}
|
|
4703
|
+
return resolved;
|
|
4704
|
+
}
|
|
4570
4705
|
async function resolveExplicitSkillSources(operatorHome, names) {
|
|
4571
4706
|
const unique = [...new Set(names)];
|
|
4572
4707
|
for (const name of unique) {
|
|
@@ -4576,7 +4711,7 @@ async function resolveExplicitSkillSources(operatorHome, names) {
|
|
|
4576
4711
|
const resolved = [];
|
|
4577
4712
|
for (const name of unique) {
|
|
4578
4713
|
const matches = [];
|
|
4579
|
-
for (const relativeRoot of
|
|
4714
|
+
for (const relativeRoot of OPERATOR_SKILL_SOURCE_DIRS) {
|
|
4580
4715
|
const sourceRoot = resolve6(operatorHome, relativeRoot);
|
|
4581
4716
|
const candidate = resolve6(sourceRoot, name);
|
|
4582
4717
|
const rootStats = await lstat(sourceRoot).catch(() => void 0);
|
|
@@ -4828,7 +4963,34 @@ function isReadOnlyMcpPermissionRequest(request) {
|
|
|
4828
4963
|
}
|
|
4829
4964
|
return false;
|
|
4830
4965
|
}
|
|
4966
|
+
function isMountedMcpToolPermissionRequest(request) {
|
|
4967
|
+
const toolCall = request.toolCall;
|
|
4968
|
+
const rawInput = toolCall?.rawInput;
|
|
4969
|
+
if (rawInput && typeof rawInput === "object" && !Array.isArray(rawInput)) {
|
|
4970
|
+
const call = rawInput;
|
|
4971
|
+
if (typeof call.server === "string" && typeof call.tool === "string")
|
|
4972
|
+
return true;
|
|
4973
|
+
}
|
|
4974
|
+
if (shellPayload(toolCall))
|
|
4975
|
+
return false;
|
|
4976
|
+
const title = toolCall?.title?.trim() ?? "";
|
|
4977
|
+
if (/^mcp__[^_].*__[^_]/.test(title))
|
|
4978
|
+
return true;
|
|
4979
|
+
if (/^mcp\.[^.]+\.[^.]/.test(title))
|
|
4980
|
+
return true;
|
|
4981
|
+
return isReadOnlyMcpPermissionRequest(request) || isBeelineAgentMcpPermissionRequest(request);
|
|
4982
|
+
}
|
|
4831
4983
|
var AGENT_SURFACE_TOOL_NAMES = ["open_corner", "pr_checks_status", "attach_file"];
|
|
4984
|
+
var SQUIRE_TITLE_PREFIXES = ["mcp__squire__", "mcp.squire.", "squire.", "squire/"];
|
|
4985
|
+
function isSquireMcpPermissionRequest(request) {
|
|
4986
|
+
const rawInput = request.toolCall?.rawInput;
|
|
4987
|
+
if (rawInput && typeof rawInput === "object" && !Array.isArray(rawInput)) {
|
|
4988
|
+
if (rawInput.server === "squire")
|
|
4989
|
+
return true;
|
|
4990
|
+
}
|
|
4991
|
+
const title = request.toolCall?.title?.trim() ?? "";
|
|
4992
|
+
return SQUIRE_TITLE_PREFIXES.some((prefix) => title.startsWith(prefix));
|
|
4993
|
+
}
|
|
4832
4994
|
function isBeelineAgentMcpPermissionRequest(request) {
|
|
4833
4995
|
const toolCall = request.toolCall;
|
|
4834
4996
|
const title = toolCall?.title?.trim() ?? "";
|
|
@@ -4864,6 +5026,7 @@ function beelineAgentMcpServer(config, api, context) {
|
|
|
4864
5026
|
args: [...config.readonlyMcpArgs ?? []],
|
|
4865
5027
|
env: [
|
|
4866
5028
|
{ name: "BEELINE_MCP_SURFACE", value: "agent" },
|
|
5029
|
+
...context.directMessage ? [{ name: "BEELINE_AGENT_DM", value: "1" }] : [],
|
|
4867
5030
|
{ name: "BEELINE_DAEMON_BASE_URL", value: connection.baseUrl },
|
|
4868
5031
|
{ name: "BEELINE_DAEMON_TOKEN", value: connection.daemonToken },
|
|
4869
5032
|
{ name: "BEELINE_DAEMON_AGENT_ID", value: connection.agentId },
|
|
@@ -4899,7 +5062,7 @@ function readOnlyMcpServer(config, cwd, agentMemoryDir) {
|
|
|
4899
5062
|
// apps/body/dist/bwrap-sandbox.js
|
|
4900
5063
|
import { spawnSync } from "node:child_process";
|
|
4901
5064
|
import { lstatSync as lstatSync2 } from "node:fs";
|
|
4902
|
-
import { homedir as
|
|
5065
|
+
import { homedir as homedir3 } from "node:os";
|
|
4903
5066
|
import { isAbsolute as isAbsolute2, relative as relative2, resolve as resolve8 } from "node:path";
|
|
4904
5067
|
var DEFAULT_SANDBOX_POLICY = "bwrap";
|
|
4905
5068
|
function isSandboxPolicy(value) {
|
|
@@ -4932,7 +5095,7 @@ var HARNESS_HOME_STATE_DIRS = [
|
|
|
4932
5095
|
dirs: [".grok"]
|
|
4933
5096
|
}
|
|
4934
5097
|
];
|
|
4935
|
-
function harnessHomeStateDirs(agentCommand, home =
|
|
5098
|
+
function harnessHomeStateDirs(agentCommand, home = homedir3()) {
|
|
4936
5099
|
if (!agentCommand)
|
|
4937
5100
|
return [];
|
|
4938
5101
|
for (const { match, dirs } of HARNESS_HOME_STATE_DIRS) {
|
|
@@ -4949,7 +5112,7 @@ var KNOWN_CREDENTIAL_MASK_PATHS = [
|
|
|
4949
5112
|
".git-credentials",
|
|
4950
5113
|
".secrets.env"
|
|
4951
5114
|
];
|
|
4952
|
-
function credentialMaskPaths(extraPaths, home =
|
|
5115
|
+
function credentialMaskPaths(extraPaths, home = homedir3(), stat3 = (path) => {
|
|
4953
5116
|
try {
|
|
4954
5117
|
const info = lstatSync2(path);
|
|
4955
5118
|
return { isDirectory: info.isDirectory() };
|
|
@@ -5149,7 +5312,7 @@ import { randomBytes as randomBytes5 } from "node:crypto";
|
|
|
5149
5312
|
import { execFile } from "node:child_process";
|
|
5150
5313
|
import { closeSync, openSync } from "node:fs";
|
|
5151
5314
|
import { mkdir as mkdir2, readFile, readdir as readdir2, rename as rename2, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
5152
|
-
import { homedir as
|
|
5315
|
+
import { homedir as homedir4 } from "node:os";
|
|
5153
5316
|
import { dirname as dirname3, resolve as resolve9 } from "node:path";
|
|
5154
5317
|
import { spawn as spawn2 } from "node:child_process";
|
|
5155
5318
|
import { promisify } from "node:util";
|
|
@@ -9538,7 +9701,7 @@ function alphabet(letters) {
|
|
|
9538
9701
|
};
|
|
9539
9702
|
}
|
|
9540
9703
|
// @__NO_SIDE_EFFECTS__
|
|
9541
|
-
function
|
|
9704
|
+
function join2(separator = "") {
|
|
9542
9705
|
astr("join", separator);
|
|
9543
9706
|
return {
|
|
9544
9707
|
encode: (from) => {
|
|
@@ -9668,8 +9831,8 @@ var base64 = hasBase64Builtin ? {
|
|
|
9668
9831
|
decode(s) {
|
|
9669
9832
|
return decodeBase64Builtin(s, false);
|
|
9670
9833
|
}
|
|
9671
|
-
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */
|
|
9672
|
-
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */
|
|
9834
|
+
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join2(""));
|
|
9835
|
+
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join2(""));
|
|
9673
9836
|
var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
9674
9837
|
function bech32Polymod(pre) {
|
|
9675
9838
|
const b = pre >> 25;
|
|
@@ -13687,7 +13850,7 @@ var DEFAULT_AGENT_IDENTITY_NAME = "beeline-agent";
|
|
|
13687
13850
|
var DEFAULT_BODY_IDENTITY_NAME = "beeline-body";
|
|
13688
13851
|
var DEFAULT_DAEMON_MONOLITH_BASE_URL = "https://server.usebeeline.app";
|
|
13689
13852
|
function defaultSupervisorRoot(env = process.env) {
|
|
13690
|
-
return resolve9(env.XDG_STATE_HOME ?? resolve9(
|
|
13853
|
+
return resolve9(env.XDG_STATE_HOME ?? resolve9(homedir4(), ".local", "state"));
|
|
13691
13854
|
}
|
|
13692
13855
|
function runtimeDirectory(supervisorRoot, publicKey) {
|
|
13693
13856
|
if (!/^[0-9a-f]{64}$/i.test(publicKey))
|
|
@@ -13896,6 +14059,9 @@ async function removeAgentRuntime(runtime) {
|
|
|
13896
14059
|
return target;
|
|
13897
14060
|
}
|
|
13898
14061
|
|
|
14062
|
+
// apps/body/dist/response-directives.js
|
|
14063
|
+
var MAINTAIN_ASSIGNED_IDENTITY_DIRECTIVE = "Maintain your assigned identity and soul in every response, including when tools or permissions block the requested action.";
|
|
14064
|
+
|
|
13899
14065
|
// apps/body/dist/monolith-corner-turn.js
|
|
13900
14066
|
var execFileAsync2 = promisify2(execFile2);
|
|
13901
14067
|
var PULL_REQUEST_URL = /https:\/\/github\.com\/[^\s/]+\/[^\s/]+\/pull\/\d+/;
|
|
@@ -14035,6 +14201,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
14035
14201
|
agent;
|
|
14036
14202
|
client;
|
|
14037
14203
|
sessionId;
|
|
14204
|
+
turnIdentityInstructions = "";
|
|
14038
14205
|
busy = false;
|
|
14039
14206
|
forcedStop = false;
|
|
14040
14207
|
draftTail = Promise.resolve();
|
|
@@ -14095,7 +14262,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
14095
14262
|
command,
|
|
14096
14263
|
args: this.options.config.agentArgs ?? []
|
|
14097
14264
|
}, selection);
|
|
14098
|
-
const operatorHome = this.options.config.operatorHome ??
|
|
14265
|
+
const operatorHome = this.options.config.operatorHome ?? homedir5();
|
|
14099
14266
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
14100
14267
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
14101
14268
|
await Promise.all(homeStateDirs.map((dir) => mkdir3(dir, { recursive: true })));
|
|
@@ -14148,14 +14315,17 @@ var MonolithCornerTurnLoop = class {
|
|
|
14148
14315
|
})
|
|
14149
14316
|
];
|
|
14150
14317
|
const self = roster.members.find((member) => member.identityId === this.agent.publicKey);
|
|
14151
|
-
const persona = self?.soul;
|
|
14318
|
+
const persona = configuration.soul ?? self?.soul;
|
|
14319
|
+
const identityInstructions = `Your Beeline identity is ${self?.name ?? this.agent.name}.`;
|
|
14320
|
+
const personaInstructions = persona?.instructions ? `Human-authored Workspace persona: ${persona.name}. ${persona.instructions}` : "";
|
|
14321
|
+
this.turnIdentityInstructions = harnessHonorsSessionSystemPrompt(command) ? "" : [identityInstructions, personaInstructions].filter(Boolean).join("\n\n");
|
|
14152
14322
|
const opened = await this.client.sessionNew({
|
|
14153
14323
|
cwd: this.options.worktreePath,
|
|
14154
14324
|
mcpServers: servers,
|
|
14155
14325
|
mode: "edit",
|
|
14156
14326
|
systemPrompt: [
|
|
14157
|
-
|
|
14158
|
-
|
|
14327
|
+
identityInstructions,
|
|
14328
|
+
personaInstructions,
|
|
14159
14329
|
`You are in an isolated git worktree on ${this.options.featureBranch}, targeting ${this.options.targetBranch}.`,
|
|
14160
14330
|
"Work normally with the full coding tools. Commit and push only this feature branch. Use gh to open its pull request.",
|
|
14161
14331
|
"PR-opening turn rule: as soon as a pull request exists, print its full GitHub URL as your final response and end the turn immediately. Do not call pr_checks_status in that same turn and do not wait for checks inside it. Then stay idle until a later corner fact or human message starts another turn.",
|
|
@@ -14206,17 +14376,49 @@ var MonolithCornerTurnLoop = class {
|
|
|
14206
14376
|
const names = new Map(roster.members.map((member) => [member.identityId, member.name]));
|
|
14207
14377
|
const transcript = conversation.items.slice(-120).map((message) => `${names.get(message.authorId) ?? "Beeline"} [${message.type}]: ${message.body}`).join("\n");
|
|
14208
14378
|
const prompt = [
|
|
14379
|
+
this.turnIdentityInstructions,
|
|
14209
14380
|
`Corner objective:
|
|
14210
14381
|
${this.options.objective}`,
|
|
14211
14382
|
transcript ? `Corner transcript:
|
|
14212
14383
|
${transcript}` : "",
|
|
14213
14384
|
`Newest trigger:
|
|
14214
14385
|
${trigger}`,
|
|
14215
|
-
"Continue the objective. Obey the PR checks and human hold rules in your session instructions."
|
|
14386
|
+
"Continue the objective. Obey the PR checks and human hold rules in your session instructions.",
|
|
14387
|
+
MAINTAIN_ASSIGNED_IDENTITY_DIRECTIVE
|
|
14216
14388
|
].filter(Boolean).join("\n\n");
|
|
14217
14389
|
const sessionId = this.sessionId;
|
|
14218
14390
|
const turnId = requestId;
|
|
14219
14391
|
const publishedToolCalls = /* @__PURE__ */ new Set();
|
|
14392
|
+
const NARRATION_MAX_SEGMENTS = 20;
|
|
14393
|
+
let narrationPostedChars = 0;
|
|
14394
|
+
let narrationSegments = 0;
|
|
14395
|
+
const postNarrationSegments = (full) => {
|
|
14396
|
+
if (narrationSegments >= NARRATION_MAX_SEGMENTS)
|
|
14397
|
+
return;
|
|
14398
|
+
const unposted = full.slice(narrationPostedChars);
|
|
14399
|
+
const boundaries = [...unposted.matchAll(/\n\n|[.!?](?=\s)/g)];
|
|
14400
|
+
if (!boundaries.length)
|
|
14401
|
+
return;
|
|
14402
|
+
const boundary = boundaries[boundaries.length - 1];
|
|
14403
|
+
const segmentEnd = narrationPostedChars + boundary.index + boundary[0].length;
|
|
14404
|
+
const segment = stripAgentReplyPreamble(full.slice(narrationPostedChars, segmentEnd));
|
|
14405
|
+
const start = narrationPostedChars;
|
|
14406
|
+
narrationPostedChars = segmentEnd;
|
|
14407
|
+
narrationSegments += 1;
|
|
14408
|
+
const trimmed = segment.trim();
|
|
14409
|
+
if (!trimmed)
|
|
14410
|
+
return;
|
|
14411
|
+
this.activityTail = this.activityTail.catch(() => void 0).then(async () => {
|
|
14412
|
+
await api.execute("postRoomMessage", {
|
|
14413
|
+
roomId: cornerId,
|
|
14414
|
+
text: trimmed,
|
|
14415
|
+
presentation: "message"
|
|
14416
|
+
});
|
|
14417
|
+
}).catch(() => {
|
|
14418
|
+
narrationPostedChars = start;
|
|
14419
|
+
narrationSegments -= 1;
|
|
14420
|
+
});
|
|
14421
|
+
};
|
|
14220
14422
|
const publishToolCalls = (calls, settledOnly) => {
|
|
14221
14423
|
calls.forEach((call, index) => {
|
|
14222
14424
|
const key = toolCallKey(call, index);
|
|
@@ -14238,6 +14440,7 @@ ${trigger}`,
|
|
|
14238
14440
|
});
|
|
14239
14441
|
};
|
|
14240
14442
|
const result = await this.client.sessionPrompt(sessionId, prompt, 12e4, (_delta, full) => {
|
|
14443
|
+
postNarrationSegments(full);
|
|
14241
14444
|
this.draftTail = this.draftTail.catch(() => void 0).then(() => api.execute("postAgentDraft", {
|
|
14242
14445
|
agentId: this.agent.publicKey,
|
|
14243
14446
|
roomId: cornerId,
|
|
@@ -14249,15 +14452,19 @@ ${trigger}`,
|
|
|
14249
14452
|
publishToolCalls(result.toolCalls, false);
|
|
14250
14453
|
await this.activityTail;
|
|
14251
14454
|
await this.draftTail;
|
|
14455
|
+
await this.activityTail;
|
|
14252
14456
|
const reply = stripAgentReplyPreamble(result.agentText).trim();
|
|
14253
14457
|
if (!reply)
|
|
14254
14458
|
throw new Error("ACP corner turn produced no durable reply");
|
|
14255
|
-
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
|
|
14459
|
+
const durableTail = narrationPostedChars > 0 ? stripAgentReplyPreamble(result.agentText.slice(narrationPostedChars)).trim() : reply;
|
|
14460
|
+
if (durableTail) {
|
|
14461
|
+
await api.execute("postRoomMessage", {
|
|
14462
|
+
roomId: cornerId,
|
|
14463
|
+
requestId,
|
|
14464
|
+
text: durableTail,
|
|
14465
|
+
presentation: "message"
|
|
14466
|
+
});
|
|
14467
|
+
}
|
|
14261
14468
|
const pullRequest = reply.match(PULL_REQUEST_URL)?.[0];
|
|
14262
14469
|
const alreadyReady = conversation.items.some((item) => /\bPR ready for review\b/i.test(item.body));
|
|
14263
14470
|
if (pullRequest && !alreadyReady) {
|
|
@@ -14368,9 +14575,11 @@ async function wait(ms, signal) {
|
|
|
14368
14575
|
|
|
14369
14576
|
// apps/body/dist/monolith-room-turn.js
|
|
14370
14577
|
import { mkdir as mkdir4 } from "node:fs/promises";
|
|
14371
|
-
import { homedir as
|
|
14578
|
+
import { homedir as homedir6 } from "node:os";
|
|
14372
14579
|
function isRoomMcpPermissionRequest(request) {
|
|
14373
|
-
|
|
14580
|
+
if (isSquireMcpPermissionRequest(request))
|
|
14581
|
+
return false;
|
|
14582
|
+
return isMountedMcpToolPermissionRequest(request);
|
|
14374
14583
|
}
|
|
14375
14584
|
function roomPrincipalMayAddressAgent(authority, humanPermitted) {
|
|
14376
14585
|
return authority.member && (authority.principalKind === "agent" || authority.principalKind === "human" && humanPermitted);
|
|
@@ -14453,6 +14662,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
14453
14662
|
this.roster(),
|
|
14454
14663
|
this.options.api.execute("getRoomRepositoryState", { roomId: this.options.roomId })
|
|
14455
14664
|
]);
|
|
14665
|
+
const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
|
|
14456
14666
|
await mkdir4(this.options.cwd, { recursive: true });
|
|
14457
14667
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
14458
14668
|
root: this.options.config.agentHomeRoot,
|
|
@@ -14467,7 +14677,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
14467
14677
|
command,
|
|
14468
14678
|
args: this.options.config.agentArgs ?? []
|
|
14469
14679
|
}, selection);
|
|
14470
|
-
const operatorHome = this.options.config.operatorHome ??
|
|
14680
|
+
const operatorHome = this.options.config.operatorHome ?? homedir6();
|
|
14471
14681
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
14472
14682
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
14473
14683
|
await Promise.all(homeStateDirs.map((dir) => mkdir4(dir, { recursive: true })));
|
|
@@ -14500,7 +14710,8 @@ var MonolithRoomTurnLoop = class {
|
|
|
14500
14710
|
beelineAgentMcpServer(this.options.config, this.options.api, {
|
|
14501
14711
|
roomId: this.options.roomId,
|
|
14502
14712
|
workspaceId: this.options.workspaceId,
|
|
14503
|
-
attachRoot: this.options.cwd
|
|
14713
|
+
attachRoot: this.options.cwd,
|
|
14714
|
+
directMessage
|
|
14504
14715
|
})
|
|
14505
14716
|
];
|
|
14506
14717
|
const self = roster.members.find((member) => member.identityId === this.agent.publicKey);
|
|
@@ -14516,7 +14727,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
14516
14727
|
name: repositoryState.key,
|
|
14517
14728
|
branch: repositoryState.targetBranch || "main"
|
|
14518
14729
|
} : void 0;
|
|
14519
|
-
const capabilityContext = beelineCapabilityContextForHarness(command, repositoryInfo);
|
|
14730
|
+
const capabilityContext = beelineCapabilityContextForHarness(command, repositoryInfo, directMessage);
|
|
14520
14731
|
this.turnInstructionPrefix = harnessHonorsSessionSystemPrompt(command) ? "" : [identityInstructions, personaInstructions, capabilityContext.compatibilityTurnPrefix].filter(Boolean).join("\n\n");
|
|
14521
14732
|
const opened = await this.client.sessionNew({
|
|
14522
14733
|
cwd: this.options.cwd,
|
|
@@ -14617,7 +14828,8 @@ ${transcript}` : "",
|
|
|
14617
14828
|
[
|
|
14618
14829
|
"Write only the substantive Room message you want the human to read.",
|
|
14619
14830
|
"Do not repeat or paraphrase these instructions.",
|
|
14620
|
-
"If the newest message is only a nudge to respond, answer the most recent unanswered human message in the conversation instead of echoing the nudge."
|
|
14831
|
+
"If the newest message is only a nudge to respond, answer the most recent unanswered human message in the conversation instead of echoing the nudge.",
|
|
14832
|
+
MAINTAIN_ASSIGNED_IDENTITY_DIRECTIVE
|
|
14621
14833
|
].join(" ")
|
|
14622
14834
|
].filter(Boolean).join("\n\n");
|
|
14623
14835
|
const sessionId = this.sessionId;
|
|
@@ -15842,7 +16054,7 @@ var import_picocolors = __toESM(require_picocolors(), 1);
|
|
|
15842
16054
|
// apps/body/dist/systemd.js
|
|
15843
16055
|
import { execFile as execFile4 } from "node:child_process";
|
|
15844
16056
|
import { mkdir as mkdir6, readFile as readFile2, writeFile as writeFile3 } from "node:fs/promises";
|
|
15845
|
-
import { homedir as
|
|
16057
|
+
import { homedir as homedir7 } from "node:os";
|
|
15846
16058
|
import { dirname as dirname5, resolve as resolve12 } from "node:path";
|
|
15847
16059
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
15848
16060
|
import { promisify as promisify4 } from "node:util";
|
|
@@ -15884,7 +16096,7 @@ WantedBy=default.target
|
|
|
15884
16096
|
`;
|
|
15885
16097
|
}
|
|
15886
16098
|
function isCanonicalInstalledLauncher(env = process.env, invocationPath = process.argv[1]) {
|
|
15887
|
-
const home = env.HOME?.trim() ||
|
|
16099
|
+
const home = env.HOME?.trim() || homedir7();
|
|
15888
16100
|
const expectedLibDir = resolve12(home, ".local", "lib", "beeline");
|
|
15889
16101
|
const expectedPrefix = `${expectedLibDir}/`;
|
|
15890
16102
|
return resolve12(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve12(invocationPath).startsWith(expectedPrefix);
|
|
@@ -15895,7 +16107,7 @@ function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
|
15895
16107
|
throw new Error("refusing to modify the shared Beeline systemd unit outside the canonical ~/.local/bin/beeline launcher");
|
|
15896
16108
|
}
|
|
15897
16109
|
function systemdUserUnitPath(env = process.env) {
|
|
15898
|
-
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve12(
|
|
16110
|
+
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve12(homedir7(), ".config");
|
|
15899
16111
|
return resolve12(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
|
|
15900
16112
|
}
|
|
15901
16113
|
var runSystemctl = async (args) => {
|
|
@@ -16069,8 +16281,9 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
16069
16281
|
|
|
16070
16282
|
// apps/body/dist/connect-command.js
|
|
16071
16283
|
import { spawn as spawn5 } from "node:child_process";
|
|
16072
|
-
import {
|
|
16073
|
-
import {
|
|
16284
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
16285
|
+
import { chmod as chmod4, mkdir as mkdir9, readFile as readFile5, unlink as unlink2, writeFile as writeFile6 } from "node:fs/promises";
|
|
16286
|
+
import { dirname as dirname9, resolve as resolve15 } from "node:path";
|
|
16074
16287
|
import { stdin as stdin3, stdout as stdout4 } from "node:process";
|
|
16075
16288
|
|
|
16076
16289
|
// packages/api-contract/dist/agent-pairing-code.js
|
|
@@ -16107,6 +16320,65 @@ function unwrapPrompt(value, cancelMessage = "Cancelled.") {
|
|
|
16107
16320
|
return value;
|
|
16108
16321
|
}
|
|
16109
16322
|
|
|
16323
|
+
// apps/body/dist/provider-key-check.js
|
|
16324
|
+
var PROVIDER_LABELS = {
|
|
16325
|
+
openrouter: "OpenRouter",
|
|
16326
|
+
openai: "OpenAI",
|
|
16327
|
+
anthropic: "Anthropic",
|
|
16328
|
+
google: "Google",
|
|
16329
|
+
xai: "xAI"
|
|
16330
|
+
};
|
|
16331
|
+
function keyCheckEndpoint(provider, apiKey) {
|
|
16332
|
+
switch (provider) {
|
|
16333
|
+
case "openrouter":
|
|
16334
|
+
return {
|
|
16335
|
+
url: "https://openrouter.ai/api/v1/key",
|
|
16336
|
+
headers: { authorization: `Bearer ${apiKey}` }
|
|
16337
|
+
};
|
|
16338
|
+
case "openai":
|
|
16339
|
+
return {
|
|
16340
|
+
url: "https://api.openai.com/v1/models?limit=1",
|
|
16341
|
+
headers: { authorization: `Bearer ${apiKey}` }
|
|
16342
|
+
};
|
|
16343
|
+
case "anthropic":
|
|
16344
|
+
return {
|
|
16345
|
+
url: "https://api.anthropic.com/v1/models?limit=1",
|
|
16346
|
+
headers: { "x-api-key": apiKey, "anthropic-version": "2023-06-01" }
|
|
16347
|
+
};
|
|
16348
|
+
case "google":
|
|
16349
|
+
return {
|
|
16350
|
+
url: "https://generativelanguage.googleapis.com/v1beta/models?pageSize=1",
|
|
16351
|
+
headers: { "x-goog-api-key": apiKey }
|
|
16352
|
+
};
|
|
16353
|
+
case "xai":
|
|
16354
|
+
return {
|
|
16355
|
+
url: "https://api.x.ai/v1/models?limit=1",
|
|
16356
|
+
headers: { authorization: `Bearer ${apiKey}` }
|
|
16357
|
+
};
|
|
16358
|
+
}
|
|
16359
|
+
}
|
|
16360
|
+
var REJECTED_STATUS = /* @__PURE__ */ new Set([400, 401, 403]);
|
|
16361
|
+
async function verifyProviderKey(input) {
|
|
16362
|
+
const label = PROVIDER_LABELS[input.provider];
|
|
16363
|
+
const { url, headers } = keyCheckEndpoint(input.provider, input.apiKey);
|
|
16364
|
+
let response;
|
|
16365
|
+
try {
|
|
16366
|
+
response = await (input.fetchImpl ?? fetch)(url, {
|
|
16367
|
+
headers,
|
|
16368
|
+
signal: AbortSignal.timeout(input.timeoutMs ?? 15e3)
|
|
16369
|
+
});
|
|
16370
|
+
} catch (error) {
|
|
16371
|
+
const cause = error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
16372
|
+
throw new Error(`Could not reach ${label} to verify the key (${cause}). Check the network and paste the key again.`);
|
|
16373
|
+
}
|
|
16374
|
+
if (response.ok)
|
|
16375
|
+
return;
|
|
16376
|
+
if (REJECTED_STATUS.has(response.status)) {
|
|
16377
|
+
throw new Error(`${label} rejected the key (${response.status}).`);
|
|
16378
|
+
}
|
|
16379
|
+
throw new Error(`${label} could not verify the key right now (HTTP ${response.status}). Try again in a moment.`);
|
|
16380
|
+
}
|
|
16381
|
+
|
|
16110
16382
|
// apps/body/dist/pair-agent-selection.js
|
|
16111
16383
|
import { spawn as spawn3 } from "node:child_process";
|
|
16112
16384
|
import { stdin as stdin2, stdout as stdout3 } from "node:process";
|
|
@@ -16305,6 +16577,63 @@ async function completeDevicePairing(grant, options = {}) {
|
|
|
16305
16577
|
return { runtime: activated.runtime, configPath: staged.configPath, pid };
|
|
16306
16578
|
}
|
|
16307
16579
|
|
|
16580
|
+
// apps/body/dist/provider-key-store.js
|
|
16581
|
+
import { chmod as chmod2, mkdir as mkdir7, readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
|
|
16582
|
+
import { homedir as homedir8 } from "node:os";
|
|
16583
|
+
import { dirname as dirname7, resolve as resolve13 } from "node:path";
|
|
16584
|
+
var PROVIDER_KEY_ENV_VARS = {
|
|
16585
|
+
openrouter: "OPENROUTER_API_KEY",
|
|
16586
|
+
openai: "OPENAI_API_KEY",
|
|
16587
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
16588
|
+
google: "GOOGLE_API_KEY",
|
|
16589
|
+
xai: "XAI_API_KEY"
|
|
16590
|
+
};
|
|
16591
|
+
var GOOGLE_ENV_ALIAS = "GEMINI_API_KEY";
|
|
16592
|
+
function providerKeyStorePath(env = process.env) {
|
|
16593
|
+
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve13(homedir8(), ".config");
|
|
16594
|
+
return resolve13(configRoot, "beeline", "providers.json");
|
|
16595
|
+
}
|
|
16596
|
+
async function readProviderKeyStore(env = process.env) {
|
|
16597
|
+
const path = providerKeyStorePath(env);
|
|
16598
|
+
const raw = await readFile3(path, "utf8").catch(() => void 0);
|
|
16599
|
+
if (!raw)
|
|
16600
|
+
return {};
|
|
16601
|
+
try {
|
|
16602
|
+
const parsed = JSON.parse(raw);
|
|
16603
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
16604
|
+
return {};
|
|
16605
|
+
const entries = Object.entries(parsed).filter((entry) => entry[0] in PROVIDER_KEY_ENV_VARS && typeof entry[1] === "string" && entry[1].length > 0);
|
|
16606
|
+
return Object.fromEntries(entries);
|
|
16607
|
+
} catch {
|
|
16608
|
+
return {};
|
|
16609
|
+
}
|
|
16610
|
+
}
|
|
16611
|
+
async function readSavedProviderKey(provider, env = process.env) {
|
|
16612
|
+
return (await readProviderKeyStore(env))[provider];
|
|
16613
|
+
}
|
|
16614
|
+
async function saveProviderKey(provider, key, env = process.env) {
|
|
16615
|
+
const path = providerKeyStorePath(env);
|
|
16616
|
+
const store = { ...await readProviderKeyStore(env), [provider]: key };
|
|
16617
|
+
await mkdir7(dirname7(path), { recursive: true, mode: 448 });
|
|
16618
|
+
await writeFile4(path, `${JSON.stringify(store, null, 2)}
|
|
16619
|
+
`, { mode: 384 });
|
|
16620
|
+
await chmod2(path, 384);
|
|
16621
|
+
}
|
|
16622
|
+
function providerKeyFromEnvironment(provider, env = process.env) {
|
|
16623
|
+
const primary = env[PROVIDER_KEY_ENV_VARS[provider]]?.trim();
|
|
16624
|
+
if (primary)
|
|
16625
|
+
return primary;
|
|
16626
|
+
if (provider === "google")
|
|
16627
|
+
return env[GOOGLE_ENV_ALIAS]?.trim() || void 0;
|
|
16628
|
+
return void 0;
|
|
16629
|
+
}
|
|
16630
|
+
function maskProviderKey(key) {
|
|
16631
|
+
const trimmed = key.trim();
|
|
16632
|
+
if (trimmed.length <= 9)
|
|
16633
|
+
return "\u2026";
|
|
16634
|
+
return `${trimmed.slice(0, 6)}\u2026${trimmed.slice(-3)}`;
|
|
16635
|
+
}
|
|
16636
|
+
|
|
16308
16637
|
// apps/body/dist/connect-command.js
|
|
16309
16638
|
init_self_update();
|
|
16310
16639
|
init_self_update_manifest();
|
|
@@ -16315,7 +16644,17 @@ function isReasonableAgentName(value) {
|
|
|
16315
16644
|
return normalized.length > 0 && normalized.length <= AGENT_NAME_MAX_LENGTH && new RegExp("^\\p{L}[\\p{L}\\p{M}'\u2019 -]*$", "u").test(normalized);
|
|
16316
16645
|
}
|
|
16317
16646
|
var CONNECT_PROVIDER_HARNESSES = /* @__PURE__ */ new Set(["goose", "pi"]);
|
|
16318
|
-
var CONNECT_PROVIDERS = [
|
|
16647
|
+
var CONNECT_PROVIDERS = [
|
|
16648
|
+
"openrouter",
|
|
16649
|
+
"openai",
|
|
16650
|
+
"anthropic",
|
|
16651
|
+
"google",
|
|
16652
|
+
"xai"
|
|
16653
|
+
];
|
|
16654
|
+
var fileConnectKeyStore = {
|
|
16655
|
+
read: (provider) => readSavedProviderKey(provider),
|
|
16656
|
+
save: (provider, key) => saveProviderKey(provider, key)
|
|
16657
|
+
};
|
|
16319
16658
|
var DEFAULT_MODELS = {
|
|
16320
16659
|
openrouter: "z-ai/glm-5.3-flash",
|
|
16321
16660
|
openai: "gpt-5.4",
|
|
@@ -16373,6 +16712,21 @@ var clackPrompts = {
|
|
|
16373
16712
|
}), "Connection cancelled.");
|
|
16374
16713
|
}
|
|
16375
16714
|
};
|
|
16715
|
+
function connectModelPickerFromAxes(axes, fallbackModel, harness) {
|
|
16716
|
+
const filtered = axes.find((axis) => axis.category === "model");
|
|
16717
|
+
if (filtered?.options.length) {
|
|
16718
|
+
return { currentValue: filtered.currentValue, options: filtered.options };
|
|
16719
|
+
}
|
|
16720
|
+
const raw = axes.find((axis) => axis.category === "model" && axis.options.length);
|
|
16721
|
+
if (raw) {
|
|
16722
|
+
return { currentValue: raw.currentValue, options: raw.options };
|
|
16723
|
+
}
|
|
16724
|
+
return {
|
|
16725
|
+
currentValue: fallbackModel,
|
|
16726
|
+
options: [{ id: fallbackModel }],
|
|
16727
|
+
note: `${harness} did not enumerate models; offering the provider default`
|
|
16728
|
+
};
|
|
16729
|
+
}
|
|
16376
16730
|
async function loadConnectModelCatalog(input) {
|
|
16377
16731
|
const agent = resolveAgentCommand({ kind: input.harness });
|
|
16378
16732
|
const catalog = await fetchAgentModelCatalog(agent, providerEnvironment({
|
|
@@ -16381,13 +16735,9 @@ async function loadConnectModelCatalog(input) {
|
|
|
16381
16735
|
...input.apiKey ? { apiKey: input.apiKey } : {},
|
|
16382
16736
|
model: defaultConnectModel(input.harness, input.provider)
|
|
16383
16737
|
}));
|
|
16384
|
-
|
|
16385
|
-
if (!modelAxis?.options.length) {
|
|
16386
|
-
throw new Error(`${input.harness} did not advertise any available models`);
|
|
16387
|
-
}
|
|
16388
|
-
return { currentValue: modelAxis.currentValue, options: modelAxis.options };
|
|
16738
|
+
return connectModelPickerFromAxes(catalog.catalog, defaultConnectModel(input.harness, input.provider), input.harness);
|
|
16389
16739
|
}
|
|
16390
|
-
async function collectConnectWizard(prompts = clackPrompts, loadModels = loadConnectModelCatalog) {
|
|
16740
|
+
async function collectConnectWizard(prompts = clackPrompts, loadModels = loadConnectModelCatalog, keyStore = fileConnectKeyStore, env = process.env, verifyKey = (input) => verifyProviderKey(input)) {
|
|
16391
16741
|
const harness = await prompts.select({
|
|
16392
16742
|
message: brass("Choose harness"),
|
|
16393
16743
|
options: CONNECT_HARNESSES.map((value) => ({
|
|
@@ -16407,10 +16757,44 @@ async function collectConnectWizard(prompts = clackPrompts, loadModels = loadCon
|
|
|
16407
16757
|
...value === "openrouter" ? { hint: "default" } : {}
|
|
16408
16758
|
}))
|
|
16409
16759
|
});
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
|
|
16760
|
+
const providerLabel = provider === "openrouter" ? "OpenRouter" : provider;
|
|
16761
|
+
const savedKey = await keyStore.read(provider);
|
|
16762
|
+
const envKey = providerKeyFromEnvironment(provider, env);
|
|
16763
|
+
const availableKey = savedKey ?? envKey;
|
|
16764
|
+
if (availableKey) {
|
|
16765
|
+
const masked = maskProviderKey(availableKey);
|
|
16766
|
+
const choice = await prompts.select({
|
|
16767
|
+
message: brass(`${providerLabel} API key`),
|
|
16768
|
+
initialValue: "saved",
|
|
16769
|
+
options: [
|
|
16770
|
+
{
|
|
16771
|
+
value: "saved",
|
|
16772
|
+
label: savedKey ? `Use saved ${providerLabel} key (${masked})` : `Use ${PROVIDER_KEY_ENV_VARS[provider]} from the environment (${masked})`
|
|
16773
|
+
},
|
|
16774
|
+
{ value: "new", label: "Enter a new key" }
|
|
16775
|
+
]
|
|
16776
|
+
});
|
|
16777
|
+
if (choice === "saved") {
|
|
16778
|
+
apiKey = availableKey;
|
|
16779
|
+
await verifyKey({ provider, apiKey });
|
|
16780
|
+
} else {
|
|
16781
|
+
apiKey = await prompts.password({
|
|
16782
|
+
message: brass(`${providerLabel} API key`),
|
|
16783
|
+
validate: (value) => value.trim() ? void 0 : "API key is required"
|
|
16784
|
+
});
|
|
16785
|
+
apiKey = apiKey.trim();
|
|
16786
|
+
await verifyKey({ provider, apiKey });
|
|
16787
|
+
await keyStore.save(provider, apiKey);
|
|
16788
|
+
}
|
|
16789
|
+
} else {
|
|
16790
|
+
apiKey = await prompts.password({
|
|
16791
|
+
message: brass(`${providerLabel} API key`),
|
|
16792
|
+
validate: (value) => value.trim() ? void 0 : "API key is required"
|
|
16793
|
+
});
|
|
16794
|
+
apiKey = apiKey.trim();
|
|
16795
|
+
await verifyKey({ provider, apiKey });
|
|
16796
|
+
await keyStore.save(provider, apiKey);
|
|
16797
|
+
}
|
|
16414
16798
|
}
|
|
16415
16799
|
const catalog = await loadModels({
|
|
16416
16800
|
harness,
|
|
@@ -16419,7 +16803,7 @@ async function collectConnectWizard(prompts = clackPrompts, loadModels = loadCon
|
|
|
16419
16803
|
});
|
|
16420
16804
|
const initialModel = catalog.currentValue ?? defaultConnectModel(harness, provider);
|
|
16421
16805
|
const model = await prompts.autocomplete({
|
|
16422
|
-
message: brass("Choose model"),
|
|
16806
|
+
message: brass(catalog.note ? `Choose model (${catalog.note})` : "Choose model"),
|
|
16423
16807
|
options: catalog.options.map((choice) => ({
|
|
16424
16808
|
value: choice.id,
|
|
16425
16809
|
label: choice.name ? `${choice.name} (${choice.id})` : choice.id
|
|
@@ -16466,12 +16850,14 @@ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl) {
|
|
|
16466
16850
|
const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
|
|
16467
16851
|
if (!normalizedPairingCode)
|
|
16468
16852
|
throw new Error("invalid pairing code");
|
|
16853
|
+
const avatarSeed = createHash3("sha256").update(normalizedPairingCode.toUpperCase()).digest("hex").slice(0, 32);
|
|
16469
16854
|
return jsonRequest(`${baseUrl}/auth/agent/connect`, {
|
|
16470
16855
|
pairing_code: normalizedPairingCode,
|
|
16471
16856
|
harness: selection.harness,
|
|
16472
16857
|
...selection.provider ? { provider: selection.provider } : {},
|
|
16473
16858
|
model: selection.model,
|
|
16474
16859
|
soul: selection.soul,
|
|
16860
|
+
avatar_seed: avatarSeed,
|
|
16475
16861
|
agent_name: selection.name
|
|
16476
16862
|
}, fetchImpl);
|
|
16477
16863
|
}
|
|
@@ -16489,7 +16875,7 @@ async function installCurrentRelease(fetchImpl) {
|
|
|
16489
16875
|
});
|
|
16490
16876
|
await activateRelease(layout, releaseId);
|
|
16491
16877
|
return {
|
|
16492
|
-
binary:
|
|
16878
|
+
binary: resolve15(layout.binDir, "beeline"),
|
|
16493
16879
|
version: published.version ?? releaseId
|
|
16494
16880
|
};
|
|
16495
16881
|
}
|
|
@@ -16512,21 +16898,21 @@ function providerEnvironment(selection) {
|
|
|
16512
16898
|
};
|
|
16513
16899
|
}
|
|
16514
16900
|
async function writePrivateJson(path, value) {
|
|
16515
|
-
await
|
|
16516
|
-
await
|
|
16901
|
+
await mkdir9(dirname9(path), { recursive: true, mode: 448 });
|
|
16902
|
+
await writeFile6(path, `${JSON.stringify(value, null, 2)}
|
|
16517
16903
|
`, { mode: 384 });
|
|
16518
|
-
await
|
|
16904
|
+
await chmod4(path, 384);
|
|
16519
16905
|
}
|
|
16520
16906
|
async function writeProviderEnv(selection, agentPubkey) {
|
|
16521
16907
|
const values = providerEnvironment(selection);
|
|
16522
16908
|
if (Object.keys(values).length === 0)
|
|
16523
16909
|
return void 0;
|
|
16524
|
-
const path =
|
|
16525
|
-
await
|
|
16910
|
+
const path = resolve15(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
|
|
16911
|
+
await mkdir9(dirname9(path), { recursive: true, mode: 448 });
|
|
16526
16912
|
const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
|
|
16527
|
-
await
|
|
16913
|
+
await writeFile6(path, `${contents}
|
|
16528
16914
|
`, { mode: 384 });
|
|
16529
|
-
await
|
|
16915
|
+
await chmod4(path, 384);
|
|
16530
16916
|
return path;
|
|
16531
16917
|
}
|
|
16532
16918
|
async function runInstalledFinish(binary, grantPath) {
|
|
@@ -16568,17 +16954,17 @@ async function runConnectCommand(code, options = {}) {
|
|
|
16568
16954
|
throw new Error("`usebeeline connect` needs an interactive terminal");
|
|
16569
16955
|
}
|
|
16570
16956
|
intro(brass("Beeline connect"));
|
|
16957
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
16571
16958
|
const pairingCode = code?.trim() || await clackPrompts.text({
|
|
16572
16959
|
message: brass("Pairing code from the app"),
|
|
16573
16960
|
validate: (value) => normalizeAgentPairingCode(value) ? void 0 : "Enter the pairing code shown in the app"
|
|
16574
16961
|
});
|
|
16575
|
-
const selection = await collectConnectWizard();
|
|
16576
|
-
const fetchImpl = options.fetchImpl ?? fetch;
|
|
16962
|
+
const selection = await collectConnectWizard(clackPrompts, loadConnectModelCatalog, fileConnectKeyStore, process.env, (input) => verifyProviderKey({ ...input, fetchImpl }));
|
|
16577
16963
|
const baseUrl = (process.env.BEELINE_AUTH_URL ?? "https://server.usebeeline.app").replace(/\/$/, "");
|
|
16578
16964
|
const grant = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl), (connectedGrant) => `Connected to ${connectedGrant.workspace_name}`);
|
|
16579
16965
|
const installedRelease = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl), (release) => `Installed Beeline helper ${release.version}`);
|
|
16580
16966
|
const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
|
|
16581
|
-
const grantPath =
|
|
16967
|
+
const grantPath = resolve15(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
|
|
16582
16968
|
await writePrivateJson(grantPath, {
|
|
16583
16969
|
agentSecretKey: grant.agent_secret_key,
|
|
16584
16970
|
bodySecretKey: grant.body_secret_key,
|
|
@@ -16611,17 +16997,32 @@ function isDevicePairingGrant(value) {
|
|
|
16611
16997
|
}
|
|
16612
16998
|
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);
|
|
16613
16999
|
}
|
|
17000
|
+
function connectPlainFailure(error) {
|
|
17001
|
+
const raw = error instanceof Error ? error.message : String(error);
|
|
17002
|
+
const firstLine = raw.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
|
|
17003
|
+
return `Connecting your agent failed: ${firstLine ?? "unknown error"}`;
|
|
17004
|
+
}
|
|
17005
|
+
var ConnectFailureError = class extends Error {
|
|
17006
|
+
constructor(sentence) {
|
|
17007
|
+
super(sentence);
|
|
17008
|
+
this.name = "ConnectFailureError";
|
|
17009
|
+
}
|
|
17010
|
+
};
|
|
16614
17011
|
async function runConnectFinishCommand(path) {
|
|
16615
17012
|
if (!path)
|
|
16616
17013
|
throw new Error("connect-finish requires a grant path");
|
|
16617
17014
|
if (!isCanonicalInstalledLauncher(process.env, process.argv[1])) {
|
|
16618
17015
|
throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
|
|
16619
17016
|
}
|
|
16620
|
-
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
16624
|
-
|
|
17017
|
+
try {
|
|
17018
|
+
const grant = JSON.parse(await readFile5(resolve15(path), "utf8"));
|
|
17019
|
+
if (!isDevicePairingGrant(grant))
|
|
17020
|
+
throw new Error("device connection grant is invalid");
|
|
17021
|
+
await completeDevicePairing(grant);
|
|
17022
|
+
await unlink2(resolve15(path));
|
|
17023
|
+
} catch (error) {
|
|
17024
|
+
throw new ConnectFailureError(connectPlainFailure(error));
|
|
17025
|
+
}
|
|
16625
17026
|
}
|
|
16626
17027
|
|
|
16627
17028
|
// apps/body/dist/self-update-cli.js
|
|
@@ -16632,20 +17033,20 @@ init_self_update_manifest();
|
|
|
16632
17033
|
// apps/body/dist/managed-update.js
|
|
16633
17034
|
init_self_update();
|
|
16634
17035
|
import { spawn as spawn6 } from "node:child_process";
|
|
16635
|
-
import { mkdir as
|
|
16636
|
-
import { dirname as
|
|
17036
|
+
import { mkdir as mkdir11, rm as rm5, stat as stat2, writeFile as writeFile8 } from "node:fs/promises";
|
|
17037
|
+
import { dirname as dirname11, resolve as resolve17 } from "node:path";
|
|
16637
17038
|
|
|
16638
17039
|
// apps/body/dist/update-rollback-alert.js
|
|
16639
|
-
import { mkdir as
|
|
16640
|
-
import { dirname as
|
|
17040
|
+
import { mkdir as mkdir10, readFile as readFile6, rename as rename4, writeFile as writeFile7 } from "node:fs/promises";
|
|
17041
|
+
import { dirname as dirname10, resolve as resolve16 } from "node:path";
|
|
16641
17042
|
function updateRollbackAlertPath(runtimeDir) {
|
|
16642
|
-
return
|
|
17043
|
+
return resolve16(runtimeDir, "update-rollback-alert.json");
|
|
16643
17044
|
}
|
|
16644
17045
|
async function writeAlert(runtimeDir, alert) {
|
|
16645
17046
|
const path = updateRollbackAlertPath(runtimeDir);
|
|
16646
17047
|
const staged = `${path}.${process.pid}.tmp`;
|
|
16647
|
-
await
|
|
16648
|
-
await
|
|
17048
|
+
await mkdir10(dirname10(path), { recursive: true });
|
|
17049
|
+
await writeFile7(staged, `${JSON.stringify(alert, null, 2)}
|
|
16649
17050
|
`, { mode: 384 });
|
|
16650
17051
|
await rename4(staged, path);
|
|
16651
17052
|
}
|
|
@@ -16657,7 +17058,7 @@ async function queueUpdateRollbackAlert(runtimeDir, releaseId, now2 = Date.now()
|
|
|
16657
17058
|
}
|
|
16658
17059
|
async function readUpdateRollbackAlert(runtimeDir) {
|
|
16659
17060
|
try {
|
|
16660
|
-
const value = JSON.parse(await
|
|
17061
|
+
const value = JSON.parse(await readFile6(updateRollbackAlertPath(runtimeDir), "utf8"));
|
|
16661
17062
|
if (value.version !== 1 || typeof value.releaseId !== "string")
|
|
16662
17063
|
return void 0;
|
|
16663
17064
|
return value;
|
|
@@ -16682,13 +17083,13 @@ var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
|
|
|
16682
17083
|
var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
|
|
16683
17084
|
async function withInstallLock(layout, work, options = {}) {
|
|
16684
17085
|
const now2 = options.now ?? Date.now;
|
|
16685
|
-
const lock =
|
|
17086
|
+
const lock = resolve17(layout.releasesRoot, ".state", "install.lock");
|
|
16686
17087
|
const deadline = now2() + (options.waitMs ?? 1e4);
|
|
16687
|
-
await
|
|
17088
|
+
await mkdir11(dirname11(lock), { recursive: true });
|
|
16688
17089
|
for (; ; ) {
|
|
16689
17090
|
try {
|
|
16690
|
-
await
|
|
16691
|
-
await
|
|
17091
|
+
await mkdir11(lock);
|
|
17092
|
+
await writeFile8(resolve17(lock, "owner"), `${process.pid}
|
|
16692
17093
|
${now2()}
|
|
16693
17094
|
`, "utf8");
|
|
16694
17095
|
break;
|
|
@@ -16812,7 +17213,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
16812
17213
|
if (!attempt || attempt.releaseId !== desiredRelease || attempt.status !== "pending") {
|
|
16813
17214
|
const from = await readInstalledBundleIdentity({
|
|
16814
17215
|
...this.#layout,
|
|
16815
|
-
libDir:
|
|
17216
|
+
libDir: resolve17(this.#layout.releasesRoot, this.#loadedRelease)
|
|
16816
17217
|
}).catch(() => void 0) ?? {};
|
|
16817
17218
|
const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
|
|
16818
17219
|
const record2 = {
|
|
@@ -17019,7 +17420,7 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
|
|
|
17019
17420
|
});
|
|
17020
17421
|
if (!accepted)
|
|
17021
17422
|
return false;
|
|
17022
|
-
await
|
|
17423
|
+
await writeFile8(resolve17(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
|
|
17023
17424
|
readyAt: (options.now ?? Date.now)(),
|
|
17024
17425
|
loadedRelease,
|
|
17025
17426
|
functionalProof: options.functionalProof
|
|
@@ -17224,16 +17625,16 @@ async function runUpdateCommand(args) {
|
|
|
17224
17625
|
init_self_update();
|
|
17225
17626
|
|
|
17226
17627
|
// apps/body/dist/daemon-failure.js
|
|
17227
|
-
import { mkdir as
|
|
17228
|
-
import { dirname as
|
|
17628
|
+
import { mkdir as mkdir12, readFile as readFile7, rename as rename5, rm as rm6, writeFile as writeFile9 } from "node:fs/promises";
|
|
17629
|
+
import { dirname as dirname12, resolve as resolve18 } from "node:path";
|
|
17229
17630
|
var DAEMON_FAILURE_LIMIT = 3;
|
|
17230
17631
|
var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
17231
17632
|
function daemonFailurePath(runtimeDir) {
|
|
17232
|
-
return
|
|
17633
|
+
return resolve18(runtimeDir, "daemon-distress.json");
|
|
17233
17634
|
}
|
|
17234
17635
|
async function readFailureRecord(runtimeDir) {
|
|
17235
17636
|
try {
|
|
17236
|
-
const value = JSON.parse(await
|
|
17637
|
+
const value = JSON.parse(await readFile7(daemonFailurePath(runtimeDir), "utf8"));
|
|
17237
17638
|
if (value.version !== 1 || !Array.isArray(value.failures) || value.failures.some((failure) => typeof failure !== "number") || typeof value.lastError !== "string") {
|
|
17238
17639
|
return void 0;
|
|
17239
17640
|
}
|
|
@@ -17245,8 +17646,8 @@ async function readFailureRecord(runtimeDir) {
|
|
|
17245
17646
|
async function writeFailureRecord(runtimeDir, record2) {
|
|
17246
17647
|
const path = daemonFailurePath(runtimeDir);
|
|
17247
17648
|
const staged = `${path}.${process.pid}.tmp`;
|
|
17248
|
-
await
|
|
17249
|
-
await
|
|
17649
|
+
await mkdir12(dirname12(path), { recursive: true, mode: 448 });
|
|
17650
|
+
await writeFile9(staged, `${JSON.stringify(record2, null, 2)}
|
|
17250
17651
|
`, { mode: 384 });
|
|
17251
17652
|
await rename5(staged, path);
|
|
17252
17653
|
}
|
|
@@ -17268,9 +17669,9 @@ async function clearDaemonStartFailures(runtimeDir) {
|
|
|
17268
17669
|
}
|
|
17269
17670
|
|
|
17270
17671
|
// apps/body/dist/update-functional-probe.js
|
|
17271
|
-
import { mkdir as
|
|
17272
|
-
import { homedir as
|
|
17273
|
-
import { resolve as
|
|
17672
|
+
import { mkdir as mkdir13, rm as rm7 } from "node:fs/promises";
|
|
17673
|
+
import { homedir as homedir10 } from "node:os";
|
|
17674
|
+
import { resolve as resolve19 } from "node:path";
|
|
17274
17675
|
var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
|
|
17275
17676
|
var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
|
|
17276
17677
|
var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
|
|
@@ -17292,18 +17693,18 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
17292
17693
|
if (input.sandboxRequired && !input.config.bwrapPath) {
|
|
17293
17694
|
throw new UpdateFunctionalProbeError("sandbox-unavailable", "the configured bubblewrap boundary did not pass its startup self-test");
|
|
17294
17695
|
}
|
|
17295
|
-
const root =
|
|
17296
|
-
const cwd =
|
|
17297
|
-
const homeRoot =
|
|
17696
|
+
const root = resolve19(input.runtimeDir, "update-functional-probe");
|
|
17697
|
+
const cwd = resolve19(root, "checkout");
|
|
17698
|
+
const homeRoot = resolve19(root, "agent-home");
|
|
17298
17699
|
await rm7(root, { recursive: true, force: true });
|
|
17299
|
-
await
|
|
17700
|
+
await mkdir13(cwd, { recursive: true, mode: 448 });
|
|
17300
17701
|
let client;
|
|
17301
17702
|
try {
|
|
17302
17703
|
const agentEnv = {
|
|
17303
17704
|
...input.config.agentEnv,
|
|
17304
17705
|
...await prepareRoomAgentHome({
|
|
17305
17706
|
root: homeRoot,
|
|
17306
|
-
operatorHome: input.config.operatorHome ??
|
|
17707
|
+
operatorHome: input.config.operatorHome ?? homedir10(),
|
|
17307
17708
|
sharedSkills: input.config.sharedSkills ?? [],
|
|
17308
17709
|
skillReleaseId: input.releaseId,
|
|
17309
17710
|
failClosed: true
|
|
@@ -17320,9 +17721,9 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
17320
17721
|
};
|
|
17321
17722
|
if (input.config.bwrapPath) {
|
|
17322
17723
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
17323
|
-
const operatorHome = input.config.operatorHome ??
|
|
17724
|
+
const operatorHome = input.config.operatorHome ?? homedir10();
|
|
17324
17725
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
17325
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
17726
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir13(dir, { recursive: true })));
|
|
17326
17727
|
spawnCommand = wrapAgentCommand({
|
|
17327
17728
|
bwrapPath: input.config.bwrapPath,
|
|
17328
17729
|
spec: {
|
|
@@ -17386,8 +17787,8 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
17386
17787
|
}
|
|
17387
17788
|
|
|
17388
17789
|
// apps/body/dist/release-status.js
|
|
17389
|
-
import { readFile as
|
|
17390
|
-
import { resolve as
|
|
17790
|
+
import { readFile as readFile8, readdir as readdir3, rename as rename6, writeFile as writeFile10 } from "node:fs/promises";
|
|
17791
|
+
import { resolve as resolve20 } from "node:path";
|
|
17391
17792
|
var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
|
|
17392
17793
|
var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
|
|
17393
17794
|
var SOURCE_SHA = /^[0-9a-f]{7,64}$/;
|
|
@@ -17404,9 +17805,9 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
17404
17805
|
pid: options.pid ?? process.pid,
|
|
17405
17806
|
readyAt: (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
|
|
17406
17807
|
};
|
|
17407
|
-
const target =
|
|
17808
|
+
const target = resolve20(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
|
|
17408
17809
|
const temporary = `${target}.${status.pid}.tmp`;
|
|
17409
|
-
await
|
|
17810
|
+
await writeFile10(temporary, `${JSON.stringify(status, null, 2)}
|
|
17410
17811
|
`, { mode: 384 });
|
|
17411
17812
|
await rename6(temporary, target);
|
|
17412
17813
|
return status;
|
|
@@ -17447,7 +17848,7 @@ var DaemonExitError = class extends Error {
|
|
|
17447
17848
|
};
|
|
17448
17849
|
async function runStoredDaemon(pathOrPointer) {
|
|
17449
17850
|
const configPath = await resolveRuntimeConfigPath(pathOrPointer);
|
|
17450
|
-
daemonFailureRuntimeDir =
|
|
17851
|
+
daemonFailureRuntimeDir = dirname13(configPath);
|
|
17451
17852
|
const accessMigration = await migrateRuntimeRecordAccessPolicy(configPath);
|
|
17452
17853
|
let runtime = accessMigration.runtime;
|
|
17453
17854
|
if (!runtime.transport) {
|
|
@@ -17459,7 +17860,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
17459
17860
|
runtime = activated.runtime;
|
|
17460
17861
|
const daemonApi = activated.client;
|
|
17461
17862
|
const agent = runtimeAgentCommand(runtime);
|
|
17462
|
-
await
|
|
17863
|
+
await writeFile11(resolve21(dirname13(configPath), "daemon.pid"), `${process.pid}
|
|
17463
17864
|
`, { mode: 384 });
|
|
17464
17865
|
const env = {
|
|
17465
17866
|
...process.env,
|
|
@@ -17467,7 +17868,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
17467
17868
|
BUZZ_DEV_MCP_BIN: runtime.mcpBinary
|
|
17468
17869
|
};
|
|
17469
17870
|
const config = loadBodyConfig({
|
|
17470
|
-
workspaceRoot:
|
|
17871
|
+
workspaceRoot: resolve21(dirname13(configPath), "workspace"),
|
|
17471
17872
|
llmEnvFile: runtime.llmEnvFile,
|
|
17472
17873
|
env,
|
|
17473
17874
|
agent
|
|
@@ -17502,7 +17903,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
17502
17903
|
const stop = () => controller.abort();
|
|
17503
17904
|
process.once("SIGINT", stop);
|
|
17504
17905
|
process.once("SIGTERM", stop);
|
|
17505
|
-
const runtimeDir =
|
|
17906
|
+
const runtimeDir = dirname13(configPath);
|
|
17506
17907
|
const layout = beelineInstallLayout(process.env);
|
|
17507
17908
|
const notifier = new SystemdNotifier();
|
|
17508
17909
|
let rollbackAlertDrain;
|
|
@@ -17614,8 +18015,8 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
17614
18015
|
throw error;
|
|
17615
18016
|
} finally {
|
|
17616
18017
|
await notifier.stopping(stoppingStatus).catch(() => void 0);
|
|
17617
|
-
const pidPath =
|
|
17618
|
-
const recorded = Number((await
|
|
18018
|
+
const pidPath = resolve21(dirname13(configPath), "daemon.pid");
|
|
18019
|
+
const recorded = Number((await readFile9(pidPath, "utf8").catch(() => "")).trim());
|
|
17619
18020
|
if (recorded === process.pid) {
|
|
17620
18021
|
await unlink3(pidPath).catch(() => void 0);
|
|
17621
18022
|
}
|
|
@@ -17671,14 +18072,14 @@ async function main() {
|
|
|
17671
18072
|
const agentPubkey = agentFlag >= 0 ? args[agentFlag + 1] : void 0;
|
|
17672
18073
|
if (!configPath && agentPubkey) {
|
|
17673
18074
|
const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
|
|
17674
|
-
configPath = configs.find((candidate) =>
|
|
18075
|
+
configPath = configs.find((candidate) => dirname13(candidate).endsWith(agentPubkey));
|
|
17675
18076
|
}
|
|
17676
18077
|
if (!configPath && agentPubkey) {
|
|
17677
18078
|
throw new DaemonExitError(`unknown agent ${agentPubkey}: no durable runtime exists; refusing systemd restart loop`, UNKNOWN_AGENT_EXIT_STATUS);
|
|
17678
18079
|
}
|
|
17679
18080
|
if (!configPath)
|
|
17680
18081
|
throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
|
|
17681
|
-
await runStoredDaemon(
|
|
18082
|
+
await runStoredDaemon(resolve21(configPath));
|
|
17682
18083
|
return;
|
|
17683
18084
|
}
|
|
17684
18085
|
if (command === "update") {
|
|
@@ -17695,7 +18096,7 @@ async function main() {
|
|
|
17695
18096
|
if (!agentPubkey)
|
|
17696
18097
|
throw new Error("stop requires --agent <pubkey>");
|
|
17697
18098
|
const configs = await findAgentRuntimeConfigPaths(process.env, process.cwd());
|
|
17698
|
-
const configPath = configs.find((candidate) =>
|
|
18099
|
+
const configPath = configs.find((candidate) => dirname13(candidate).endsWith(agentPubkey));
|
|
17699
18100
|
if (!configPath)
|
|
17700
18101
|
throw new Error(`no stored runtime found for agent ${agentPubkey}`);
|
|
17701
18102
|
const runtime = await readRuntimeRecord(configPath);
|
|
@@ -17719,6 +18120,8 @@ main().catch(async (err) => {
|
|
|
17719
18120
|
const interactiveUi = process.argv[2] !== "daemon" && Boolean(stdin4.isTTY && stdout5.isTTY);
|
|
17720
18121
|
if (interactiveUi) {
|
|
17721
18122
|
cancel(err instanceof Error ? err.message : String(err));
|
|
18123
|
+
} else if (err instanceof Error && err.name === "ConnectFailureError" && (process.argv[2] === "connect" || process.argv[2] === "connect-finish")) {
|
|
18124
|
+
console.error(import_picocolors3.default.red(err.message));
|
|
17722
18125
|
} else {
|
|
17723
18126
|
console.error(import_picocolors3.default.red("[body] fatal:"), err);
|
|
17724
18127
|
}
|