usebeeline 0.0.48 → 0.0.49
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 +314 -105
- 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 createHash5 } from "node:crypto";
|
|
311
311
|
import { constants as fsConstants } from "node:fs";
|
|
312
|
-
import { access, chmod as chmod3, lstat as lstat2, mkdir as
|
|
312
|
+
import { access, chmod as chmod3, lstat as lstat2, mkdir as mkdir12, open, readFile as readFile9, rename as rename3, rm as rm5, symlink as symlink2, writeFile as writeFile8 } 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 resolve20 } from "node:path";
|
|
316
316
|
function anchorLayout(rawLibDir) {
|
|
317
|
-
const libDir =
|
|
317
|
+
const libDir = resolve20(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: resolve20(libDir, "../../bin"),
|
|
334
334
|
libDir,
|
|
335
|
-
releasesRoot:
|
|
335
|
+
releasesRoot: resolve20(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(resolve20(home, ".local", "lib", "beeline"));
|
|
347
347
|
}
|
|
348
348
|
function hostPlatformKey() {
|
|
349
349
|
const os = process.platform === "linux" ? "linux" : process.platform === "darwin" ? "darwin" : "";
|
|
@@ -387,7 +387,7 @@ async function readUpdateState(layout) {
|
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
389
|
async function writeUpdateState(layout, state) {
|
|
390
|
-
await
|
|
390
|
+
await mkdir12(join7(layout.releasesRoot, ".state"), { recursive: true });
|
|
391
391
|
await writeFile8(updateStatePath(layout), `${JSON.stringify(state, null, 2)}
|
|
392
392
|
`, "utf8");
|
|
393
393
|
}
|
|
@@ -501,7 +501,7 @@ async function stageRelease(layout, manifestUrl, published, opts = {}) {
|
|
|
501
501
|
previouslyVerified = true;
|
|
502
502
|
} catch {
|
|
503
503
|
}
|
|
504
|
-
await
|
|
504
|
+
await mkdir12(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}`);
|
|
@@ -588,8 +588,8 @@ async function replaceFile(path, contents, mode) {
|
|
|
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 mkdir12(layout.releasesRoot, { recursive: true });
|
|
592
|
+
await mkdir12(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 mkdir12(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 mkdir12(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,7 +693,7 @@ async function readUpdateAttempt(layout) {
|
|
|
693
693
|
}
|
|
694
694
|
}
|
|
695
695
|
async function writeUpdateAttempt(layout, record2) {
|
|
696
|
-
await
|
|
696
|
+
await mkdir12(join7(layout.releasesRoot, ".state"), { recursive: true });
|
|
697
697
|
const path = updateAttemptPath(layout);
|
|
698
698
|
const staged = `${path}.${process.pid}.tmp`;
|
|
699
699
|
await writeFile8(staged, `${JSON.stringify(record2, null, 2)}
|
|
@@ -955,7 +955,7 @@ var init_self_update = __esm({
|
|
|
955
955
|
});
|
|
956
956
|
|
|
957
957
|
// apps/body/dist/cli.js
|
|
958
|
-
import { dirname as dirname15, resolve as
|
|
958
|
+
import { dirname as dirname15, resolve as resolve27 } from "node:path";
|
|
959
959
|
import { readFile as readFile14, unlink as unlink3, writeFile as writeFile14 } from "node:fs/promises";
|
|
960
960
|
import { stdin as stdin4, stdout as stdout5 } from "node:process";
|
|
961
961
|
|
|
@@ -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((resolve28, 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
|
+
resolve28(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((resolve28, 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: resolve28,
|
|
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 mkdir10, rm as rm4 } from "node:fs/promises";
|
|
13287
|
+
import { dirname as dirname6, resolve as resolve18 } 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 mkdir8 } 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,7 +16606,7 @@ 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
|
|
|
@@ -16681,7 +16866,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
16681
16866
|
soul: configuration.soul ?? self?.soul,
|
|
16682
16867
|
agentName: self?.name ?? this.agent.name
|
|
16683
16868
|
});
|
|
16684
|
-
await
|
|
16869
|
+
await mkdir8(this.options.worktreePath, { recursive: true });
|
|
16685
16870
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
16686
16871
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
16687
16872
|
root: this.options.config.agentHomeRoot,
|
|
@@ -16715,7 +16900,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
16715
16900
|
this.attachmentDir = tmpDir ? join5(tmpDir, "beeline-attachments") : void 0;
|
|
16716
16901
|
this.sessionScratchDir = tmpDir;
|
|
16717
16902
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
16718
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
16903
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir8(dir, { recursive: true })));
|
|
16719
16904
|
const spawnCommand = wrapAgentCommand({
|
|
16720
16905
|
bwrapPath: this.options.config.bwrapPath,
|
|
16721
16906
|
spec: {
|
|
@@ -16768,6 +16953,11 @@ var MonolithCornerTurnLoop = class {
|
|
|
16768
16953
|
...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
|
|
16769
16954
|
})
|
|
16770
16955
|
];
|
|
16956
|
+
await installPiMcpBridge({
|
|
16957
|
+
agentCommand: command,
|
|
16958
|
+
piHome: agentEnv.PI_CODING_AGENT_DIR,
|
|
16959
|
+
servers
|
|
16960
|
+
});
|
|
16771
16961
|
const persona = configuration.soul ?? self?.soul;
|
|
16772
16962
|
const identityInstructions = `Your Beeline identity is ${self?.name ?? this.agent.name}.`;
|
|
16773
16963
|
const personaInstructions = [
|
|
@@ -17146,7 +17336,7 @@ async function wait(ms, signal) {
|
|
|
17146
17336
|
}
|
|
17147
17337
|
|
|
17148
17338
|
// apps/body/dist/monolith-room-turn.js
|
|
17149
|
-
import { mkdir as
|
|
17339
|
+
import { mkdir as mkdir9 } from "node:fs/promises";
|
|
17150
17340
|
import { homedir as homedir7 } from "node:os";
|
|
17151
17341
|
import { join as join6 } from "node:path";
|
|
17152
17342
|
|
|
@@ -17461,7 +17651,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
17461
17651
|
agentName: self?.name ?? this.agent.name
|
|
17462
17652
|
});
|
|
17463
17653
|
const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
|
|
17464
|
-
await
|
|
17654
|
+
await mkdir9(this.options.cwd, { recursive: true });
|
|
17465
17655
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
17466
17656
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
17467
17657
|
root: this.options.config.agentHomeRoot,
|
|
@@ -17491,7 +17681,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
17491
17681
|
this.sessionScratchDir = tmpDir;
|
|
17492
17682
|
this.sessionStateDirs = stateDirs;
|
|
17493
17683
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
17494
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
17684
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir9(dir, { recursive: true })));
|
|
17495
17685
|
const spawnCommand = wrapAgentCommand({
|
|
17496
17686
|
bwrapPath: this.options.config.bwrapPath,
|
|
17497
17687
|
spec: {
|
|
@@ -17520,6 +17710,11 @@ var MonolithRoomTurnLoop = class {
|
|
|
17520
17710
|
...this.options.grantRunnerEndpoint ? { grantRunner: this.options.grantRunnerEndpoint } : {}
|
|
17521
17711
|
})
|
|
17522
17712
|
];
|
|
17713
|
+
await installPiMcpBridge({
|
|
17714
|
+
agentCommand: command,
|
|
17715
|
+
piHome: agentEnv.PI_CODING_AGENT_DIR,
|
|
17716
|
+
servers
|
|
17717
|
+
});
|
|
17523
17718
|
const mountedServers = servers.map((server) => server.name);
|
|
17524
17719
|
const clientOptions = {
|
|
17525
17720
|
agentCommand: spawnCommand.command,
|
|
@@ -18535,13 +18730,13 @@ var RoomRuntimeCoordinator = class {
|
|
|
18535
18730
|
return this.runtime.rooms.find((room) => room.channelId === roomId);
|
|
18536
18731
|
}
|
|
18537
18732
|
roomRoot(roomId) {
|
|
18538
|
-
return this.roomRecord(roomId)?.root ??
|
|
18733
|
+
return this.roomRecord(roomId)?.root ?? resolve18(dirname6(this.configPath), "rooms", roomId);
|
|
18539
18734
|
}
|
|
18540
18735
|
roomAgentHomeRoot(workspaceRoot, required = false) {
|
|
18541
18736
|
const flag = process.env.BUZZY_BODY_ROOM_HOME;
|
|
18542
18737
|
if (!required && flag === "0")
|
|
18543
18738
|
return void 0;
|
|
18544
|
-
const home =
|
|
18739
|
+
const home = resolve18(workspaceRoot, "agent-home");
|
|
18545
18740
|
if (!required && flag !== "1" && !existsSync4(home) && existsSync4(workspaceRoot))
|
|
18546
18741
|
return void 0;
|
|
18547
18742
|
try {
|
|
@@ -18558,8 +18753,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
18558
18753
|
return {
|
|
18559
18754
|
...this.baseConfig,
|
|
18560
18755
|
workspaceRoot,
|
|
18561
|
-
agentPrivateRoot:
|
|
18562
|
-
agentMemoryRoot:
|
|
18756
|
+
agentPrivateRoot: resolve18(workspaceRoot, "agent-private"),
|
|
18757
|
+
agentMemoryRoot: resolve18(dirname6(this.configPath), "memory"),
|
|
18563
18758
|
openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname6(this.configPath)),
|
|
18564
18759
|
turnTraceDir: turnTraceDirectory(dirname6(this.configPath)),
|
|
18565
18760
|
...agentHomeRoot ? { agentHomeRoot } : {}
|
|
@@ -18628,11 +18823,11 @@ var RoomRuntimeCoordinator = class {
|
|
|
18628
18823
|
const remote = roomCheckoutRemote(repository.remote);
|
|
18629
18824
|
const targetBranch = repository.targetBranch || "main";
|
|
18630
18825
|
const checkoutId = createHash4("sha256").update(`${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
|
|
18631
|
-
const path =
|
|
18632
|
-
await
|
|
18826
|
+
const path = resolve18(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
|
|
18827
|
+
await mkdir10(dirname6(path), { recursive: true, mode: 448 });
|
|
18633
18828
|
const token = remote.startsWith("https://github.com/") ? await this.options.daemonApi.execute("getRoomGitHubToken", { roomId }) : void 0;
|
|
18634
18829
|
const env = token ? githubGitEnv(token.token) : process.env;
|
|
18635
|
-
if (!existsSync4(
|
|
18830
|
+
if (!existsSync4(resolve18(path, ".git"))) {
|
|
18636
18831
|
await execFileAsync3("git", ["clone", "--no-checkout", remote, path], {
|
|
18637
18832
|
env,
|
|
18638
18833
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -18757,12 +18952,12 @@ var RoomRuntimeCoordinator = class {
|
|
|
18757
18952
|
async materializeCornerWorktree(input) {
|
|
18758
18953
|
const remote = githubHttpsRemote(input.remote);
|
|
18759
18954
|
const repositoryHash = createHash4("sha256").update(remote).digest("hex").slice(0, 24);
|
|
18760
|
-
const gitCommonDir =
|
|
18761
|
-
const path =
|
|
18762
|
-
await
|
|
18763
|
-
await
|
|
18955
|
+
const gitCommonDir = resolve18(this.runtime.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
|
|
18956
|
+
const path = resolve18(this.runtime.supervisorRoot, "beeline", "corners", input.cornerId);
|
|
18957
|
+
await mkdir10(dirname6(gitCommonDir), { recursive: true, mode: 448 });
|
|
18958
|
+
await mkdir10(dirname6(path), { recursive: true, mode: 448 });
|
|
18764
18959
|
const authEnv = githubGitEnv(input.token);
|
|
18765
|
-
if (!existsSync4(
|
|
18960
|
+
if (!existsSync4(resolve18(gitCommonDir, "HEAD"))) {
|
|
18766
18961
|
await execFileAsync3("git", ["clone", "--bare", remote, gitCommonDir], {
|
|
18767
18962
|
env: authEnv,
|
|
18768
18963
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -18775,7 +18970,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
18775
18970
|
"origin",
|
|
18776
18971
|
`+refs/heads/${input.targetBranch}:refs/remotes/origin/${input.targetBranch}`
|
|
18777
18972
|
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
|
|
18778
|
-
if (!existsSync4(
|
|
18973
|
+
if (!existsSync4(resolve18(path, ".git"))) {
|
|
18779
18974
|
await rm4(path, { recursive: true, force: true });
|
|
18780
18975
|
await execFileAsync3("git", [
|
|
18781
18976
|
`--git-dir=${gitCommonDir}`,
|
|
@@ -18812,7 +19007,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
18812
19007
|
`${this.agent.publicKey.slice(0, 16)}@users.noreply.github.com`
|
|
18813
19008
|
]);
|
|
18814
19009
|
const top = await execFileAsync3("git", ["-C", path, "rev-parse", "--show-toplevel"]);
|
|
18815
|
-
if (
|
|
19010
|
+
if (resolve18(top.stdout.trim()) !== resolve18(path)) {
|
|
18816
19011
|
throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
|
|
18817
19012
|
}
|
|
18818
19013
|
return { path, gitCommonDir };
|
|
@@ -18990,9 +19185,9 @@ var ThinDaemonCore = class {
|
|
|
18990
19185
|
|
|
18991
19186
|
// apps/body/dist/systemd.js
|
|
18992
19187
|
import { execFile as execFile5 } from "node:child_process";
|
|
18993
|
-
import { mkdir as
|
|
19188
|
+
import { mkdir as mkdir11, readFile as readFile8, writeFile as writeFile7 } from "node:fs/promises";
|
|
18994
19189
|
import { homedir as homedir8 } from "node:os";
|
|
18995
|
-
import { dirname as dirname7, resolve as
|
|
19190
|
+
import { dirname as dirname7, resolve as resolve19 } from "node:path";
|
|
18996
19191
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
18997
19192
|
import { promisify as promisify4 } from "node:util";
|
|
18998
19193
|
var execFileAsync4 = promisify4(execFile5);
|
|
@@ -19034,9 +19229,9 @@ WantedBy=default.target
|
|
|
19034
19229
|
}
|
|
19035
19230
|
function isCanonicalInstalledLauncher(env = process.env, invocationPath = process.argv[1]) {
|
|
19036
19231
|
const home = env.HOME?.trim() || homedir8();
|
|
19037
|
-
const expectedLibDir =
|
|
19232
|
+
const expectedLibDir = resolve19(home, ".local", "lib", "beeline");
|
|
19038
19233
|
const expectedPrefix = `${expectedLibDir}/`;
|
|
19039
|
-
return
|
|
19234
|
+
return resolve19(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve19(invocationPath).startsWith(expectedPrefix);
|
|
19040
19235
|
}
|
|
19041
19236
|
function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
19042
19237
|
if (isCanonicalInstalledLauncher(env, invocationPath))
|
|
@@ -19044,8 +19239,8 @@ function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
|
19044
19239
|
throw new Error("refusing to modify the shared Beeline systemd unit outside the canonical ~/.local/bin/beeline launcher");
|
|
19045
19240
|
}
|
|
19046
19241
|
function systemdUserUnitPath(env = process.env) {
|
|
19047
|
-
const configRoot = env.XDG_CONFIG_HOME?.trim() ||
|
|
19048
|
-
return
|
|
19242
|
+
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve19(homedir8(), ".config");
|
|
19243
|
+
return resolve19(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
|
|
19049
19244
|
}
|
|
19050
19245
|
var runSystemctl = async (args) => {
|
|
19051
19246
|
const result = await execFileAsync4("systemctl", ["--user", ...args], {
|
|
@@ -19063,7 +19258,7 @@ async function installAgentService(publicKey, options = {}) {
|
|
|
19063
19258
|
const content = agentServiceUnit();
|
|
19064
19259
|
const existing = await readFile8(path, "utf8").catch(() => "");
|
|
19065
19260
|
if (existing !== content) {
|
|
19066
|
-
await
|
|
19261
|
+
await mkdir11(dirname7(path), { recursive: true, mode: 448 });
|
|
19067
19262
|
await writeFile7(path, content, { mode: 384 });
|
|
19068
19263
|
}
|
|
19069
19264
|
const run2 = options.run ?? runSystemctl;
|
|
@@ -19236,8 +19431,8 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
19236
19431
|
// apps/body/dist/connect-command.js
|
|
19237
19432
|
import { spawn as spawn5 } from "node:child_process";
|
|
19238
19433
|
import { createHash as createHash6 } from "node:crypto";
|
|
19239
|
-
import { chmod as chmod4, mkdir as
|
|
19240
|
-
import { dirname as dirname10, resolve as
|
|
19434
|
+
import { chmod as chmod4, mkdir as mkdir13, readFile as readFile10, unlink as unlink2, writeFile as writeFile9 } from "node:fs/promises";
|
|
19435
|
+
import { dirname as dirname10, resolve as resolve21 } from "node:path";
|
|
19241
19436
|
import { stdin as stdin3, stdout as stdout4 } from "node:process";
|
|
19242
19437
|
|
|
19243
19438
|
// packages/api-contract/dist/agent-pairing-code.js
|
|
@@ -19820,7 +20015,7 @@ function parseConnectSubscriptions(value) {
|
|
|
19820
20015
|
...new Set((value ?? "").split(",").map((entry) => entry.trim().toLowerCase()).filter(Boolean))
|
|
19821
20016
|
];
|
|
19822
20017
|
}
|
|
19823
|
-
function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl
|
|
20018
|
+
function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl) {
|
|
19824
20019
|
const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
|
|
19825
20020
|
if (!normalizedPairingCode)
|
|
19826
20021
|
throw new Error("invalid pairing code");
|
|
@@ -19831,7 +20026,10 @@ function requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl, eventSu
|
|
|
19831
20026
|
...selection.provider ? { provider: selection.provider } : {},
|
|
19832
20027
|
model: selection.model,
|
|
19833
20028
|
avatar_seed: avatarSeed,
|
|
19834
|
-
|
|
20029
|
+
// This wizard always finishes the join itself (`finishConnectedAgentPairing`,
|
|
20030
|
+
// called once the rename prompt below settles), so the claim must not
|
|
20031
|
+
// join Rooms or announce yet.
|
|
20032
|
+
defer_join: true
|
|
19835
20033
|
}, fetchImpl);
|
|
19836
20034
|
}
|
|
19837
20035
|
async function renameConnectedAgent(baseUrl, pairingCode, name, fetchImpl) {
|
|
@@ -19841,6 +20039,16 @@ async function renameConnectedAgent(baseUrl, pairingCode, name, fetchImpl) {
|
|
|
19841
20039
|
const renamed = await jsonRequest(`${baseUrl}/auth/agent/connect/name`, { pairing_code: normalizedPairingCode, agent_name: name.trim().replace(/\s+/g, " ") }, fetchImpl);
|
|
19842
20040
|
return renamed.agent_name;
|
|
19843
20041
|
}
|
|
20042
|
+
async function finishConnectedAgentPairing(baseUrl, pairingCode, workspaceJoined, eventSubscriptions, fetchImpl) {
|
|
20043
|
+
const normalizedPairingCode = normalizeAgentPairingCode(pairingCode);
|
|
20044
|
+
if (!normalizedPairingCode)
|
|
20045
|
+
throw new Error("invalid pairing code");
|
|
20046
|
+
await jsonRequest(`${baseUrl}/auth/agent/connect/finish`, {
|
|
20047
|
+
pairing_code: normalizedPairingCode,
|
|
20048
|
+
workspace_joined: workspaceJoined,
|
|
20049
|
+
...eventSubscriptions.length ? { event_subscriptions: [...eventSubscriptions] } : {}
|
|
20050
|
+
}, fetchImpl);
|
|
20051
|
+
}
|
|
19844
20052
|
function seededIdentityLine(grant) {
|
|
19845
20053
|
return grant.agent_face ? `${grant.agent_name} the ${grant.agent_face}` : grant.agent_name;
|
|
19846
20054
|
}
|
|
@@ -19858,7 +20066,7 @@ async function installCurrentRelease(fetchImpl) {
|
|
|
19858
20066
|
});
|
|
19859
20067
|
await activateRelease(layout, releaseId);
|
|
19860
20068
|
return {
|
|
19861
|
-
binary:
|
|
20069
|
+
binary: resolve21(layout.binDir, "beeline"),
|
|
19862
20070
|
version: published.version ?? releaseId
|
|
19863
20071
|
};
|
|
19864
20072
|
}
|
|
@@ -19881,7 +20089,7 @@ function providerEnvironment(selection) {
|
|
|
19881
20089
|
};
|
|
19882
20090
|
}
|
|
19883
20091
|
async function writePrivateJson(path, value) {
|
|
19884
|
-
await
|
|
20092
|
+
await mkdir13(dirname10(path), { recursive: true, mode: 448 });
|
|
19885
20093
|
await writeFile9(path, `${JSON.stringify(value, null, 2)}
|
|
19886
20094
|
`, { mode: 384 });
|
|
19887
20095
|
await chmod4(path, 384);
|
|
@@ -19890,8 +20098,8 @@ async function writeProviderEnv(selection, agentPubkey) {
|
|
|
19890
20098
|
const values = providerEnvironment(selection);
|
|
19891
20099
|
if (Object.keys(values).length === 0)
|
|
19892
20100
|
return void 0;
|
|
19893
|
-
const path =
|
|
19894
|
-
await
|
|
20101
|
+
const path = resolve21(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
|
|
20102
|
+
await mkdir13(dirname10(path), { recursive: true, mode: 448 });
|
|
19895
20103
|
const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
|
|
19896
20104
|
await writeFile9(path, `${contents}
|
|
19897
20105
|
`, { mode: 384 });
|
|
@@ -19951,11 +20159,12 @@ async function runConnectWizard(code, fetchImpl, eventSubscriptions, accessPolic
|
|
|
19951
20159
|
});
|
|
19952
20160
|
const selection = await collectConnectWizard(clackPrompts, loadConnectModelCatalog, fileConnectKeyStore, process.env, (input) => verifyProviderKey({ ...input, fetchImpl }));
|
|
19953
20161
|
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
|
|
20162
|
+
const claimed = await brassSpinner("Connecting to your Beeline Workspace\u2026", () => requestConnectGrant(baseUrl, pairingCode, selection, fetchImpl), (connectedGrant) => `Connected to ${connectedGrant.workspace_name}`);
|
|
19955
20163
|
const grant = { ...claimed, agent_name: await confirmSeededName(baseUrl, pairingCode, claimed, fetchImpl) };
|
|
20164
|
+
await finishConnectedAgentPairing(baseUrl, pairingCode, grant.workspace_joined, eventSubscriptions, fetchImpl);
|
|
19956
20165
|
const installedRelease = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl), (release) => `Installed Beeline helper ${release.version}`);
|
|
19957
20166
|
const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
|
|
19958
|
-
const grantPath =
|
|
20167
|
+
const grantPath = resolve21(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
|
|
19959
20168
|
await writePrivateJson(grantPath, {
|
|
19960
20169
|
agentSecretKey: grant.agent_secret_key,
|
|
19961
20170
|
bodySecretKey: grant.body_secret_key,
|
|
@@ -20037,11 +20246,11 @@ async function runConnectFinishCommand(path) {
|
|
|
20037
20246
|
throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
|
|
20038
20247
|
}
|
|
20039
20248
|
try {
|
|
20040
|
-
const grant = JSON.parse(await readFile10(
|
|
20249
|
+
const grant = JSON.parse(await readFile10(resolve21(path), "utf8"));
|
|
20041
20250
|
if (!isDevicePairingGrant(grant))
|
|
20042
20251
|
throw new Error("device connection grant is invalid");
|
|
20043
20252
|
const connected = await completeDevicePairing(grant);
|
|
20044
|
-
await unlink2(
|
|
20253
|
+
await unlink2(resolve21(path));
|
|
20045
20254
|
const providerEnv = grant.llmEnvFile ? await readFile10(grant.llmEnvFile, "utf8").catch(() => "") : "";
|
|
20046
20255
|
const apiKey = (/^OPENROUTER_API_KEY=(\S+)/m.exec(providerEnv)?.[1] ?? "").replace(/^["']|["']$/g, "");
|
|
20047
20256
|
const model = openRouterModelId(grant.model, { OPENROUTER_API_KEY: apiKey });
|
|
@@ -20070,19 +20279,19 @@ init_self_update_manifest();
|
|
|
20070
20279
|
// apps/body/dist/managed-update.js
|
|
20071
20280
|
init_self_update();
|
|
20072
20281
|
import { spawn as spawn6 } from "node:child_process";
|
|
20073
|
-
import { mkdir as
|
|
20074
|
-
import { dirname as dirname12, resolve as
|
|
20282
|
+
import { mkdir as mkdir15, rm as rm6, stat as stat2, writeFile as writeFile11 } from "node:fs/promises";
|
|
20283
|
+
import { dirname as dirname12, resolve as resolve23 } from "node:path";
|
|
20075
20284
|
|
|
20076
20285
|
// apps/body/dist/update-rollback-alert.js
|
|
20077
|
-
import { mkdir as
|
|
20078
|
-
import { dirname as dirname11, resolve as
|
|
20286
|
+
import { mkdir as mkdir14, readFile as readFile11, rename as rename4, writeFile as writeFile10 } from "node:fs/promises";
|
|
20287
|
+
import { dirname as dirname11, resolve as resolve22 } from "node:path";
|
|
20079
20288
|
function updateRollbackAlertPath(runtimeDir) {
|
|
20080
|
-
return
|
|
20289
|
+
return resolve22(runtimeDir, "update-rollback-alert.json");
|
|
20081
20290
|
}
|
|
20082
20291
|
async function writeAlert(runtimeDir, alert) {
|
|
20083
20292
|
const path = updateRollbackAlertPath(runtimeDir);
|
|
20084
20293
|
const staged = `${path}.${process.pid}.tmp`;
|
|
20085
|
-
await
|
|
20294
|
+
await mkdir14(dirname11(path), { recursive: true });
|
|
20086
20295
|
await writeFile10(staged, `${JSON.stringify(alert, null, 2)}
|
|
20087
20296
|
`, { mode: 384 });
|
|
20088
20297
|
await rename4(staged, path);
|
|
@@ -20120,13 +20329,13 @@ var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
|
|
|
20120
20329
|
var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
|
|
20121
20330
|
async function withInstallLock(layout, work, options = {}) {
|
|
20122
20331
|
const now2 = options.now ?? Date.now;
|
|
20123
|
-
const lock =
|
|
20332
|
+
const lock = resolve23(layout.releasesRoot, ".state", "install.lock");
|
|
20124
20333
|
const deadline = now2() + (options.waitMs ?? 1e4);
|
|
20125
|
-
await
|
|
20334
|
+
await mkdir15(dirname12(lock), { recursive: true });
|
|
20126
20335
|
for (; ; ) {
|
|
20127
20336
|
try {
|
|
20128
|
-
await
|
|
20129
|
-
await writeFile11(
|
|
20337
|
+
await mkdir15(lock);
|
|
20338
|
+
await writeFile11(resolve23(lock, "owner"), `${process.pid}
|
|
20130
20339
|
${now2()}
|
|
20131
20340
|
`, "utf8");
|
|
20132
20341
|
break;
|
|
@@ -20249,7 +20458,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
20249
20458
|
if (!attempt || attempt.releaseId !== desiredRelease || attempt.status !== "pending") {
|
|
20250
20459
|
const from = await readInstalledBundleIdentity({
|
|
20251
20460
|
...this.#layout,
|
|
20252
|
-
libDir:
|
|
20461
|
+
libDir: resolve23(this.#layout.releasesRoot, this.#loadedRelease)
|
|
20253
20462
|
}).catch(() => void 0) ?? {};
|
|
20254
20463
|
const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
|
|
20255
20464
|
const record2 = {
|
|
@@ -20536,7 +20745,7 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
|
|
|
20536
20745
|
});
|
|
20537
20746
|
if (!accepted)
|
|
20538
20747
|
return false;
|
|
20539
|
-
await writeFile11(
|
|
20748
|
+
await writeFile11(resolve23(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
|
|
20540
20749
|
readyAt: (options.now ?? Date.now)(),
|
|
20541
20750
|
loadedRelease,
|
|
20542
20751
|
functionalProof: options.functionalProof
|
|
@@ -20741,12 +20950,12 @@ async function runUpdateCommand(args) {
|
|
|
20741
20950
|
init_self_update();
|
|
20742
20951
|
|
|
20743
20952
|
// apps/body/dist/daemon-failure.js
|
|
20744
|
-
import { mkdir as
|
|
20745
|
-
import { dirname as dirname13, resolve as
|
|
20953
|
+
import { mkdir as mkdir16, readFile as readFile12, rename as rename5, rm as rm7, writeFile as writeFile12 } from "node:fs/promises";
|
|
20954
|
+
import { dirname as dirname13, resolve as resolve24 } from "node:path";
|
|
20746
20955
|
var DAEMON_FAILURE_LIMIT = 3;
|
|
20747
20956
|
var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
20748
20957
|
function daemonFailurePath(runtimeDir) {
|
|
20749
|
-
return
|
|
20958
|
+
return resolve24(runtimeDir, "daemon-distress.json");
|
|
20750
20959
|
}
|
|
20751
20960
|
async function readFailureRecord(runtimeDir) {
|
|
20752
20961
|
try {
|
|
@@ -20762,7 +20971,7 @@ async function readFailureRecord(runtimeDir) {
|
|
|
20762
20971
|
async function writeFailureRecord(runtimeDir, record2) {
|
|
20763
20972
|
const path = daemonFailurePath(runtimeDir);
|
|
20764
20973
|
const staged = `${path}.${process.pid}.tmp`;
|
|
20765
|
-
await
|
|
20974
|
+
await mkdir16(dirname13(path), { recursive: true, mode: 448 });
|
|
20766
20975
|
await writeFile12(staged, `${JSON.stringify(record2, null, 2)}
|
|
20767
20976
|
`, { mode: 384 });
|
|
20768
20977
|
await rename5(staged, path);
|
|
@@ -20785,9 +20994,9 @@ async function clearDaemonStartFailures(runtimeDir) {
|
|
|
20785
20994
|
}
|
|
20786
20995
|
|
|
20787
20996
|
// apps/body/dist/update-functional-probe.js
|
|
20788
|
-
import { mkdir as
|
|
20997
|
+
import { mkdir as mkdir17, rm as rm8 } from "node:fs/promises";
|
|
20789
20998
|
import { homedir as homedir10 } from "node:os";
|
|
20790
|
-
import { resolve as
|
|
20999
|
+
import { resolve as resolve25 } from "node:path";
|
|
20791
21000
|
var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
|
|
20792
21001
|
var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
|
|
20793
21002
|
var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
|
|
@@ -20833,11 +21042,11 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
20833
21042
|
if (input.sandboxRequired && !input.config.bwrapPath) {
|
|
20834
21043
|
throw new UpdateFunctionalProbeError("sandbox-unavailable", "the configured bubblewrap boundary did not pass its startup self-test");
|
|
20835
21044
|
}
|
|
20836
|
-
const root = input.probeRoot ??
|
|
20837
|
-
const cwd =
|
|
20838
|
-
const homeRoot =
|
|
21045
|
+
const root = input.probeRoot ?? resolve25(input.runtimeDir, "update-functional-probe");
|
|
21046
|
+
const cwd = resolve25(root, "checkout");
|
|
21047
|
+
const homeRoot = resolve25(root, "agent-home");
|
|
20839
21048
|
await rm8(root, { recursive: true, force: true });
|
|
20840
|
-
await
|
|
21049
|
+
await mkdir17(cwd, { recursive: true, mode: 448 });
|
|
20841
21050
|
let client;
|
|
20842
21051
|
try {
|
|
20843
21052
|
const agentEnv = {
|
|
@@ -20866,7 +21075,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
20866
21075
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
20867
21076
|
const operatorHome = input.config.operatorHome ?? homedir10();
|
|
20868
21077
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
20869
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
21078
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir17(dir, { recursive: true })));
|
|
20870
21079
|
spawnCommand = wrapAgentCommand({
|
|
20871
21080
|
bwrapPath: input.config.bwrapPath,
|
|
20872
21081
|
spec: {
|
|
@@ -21002,7 +21211,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
21002
21211
|
return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
|
|
21003
21212
|
}
|
|
21004
21213
|
const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
|
|
21005
|
-
return new Promise((
|
|
21214
|
+
return new Promise((resolve28) => {
|
|
21006
21215
|
const child = spawn7(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
21007
21216
|
let stdout6 = "";
|
|
21008
21217
|
let stderr = "";
|
|
@@ -21012,7 +21221,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
21012
21221
|
return;
|
|
21013
21222
|
settled = true;
|
|
21014
21223
|
clearTimeout(timer);
|
|
21015
|
-
|
|
21224
|
+
resolve28(outcome);
|
|
21016
21225
|
};
|
|
21017
21226
|
const timer = setTimeout(() => {
|
|
21018
21227
|
child.kill("SIGKILL");
|
|
@@ -21092,7 +21301,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
21092
21301
|
|
|
21093
21302
|
// apps/body/dist/release-status.js
|
|
21094
21303
|
import { readFile as readFile13, readdir as readdir5, rename as rename6, writeFile as writeFile13 } from "node:fs/promises";
|
|
21095
|
-
import { resolve as
|
|
21304
|
+
import { resolve as resolve26 } from "node:path";
|
|
21096
21305
|
var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
|
|
21097
21306
|
var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
|
|
21098
21307
|
var SOURCE_SHA = /^[0-9a-f]{7,64}$/;
|
|
@@ -21109,7 +21318,7 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
21109
21318
|
pid: options.pid ?? process.pid,
|
|
21110
21319
|
readyAt: (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
|
|
21111
21320
|
};
|
|
21112
|
-
const target =
|
|
21321
|
+
const target = resolve26(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
|
|
21113
21322
|
const temporary = `${target}.${status.pid}.tmp`;
|
|
21114
21323
|
await writeFile13(temporary, `${JSON.stringify(status, null, 2)}
|
|
21115
21324
|
`, { mode: 384 });
|
|
@@ -21169,7 +21378,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21169
21378
|
runtime = activated.runtime;
|
|
21170
21379
|
const daemonApi = activated.client;
|
|
21171
21380
|
const agent = runtimeAgentCommand(runtime);
|
|
21172
|
-
await writeFile14(
|
|
21381
|
+
await writeFile14(resolve27(dirname15(configPath), "daemon.pid"), `${process.pid}
|
|
21173
21382
|
`, { mode: 384 });
|
|
21174
21383
|
const env = {
|
|
21175
21384
|
...process.env,
|
|
@@ -21177,7 +21386,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21177
21386
|
BUZZ_DEV_MCP_BIN: runtime.mcpBinary
|
|
21178
21387
|
};
|
|
21179
21388
|
const config = loadBodyConfig({
|
|
21180
|
-
workspaceRoot:
|
|
21389
|
+
workspaceRoot: resolve27(dirname15(configPath), "workspace"),
|
|
21181
21390
|
llmEnvFile: runtime.llmEnvFile,
|
|
21182
21391
|
env,
|
|
21183
21392
|
agent
|
|
@@ -21347,7 +21556,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21347
21556
|
throw error;
|
|
21348
21557
|
} finally {
|
|
21349
21558
|
await notifier.stopping(stoppingStatus).catch(() => void 0);
|
|
21350
|
-
const pidPath =
|
|
21559
|
+
const pidPath = resolve27(dirname15(configPath), "daemon.pid");
|
|
21351
21560
|
const recorded = Number((await readFile14(pidPath, "utf8").catch(() => "")).trim());
|
|
21352
21561
|
if (recorded === process.pid) {
|
|
21353
21562
|
await unlink3(pidPath).catch(() => void 0);
|
|
@@ -21422,7 +21631,7 @@ async function main() {
|
|
|
21422
21631
|
}
|
|
21423
21632
|
if (!configPath)
|
|
21424
21633
|
throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
|
|
21425
|
-
await runStoredDaemon(
|
|
21634
|
+
await runStoredDaemon(resolve27(configPath));
|
|
21426
21635
|
return;
|
|
21427
21636
|
}
|
|
21428
21637
|
if (command === "update") {
|