usebeeline 0.0.48 → 0.0.50
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 +1 -1
- package/dist/usebeeline.mjs +414 -123
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -148,7 +148,7 @@ Two MCP surfaces are mounted into every agent session.
|
|
|
148
148
|
Beeline is on both stores:
|
|
149
149
|
|
|
150
150
|
- [App Store](https://apps.apple.com/app/id6803948500)
|
|
151
|
-
- [Google Play](https://play.google.com/store/apps/details?id=app.usebeeline
|
|
151
|
+
- [Google Play](https://play.google.com/store/apps/details?id=app.usebeeline)
|
|
152
152
|
|
|
153
153
|
Sign in with GitHub, and the app hands you the pairing code that `npx usebeeline connect` asks for.
|
|
154
154
|
|
package/dist/usebeeline.mjs
CHANGED
|
@@ -309,12 +309,12 @@ __export(self_update_exports, {
|
|
|
309
309
|
});
|
|
310
310
|
import { createHash as createHash5 } from "node:crypto";
|
|
311
311
|
import { constants as fsConstants } from "node:fs";
|
|
312
|
-
import { access, chmod as
|
|
312
|
+
import { access, chmod as chmod4, lstat as lstat2, mkdir as mkdir13, open, readFile as readFile9, rename as rename3, rm as rm5, symlink as symlink2, writeFile as writeFile9 } from "node:fs/promises";
|
|
313
313
|
import { spawn as spawn4 } from "node:child_process";
|
|
314
314
|
import { homedir as homedir9 } from "node:os";
|
|
315
|
-
import { dirname as dirname9, join as join7, resolve as
|
|
315
|
+
import { dirname as dirname9, join as join7, resolve as resolve21 } from "node:path";
|
|
316
316
|
function anchorLayout(rawLibDir) {
|
|
317
|
-
const libDir =
|
|
317
|
+
const libDir = resolve21(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: resolve21(libDir, "../../bin"),
|
|
334
334
|
libDir,
|
|
335
|
-
releasesRoot:
|
|
335
|
+
releasesRoot: resolve21(libDir, `../${RELEASES_SEGMENT}`)
|
|
336
336
|
};
|
|
337
337
|
}
|
|
338
338
|
function beelineInstallLayout(env = process.env) {
|
|
@@ -343,7 +343,7 @@ function beelineInstallLayout(env = process.env) {
|
|
|
343
343
|
}
|
|
344
344
|
function defaultBeelineInstallLayout(env = process.env) {
|
|
345
345
|
const home = env.HOME?.trim() || homedir9();
|
|
346
|
-
return anchorLayout(
|
|
346
|
+
return anchorLayout(resolve21(home, ".local", "lib", "beeline"));
|
|
347
347
|
}
|
|
348
348
|
function hostPlatformKey() {
|
|
349
349
|
const os = process.platform === "linux" ? "linux" : process.platform === "darwin" ? "darwin" : "";
|
|
@@ -387,8 +387,8 @@ async function readUpdateState(layout) {
|
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
389
|
async function writeUpdateState(layout, state) {
|
|
390
|
-
await
|
|
391
|
-
await
|
|
390
|
+
await mkdir13(join7(layout.releasesRoot, ".state"), { recursive: true });
|
|
391
|
+
await writeFile9(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
|
|
392
392
|
`, "utf8");
|
|
393
393
|
}
|
|
394
394
|
async function readInstalledBundleIdentity(layout, _state = {}) {
|
|
@@ -501,7 +501,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
501
501
|
previouslyVerified = true;
|
|
502
502
|
} catch {
|
|
503
503
|
}
|
|
504
|
-
await
|
|
504
|
+
await mkdir13(releaseDir, { recursive: true });
|
|
505
505
|
const tempArchive = join7(layout.releasesRoot, `.download-${releaseId}-${process.pid}.tar.gz`);
|
|
506
506
|
try {
|
|
507
507
|
log2(`downloading ${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 writeFile9(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 = "";
|
|
@@ -553,7 +553,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
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 writeFile9(okMarker, `${published.sha256}
|
|
557
557
|
`, "utf8");
|
|
558
558
|
log2(`staged release ${releaseId} (sha256 verified)`);
|
|
559
559
|
return releaseId;
|
|
@@ -581,15 +581,15 @@ 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 writeFile9(temp, contents, { mode });
|
|
585
|
+
await chmod4(temp, mode);
|
|
586
586
|
await rename3(temp, path);
|
|
587
587
|
}
|
|
588
588
|
async function activateRelease(layout, releaseId) {
|
|
589
589
|
const releaseDir = join7(layout.releasesRoot, releaseId);
|
|
590
590
|
await access(join7(releaseDir, BUNDLE_ENTRYPOINT), fsConstants.F_OK);
|
|
591
|
-
await
|
|
592
|
-
await
|
|
591
|
+
await mkdir13(layout.releasesRoot, { recursive: true });
|
|
592
|
+
await mkdir13(layout.binDir, { recursive: true });
|
|
593
593
|
let previousReleaseId = await activeReleaseId(layout);
|
|
594
594
|
const kind = await pathKind(layout.libDir);
|
|
595
595
|
if (kind === "directory") {
|
|
@@ -628,7 +628,7 @@ async function normalizeLegacyBundleShape(bundleDir) {
|
|
|
628
628
|
}
|
|
629
629
|
if (!anyFlat)
|
|
630
630
|
return;
|
|
631
|
-
await
|
|
631
|
+
await mkdir13(innerLib, { recursive: true });
|
|
632
632
|
for (const name of LEGACY_FLAT_BUNDLE_FILES) {
|
|
633
633
|
try {
|
|
634
634
|
await access(join7(innerLib, name), fsConstants.F_OK);
|
|
@@ -661,7 +661,7 @@ async function repairInstallForwarders(layout, opts = {}) {
|
|
|
661
661
|
}
|
|
662
662
|
if (current === forwarderScript("beeline"))
|
|
663
663
|
return false;
|
|
664
|
-
await
|
|
664
|
+
await mkdir13(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;
|
|
@@ -693,10 +693,10 @@ async function readUpdateAttempt(layout) {
|
|
|
693
693
|
}
|
|
694
694
|
}
|
|
695
695
|
async function writeUpdateAttempt(layout, record2) {
|
|
696
|
-
await
|
|
696
|
+
await mkdir13(join7(layout.releasesRoot, ".state"), { recursive: true });
|
|
697
697
|
const path = updateAttemptPath(layout);
|
|
698
698
|
const staged = `${path}.${process.pid}.tmp`;
|
|
699
|
-
await
|
|
699
|
+
await writeFile9(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 dirname15, resolve as
|
|
959
|
-
import { readFile as readFile14, unlink as unlink3, writeFile as
|
|
958
|
+
import { dirname as dirname15, resolve as resolve28 } from "node:path";
|
|
959
|
+
import { readFile as readFile14, unlink as unlink3, writeFile as writeFile15 } 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
|
|
@@ -3832,7 +3832,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
3832
3832
|
const current = this.activeRunIds.get(sessionId);
|
|
3833
3833
|
if (current)
|
|
3834
3834
|
return Promise.resolve(current);
|
|
3835
|
-
return new Promise((
|
|
3835
|
+
return new Promise((resolve29, reject) => {
|
|
3836
3836
|
const onUpdate = (update) => {
|
|
3837
3837
|
if (update.sessionId !== sessionId)
|
|
3838
3838
|
return;
|
|
@@ -3840,7 +3840,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
3840
3840
|
if (!runId)
|
|
3841
3841
|
return;
|
|
3842
3842
|
cleanup();
|
|
3843
|
-
|
|
3843
|
+
resolve29(runId);
|
|
3844
3844
|
};
|
|
3845
3845
|
const timer = setTimeout(() => {
|
|
3846
3846
|
cleanup();
|
|
@@ -3924,13 +3924,13 @@ var AcpClient = class extends EventEmitter {
|
|
|
3924
3924
|
}
|
|
3925
3925
|
const id = this.nextId++;
|
|
3926
3926
|
const payload = { jsonrpc: "2.0", id, method, params };
|
|
3927
|
-
return new Promise((
|
|
3927
|
+
return new Promise((resolve29, reject) => {
|
|
3928
3928
|
const timer = setTimeout(() => {
|
|
3929
3929
|
this.pending.delete(id);
|
|
3930
3930
|
reject(new AcpRequestTimeoutError(method, timeoutMs, this.stderrTail, Boolean(onStart), detail));
|
|
3931
3931
|
}, timeoutMs);
|
|
3932
3932
|
this.pending.set(id, {
|
|
3933
|
-
resolve:
|
|
3933
|
+
resolve: resolve29,
|
|
3934
3934
|
reject,
|
|
3935
3935
|
timer,
|
|
3936
3936
|
method,
|
|
@@ -13283,8 +13283,8 @@ async function activateDaemonTransport(path, fetchImpl = fetch) {
|
|
|
13283
13283
|
import { execFile as execFile4 } from "node:child_process";
|
|
13284
13284
|
import { createHash as createHash4 } from "node:crypto";
|
|
13285
13285
|
import { existsSync as existsSync4, mkdirSync } from "node:fs";
|
|
13286
|
-
import { mkdir as
|
|
13287
|
-
import { dirname as dirname6, resolve as
|
|
13286
|
+
import { mkdir as mkdir11, rm as rm4 } from "node:fs/promises";
|
|
13287
|
+
import { dirname as dirname6, resolve as resolve19 } from "node:path";
|
|
13288
13288
|
import { promisify as promisify3 } from "node:util";
|
|
13289
13289
|
|
|
13290
13290
|
// apps/body/dist/grant-runner.js
|
|
@@ -14126,7 +14126,7 @@ var GrantRunnerServer = class {
|
|
|
14126
14126
|
|
|
14127
14127
|
// apps/body/dist/monolith-corner-turn.js
|
|
14128
14128
|
import { execFile as execFile3 } from "node:child_process";
|
|
14129
|
-
import { mkdir as
|
|
14129
|
+
import { mkdir as mkdir9 } from "node:fs/promises";
|
|
14130
14130
|
import { homedir as homedir6 } from "node:os";
|
|
14131
14131
|
import { join as join5 } from "node:path";
|
|
14132
14132
|
import { promisify as promisify2 } from "node:util";
|
|
@@ -14151,6 +14151,8 @@ var BEELINE_ROOM_CAPABILITIES = [
|
|
|
14151
14151
|
"Files and photos people share are downloaded for you: read them at the local path named in the prompt (photos may also arrive inline); never fetch the reference URL.",
|
|
14152
14152
|
"To create a file (this Room has no other way to write one), call beeline-agent write_scratch_file with a relative path and content - text by default, or base64 for bytes you computed; it returns a path in your writable session home. To send a file, call beeline-agent attach_file with a path inside your checkout or anywhere in your writable session home (wherever a file you or your harness generated actually landed, including one you just wrote); it is attached to your reply. write_scratch_file produces the file, not a picture - turning it into a raster image needs a converter, which needs shell, which this Room does not have.",
|
|
14153
14153
|
"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.",
|
|
14154
|
+
"To react to things that HAPPEN in this Room rather than only to what is said to you, call beeline-agent subscribe_events with the kinds you want (joined, schedule-ran, corner-opened, check-passed, check-failed, merged); each one then wakes you for a turn. It replaces your list, so send every kind you want - list_event_subscriptions shows the current one. You do this yourself: nobody has to configure it for you.",
|
|
14155
|
+
"To state something that happened so the Room and other agents can act on it, call beeline-agent emit_event with your own agent:<slug> kind, one sentence, and optionally the agent members to wake. Chains of events are bounded and a refused emit posts nothing.",
|
|
14154
14156
|
"When repository work is needed, you MUST call beeline-agent open_corner with a name of at most three words - it titles the corner everywhere - and a complete objective of no more than 24 words. The host-governed call is the only way to start write work.",
|
|
14155
14157
|
"When open_corner succeeds, the server posts the corner card: do not announce or restate the opening. End the turn with nothing more unless the person asked something else.",
|
|
14156
14158
|
"Never claim an action or reply happened unless the prompt or a tool result proves it."
|
|
@@ -15668,8 +15670,191 @@ function sessionConfigFingerprint(input) {
|
|
|
15668
15670
|
]);
|
|
15669
15671
|
}
|
|
15670
15672
|
|
|
15671
|
-
// apps/body/dist/
|
|
15673
|
+
// apps/body/dist/pi-mcp-bridge.js
|
|
15674
|
+
import { mkdir as mkdir6 } from "node:fs/promises";
|
|
15672
15675
|
import { resolve as resolve14 } from "node:path";
|
|
15676
|
+
var PI_MCP_BRIDGE_FILENAME = "beeline-mcp-bridge.js";
|
|
15677
|
+
function harnessMountsSessionMcpServers(agentCommand) {
|
|
15678
|
+
return !(agentCommand && /(^|[/\\])pi-acp(\.[a-z]+)?$/i.test(agentCommand));
|
|
15679
|
+
}
|
|
15680
|
+
function piMcpBridgeSource(servers) {
|
|
15681
|
+
const manifest = servers.map((server) => ({
|
|
15682
|
+
name: server.name,
|
|
15683
|
+
command: server.command,
|
|
15684
|
+
args: server.args ?? [],
|
|
15685
|
+
env: Object.fromEntries((server.env ?? []).map((entry) => [entry.name, entry.value]))
|
|
15686
|
+
}));
|
|
15687
|
+
return `${BRIDGE_PREAMBLE}const SERVERS = ${JSON.stringify(manifest, null, 2)};
|
|
15688
|
+
${BRIDGE_BODY}`;
|
|
15689
|
+
}
|
|
15690
|
+
async function installPiMcpBridge(input) {
|
|
15691
|
+
if (harnessMountsSessionMcpServers(input.agentCommand))
|
|
15692
|
+
return void 0;
|
|
15693
|
+
if (!input.piHome || !input.servers.length)
|
|
15694
|
+
return void 0;
|
|
15695
|
+
const directory = resolve14(input.piHome, "extensions");
|
|
15696
|
+
const path = resolve14(directory, PI_MCP_BRIDGE_FILENAME);
|
|
15697
|
+
try {
|
|
15698
|
+
await mkdir6(directory, { recursive: true, mode: 448 });
|
|
15699
|
+
await writeIsolatedHarnessFile(path, piMcpBridgeSource(input.servers));
|
|
15700
|
+
return path;
|
|
15701
|
+
} catch (error) {
|
|
15702
|
+
console.error("[body] pi MCP bridge could not be written", path, error);
|
|
15703
|
+
return void 0;
|
|
15704
|
+
}
|
|
15705
|
+
}
|
|
15706
|
+
var BRIDGE_PREAMBLE = `// Generated by Beeline for one Room session. Do not edit: it is rewritten on
|
|
15707
|
+
// every activation. It republishes this session's MCP servers as pi tools,
|
|
15708
|
+
// because pi has no MCP client of its own (apps/body/src/pi-mcp-bridge.ts).
|
|
15709
|
+
import { spawn } from 'node:child_process';
|
|
15710
|
+
|
|
15711
|
+
`;
|
|
15712
|
+
var BRIDGE_BODY = `const LIST_TIMEOUT_MS = 20000;
|
|
15713
|
+
|
|
15714
|
+
/**
|
|
15715
|
+
* One request/response against one MCP server over a short-lived process.
|
|
15716
|
+
*
|
|
15717
|
+
* A fresh process per call keeps nothing alive between turns: these servers
|
|
15718
|
+
* hold no session state - each tool call is a bounded daemon HTTP request - so
|
|
15719
|
+
* a pool would buy latency at the cost of processes outliving the session that
|
|
15720
|
+
* spawned them.
|
|
15721
|
+
*/
|
|
15722
|
+
function callServer(server, request, signal, timeoutMs) {
|
|
15723
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
15724
|
+
const child = spawn(server.command, server.args, {
|
|
15725
|
+
env: { ...process.env, ...server.env },
|
|
15726
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
15727
|
+
});
|
|
15728
|
+
let settled = false;
|
|
15729
|
+
let buffer = '';
|
|
15730
|
+
let timer;
|
|
15731
|
+
const finish = (error, value) => {
|
|
15732
|
+
if (settled) return;
|
|
15733
|
+
settled = true;
|
|
15734
|
+
if (timer) clearTimeout(timer);
|
|
15735
|
+
signal?.removeEventListener?.('abort', onAbort);
|
|
15736
|
+
child.kill('SIGKILL');
|
|
15737
|
+
if (error) rejectPromise(error); else resolvePromise(value);
|
|
15738
|
+
};
|
|
15739
|
+
const onAbort = () => finish(new Error(server.name + ' call cancelled'));
|
|
15740
|
+
if (timeoutMs) {
|
|
15741
|
+
timer = setTimeout(
|
|
15742
|
+
() => finish(new Error(server.name + ' did not answer in ' + timeoutMs + 'ms')),
|
|
15743
|
+
timeoutMs,
|
|
15744
|
+
);
|
|
15745
|
+
}
|
|
15746
|
+
if (signal) {
|
|
15747
|
+
if (signal.aborted) { onAbort(); return; }
|
|
15748
|
+
signal.addEventListener?.('abort', onAbort, { once: true });
|
|
15749
|
+
}
|
|
15750
|
+
child.on('error', (error) => finish(error));
|
|
15751
|
+
child.on('exit', () => finish(new Error(server.name + ' exited before answering')));
|
|
15752
|
+
child.stdout.setEncoding('utf8');
|
|
15753
|
+
child.stdout.on('data', (chunk) => {
|
|
15754
|
+
buffer += chunk;
|
|
15755
|
+
let newline = buffer.indexOf('\\n');
|
|
15756
|
+
while (newline >= 0) {
|
|
15757
|
+
const line = buffer.slice(0, newline).trim();
|
|
15758
|
+
buffer = buffer.slice(newline + 1);
|
|
15759
|
+
if (line) {
|
|
15760
|
+
let message;
|
|
15761
|
+
try { message = JSON.parse(line); } catch { message = undefined; }
|
|
15762
|
+
// Only the answer to OUR id: the initialize reply and any
|
|
15763
|
+
// notification the server writes share this stream.
|
|
15764
|
+
if (message && message.id === request.id) {
|
|
15765
|
+
if (message.error) {
|
|
15766
|
+
finish(new Error(message.error.message || 'MCP error'));
|
|
15767
|
+
} else {
|
|
15768
|
+
finish(undefined, message.result ?? {});
|
|
15769
|
+
}
|
|
15770
|
+
return;
|
|
15771
|
+
}
|
|
15772
|
+
}
|
|
15773
|
+
newline = buffer.indexOf('\\n');
|
|
15774
|
+
}
|
|
15775
|
+
});
|
|
15776
|
+
child.stdin.write(
|
|
15777
|
+
JSON.stringify({
|
|
15778
|
+
jsonrpc: '2.0',
|
|
15779
|
+
id: 0,
|
|
15780
|
+
method: 'initialize',
|
|
15781
|
+
params: {
|
|
15782
|
+
protocolVersion: '2024-11-05',
|
|
15783
|
+
capabilities: {},
|
|
15784
|
+
clientInfo: { name: 'beeline-pi-bridge', version: '1.0.0' },
|
|
15785
|
+
},
|
|
15786
|
+
}) + '\\n',
|
|
15787
|
+
);
|
|
15788
|
+
child.stdin.write(JSON.stringify(request) + '\\n');
|
|
15789
|
+
});
|
|
15790
|
+
}
|
|
15791
|
+
|
|
15792
|
+
function textOf(result) {
|
|
15793
|
+
const content = Array.isArray(result?.content) ? result.content : [];
|
|
15794
|
+
const text = content
|
|
15795
|
+
.filter((part) => part && part.type === 'text' && typeof part.text === 'string')
|
|
15796
|
+
.map((part) => part.text)
|
|
15797
|
+
.join('\\n');
|
|
15798
|
+
return text || 'The tool returned no text.';
|
|
15799
|
+
}
|
|
15800
|
+
|
|
15801
|
+
function labelOf(name) {
|
|
15802
|
+
return name.replace(/_/g, ' ').replace(/^./, (first) => first.toUpperCase());
|
|
15803
|
+
}
|
|
15804
|
+
|
|
15805
|
+
export default async function (pi) {
|
|
15806
|
+
for (const server of SERVERS) {
|
|
15807
|
+
let tools = [];
|
|
15808
|
+
try {
|
|
15809
|
+
const listed = await callServer(
|
|
15810
|
+
server,
|
|
15811
|
+
{ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} },
|
|
15812
|
+
undefined,
|
|
15813
|
+
LIST_TIMEOUT_MS,
|
|
15814
|
+
);
|
|
15815
|
+
tools = Array.isArray(listed?.tools) ? listed.tools : [];
|
|
15816
|
+
} catch (error) {
|
|
15817
|
+
// A server that will not list is a server whose tools this session does
|
|
15818
|
+
// not have. Say so once; never fail the session over it.
|
|
15819
|
+
console.error('[beeline] MCP server ' + server.name + ' did not list its tools:', error);
|
|
15820
|
+
continue;
|
|
15821
|
+
}
|
|
15822
|
+
for (const tool of tools) {
|
|
15823
|
+
if (!tool || typeof tool.name !== 'string') continue;
|
|
15824
|
+
const schema =
|
|
15825
|
+
tool.inputSchema && typeof tool.inputSchema === 'object'
|
|
15826
|
+
? tool.inputSchema
|
|
15827
|
+
: { type: 'object', properties: {} };
|
|
15828
|
+
pi.registerTool({
|
|
15829
|
+
name: server.name + '__' + tool.name,
|
|
15830
|
+
label: labelOf(tool.name),
|
|
15831
|
+
description: typeof tool.description === 'string' ? tool.description : tool.name,
|
|
15832
|
+
parameters: schema,
|
|
15833
|
+
async execute(_toolCallId, params, signal) {
|
|
15834
|
+
const result = await callServer(
|
|
15835
|
+
server,
|
|
15836
|
+
{
|
|
15837
|
+
jsonrpc: '2.0',
|
|
15838
|
+
id: 1,
|
|
15839
|
+
method: 'tools/call',
|
|
15840
|
+
params: { name: tool.name, arguments: params ?? {} },
|
|
15841
|
+
},
|
|
15842
|
+
signal,
|
|
15843
|
+
);
|
|
15844
|
+
// An MCP refusal is a RESULT carrying isError. Throwing is how a pi
|
|
15845
|
+
// tool reports failure, so the sentence explaining the refusal is
|
|
15846
|
+
// what the model reads.
|
|
15847
|
+
if (result?.isError) throw new Error(textOf(result));
|
|
15848
|
+
return { content: [{ type: 'text', text: textOf(result) }], details: {} };
|
|
15849
|
+
},
|
|
15850
|
+
});
|
|
15851
|
+
}
|
|
15852
|
+
}
|
|
15853
|
+
}
|
|
15854
|
+
`;
|
|
15855
|
+
|
|
15856
|
+
// apps/body/dist/room-session.js
|
|
15857
|
+
import { resolve as resolve15 } from "node:path";
|
|
15673
15858
|
|
|
15674
15859
|
// apps/body/dist/read-only-policy.js
|
|
15675
15860
|
var READ_ONLY_MCP_SERVER_NAME = "beeline-readonly-mcp";
|
|
@@ -15892,21 +16077,21 @@ function readOnlyMcpServer(config, cwd, agentMemoryDir) {
|
|
|
15892
16077
|
command: config.readonlyMcpCommand,
|
|
15893
16078
|
args: [...config.readonlyMcpArgs ?? []],
|
|
15894
16079
|
env: [
|
|
15895
|
-
{ name: "BEELINE_READONLY_ROOT", value:
|
|
16080
|
+
{ name: "BEELINE_READONLY_ROOT", value: resolve15(cwd) },
|
|
15896
16081
|
...config.agentHomeRoot ? [
|
|
15897
16082
|
{
|
|
15898
16083
|
name: "BEELINE_READONLY_AGENT_SKILLS_ROOT",
|
|
15899
|
-
value:
|
|
16084
|
+
value: resolve15(config.agentHomeRoot, skillDir, "skills")
|
|
15900
16085
|
}
|
|
15901
16086
|
] : [],
|
|
15902
|
-
...agentMemoryDir ? [{ name: "BEELINE_READONLY_AGENT_MEMORY_ROOT", value:
|
|
16087
|
+
...agentMemoryDir ? [{ name: "BEELINE_READONLY_AGENT_MEMORY_ROOT", value: resolve15(agentMemoryDir) }] : []
|
|
15903
16088
|
]
|
|
15904
16089
|
};
|
|
15905
16090
|
}
|
|
15906
16091
|
|
|
15907
16092
|
// apps/body/dist/pi-turn-record.js
|
|
15908
16093
|
import { readdir as readdir3, readFile as readFile7 } from "node:fs/promises";
|
|
15909
|
-
import { resolve as
|
|
16094
|
+
import { resolve as resolve16 } from "node:path";
|
|
15910
16095
|
function summarizeProviderError(errorMessage2) {
|
|
15911
16096
|
const trimmed = errorMessage2.trim();
|
|
15912
16097
|
const statusMatch = /^(\d{3}):\s*([\s\S]*)$/.exec(trimmed);
|
|
@@ -15927,7 +16112,7 @@ function summarizeProviderError(errorMessage2) {
|
|
|
15927
16112
|
}
|
|
15928
16113
|
async function sessionFileFromMap(home, sessionId) {
|
|
15929
16114
|
try {
|
|
15930
|
-
const raw = await readFile7(
|
|
16115
|
+
const raw = await readFile7(resolve16(home, ".pi", "pi-acp", "session-map.json"), "utf8");
|
|
15931
16116
|
const map = JSON.parse(raw);
|
|
15932
16117
|
const file = map.sessions?.[sessionId]?.sessionFile;
|
|
15933
16118
|
return typeof file === "string" && file ? file : void 0;
|
|
@@ -15936,7 +16121,7 @@ async function sessionFileFromMap(home, sessionId) {
|
|
|
15936
16121
|
}
|
|
15937
16122
|
}
|
|
15938
16123
|
async function sessionFileFromLayout(piDir, sessionId) {
|
|
15939
|
-
const sessionsRoot =
|
|
16124
|
+
const sessionsRoot = resolve16(piDir, "sessions");
|
|
15940
16125
|
const suffix = `_${sessionId}.jsonl`;
|
|
15941
16126
|
let projects;
|
|
15942
16127
|
try {
|
|
@@ -15945,7 +16130,7 @@ async function sessionFileFromLayout(piDir, sessionId) {
|
|
|
15945
16130
|
return void 0;
|
|
15946
16131
|
}
|
|
15947
16132
|
for (const project of projects) {
|
|
15948
|
-
const dir =
|
|
16133
|
+
const dir = resolve16(sessionsRoot, project);
|
|
15949
16134
|
let files;
|
|
15950
16135
|
try {
|
|
15951
16136
|
files = await readdir3(dir);
|
|
@@ -15954,7 +16139,7 @@ async function sessionFileFromLayout(piDir, sessionId) {
|
|
|
15954
16139
|
}
|
|
15955
16140
|
const match = files.find((file) => file.endsWith(suffix));
|
|
15956
16141
|
if (match)
|
|
15957
|
-
return
|
|
16142
|
+
return resolve16(dir, match);
|
|
15958
16143
|
}
|
|
15959
16144
|
return void 0;
|
|
15960
16145
|
}
|
|
@@ -16149,8 +16334,8 @@ async function withTurnReceiptHeartbeat(api, receipt, task, onHeartbeatError) {
|
|
|
16149
16334
|
}
|
|
16150
16335
|
|
|
16151
16336
|
// apps/body/dist/turn-trace.js
|
|
16152
|
-
import { appendFile, mkdir as
|
|
16153
|
-
import { resolve as
|
|
16337
|
+
import { appendFile, mkdir as mkdir7, readdir as readdir4, rm as rm3 } from "node:fs/promises";
|
|
16338
|
+
import { resolve as resolve17 } from "node:path";
|
|
16154
16339
|
import { performance as performance2 } from "node:perf_hooks";
|
|
16155
16340
|
var TURN_PHASES = [
|
|
16156
16341
|
/** Enqueued on `SessionScheduler` until this turn holds a slot. A capacity wait lives here. */
|
|
@@ -16380,7 +16565,7 @@ function formatTurnTraceLine(record2) {
|
|
|
16380
16565
|
return [head, ...record2.attempts.map((attempt) => formatTurnAttempt(attempt))].join("\n ");
|
|
16381
16566
|
}
|
|
16382
16567
|
function turnTraceDirectory(runtimeDir) {
|
|
16383
|
-
return
|
|
16568
|
+
return resolve17(runtimeDir, "turn-traces");
|
|
16384
16569
|
}
|
|
16385
16570
|
var TURN_TRACE_RETENTION_DAYS = 7;
|
|
16386
16571
|
function traceFileName(date) {
|
|
@@ -16397,13 +16582,13 @@ var TurnTraceFile = class {
|
|
|
16397
16582
|
this.options = options;
|
|
16398
16583
|
}
|
|
16399
16584
|
path(now2 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))()) {
|
|
16400
|
-
return
|
|
16585
|
+
return resolve17(this.directory, traceFileName(now2));
|
|
16401
16586
|
}
|
|
16402
16587
|
write(record2) {
|
|
16403
16588
|
this.tail = this.tail.catch(() => void 0).then(async () => {
|
|
16404
16589
|
const now2 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))();
|
|
16405
16590
|
const path = this.path(now2);
|
|
16406
|
-
await
|
|
16591
|
+
await mkdir7(this.directory, { recursive: true, mode: 448 });
|
|
16407
16592
|
await appendFile(path, `${JSON.stringify(record2)}
|
|
16408
16593
|
`, { mode: 384 });
|
|
16409
16594
|
await this.prune(now2);
|
|
@@ -16421,10 +16606,61 @@ var TurnTraceFile = class {
|
|
|
16421
16606
|
this.prunedDay = day;
|
|
16422
16607
|
const cutoff = traceFileName(new Date(now2.getTime() - TURN_TRACE_RETENTION_DAYS * 864e5));
|
|
16423
16608
|
const names = await readdir4(this.directory).catch(() => []);
|
|
16424
|
-
await Promise.all(names.filter((name) => /^turns-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name) && name < cutoff).map((name) => rm3(
|
|
16609
|
+
await Promise.all(names.filter((name) => /^turns-\d{4}-\d{2}-\d{2}\.jsonl$/.test(name) && name < cutoff).map((name) => rm3(resolve17(this.directory, name), { force: true })));
|
|
16425
16610
|
}
|
|
16426
16611
|
};
|
|
16427
16612
|
|
|
16613
|
+
// apps/body/dist/corner-github-auth.js
|
|
16614
|
+
import { chmod as chmod3, mkdir as mkdir8, writeFile as writeFile7 } from "node:fs/promises";
|
|
16615
|
+
import { delimiter as delimiter2, resolve as resolve18 } from "node:path";
|
|
16616
|
+
async function installCornerGitHubWrappers(input) {
|
|
16617
|
+
const bin = resolve18(input.root, "beeline-github-bin");
|
|
16618
|
+
await mkdir8(bin, { recursive: true, mode: 448 });
|
|
16619
|
+
const common = {
|
|
16620
|
+
node: process.execPath,
|
|
16621
|
+
cli: input.cliEntrypoint,
|
|
16622
|
+
config: input.runtimeConfigPath,
|
|
16623
|
+
room: input.roomId
|
|
16624
|
+
};
|
|
16625
|
+
await writeLauncher(resolve18(bin, "git"), { ...common, command: input.gitBinary });
|
|
16626
|
+
if (input.ghBinary)
|
|
16627
|
+
await writeLauncher(resolve18(bin, "gh"), { ...common, command: input.ghBinary });
|
|
16628
|
+
return {
|
|
16629
|
+
PATH: [bin, input.inheritedPath].filter(Boolean).join(delimiter2),
|
|
16630
|
+
// Static startup tokens take precedence over the refreshed token in gh.
|
|
16631
|
+
GH_TOKEN: "",
|
|
16632
|
+
GITHUB_TOKEN: ""
|
|
16633
|
+
};
|
|
16634
|
+
}
|
|
16635
|
+
async function writeLauncher(path, config) {
|
|
16636
|
+
const source = `#!/usr/bin/env node
|
|
16637
|
+
import { spawnSync } from 'node:child_process';
|
|
16638
|
+
const config = ${JSON.stringify(config)};
|
|
16639
|
+
const authFailure = /(?:authentication failed|bad credentials|could not read username|http(?:\\/\\d(?:\\.\\d)?)? 40[13]|status (?:code )?40[13])/i;
|
|
16640
|
+
function token() {
|
|
16641
|
+
const result = spawnSync(config.node, [config.cli, 'corner-read-token', '--config', config.config, '--room', config.room], { encoding: 'utf8' });
|
|
16642
|
+
if (result.status !== 0) {
|
|
16643
|
+
process.stderr.write(result.stderr || 'Beeline could not refresh the repository credential.\\n');
|
|
16644
|
+
process.exit(result.status || 1);
|
|
16645
|
+
}
|
|
16646
|
+
return result.stdout.trim();
|
|
16647
|
+
}
|
|
16648
|
+
function run(value) {
|
|
16649
|
+
const env = { ...process.env, GH_TOKEN: value, GITHUB_TOKEN: value, GIT_TERMINAL_PROMPT: '0' };
|
|
16650
|
+
return spawnSync(config.command, process.argv.slice(2), { env, encoding: 'buffer', stdio: ['inherit', 'pipe', 'pipe'] });
|
|
16651
|
+
}
|
|
16652
|
+
let result = run(token());
|
|
16653
|
+
const diagnostic = Buffer.concat([result.stdout || Buffer.alloc(0), result.stderr || Buffer.alloc(0)]).toString('utf8');
|
|
16654
|
+
if (result.status !== 0 && authFailure.test(diagnostic)) result = run(token());
|
|
16655
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
16656
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
16657
|
+
if (result.error) throw result.error;
|
|
16658
|
+
process.exit(result.status ?? 1);
|
|
16659
|
+
`;
|
|
16660
|
+
await writeFile7(path, source, { mode: 448 });
|
|
16661
|
+
await chmod3(path, 448);
|
|
16662
|
+
}
|
|
16663
|
+
|
|
16428
16664
|
// apps/body/dist/monolith-corner-turn.js
|
|
16429
16665
|
var execFileAsync2 = promisify2(execFile3);
|
|
16430
16666
|
var TOOL_ARGUMENT_MAX_BYTES = 1200;
|
|
@@ -16681,7 +16917,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
16681
16917
|
soul: configuration.soul ?? self?.soul,
|
|
16682
16918
|
agentName: self?.name ?? this.agent.name
|
|
16683
16919
|
});
|
|
16684
|
-
await
|
|
16920
|
+
await mkdir9(this.options.worktreePath, { recursive: true });
|
|
16685
16921
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
16686
16922
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
16687
16923
|
root: this.options.config.agentHomeRoot,
|
|
@@ -16698,11 +16934,27 @@ var MonolithCornerTurnLoop = class {
|
|
|
16698
16934
|
})
|
|
16699
16935
|
}) : {};
|
|
16700
16936
|
const command = this.options.config.agentCommand ?? this.options.config.agentBinary;
|
|
16937
|
+
let githubEnv = {
|
|
16938
|
+
GH_TOKEN: this.options.githubToken,
|
|
16939
|
+
GITHUB_TOKEN: this.options.githubToken
|
|
16940
|
+
};
|
|
16941
|
+
if (this.options.config.runtimeConfigPath && this.options.config.agentHomeRoot) {
|
|
16942
|
+
const gitBinary = (await execFileAsync2("which", ["git"])).stdout.trim();
|
|
16943
|
+
const ghBinary = await execFileAsync2("which", ["gh"]).then((result) => result.stdout.trim()).catch(() => void 0);
|
|
16944
|
+
githubEnv = await installCornerGitHubWrappers({
|
|
16945
|
+
root: this.options.config.agentHomeRoot,
|
|
16946
|
+
runtimeConfigPath: this.options.config.runtimeConfigPath,
|
|
16947
|
+
roomId: this.options.parentRoomId,
|
|
16948
|
+
cliEntrypoint: process.argv[1],
|
|
16949
|
+
gitBinary,
|
|
16950
|
+
...ghBinary ? { ghBinary } : {},
|
|
16951
|
+
inheritedPath: this.options.config.agentEnv.PATH ?? process.env.PATH
|
|
16952
|
+
});
|
|
16953
|
+
}
|
|
16701
16954
|
const agentEnv = {
|
|
16702
16955
|
...this.options.config.agentEnv,
|
|
16703
16956
|
...homeOverlay,
|
|
16704
|
-
|
|
16705
|
-
GITHUB_TOKEN: this.options.githubToken
|
|
16957
|
+
...githubEnv
|
|
16706
16958
|
};
|
|
16707
16959
|
this.agentEnv = agentEnv;
|
|
16708
16960
|
const agentArgs = agentArgsWithModelSelection({
|
|
@@ -16715,7 +16967,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
16715
16967
|
this.attachmentDir = tmpDir ? join5(tmpDir, "beeline-attachments") : void 0;
|
|
16716
16968
|
this.sessionScratchDir = tmpDir;
|
|
16717
16969
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
16718
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
16970
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir9(dir, { recursive: true })));
|
|
16719
16971
|
const spawnCommand = wrapAgentCommand({
|
|
16720
16972
|
bwrapPath: this.options.config.bwrapPath,
|
|
16721
16973
|
spec: {
|
|
@@ -16768,6 +17020,11 @@ var MonolithCornerTurnLoop = class {
|
|
|
16768
17020
|
...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
|
|
16769
17021
|
})
|
|
16770
17022
|
];
|
|
17023
|
+
await installPiMcpBridge({
|
|
17024
|
+
agentCommand: command,
|
|
17025
|
+
piHome: agentEnv.PI_CODING_AGENT_DIR,
|
|
17026
|
+
servers
|
|
17027
|
+
});
|
|
16771
17028
|
const persona = configuration.soul ?? self?.soul;
|
|
16772
17029
|
const identityInstructions = `Your Beeline identity is ${self?.name ?? this.agent.name}.`;
|
|
16773
17030
|
const personaInstructions = [
|
|
@@ -17146,7 +17403,7 @@ async function wait(ms, signal) {
|
|
|
17146
17403
|
}
|
|
17147
17404
|
|
|
17148
17405
|
// apps/body/dist/monolith-room-turn.js
|
|
17149
|
-
import { mkdir as
|
|
17406
|
+
import { mkdir as mkdir10 } from "node:fs/promises";
|
|
17150
17407
|
import { homedir as homedir7 } from "node:os";
|
|
17151
17408
|
import { join as join6 } from "node:path";
|
|
17152
17409
|
|
|
@@ -17461,7 +17718,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
17461
17718
|
agentName: self?.name ?? this.agent.name
|
|
17462
17719
|
});
|
|
17463
17720
|
const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
|
|
17464
|
-
await
|
|
17721
|
+
await mkdir10(this.options.cwd, { recursive: true });
|
|
17465
17722
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
17466
17723
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
17467
17724
|
root: this.options.config.agentHomeRoot,
|
|
@@ -17491,7 +17748,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
17491
17748
|
this.sessionScratchDir = tmpDir;
|
|
17492
17749
|
this.sessionStateDirs = stateDirs;
|
|
17493
17750
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
17494
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
17751
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir10(dir, { recursive: true })));
|
|
17495
17752
|
const spawnCommand = wrapAgentCommand({
|
|
17496
17753
|
bwrapPath: this.options.config.bwrapPath,
|
|
17497
17754
|
spec: {
|
|
@@ -17520,6 +17777,11 @@ var MonolithRoomTurnLoop = class {
|
|
|
17520
17777
|
...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
|
|
17521
17778
|
})
|
|
17522
17779
|
];
|
|
17780
|
+
await installPiMcpBridge({
|
|
17781
|
+
agentCommand: command,
|
|
17782
|
+
piHome: agentEnv.PI_CODING_AGENT_DIR,
|
|
17783
|
+
servers
|
|
17784
|
+
});
|
|
17523
17785
|
const mountedServers = servers.map((server) => server.name);
|
|
17524
17786
|
const clientOptions = {
|
|
17525
17787
|
agentCommand: spawnCommand.command,
|
|
@@ -18535,13 +18797,13 @@ var RoomRuntimeCoordinator = class {
|
|
|
18535
18797
|
return this.runtime.rooms.find((room) => room.channelId === roomId);
|
|
18536
18798
|
}
|
|
18537
18799
|
roomRoot(roomId) {
|
|
18538
|
-
return this.roomRecord(roomId)?.root ??
|
|
18800
|
+
return this.roomRecord(roomId)?.root ?? resolve19(dirname6(this.configPath), "rooms", roomId);
|
|
18539
18801
|
}
|
|
18540
18802
|
roomAgentHomeRoot(workspaceRoot, required = false) {
|
|
18541
18803
|
const flag = process.env.BUZZY_BODY_ROOM_HOME;
|
|
18542
18804
|
if (!required && flag === "0")
|
|
18543
18805
|
return void 0;
|
|
18544
|
-
const home =
|
|
18806
|
+
const home = resolve19(workspaceRoot, "agent-home");
|
|
18545
18807
|
if (!required && flag !== "1" && !existsSync4(home) && existsSync4(workspaceRoot))
|
|
18546
18808
|
return void 0;
|
|
18547
18809
|
try {
|
|
@@ -18558,8 +18820,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
18558
18820
|
return {
|
|
18559
18821
|
...this.baseConfig,
|
|
18560
18822
|
workspaceRoot,
|
|
18561
|
-
agentPrivateRoot:
|
|
18562
|
-
agentMemoryRoot:
|
|
18823
|
+
agentPrivateRoot: resolve19(workspaceRoot, "agent-private"),
|
|
18824
|
+
agentMemoryRoot: resolve19(dirname6(this.configPath), "memory"),
|
|
18563
18825
|
openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname6(this.configPath)),
|
|
18564
18826
|
turnTraceDir: turnTraceDirectory(dirname6(this.configPath)),
|
|
18565
18827
|
...agentHomeRoot ? { agentHomeRoot } : {}
|
|
@@ -18628,11 +18890,11 @@ var RoomRuntimeCoordinator = class {
|
|
|
18628
18890
|
const remote = roomCheckoutRemote(repository.remote);
|
|
18629
18891
|
const targetBranch = repository.targetBranch || "main";
|
|
18630
18892
|
const checkoutId = createHash4("sha256").update(`${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
|
|
18631
|
-
const path =
|
|
18632
|
-
await
|
|
18893
|
+
const path = resolve19(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
|
|
18894
|
+
await mkdir11(dirname6(path), { recursive: true, mode: 448 });
|
|
18633
18895
|
const token = remote.startsWith("https://github.com/") ? await this.options.daemonApi.execute("getRoomGitHubToken", { roomId }) : void 0;
|
|
18634
18896
|
const env = token ? githubGitEnv(token.token) : process.env;
|
|
18635
|
-
if (!existsSync4(
|
|
18897
|
+
if (!existsSync4(resolve19(path, ".git"))) {
|
|
18636
18898
|
await execFileAsync3("git", ["clone", "--no-checkout", remote, path], {
|
|
18637
18899
|
env,
|
|
18638
18900
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -18757,12 +19019,12 @@ var RoomRuntimeCoordinator = class {
|
|
|
18757
19019
|
async materializeCornerWorktree(input) {
|
|
18758
19020
|
const remote = githubHttpsRemote(input.remote);
|
|
18759
19021
|
const repositoryHash = createHash4("sha256").update(remote).digest("hex").slice(0, 24);
|
|
18760
|
-
const gitCommonDir =
|
|
18761
|
-
const path =
|
|
18762
|
-
await
|
|
18763
|
-
await
|
|
19022
|
+
const gitCommonDir = resolve19(this.runtime.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
|
|
19023
|
+
const path = resolve19(this.runtime.supervisorRoot, "beeline", "corners", input.cornerId);
|
|
19024
|
+
await mkdir11(dirname6(gitCommonDir), { recursive: true, mode: 448 });
|
|
19025
|
+
await mkdir11(dirname6(path), { recursive: true, mode: 448 });
|
|
18764
19026
|
const authEnv = githubGitEnv(input.token);
|
|
18765
|
-
if (!existsSync4(
|
|
19027
|
+
if (!existsSync4(resolve19(gitCommonDir, "HEAD"))) {
|
|
18766
19028
|
await execFileAsync3("git", ["clone", "--bare", remote, gitCommonDir], {
|
|
18767
19029
|
env: authEnv,
|
|
18768
19030
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -18775,7 +19037,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
18775
19037
|
"origin",
|
|
18776
19038
|
`+refs/heads/${input.targetBranch}:refs/remotes/origin/${input.targetBranch}`
|
|
18777
19039
|
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
|
|
18778
|
-
if (!existsSync4(
|
|
19040
|
+
if (!existsSync4(resolve19(path, ".git"))) {
|
|
18779
19041
|
await rm4(path, { recursive: true, force: true });
|
|
18780
19042
|
await execFileAsync3("git", [
|
|
18781
19043
|
`--git-dir=${gitCommonDir}`,
|
|
@@ -18812,7 +19074,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
18812
19074
|
`${this.agent.publicKey.slice(0, 16)}@users.noreply.github.com`
|
|
18813
19075
|
]);
|
|
18814
19076
|
const top = await execFileAsync3("git", ["-C", path, "rev-parse", "--show-toplevel"]);
|
|
18815
|
-
if (
|
|
19077
|
+
if (resolve19(top.stdout.trim()) !== resolve19(path)) {
|
|
18816
19078
|
throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
|
|
18817
19079
|
}
|
|
18818
19080
|
return { path, gitCommonDir };
|
|
@@ -18990,9 +19252,9 @@ var ThinDaemonCore = class {
|
|
|
18990
19252
|
|
|
18991
19253
|
// apps/body/dist/systemd.js
|
|
18992
19254
|
import { execFile as execFile5 } from "node:child_process";
|
|
18993
|
-
import { mkdir as
|
|
19255
|
+
import { mkdir as mkdir12, readFile as readFile8, writeFile as writeFile8 } from "node:fs/promises";
|
|
18994
19256
|
import { homedir as homedir8 } from "node:os";
|
|
18995
|
-
import { dirname as dirname7, resolve as
|
|
19257
|
+
import { dirname as dirname7, resolve as resolve20 } from "node:path";
|
|
18996
19258
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
18997
19259
|
import { promisify as promisify4 } from "node:util";
|
|
18998
19260
|
var execFileAsync4 = promisify4(execFile5);
|
|
@@ -19034,9 +19296,9 @@ WantedBy=default.target
|
|
|
19034
19296
|
}
|
|
19035
19297
|
function isCanonicalInstalledLauncher(env = process.env, invocationPath = process.argv[1]) {
|
|
19036
19298
|
const home = env.HOME?.trim() || homedir8();
|
|
19037
|
-
const expectedLibDir =
|
|
19299
|
+
const expectedLibDir = resolve20(home, ".local", "lib", "beeline");
|
|
19038
19300
|
const expectedPrefix = `${expectedLibDir}/`;
|
|
19039
|
-
return
|
|
19301
|
+
return resolve20(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve20(invocationPath).startsWith(expectedPrefix);
|
|
19040
19302
|
}
|
|
19041
19303
|
function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
19042
19304
|
if (isCanonicalInstalledLauncher(env, invocationPath))
|
|
@@ -19044,8 +19306,8 @@ function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
|
19044
19306
|
throw new Error("refusing to modify the shared Beeline systemd unit outside the canonical ~/.local/bin/beeline launcher");
|
|
19045
19307
|
}
|
|
19046
19308
|
function systemdUserUnitPath(env = process.env) {
|
|
19047
|
-
const configRoot = env.XDG_CONFIG_HOME?.trim() ||
|
|
19048
|
-
return
|
|
19309
|
+
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve20(homedir8(), ".config");
|
|
19310
|
+
return resolve20(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
|
|
19049
19311
|
}
|
|
19050
19312
|
var runSystemctl = async (args) => {
|
|
19051
19313
|
const result = await execFileAsync4("systemctl", ["--user", ...args], {
|
|
@@ -19063,8 +19325,8 @@ async function installAgentService(publicKey, options = {}) {
|
|
|
19063
19325
|
const content = agentServiceUnit();
|
|
19064
19326
|
const existing = await readFile8(path, "utf8").catch(() => "");
|
|
19065
19327
|
if (existing !== content) {
|
|
19066
|
-
await
|
|
19067
|
-
await
|
|
19328
|
+
await mkdir12(dirname7(path), { recursive: true, mode: 448 });
|
|
19329
|
+
await writeFile8(path, content, { mode: 384 });
|
|
19068
19330
|
}
|
|
19069
19331
|
const run2 = options.run ?? runSystemctl;
|
|
19070
19332
|
await run2(["daemon-reload"]);
|
|
@@ -19236,8 +19498,8 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
19236
19498
|
// apps/body/dist/connect-command.js
|
|
19237
19499
|
import { spawn as spawn5 } from "node:child_process";
|
|
19238
19500
|
import { createHash as createHash6 } from "node:crypto";
|
|
19239
|
-
import { chmod as
|
|
19240
|
-
import { dirname as dirname10, resolve as
|
|
19501
|
+
import { chmod as chmod5, mkdir as mkdir14, readFile as readFile10, unlink as unlink2, writeFile as writeFile10 } from "node:fs/promises";
|
|
19502
|
+
import { dirname as dirname10, resolve as resolve22 } from "node:path";
|
|
19241
19503
|
import { stdin as stdin3, stdout as stdout4 } from "node:process";
|
|
19242
19504
|
|
|
19243
19505
|
// packages/api-contract/dist/agent-pairing-code.js
|
|
@@ -19820,7 +20082,7 @@ function parseConnectSubscriptions(value) {
|
|
|
19820
20082
|
...new Set((value ?? "").split(",").map((entry) => entry.trim().toLowerCase()).filter(Boolean))
|
|
19821
20083
|
];
|
|
19822
20084
|
}
|
|
19823
|
-
function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl
|
|
20085
|
+
function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl) {
|
|
19824
20086
|
const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
|
|
19825
20087
|
if (!normalizedPairingCode)
|
|
19826
20088
|
throw new Error("invalid pairing code");
|
|
@@ -19831,7 +20093,10 @@ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl, eventSu
|
|
|
19831
20093
|
...selection.provider ? { provider: selection.provider } : {},
|
|
19832
20094
|
model: selection.model,
|
|
19833
20095
|
avatar_seed: avatarSeed,
|
|
19834
|
-
|
|
20096
|
+
// This wizard always finishes the join itself (`finishConnectedAgentPairing`,
|
|
20097
|
+
// called once the rename prompt below settles), so the claim must not
|
|
20098
|
+
// join Rooms or announce yet.
|
|
20099
|
+
defer_join: true
|
|
19835
20100
|
}, fetchImpl);
|
|
19836
20101
|
}
|
|
19837
20102
|
async function renameConnectedAgent(baseUrl, pairingCode, name, fetchImpl) {
|
|
@@ -19841,6 +20106,16 @@ async function renameConnectedAgent(baseUrl, pairingCode, name, fetchImpl) {
|
|
|
19841
20106
|
const renamed = await jsonRequest(`${baseUrl}/auth/agent/connect/name`, { pairing_code: normalizedPairingCode, agent_name: name.trim().replace(/\s+/g, " ") }, fetchImpl);
|
|
19842
20107
|
return renamed.agent_name;
|
|
19843
20108
|
}
|
|
20109
|
+
async function finishConnectedAgentPairing(baseUrl, pairingCode, workspaceJoined, eventSubscriptions, fetchImpl) {
|
|
20110
|
+
const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
|
|
20111
|
+
if (!normalizedPairingCode)
|
|
20112
|
+
throw new Error("invalid pairing code");
|
|
20113
|
+
await jsonRequest(`${baseUrl}/auth/agent/connect/finish`, {
|
|
20114
|
+
pairing_code: normalizedPairingCode,
|
|
20115
|
+
workspace_joined: workspaceJoined,
|
|
20116
|
+
...eventSubscriptions.length ? { event_subscriptions: [...eventSubscriptions] } : {}
|
|
20117
|
+
}, fetchImpl);
|
|
20118
|
+
}
|
|
19844
20119
|
function seededIdentityLine(grant) {
|
|
19845
20120
|
return grant.agent_face ? `${grant.agent_name} the ${grant.agent_face}` : grant.agent_name;
|
|
19846
20121
|
}
|
|
@@ -19858,7 +20133,7 @@ async function installCurrentRelease(fetchImpl) {
|
|
|
19858
20133
|
});
|
|
19859
20134
|
await activateRelease(layout, releaseId);
|
|
19860
20135
|
return {
|
|
19861
|
-
binary:
|
|
20136
|
+
binary: resolve22(layout.binDir, "beeline"),
|
|
19862
20137
|
version: published.version ?? releaseId
|
|
19863
20138
|
};
|
|
19864
20139
|
}
|
|
@@ -19881,21 +20156,21 @@ function providerEnvironment(selection) {
|
|
|
19881
20156
|
};
|
|
19882
20157
|
}
|
|
19883
20158
|
async function writePrivateJson(path, value) {
|
|
19884
|
-
await
|
|
19885
|
-
await
|
|
20159
|
+
await mkdir14(dirname10(path), { recursive: true, mode: 448 });
|
|
20160
|
+
await writeFile10(path, `${JSON.stringify(value, null, 2)}
|
|
19886
20161
|
`, { mode: 384 });
|
|
19887
|
-
await
|
|
20162
|
+
await chmod5(path, 384);
|
|
19888
20163
|
}
|
|
19889
20164
|
async function writeProviderEnv(selection, agentPubkey) {
|
|
19890
20165
|
const values = providerEnvironment(selection);
|
|
19891
20166
|
if (Object.keys(values).length === 0)
|
|
19892
20167
|
return void 0;
|
|
19893
|
-
const path =
|
|
19894
|
-
await
|
|
20168
|
+
const path = resolve22(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
|
|
20169
|
+
await mkdir14(dirname10(path), { recursive: true, mode: 448 });
|
|
19895
20170
|
const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
|
|
19896
|
-
await
|
|
20171
|
+
await writeFile10(path, `${contents}
|
|
19897
20172
|
`, { mode: 384 });
|
|
19898
|
-
await
|
|
20173
|
+
await chmod5(path, 384);
|
|
19899
20174
|
return path;
|
|
19900
20175
|
}
|
|
19901
20176
|
async function runInstalledFinish(binary, grantPath) {
|
|
@@ -19951,11 +20226,12 @@ async function runConnectWizard(code, fetchImpl, eventSubscriptions, accessPolic
|
|
|
19951
20226
|
});
|
|
19952
20227
|
const selection = await collectConnectWizard(clackPrompts, loadConnectModelCatalog, fileConnectKeyStore, process.env, (input) => verifyProviderKey({ ...input, fetchImpl }));
|
|
19953
20228
|
const baseUrl = (process.env.BEELINE_AUTH_URL ?? "https://server.usebeeline.app").replace(/\/$/, "");
|
|
19954
|
-
const claimed = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl
|
|
20229
|
+
const claimed = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl), (connectedGrant) => `Connected to ${connectedGrant.workspace_name}`);
|
|
19955
20230
|
const grant = { ...claimed, agent_name: await confirmSeededName(baseUrl, pairingCode, claimed, fetchImpl) };
|
|
20231
|
+
await finishConnectedAgentPairing(baseUrl, pairingCode, grant.workspace_joined, eventSubscriptions, fetchImpl);
|
|
19956
20232
|
const installedRelease = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl), (release) => `Installed Beeline helper ${release.version}`);
|
|
19957
20233
|
const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
|
|
19958
|
-
const grantPath =
|
|
20234
|
+
const grantPath = resolve22(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
|
|
19959
20235
|
await writePrivateJson(grantPath, {
|
|
19960
20236
|
agentSecretKey: grant.agent_secret_key,
|
|
19961
20237
|
bodySecretKey: grant.body_secret_key,
|
|
@@ -20037,11 +20313,11 @@ async function runConnectFinishCommand(path) {
|
|
|
20037
20313
|
throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
|
|
20038
20314
|
}
|
|
20039
20315
|
try {
|
|
20040
|
-
const grant = JSON.parse(await readFile10(
|
|
20316
|
+
const grant = JSON.parse(await readFile10(resolve22(path), "utf8"));
|
|
20041
20317
|
if (!isDevicePairingGrant(grant))
|
|
20042
20318
|
throw new Error("device connection grant is invalid");
|
|
20043
20319
|
const connected = await completeDevicePairing(grant);
|
|
20044
|
-
await unlink2(
|
|
20320
|
+
await unlink2(resolve22(path));
|
|
20045
20321
|
const providerEnv = grant.llmEnvFile ? await readFile10(grant.llmEnvFile, "utf8").catch(() => "") : "";
|
|
20046
20322
|
const apiKey = (/^OPENROUTER_API_KEY=(\S+)/m.exec(providerEnv)?.[1] ?? "").replace(/^["']|["']$/g, "");
|
|
20047
20323
|
const model = openRouterModelId(grant.model, { OPENROUTER_API_KEY: apiKey });
|
|
@@ -20070,20 +20346,20 @@ init_self_update_manifest();
|
|
|
20070
20346
|
// apps/body/dist/managed-update.js
|
|
20071
20347
|
init_self_update();
|
|
20072
20348
|
import { spawn as spawn6 } from "node:child_process";
|
|
20073
|
-
import { mkdir as
|
|
20074
|
-
import { dirname as dirname12, resolve as
|
|
20349
|
+
import { mkdir as mkdir16, rm as rm6, stat as stat2, writeFile as writeFile12 } from "node:fs/promises";
|
|
20350
|
+
import { dirname as dirname12, resolve as resolve24 } from "node:path";
|
|
20075
20351
|
|
|
20076
20352
|
// apps/body/dist/update-rollback-alert.js
|
|
20077
|
-
import { mkdir as
|
|
20078
|
-
import { dirname as dirname11, resolve as
|
|
20353
|
+
import { mkdir as mkdir15, readFile as readFile11, rename as rename4, writeFile as writeFile11 } from "node:fs/promises";
|
|
20354
|
+
import { dirname as dirname11, resolve as resolve23 } from "node:path";
|
|
20079
20355
|
function updateRollbackAlertPath(runtimeDir) {
|
|
20080
|
-
return
|
|
20356
|
+
return resolve23(runtimeDir, "update-rollback-alert.json");
|
|
20081
20357
|
}
|
|
20082
20358
|
async function writeAlert(runtimeDir, alert) {
|
|
20083
20359
|
const path = updateRollbackAlertPath(runtimeDir);
|
|
20084
20360
|
const staged = `${path}.${process.pid}.tmp`;
|
|
20085
|
-
await
|
|
20086
|
-
await
|
|
20361
|
+
await mkdir15(dirname11(path), { recursive: true });
|
|
20362
|
+
await writeFile11(staged, `${JSON.stringify(alert, null, 2)}
|
|
20087
20363
|
`, { mode: 384 });
|
|
20088
20364
|
await rename4(staged, path);
|
|
20089
20365
|
}
|
|
@@ -20120,13 +20396,13 @@ var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
|
|
|
20120
20396
|
var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
|
|
20121
20397
|
async function withInstallLock(layout, work, options = {}) {
|
|
20122
20398
|
const now2 = options.now ?? Date.now;
|
|
20123
|
-
const lock =
|
|
20399
|
+
const lock = resolve24(layout.releasesRoot, ".state", "install.lock");
|
|
20124
20400
|
const deadline = now2() + (options.waitMs ?? 1e4);
|
|
20125
|
-
await
|
|
20401
|
+
await mkdir16(dirname12(lock), { recursive: true });
|
|
20126
20402
|
for (; ; ) {
|
|
20127
20403
|
try {
|
|
20128
|
-
await
|
|
20129
|
-
await
|
|
20404
|
+
await mkdir16(lock);
|
|
20405
|
+
await writeFile12(resolve24(lock, "owner"), `${process.pid}
|
|
20130
20406
|
${now2()}
|
|
20131
20407
|
`, "utf8");
|
|
20132
20408
|
break;
|
|
@@ -20249,7 +20525,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
20249
20525
|
if (!attempt || attempt.releaseId !== desiredRelease || attempt.status !== "pending") {
|
|
20250
20526
|
const from = await readInstalledBundleIdentity({
|
|
20251
20527
|
...this.#layout,
|
|
20252
|
-
libDir:
|
|
20528
|
+
libDir: resolve24(this.#layout.releasesRoot, this.#loadedRelease)
|
|
20253
20529
|
}).catch(() => void 0) ?? {};
|
|
20254
20530
|
const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
|
|
20255
20531
|
const record2 = {
|
|
@@ -20536,7 +20812,7 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
|
|
|
20536
20812
|
});
|
|
20537
20813
|
if (!accepted)
|
|
20538
20814
|
return false;
|
|
20539
|
-
await
|
|
20815
|
+
await writeFile12(resolve24(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
|
|
20540
20816
|
readyAt: (options.now ?? Date.now)(),
|
|
20541
20817
|
loadedRelease,
|
|
20542
20818
|
functionalProof: options.functionalProof
|
|
@@ -20741,12 +21017,12 @@ async function runUpdateCommand(args) {
|
|
|
20741
21017
|
init_self_update();
|
|
20742
21018
|
|
|
20743
21019
|
// apps/body/dist/daemon-failure.js
|
|
20744
|
-
import { mkdir as
|
|
20745
|
-
import { dirname as dirname13, resolve as
|
|
21020
|
+
import { mkdir as mkdir17, readFile as readFile12, rename as rename5, rm as rm7, writeFile as writeFile13 } from "node:fs/promises";
|
|
21021
|
+
import { dirname as dirname13, resolve as resolve25 } from "node:path";
|
|
20746
21022
|
var DAEMON_FAILURE_LIMIT = 3;
|
|
20747
21023
|
var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
20748
21024
|
function daemonFailurePath(runtimeDir) {
|
|
20749
|
-
return
|
|
21025
|
+
return resolve25(runtimeDir, "daemon-distress.json");
|
|
20750
21026
|
}
|
|
20751
21027
|
async function readFailureRecord(runtimeDir) {
|
|
20752
21028
|
try {
|
|
@@ -20762,8 +21038,8 @@ async function readFailureRecord(runtimeDir) {
|
|
|
20762
21038
|
async function writeFailureRecord(runtimeDir, record2) {
|
|
20763
21039
|
const path = daemonFailurePath(runtimeDir);
|
|
20764
21040
|
const staged = `${path}.${process.pid}.tmp`;
|
|
20765
|
-
await
|
|
20766
|
-
await
|
|
21041
|
+
await mkdir17(dirname13(path), { recursive: true, mode: 448 });
|
|
21042
|
+
await writeFile13(staged, `${JSON.stringify(record2, null, 2)}
|
|
20767
21043
|
`, { mode: 384 });
|
|
20768
21044
|
await rename5(staged, path);
|
|
20769
21045
|
}
|
|
@@ -20785,9 +21061,9 @@ async function clearDaemonStartFailures(runtimeDir) {
|
|
|
20785
21061
|
}
|
|
20786
21062
|
|
|
20787
21063
|
// apps/body/dist/update-functional-probe.js
|
|
20788
|
-
import { mkdir as
|
|
21064
|
+
import { mkdir as mkdir18, rm as rm8 } from "node:fs/promises";
|
|
20789
21065
|
import { homedir as homedir10 } from "node:os";
|
|
20790
|
-
import { resolve as
|
|
21066
|
+
import { resolve as resolve26 } from "node:path";
|
|
20791
21067
|
var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
|
|
20792
21068
|
var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
|
|
20793
21069
|
var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
|
|
@@ -20833,11 +21109,11 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
20833
21109
|
if (input.sandboxRequired && !input.config.bwrapPath) {
|
|
20834
21110
|
throw new UpdateFunctionalProbeError("sandbox-unavailable", "the configured bubblewrap boundary did not pass its startup self-test");
|
|
20835
21111
|
}
|
|
20836
|
-
const root = input.probeRoot ??
|
|
20837
|
-
const cwd =
|
|
20838
|
-
const homeRoot =
|
|
21112
|
+
const root = input.probeRoot ?? resolve26(input.runtimeDir, "update-functional-probe");
|
|
21113
|
+
const cwd = resolve26(root, "checkout");
|
|
21114
|
+
const homeRoot = resolve26(root, "agent-home");
|
|
20839
21115
|
await rm8(root, { recursive: true, force: true });
|
|
20840
|
-
await
|
|
21116
|
+
await mkdir18(cwd, { recursive: true, mode: 448 });
|
|
20841
21117
|
let client;
|
|
20842
21118
|
try {
|
|
20843
21119
|
const agentEnv = {
|
|
@@ -20866,7 +21142,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
20866
21142
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
20867
21143
|
const operatorHome = input.config.operatorHome ?? homedir10();
|
|
20868
21144
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
20869
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
21145
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir18(dir, { recursive: true })));
|
|
20870
21146
|
spawnCommand = wrapAgentCommand({
|
|
20871
21147
|
bwrapPath: input.config.bwrapPath,
|
|
20872
21148
|
spec: {
|
|
@@ -21002,7 +21278,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
21002
21278
|
return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
|
|
21003
21279
|
}
|
|
21004
21280
|
const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
|
|
21005
|
-
return new Promise((
|
|
21281
|
+
return new Promise((resolve29) => {
|
|
21006
21282
|
const child = spawn7(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
21007
21283
|
let stdout6 = "";
|
|
21008
21284
|
let stderr = "";
|
|
@@ -21012,7 +21288,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
21012
21288
|
return;
|
|
21013
21289
|
settled = true;
|
|
21014
21290
|
clearTimeout(timer);
|
|
21015
|
-
|
|
21291
|
+
resolve29(outcome);
|
|
21016
21292
|
};
|
|
21017
21293
|
const timer = setTimeout(() => {
|
|
21018
21294
|
child.kill("SIGKILL");
|
|
@@ -21091,8 +21367,8 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
21091
21367
|
}
|
|
21092
21368
|
|
|
21093
21369
|
// apps/body/dist/release-status.js
|
|
21094
|
-
import { readFile as readFile13, readdir as readdir5, rename as rename6, writeFile as
|
|
21095
|
-
import { resolve as
|
|
21370
|
+
import { readFile as readFile13, readdir as readdir5, rename as rename6, writeFile as writeFile14 } from "node:fs/promises";
|
|
21371
|
+
import { resolve as resolve27 } from "node:path";
|
|
21096
21372
|
var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
|
|
21097
21373
|
var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
|
|
21098
21374
|
var SOURCE_SHA = /^[0-9a-f]{7,64}$/;
|
|
@@ -21109,9 +21385,9 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
21109
21385
|
pid: options.pid ?? process.pid,
|
|
21110
21386
|
readyAt: (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
|
|
21111
21387
|
};
|
|
21112
|
-
const target =
|
|
21388
|
+
const target = resolve27(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
|
|
21113
21389
|
const temporary = `${target}.${status.pid}.tmp`;
|
|
21114
|
-
await
|
|
21390
|
+
await writeFile14(temporary, `${JSON.stringify(status, null, 2)}
|
|
21115
21391
|
`, { mode: 384 });
|
|
21116
21392
|
await rename6(temporary, target);
|
|
21117
21393
|
return status;
|
|
@@ -21169,7 +21445,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21169
21445
|
runtime = activated.runtime;
|
|
21170
21446
|
const daemonApi = activated.client;
|
|
21171
21447
|
const agent = runtimeAgentCommand(runtime);
|
|
21172
|
-
await
|
|
21448
|
+
await writeFile15(resolve28(dirname15(configPath), "daemon.pid"), `${process.pid}
|
|
21173
21449
|
`, { mode: 384 });
|
|
21174
21450
|
const env = {
|
|
21175
21451
|
...process.env,
|
|
@@ -21177,7 +21453,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21177
21453
|
BUZZ_DEV_MCP_BIN: runtime.mcpBinary
|
|
21178
21454
|
};
|
|
21179
21455
|
const config = loadBodyConfig({
|
|
21180
|
-
workspaceRoot:
|
|
21456
|
+
workspaceRoot: resolve28(dirname15(configPath), "workspace"),
|
|
21181
21457
|
llmEnvFile: runtime.llmEnvFile,
|
|
21182
21458
|
env,
|
|
21183
21459
|
agent
|
|
@@ -21347,7 +21623,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21347
21623
|
throw error;
|
|
21348
21624
|
} finally {
|
|
21349
21625
|
await notifier.stopping(stoppingStatus).catch(() => void 0);
|
|
21350
|
-
const pidPath =
|
|
21626
|
+
const pidPath = resolve28(dirname15(configPath), "daemon.pid");
|
|
21351
21627
|
const recorded = Number((await readFile14(pidPath, "utf8").catch(() => "")).trim());
|
|
21352
21628
|
if (recorded === process.pid) {
|
|
21353
21629
|
await unlink3(pidPath).catch(() => void 0);
|
|
@@ -21368,6 +21644,21 @@ async function main() {
|
|
|
21368
21644
|
console.log(JSON.stringify(await runManagedUpdateWorker()));
|
|
21369
21645
|
return;
|
|
21370
21646
|
}
|
|
21647
|
+
if (command === "corner-read-token") {
|
|
21648
|
+
const configFlag = args.indexOf("--config");
|
|
21649
|
+
const roomFlag = args.indexOf("--room");
|
|
21650
|
+
const configPath = configFlag >= 0 ? args[configFlag + 1] : void 0;
|
|
21651
|
+
const roomId = roomFlag >= 0 ? args[roomFlag + 1] : void 0;
|
|
21652
|
+
if (!configPath || !roomId)
|
|
21653
|
+
throw new Error("corner-read-token requires --config and --room");
|
|
21654
|
+
const activated = await activateDaemonTransport(resolve28(configPath));
|
|
21655
|
+
if (!activated)
|
|
21656
|
+
throw new Error("corner-read-token requires monolith transport");
|
|
21657
|
+
const credential = await activated.client.execute("getRoomGitHubToken", { roomId });
|
|
21658
|
+
process.stdout.write(`${credential.token}
|
|
21659
|
+
`);
|
|
21660
|
+
return;
|
|
21661
|
+
}
|
|
21371
21662
|
if (command === "connect") {
|
|
21372
21663
|
const subscribeFlag = args.indexOf("--subscribe");
|
|
21373
21664
|
const subscribe = subscribeFlag >= 0 ? parseConnectSubscriptions(args[subscribeFlag + 1]) : [];
|
|
@@ -21422,7 +21713,7 @@ async function main() {
|
|
|
21422
21713
|
}
|
|
21423
21714
|
if (!configPath)
|
|
21424
21715
|
throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
|
|
21425
|
-
await runStoredDaemon(
|
|
21716
|
+
await runStoredDaemon(resolve28(configPath));
|
|
21426
21717
|
return;
|
|
21427
21718
|
}
|
|
21428
21719
|
if (command === "update") {
|