usebeeline 0.0.49 → 0.0.52
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 +357 -153
- 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";
|
|
@@ -14141,6 +14141,39 @@ import { basename as basename3, dirname as dirname5, join as join3, relative as
|
|
|
14141
14141
|
// apps/body/dist/beeline-skill.js
|
|
14142
14142
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
14143
14143
|
import { resolve as resolve11 } from "node:path";
|
|
14144
|
+
|
|
14145
|
+
// packages/api-contract/dist/system-events.js
|
|
14146
|
+
var SERVER_EVENT_KINDS = [
|
|
14147
|
+
"joined",
|
|
14148
|
+
"schedule-ran",
|
|
14149
|
+
"corner-opened",
|
|
14150
|
+
"check-passed",
|
|
14151
|
+
"check-failed",
|
|
14152
|
+
"merged",
|
|
14153
|
+
"grant-decided"
|
|
14154
|
+
];
|
|
14155
|
+
function isServerEventKind(value) {
|
|
14156
|
+
return SERVER_EVENT_KINDS.includes(value);
|
|
14157
|
+
}
|
|
14158
|
+
var RESUME_KINDS = ["grant-decided"];
|
|
14159
|
+
function isResumeKind(value) {
|
|
14160
|
+
return RESUME_KINDS.includes(value);
|
|
14161
|
+
}
|
|
14162
|
+
|
|
14163
|
+
// packages/api-contract/dist/agent-pairing-code.js
|
|
14164
|
+
var CURRENT_AGENT_PAIRING_CODE = /^[0-9A-F]{8}-[0-9A-F]{8}$/;
|
|
14165
|
+
var LEGACY_AGENT_PAIRING_CODE = /^BUZZ-(?:[0-9A-F]{8}-[0-9A-F]{8}|[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4})$/;
|
|
14166
|
+
function normalizeAgentPairingCode(value) {
|
|
14167
|
+
if (typeof value !== "string")
|
|
14168
|
+
return void 0;
|
|
14169
|
+
const normalized = value.trim().toUpperCase();
|
|
14170
|
+
return isAgentPairingCode(normalized) ? normalized : void 0;
|
|
14171
|
+
}
|
|
14172
|
+
function isAgentPairingCode(value) {
|
|
14173
|
+
return typeof value === "string" && (CURRENT_AGENT_PAIRING_CODE.test(value) || LEGACY_AGENT_PAIRING_CODE.test(value));
|
|
14174
|
+
}
|
|
14175
|
+
|
|
14176
|
+
// apps/body/dist/beeline-skill.js
|
|
14144
14177
|
var USING_BEELINE_SKILL_NAME = "using-beeline";
|
|
14145
14178
|
var BEELINE_ROOM_CAPABILITIES = [
|
|
14146
14179
|
"The repository filesystem is read-only in this Room session.",
|
|
@@ -14151,7 +14184,7 @@ var BEELINE_ROOM_CAPABILITIES = [
|
|
|
14151
14184
|
"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
14185
|
"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
14186
|
"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
|
-
|
|
14187
|
+
`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 (${SERVER_EVENT_KINDS.join(", ")}); 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. grant-decided carries the grant id and status and resumes the turn that asked for the grant.`,
|
|
14155
14188
|
"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.",
|
|
14156
14189
|
"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.",
|
|
14157
14190
|
"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.",
|
|
@@ -15111,6 +15144,7 @@ async function resolveSharedSkillSources(operatorHome, names) {
|
|
|
15111
15144
|
return resolveExplicitSkillSources(operatorHome, names);
|
|
15112
15145
|
const seen = /* @__PURE__ */ new Set();
|
|
15113
15146
|
const resolved = [];
|
|
15147
|
+
const skipped = [];
|
|
15114
15148
|
for (const relativeRoot of OPERATOR_SKILL_SOURCE_DIRS) {
|
|
15115
15149
|
const sourceRoot = resolve13(operatorHome, relativeRoot);
|
|
15116
15150
|
const rootStats = await lstat(sourceRoot).catch(() => void 0);
|
|
@@ -15122,23 +15156,61 @@ async function resolveSharedSkillSources(operatorHome, names) {
|
|
|
15122
15156
|
const candidate = resolve13(sourceRoot, entry);
|
|
15123
15157
|
try {
|
|
15124
15158
|
const candidateStats = await lstat(candidate);
|
|
15125
|
-
if (
|
|
15159
|
+
if (candidateStats.isSymbolicLink()) {
|
|
15160
|
+
const reason = await realpath(candidate).then(() => "symlinked directory", (error) => isMissingPathError(error) ? "dangling symlink" : "symlinked directory");
|
|
15161
|
+
skipped.push({
|
|
15162
|
+
path: candidate,
|
|
15163
|
+
reason
|
|
15164
|
+
});
|
|
15165
|
+
continue;
|
|
15166
|
+
}
|
|
15167
|
+
if (!candidateStats.isDirectory()) {
|
|
15168
|
+
skipped.push({ path: candidate, reason: "not an ordinary directory" });
|
|
15126
15169
|
continue;
|
|
15170
|
+
}
|
|
15127
15171
|
assertContained(sourceRoot, candidate);
|
|
15128
15172
|
const skillMd = resolve13(candidate, "SKILL.md");
|
|
15129
|
-
const skillStats = await lstat(skillMd)
|
|
15173
|
+
const skillStats = await lstat(skillMd).catch((error) => {
|
|
15174
|
+
if (isMissingPathError(error)) {
|
|
15175
|
+
skipped.push({ path: candidate, reason: "missing SKILL.md" });
|
|
15176
|
+
return void 0;
|
|
15177
|
+
}
|
|
15178
|
+
throw error;
|
|
15179
|
+
});
|
|
15180
|
+
if (!skillStats)
|
|
15181
|
+
continue;
|
|
15130
15182
|
if (!skillStats.isFile() || skillStats.isSymbolicLink() || skillStats.nlink !== 1) {
|
|
15131
|
-
|
|
15183
|
+
skipped.push({ path: candidate, reason: "SKILL.md is not an ordinary file" });
|
|
15184
|
+
continue;
|
|
15132
15185
|
}
|
|
15133
15186
|
seen.add(entry);
|
|
15134
15187
|
resolved.push({ name: entry, source: candidate });
|
|
15135
15188
|
} catch (error) {
|
|
15189
|
+
if (isMissingPathError(error)) {
|
|
15190
|
+
skipped.push({ path: candidate, reason: "missing during discovery" });
|
|
15191
|
+
continue;
|
|
15192
|
+
}
|
|
15136
15193
|
console.warn(`[body] skipping operator skill ${entry}:`, error);
|
|
15137
15194
|
}
|
|
15138
15195
|
}
|
|
15139
15196
|
}
|
|
15197
|
+
logSkippedOperatorSkills(skipped);
|
|
15140
15198
|
return resolved;
|
|
15141
15199
|
}
|
|
15200
|
+
function isMissingPathError(error) {
|
|
15201
|
+
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
15202
|
+
}
|
|
15203
|
+
function logSkippedOperatorSkills(skipped) {
|
|
15204
|
+
const totals = /* @__PURE__ */ new Map();
|
|
15205
|
+
for (const { path, reason } of skipped) {
|
|
15206
|
+
console.warn(`[body] skipping operator skill ${path}: ${reason}`);
|
|
15207
|
+
totals.set(reason, (totals.get(reason) ?? 0) + 1);
|
|
15208
|
+
}
|
|
15209
|
+
for (const [reason, count] of totals) {
|
|
15210
|
+
if (count > 1)
|
|
15211
|
+
console.warn(`[body] ${count} skill entries skipped: ${reason}`);
|
|
15212
|
+
}
|
|
15213
|
+
}
|
|
15142
15214
|
async function resolveExplicitSkillSources(operatorHome, names) {
|
|
15143
15215
|
const unique = [...new Set(names)];
|
|
15144
15216
|
for (const name of unique) {
|
|
@@ -16610,6 +16682,57 @@ var TurnTraceFile = class {
|
|
|
16610
16682
|
}
|
|
16611
16683
|
};
|
|
16612
16684
|
|
|
16685
|
+
// apps/body/dist/corner-github-auth.js
|
|
16686
|
+
import { chmod as chmod3, mkdir as mkdir8, writeFile as writeFile7 } from "node:fs/promises";
|
|
16687
|
+
import { delimiter as delimiter2, resolve as resolve18 } from "node:path";
|
|
16688
|
+
async function installCornerGitHubWrappers(input) {
|
|
16689
|
+
const bin = resolve18(input.root, "beeline-github-bin");
|
|
16690
|
+
await mkdir8(bin, { recursive: true, mode: 448 });
|
|
16691
|
+
const common = {
|
|
16692
|
+
node: process.execPath,
|
|
16693
|
+
cli: input.cliEntrypoint,
|
|
16694
|
+
config: input.runtimeConfigPath,
|
|
16695
|
+
room: input.roomId
|
|
16696
|
+
};
|
|
16697
|
+
await writeLauncher(resolve18(bin, "git"), { ...common, command: input.gitBinary });
|
|
16698
|
+
if (input.ghBinary)
|
|
16699
|
+
await writeLauncher(resolve18(bin, "gh"), { ...common, command: input.ghBinary });
|
|
16700
|
+
return {
|
|
16701
|
+
PATH: [bin, input.inheritedPath].filter(Boolean).join(delimiter2),
|
|
16702
|
+
// Static startup tokens take precedence over the refreshed token in gh.
|
|
16703
|
+
GH_TOKEN: "",
|
|
16704
|
+
GITHUB_TOKEN: ""
|
|
16705
|
+
};
|
|
16706
|
+
}
|
|
16707
|
+
async function writeLauncher(path, config) {
|
|
16708
|
+
const source = `#!/usr/bin/env node
|
|
16709
|
+
import { spawnSync } from 'node:child_process';
|
|
16710
|
+
const config = ${JSON.stringify(config)};
|
|
16711
|
+
const authFailure = /(?:authentication failed|bad credentials|could not read username|http(?:\\/\\d(?:\\.\\d)?)? 40[13]|status (?:code )?40[13])/i;
|
|
16712
|
+
function token() {
|
|
16713
|
+
const result = spawnSync(config.node, [config.cli, 'corner-read-token', '--config', config.config, '--room', config.room], { encoding: 'utf8' });
|
|
16714
|
+
if (result.status !== 0) {
|
|
16715
|
+
process.stderr.write(result.stderr || 'Beeline could not refresh the repository credential.\\n');
|
|
16716
|
+
process.exit(result.status || 1);
|
|
16717
|
+
}
|
|
16718
|
+
return result.stdout.trim();
|
|
16719
|
+
}
|
|
16720
|
+
function run(value) {
|
|
16721
|
+
const env = { ...process.env, GH_TOKEN: value, GITHUB_TOKEN: value, GIT_TERMINAL_PROMPT: '0' };
|
|
16722
|
+
return spawnSync(config.command, process.argv.slice(2), { env, encoding: 'buffer', stdio: ['inherit', 'pipe', 'pipe'] });
|
|
16723
|
+
}
|
|
16724
|
+
let result = run(token());
|
|
16725
|
+
const diagnostic = Buffer.concat([result.stdout || Buffer.alloc(0), result.stderr || Buffer.alloc(0)]).toString('utf8');
|
|
16726
|
+
if (result.status !== 0 && authFailure.test(diagnostic)) result = run(token());
|
|
16727
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
16728
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
16729
|
+
if (result.error) throw result.error;
|
|
16730
|
+
process.exit(result.status ?? 1);
|
|
16731
|
+
`;
|
|
16732
|
+
await writeFile7(path, source, { mode: 448 });
|
|
16733
|
+
await chmod3(path, 448);
|
|
16734
|
+
}
|
|
16735
|
+
|
|
16613
16736
|
// apps/body/dist/monolith-corner-turn.js
|
|
16614
16737
|
var execFileAsync2 = promisify2(execFile3);
|
|
16615
16738
|
var TOOL_ARGUMENT_MAX_BYTES = 1200;
|
|
@@ -16866,7 +16989,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
16866
16989
|
soul: configuration.soul ?? self?.soul,
|
|
16867
16990
|
agentName: self?.name ?? this.agent.name
|
|
16868
16991
|
});
|
|
16869
|
-
await
|
|
16992
|
+
await mkdir9(this.options.worktreePath, { recursive: true });
|
|
16870
16993
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
16871
16994
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
16872
16995
|
root: this.options.config.agentHomeRoot,
|
|
@@ -16883,11 +17006,27 @@ var MonolithCornerTurnLoop = class {
|
|
|
16883
17006
|
})
|
|
16884
17007
|
}) : {};
|
|
16885
17008
|
const command = this.options.config.agentCommand ?? this.options.config.agentBinary;
|
|
17009
|
+
let githubEnv = {
|
|
17010
|
+
GH_TOKEN: this.options.githubToken,
|
|
17011
|
+
GITHUB_TOKEN: this.options.githubToken
|
|
17012
|
+
};
|
|
17013
|
+
if (this.options.config.runtimeConfigPath && this.options.config.agentHomeRoot) {
|
|
17014
|
+
const gitBinary = (await execFileAsync2("which", ["git"])).stdout.trim();
|
|
17015
|
+
const ghBinary = await execFileAsync2("which", ["gh"]).then((result) => result.stdout.trim()).catch(() => void 0);
|
|
17016
|
+
githubEnv = await installCornerGitHubWrappers({
|
|
17017
|
+
root: this.options.config.agentHomeRoot,
|
|
17018
|
+
runtimeConfigPath: this.options.config.runtimeConfigPath,
|
|
17019
|
+
roomId: this.options.parentRoomId,
|
|
17020
|
+
cliEntrypoint: process.argv[1],
|
|
17021
|
+
gitBinary,
|
|
17022
|
+
...ghBinary ? { ghBinary } : {},
|
|
17023
|
+
inheritedPath: this.options.config.agentEnv.PATH ?? process.env.PATH
|
|
17024
|
+
});
|
|
17025
|
+
}
|
|
16886
17026
|
const agentEnv = {
|
|
16887
17027
|
...this.options.config.agentEnv,
|
|
16888
17028
|
...homeOverlay,
|
|
16889
|
-
|
|
16890
|
-
GITHUB_TOKEN: this.options.githubToken
|
|
17029
|
+
...githubEnv
|
|
16891
17030
|
};
|
|
16892
17031
|
this.agentEnv = agentEnv;
|
|
16893
17032
|
const agentArgs = agentArgsWithModelSelection({
|
|
@@ -16900,7 +17039,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
16900
17039
|
this.attachmentDir = tmpDir ? join5(tmpDir, "beeline-attachments") : void 0;
|
|
16901
17040
|
this.sessionScratchDir = tmpDir;
|
|
16902
17041
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
16903
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
17042
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir9(dir, { recursive: true })));
|
|
16904
17043
|
const spawnCommand = wrapAgentCommand({
|
|
16905
17044
|
bwrapPath: this.options.config.bwrapPath,
|
|
16906
17045
|
spec: {
|
|
@@ -17336,7 +17475,7 @@ async function wait(ms, signal) {
|
|
|
17336
17475
|
}
|
|
17337
17476
|
|
|
17338
17477
|
// apps/body/dist/monolith-room-turn.js
|
|
17339
|
-
import { mkdir as
|
|
17478
|
+
import { mkdir as mkdir10 } from "node:fs/promises";
|
|
17340
17479
|
import { homedir as homedir7 } from "node:os";
|
|
17341
17480
|
import { join as join6 } from "node:path";
|
|
17342
17481
|
|
|
@@ -17344,24 +17483,6 @@ import { join as join6 } from "node:path";
|
|
|
17344
17483
|
var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
|
|
17345
17484
|
var SCHEDULE_RAN_VERB = "ran a schedule for";
|
|
17346
17485
|
|
|
17347
|
-
// packages/api-contract/dist/system-events.js
|
|
17348
|
-
var SERVER_EVENT_KINDS = [
|
|
17349
|
-
"joined",
|
|
17350
|
-
"schedule-ran",
|
|
17351
|
-
"corner-opened",
|
|
17352
|
-
"check-passed",
|
|
17353
|
-
"check-failed",
|
|
17354
|
-
"merged",
|
|
17355
|
-
"grant-decided"
|
|
17356
|
-
];
|
|
17357
|
-
function isServerEventKind(value) {
|
|
17358
|
-
return SERVER_EVENT_KINDS.includes(value);
|
|
17359
|
-
}
|
|
17360
|
-
var RESUME_KINDS = ["grant-decided"];
|
|
17361
|
-
function isResumeKind(value) {
|
|
17362
|
-
return RESUME_KINDS.includes(value);
|
|
17363
|
-
}
|
|
17364
|
-
|
|
17365
17486
|
// apps/body/dist/monolith-room-turn.js
|
|
17366
17487
|
function isRoomMcpPermissionRequest(request, mountedServers = ROOM_MOUNTED_MCP_SERVERS) {
|
|
17367
17488
|
if (isSquireMcpPermissionRequest(request))
|
|
@@ -17434,6 +17555,15 @@ function agentReplyMentionIds(text2, roster, authorId) {
|
|
|
17434
17555
|
aliases.set(key, entry);
|
|
17435
17556
|
}
|
|
17436
17557
|
}
|
|
17558
|
+
for (const member of roster.members) {
|
|
17559
|
+
if (member.identityId === authorId || !member.handle)
|
|
17560
|
+
continue;
|
|
17561
|
+
const handle = member.handle.trim().replace(/^@/, "").toLocaleLowerCase();
|
|
17562
|
+
const canonical = aliases.get(handle);
|
|
17563
|
+
const legacy = `a_${handle}`;
|
|
17564
|
+
if (canonical && !aliases.has(legacy))
|
|
17565
|
+
aliases.set(legacy, { ...canonical, display: legacy });
|
|
17566
|
+
}
|
|
17437
17567
|
const mentioned = [];
|
|
17438
17568
|
for (const { display, ids } of [...aliases.values()].sort((left, right) => right.display.length - left.display.length)) {
|
|
17439
17569
|
if (ids.size !== 1)
|
|
@@ -17651,7 +17781,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
17651
17781
|
agentName: self?.name ?? this.agent.name
|
|
17652
17782
|
});
|
|
17653
17783
|
const directMessage = Array.isArray(repositoryState.directParticipants) && repositoryState.directParticipants.length === 2;
|
|
17654
|
-
await
|
|
17784
|
+
await mkdir10(this.options.cwd, { recursive: true });
|
|
17655
17785
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
17656
17786
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
17657
17787
|
root: this.options.config.agentHomeRoot,
|
|
@@ -17681,7 +17811,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
17681
17811
|
this.sessionScratchDir = tmpDir;
|
|
17682
17812
|
this.sessionStateDirs = stateDirs;
|
|
17683
17813
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
17684
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
17814
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir10(dir, { recursive: true })));
|
|
17685
17815
|
const spawnCommand = wrapAgentCommand({
|
|
17686
17816
|
bwrapPath: this.options.config.bwrapPath,
|
|
17687
17817
|
spec: {
|
|
@@ -18730,13 +18860,13 @@ var RoomRuntimeCoordinator = class {
|
|
|
18730
18860
|
return this.runtime.rooms.find((room) => room.channelId === roomId);
|
|
18731
18861
|
}
|
|
18732
18862
|
roomRoot(roomId) {
|
|
18733
|
-
return this.roomRecord(roomId)?.root ??
|
|
18863
|
+
return this.roomRecord(roomId)?.root ?? resolve19(dirname6(this.configPath), "rooms", roomId);
|
|
18734
18864
|
}
|
|
18735
18865
|
roomAgentHomeRoot(workspaceRoot, required = false) {
|
|
18736
18866
|
const flag = process.env.BUZZY_BODY_ROOM_HOME;
|
|
18737
18867
|
if (!required && flag === "0")
|
|
18738
18868
|
return void 0;
|
|
18739
|
-
const home =
|
|
18869
|
+
const home = resolve19(workspaceRoot, "agent-home");
|
|
18740
18870
|
if (!required && flag !== "1" && !existsSync4(home) && existsSync4(workspaceRoot))
|
|
18741
18871
|
return void 0;
|
|
18742
18872
|
try {
|
|
@@ -18753,8 +18883,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
18753
18883
|
return {
|
|
18754
18884
|
...this.baseConfig,
|
|
18755
18885
|
workspaceRoot,
|
|
18756
|
-
agentPrivateRoot:
|
|
18757
|
-
agentMemoryRoot:
|
|
18886
|
+
agentPrivateRoot: resolve19(workspaceRoot, "agent-private"),
|
|
18887
|
+
agentMemoryRoot: resolve19(dirname6(this.configPath), "memory"),
|
|
18758
18888
|
openRouterRoutingCacheDir: openRouterRoutingCacheDir(dirname6(this.configPath)),
|
|
18759
18889
|
turnTraceDir: turnTraceDirectory(dirname6(this.configPath)),
|
|
18760
18890
|
...agentHomeRoot ? { agentHomeRoot } : {}
|
|
@@ -18823,11 +18953,11 @@ var RoomRuntimeCoordinator = class {
|
|
|
18823
18953
|
const remote = roomCheckoutRemote(repository.remote);
|
|
18824
18954
|
const targetBranch = repository.targetBranch || "main";
|
|
18825
18955
|
const checkoutId = createHash4("sha256").update(`${remote}\0${targetBranch}`).digest("hex").slice(0, 24);
|
|
18826
|
-
const path =
|
|
18827
|
-
await
|
|
18956
|
+
const path = resolve19(this.runtime.supervisorRoot, "beeline", "room-checkouts", checkoutId);
|
|
18957
|
+
await mkdir11(dirname6(path), { recursive: true, mode: 448 });
|
|
18828
18958
|
const token = remote.startsWith("https://github.com/") ? await this.options.daemonApi.execute("getRoomGitHubToken", { roomId }) : void 0;
|
|
18829
18959
|
const env = token ? githubGitEnv(token.token) : process.env;
|
|
18830
|
-
if (!existsSync4(
|
|
18960
|
+
if (!existsSync4(resolve19(path, ".git"))) {
|
|
18831
18961
|
await execFileAsync3("git", ["clone", "--no-checkout", remote, path], {
|
|
18832
18962
|
env,
|
|
18833
18963
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -18952,12 +19082,12 @@ var RoomRuntimeCoordinator = class {
|
|
|
18952
19082
|
async materializeCornerWorktree(input) {
|
|
18953
19083
|
const remote = githubHttpsRemote(input.remote);
|
|
18954
19084
|
const repositoryHash = createHash4("sha256").update(remote).digest("hex").slice(0, 24);
|
|
18955
|
-
const gitCommonDir =
|
|
18956
|
-
const path =
|
|
18957
|
-
await
|
|
18958
|
-
await
|
|
19085
|
+
const gitCommonDir = resolve19(this.runtime.supervisorRoot, "beeline", "repositories", `${repositoryHash}.git`);
|
|
19086
|
+
const path = resolve19(this.runtime.supervisorRoot, "beeline", "corners", input.cornerId);
|
|
19087
|
+
await mkdir11(dirname6(gitCommonDir), { recursive: true, mode: 448 });
|
|
19088
|
+
await mkdir11(dirname6(path), { recursive: true, mode: 448 });
|
|
18959
19089
|
const authEnv = githubGitEnv(input.token);
|
|
18960
|
-
if (!existsSync4(
|
|
19090
|
+
if (!existsSync4(resolve19(gitCommonDir, "HEAD"))) {
|
|
18961
19091
|
await execFileAsync3("git", ["clone", "--bare", remote, gitCommonDir], {
|
|
18962
19092
|
env: authEnv,
|
|
18963
19093
|
maxBuffer: 4 * 1024 * 1024
|
|
@@ -18970,7 +19100,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
18970
19100
|
"origin",
|
|
18971
19101
|
`+refs/heads/${input.targetBranch}:refs/remotes/origin/${input.targetBranch}`
|
|
18972
19102
|
], { env: authEnv, maxBuffer: 4 * 1024 * 1024 });
|
|
18973
|
-
if (!existsSync4(
|
|
19103
|
+
if (!existsSync4(resolve19(path, ".git"))) {
|
|
18974
19104
|
await rm4(path, { recursive: true, force: true });
|
|
18975
19105
|
await execFileAsync3("git", [
|
|
18976
19106
|
`--git-dir=${gitCommonDir}`,
|
|
@@ -19007,7 +19137,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
19007
19137
|
`${this.agent.publicKey.slice(0, 16)}@users.noreply.github.com`
|
|
19008
19138
|
]);
|
|
19009
19139
|
const top = await execFileAsync3("git", ["-C", path, "rev-parse", "--show-toplevel"]);
|
|
19010
|
-
if (
|
|
19140
|
+
if (resolve19(top.stdout.trim()) !== resolve19(path)) {
|
|
19011
19141
|
throw new Error(`corner worktree escaped its isolated root: ${top.stdout.trim()}`);
|
|
19012
19142
|
}
|
|
19013
19143
|
return { path, gitCommonDir };
|
|
@@ -19185,9 +19315,9 @@ var ThinDaemonCore = class {
|
|
|
19185
19315
|
|
|
19186
19316
|
// apps/body/dist/systemd.js
|
|
19187
19317
|
import { execFile as execFile5 } from "node:child_process";
|
|
19188
|
-
import { mkdir as
|
|
19318
|
+
import { mkdir as mkdir12, readFile as readFile8, writeFile as writeFile8 } from "node:fs/promises";
|
|
19189
19319
|
import { homedir as homedir8 } from "node:os";
|
|
19190
|
-
import { dirname as dirname7, resolve as
|
|
19320
|
+
import { dirname as dirname7, resolve as resolve20 } from "node:path";
|
|
19191
19321
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
19192
19322
|
import { promisify as promisify4 } from "node:util";
|
|
19193
19323
|
var execFileAsync4 = promisify4(execFile5);
|
|
@@ -19229,9 +19359,9 @@ WantedBy=default.target
|
|
|
19229
19359
|
}
|
|
19230
19360
|
function isCanonicalInstalledLauncher(env = process.env, invocationPath = process.argv[1]) {
|
|
19231
19361
|
const home = env.HOME?.trim() || homedir8();
|
|
19232
|
-
const expectedLibDir =
|
|
19362
|
+
const expectedLibDir = resolve20(home, ".local", "lib", "beeline");
|
|
19233
19363
|
const expectedPrefix = `${expectedLibDir}/`;
|
|
19234
|
-
return
|
|
19364
|
+
return resolve20(env.BEELINE_LIB_DIR?.trim() || "/") === expectedLibDir && Boolean(invocationPath) && resolve20(invocationPath).startsWith(expectedPrefix);
|
|
19235
19365
|
}
|
|
19236
19366
|
function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
19237
19367
|
if (isCanonicalInstalledLauncher(env, invocationPath))
|
|
@@ -19239,8 +19369,8 @@ function assertCanonicalInstalledLauncher(env, invocationPath) {
|
|
|
19239
19369
|
throw new Error("refusing to modify the shared Beeline systemd unit outside the canonical ~/.local/bin/beeline launcher");
|
|
19240
19370
|
}
|
|
19241
19371
|
function systemdUserUnitPath(env = process.env) {
|
|
19242
|
-
const configRoot = env.XDG_CONFIG_HOME?.trim() ||
|
|
19243
|
-
return
|
|
19372
|
+
const configRoot = env.XDG_CONFIG_HOME?.trim() || resolve20(homedir8(), ".config");
|
|
19373
|
+
return resolve20(configRoot, "systemd", "user", SYSTEMD_UNIT_NAME);
|
|
19244
19374
|
}
|
|
19245
19375
|
var runSystemctl = async (args) => {
|
|
19246
19376
|
const result = await execFileAsync4("systemctl", ["--user", ...args], {
|
|
@@ -19258,8 +19388,8 @@ async function installAgentService(publicKey, options = {}) {
|
|
|
19258
19388
|
const content = agentServiceUnit();
|
|
19259
19389
|
const existing = await readFile8(path, "utf8").catch(() => "");
|
|
19260
19390
|
if (existing !== content) {
|
|
19261
|
-
await
|
|
19262
|
-
await
|
|
19391
|
+
await mkdir12(dirname7(path), { recursive: true, mode: 448 });
|
|
19392
|
+
await writeFile8(path, content, { mode: 384 });
|
|
19263
19393
|
}
|
|
19264
19394
|
const run2 = options.run ?? runSystemctl;
|
|
19265
19395
|
await run2(["daemon-reload"]);
|
|
@@ -19431,23 +19561,10 @@ async function runStartCommand(args, interactiveUi) {
|
|
|
19431
19561
|
// apps/body/dist/connect-command.js
|
|
19432
19562
|
import { spawn as spawn5 } from "node:child_process";
|
|
19433
19563
|
import { createHash as createHash6 } from "node:crypto";
|
|
19434
|
-
import { chmod as
|
|
19435
|
-
import { dirname as dirname10, resolve as
|
|
19564
|
+
import { chmod as chmod5, mkdir as mkdir14, readFile as readFile10, unlink as unlink2, writeFile as writeFile10 } from "node:fs/promises";
|
|
19565
|
+
import { dirname as dirname10, resolve as resolve22 } from "node:path";
|
|
19436
19566
|
import { stdin as stdin3, stdout as stdout4 } from "node:process";
|
|
19437
19567
|
|
|
19438
|
-
// packages/api-contract/dist/agent-pairing-code.js
|
|
19439
|
-
var CURRENT_AGENT_PAIRING_CODE = /^[0-9A-F]{8}-[0-9A-F]{8}$/;
|
|
19440
|
-
var LEGACY_AGENT_PAIRING_CODE = /^BUZZ-(?:[0-9A-F]{8}-[0-9A-F]{8}|[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4})$/;
|
|
19441
|
-
function normalizeAgentPairingCode(value) {
|
|
19442
|
-
if (typeof value !== "string")
|
|
19443
|
-
return void 0;
|
|
19444
|
-
const normalized = value.trim().toUpperCase();
|
|
19445
|
-
return isAgentPairingCode(normalized) ? normalized : void 0;
|
|
19446
|
-
}
|
|
19447
|
-
function isAgentPairingCode(value) {
|
|
19448
|
-
return typeof value === "string" && (CURRENT_AGENT_PAIRING_CODE.test(value) || LEGACY_AGENT_PAIRING_CODE.test(value));
|
|
19449
|
-
}
|
|
19450
|
-
|
|
19451
19568
|
// apps/body/dist/clack-support.js
|
|
19452
19569
|
import { stdout as stdout2 } from "node:process";
|
|
19453
19570
|
var FALLBACK_TERMINAL_COLUMNS = 80;
|
|
@@ -20066,7 +20183,7 @@ async function installCurrentRelease(fetchImpl) {
|
|
|
20066
20183
|
});
|
|
20067
20184
|
await activateRelease(layout, releaseId);
|
|
20068
20185
|
return {
|
|
20069
|
-
binary:
|
|
20186
|
+
binary: resolve22(layout.binDir, "beeline"),
|
|
20070
20187
|
version: published.version ?? releaseId
|
|
20071
20188
|
};
|
|
20072
20189
|
}
|
|
@@ -20089,21 +20206,21 @@ function providerEnvironment(selection) {
|
|
|
20089
20206
|
};
|
|
20090
20207
|
}
|
|
20091
20208
|
async function writePrivateJson(path, value) {
|
|
20092
|
-
await
|
|
20093
|
-
await
|
|
20209
|
+
await mkdir14(dirname10(path), { recursive: true, mode: 448 });
|
|
20210
|
+
await writeFile10(path, `${JSON.stringify(value, null, 2)}
|
|
20094
20211
|
`, { mode: 384 });
|
|
20095
|
-
await
|
|
20212
|
+
await chmod5(path, 384);
|
|
20096
20213
|
}
|
|
20097
20214
|
async function writeProviderEnv(selection, agentPubkey) {
|
|
20098
20215
|
const values = providerEnvironment(selection);
|
|
20099
20216
|
if (Object.keys(values).length === 0)
|
|
20100
20217
|
return void 0;
|
|
20101
|
-
const path =
|
|
20102
|
-
await
|
|
20218
|
+
const path = resolve22(defaultSupervisorRoot(process.env), "beeline", "connect", `${agentPubkey}.env`);
|
|
20219
|
+
await mkdir14(dirname10(path), { recursive: true, mode: 448 });
|
|
20103
20220
|
const contents = Object.entries(values).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join("\n");
|
|
20104
|
-
await
|
|
20221
|
+
await writeFile10(path, `${contents}
|
|
20105
20222
|
`, { mode: 384 });
|
|
20106
|
-
await
|
|
20223
|
+
await chmod5(path, 384);
|
|
20107
20224
|
return path;
|
|
20108
20225
|
}
|
|
20109
20226
|
async function runInstalledFinish(binary, grantPath) {
|
|
@@ -20164,7 +20281,7 @@ async function runConnectWizard(code, fetchImpl, eventSubscriptions, accessPolic
|
|
|
20164
20281
|
await finishConnectedAgentPairing(baseUrl, pairingCode, grant.workspace_joined, eventSubscriptions, fetchImpl);
|
|
20165
20282
|
const installedRelease = await brassSpinner("Installing the Beeline daemon\u2026", () => installCurrentRelease(fetchImpl), (release) => `Installed Beeline helper ${release.version}`);
|
|
20166
20283
|
const llmEnvFile = await writeProviderEnv(selection, grant.agent_pubkey);
|
|
20167
|
-
const grantPath =
|
|
20284
|
+
const grantPath = resolve22(defaultSupervisorRoot(process.env), "beeline", "connect", `grant-${process.pid}-${Date.now()}.json`);
|
|
20168
20285
|
await writePrivateJson(grantPath, {
|
|
20169
20286
|
agentSecretKey: grant.agent_secret_key,
|
|
20170
20287
|
bodySecretKey: grant.body_secret_key,
|
|
@@ -20246,11 +20363,11 @@ async function runConnectFinishCommand(path) {
|
|
|
20246
20363
|
throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
|
|
20247
20364
|
}
|
|
20248
20365
|
try {
|
|
20249
|
-
const grant = JSON.parse(await readFile10(
|
|
20366
|
+
const grant = JSON.parse(await readFile10(resolve22(path), "utf8"));
|
|
20250
20367
|
if (!isDevicePairingGrant(grant))
|
|
20251
20368
|
throw new Error("device connection grant is invalid");
|
|
20252
20369
|
const connected = await completeDevicePairing(grant);
|
|
20253
|
-
await unlink2(
|
|
20370
|
+
await unlink2(resolve22(path));
|
|
20254
20371
|
const providerEnv = grant.llmEnvFile ? await readFile10(grant.llmEnvFile, "utf8").catch(() => "") : "";
|
|
20255
20372
|
const apiKey = (/^OPENROUTER_API_KEY=(\S+)/m.exec(providerEnv)?.[1] ?? "").replace(/^["']|["']$/g, "");
|
|
20256
20373
|
const model = openRouterModelId(grant.model, { OPENROUTER_API_KEY: apiKey });
|
|
@@ -20279,20 +20396,20 @@ init_self_update_manifest();
|
|
|
20279
20396
|
// apps/body/dist/managed-update.js
|
|
20280
20397
|
init_self_update();
|
|
20281
20398
|
import { spawn as spawn6 } from "node:child_process";
|
|
20282
|
-
import { mkdir as
|
|
20283
|
-
import { dirname as dirname12, resolve as
|
|
20399
|
+
import { mkdir as mkdir16, rm as rm6, stat as stat2, writeFile as writeFile12 } from "node:fs/promises";
|
|
20400
|
+
import { dirname as dirname12, resolve as resolve24 } from "node:path";
|
|
20284
20401
|
|
|
20285
20402
|
// apps/body/dist/update-rollback-alert.js
|
|
20286
|
-
import { mkdir as
|
|
20287
|
-
import { dirname as dirname11, resolve as
|
|
20403
|
+
import { mkdir as mkdir15, readFile as readFile11, rename as rename4, writeFile as writeFile11 } from "node:fs/promises";
|
|
20404
|
+
import { dirname as dirname11, resolve as resolve23 } from "node:path";
|
|
20288
20405
|
function updateRollbackAlertPath(runtimeDir) {
|
|
20289
|
-
return
|
|
20406
|
+
return resolve23(runtimeDir, "update-rollback-alert.json");
|
|
20290
20407
|
}
|
|
20291
20408
|
async function writeAlert(runtimeDir, alert) {
|
|
20292
20409
|
const path = updateRollbackAlertPath(runtimeDir);
|
|
20293
20410
|
const staged = `${path}.${process.pid}.tmp`;
|
|
20294
|
-
await
|
|
20295
|
-
await
|
|
20411
|
+
await mkdir15(dirname11(path), { recursive: true });
|
|
20412
|
+
await writeFile11(staged, `${JSON.stringify(alert, null, 2)}
|
|
20296
20413
|
`, { mode: 384 });
|
|
20297
20414
|
await rename4(staged, path);
|
|
20298
20415
|
}
|
|
@@ -20329,13 +20446,13 @@ var LOCK_STALE_MS = UPDATE_WORKER_DEADLINE_MS + 5 * 6e4;
|
|
|
20329
20446
|
var DEFAULT_UPDATE_INITIAL_DELAY_MS = 0;
|
|
20330
20447
|
async function withInstallLock(layout, work, options = {}) {
|
|
20331
20448
|
const now2 = options.now ?? Date.now;
|
|
20332
|
-
const lock =
|
|
20449
|
+
const lock = resolve24(layout.releasesRoot, ".state", "install.lock");
|
|
20333
20450
|
const deadline = now2() + (options.waitMs ?? 1e4);
|
|
20334
|
-
await
|
|
20451
|
+
await mkdir16(dirname12(lock), { recursive: true });
|
|
20335
20452
|
for (; ; ) {
|
|
20336
20453
|
try {
|
|
20337
|
-
await
|
|
20338
|
-
await
|
|
20454
|
+
await mkdir16(lock);
|
|
20455
|
+
await writeFile12(resolve24(lock, "owner"), `${process.pid}
|
|
20339
20456
|
${now2()}
|
|
20340
20457
|
`, "utf8");
|
|
20341
20458
|
break;
|
|
@@ -20458,7 +20575,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
20458
20575
|
if (!attempt || attempt.releaseId !== desiredRelease || attempt.status !== "pending") {
|
|
20459
20576
|
const from = await readInstalledBundleIdentity({
|
|
20460
20577
|
...this.#layout,
|
|
20461
|
-
libDir:
|
|
20578
|
+
libDir: resolve24(this.#layout.releasesRoot, this.#loadedRelease)
|
|
20462
20579
|
}).catch(() => void 0) ?? {};
|
|
20463
20580
|
const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
|
|
20464
20581
|
const record2 = {
|
|
@@ -20745,7 +20862,7 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
|
|
|
20745
20862
|
});
|
|
20746
20863
|
if (!accepted)
|
|
20747
20864
|
return false;
|
|
20748
|
-
await
|
|
20865
|
+
await writeFile12(resolve24(runtimeDir, "daemon-ready.json"), `${JSON.stringify({
|
|
20749
20866
|
readyAt: (options.now ?? Date.now)(),
|
|
20750
20867
|
loadedRelease,
|
|
20751
20868
|
functionalProof: options.functionalProof
|
|
@@ -20753,39 +20870,59 @@ async function proveLoadedReleaseReady(layout, runtimeDir, loadedRelease, option
|
|
|
20753
20870
|
`, { mode: 384 });
|
|
20754
20871
|
return true;
|
|
20755
20872
|
}
|
|
20873
|
+
function siblingRevertNote(attempt, loadedRelease) {
|
|
20874
|
+
if (!loadedRelease || attempt?.releaseId !== loadedRelease || attempt.status !== "reverted") {
|
|
20875
|
+
return void 0;
|
|
20876
|
+
}
|
|
20877
|
+
return `shared update attempt reverted by sibling ${attempt.revertedBy ?? "unknown"}: ${attempt.failure ?? "no failure recorded"}`;
|
|
20878
|
+
}
|
|
20879
|
+
function describeOwnProof(proof) {
|
|
20880
|
+
return proof.modelAnswer === "unavailable" ? `this daemon's own probe reached the model boundary without an answer (${proof.modelAnswerReason ?? "no reason recorded"})` : "this daemon's own probe passed";
|
|
20881
|
+
}
|
|
20882
|
+
function attemptFailureText(error) {
|
|
20883
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
20884
|
+
return message.replace(/\s+/g, " ").trim().slice(0, 300);
|
|
20885
|
+
}
|
|
20756
20886
|
async function gateManagedSuccessor(input) {
|
|
20757
20887
|
try {
|
|
20758
20888
|
const attempt = await readUpdateAttempt(input.layout);
|
|
20759
20889
|
const desiredRelease = attempt?.status === "pending" ? attempt.releaseId : void 0;
|
|
20760
20890
|
if (!desiredRelease || !input.loadedRelease || desiredRelease !== input.loadedRelease) {
|
|
20761
|
-
|
|
20891
|
+
const reverted = siblingRevertNote(attempt, input.loadedRelease);
|
|
20892
|
+
throw new Error(reverted ? `successor release ${input.loadedRelease} was reverted before this daemon probed it: ${reverted}` : `successor loaded release ${input.loadedRelease ?? "unknown"}, not the pending desired release`);
|
|
20762
20893
|
}
|
|
20763
20894
|
const proof = await input.probe();
|
|
20764
20895
|
if (!await proveLoadedReleaseReady(input.layout, input.runtimeDir, input.loadedRelease, {
|
|
20765
20896
|
probeId: input.probeId,
|
|
20766
20897
|
functionalProof: proof
|
|
20767
20898
|
})) {
|
|
20768
|
-
|
|
20899
|
+
const reverted = siblingRevertNote(await readUpdateAttempt(input.layout), input.loadedRelease);
|
|
20900
|
+
throw new Error(reverted ? `successor release ${input.loadedRelease} lost its attempt while this daemon proved it: ${describeOwnProof(proof)}; ${reverted}` : `successor release ${input.loadedRelease} did not produce functional proof`);
|
|
20769
20901
|
}
|
|
20770
20902
|
return { kind: "passed", proof };
|
|
20771
20903
|
} catch (error) {
|
|
20772
20904
|
return {
|
|
20773
20905
|
kind: "failed",
|
|
20774
20906
|
error,
|
|
20775
|
-
rolledBack: await rollbackFailedSuccessor(input.layout, input.runtimeDir
|
|
20907
|
+
rolledBack: await rollbackFailedSuccessor(input.layout, input.runtimeDir, {
|
|
20908
|
+
probeId: input.probeId,
|
|
20909
|
+
failure: attemptFailureText(error)
|
|
20910
|
+
})
|
|
20776
20911
|
};
|
|
20777
20912
|
}
|
|
20778
20913
|
}
|
|
20779
|
-
async function rollbackFailedSuccessor(layout, runtimeDir) {
|
|
20914
|
+
async function rollbackFailedSuccessor(layout, runtimeDir, cause = {}) {
|
|
20780
20915
|
return withInstallLock(layout, async () => {
|
|
20781
20916
|
const attempt = await readUpdateAttempt(layout);
|
|
20782
20917
|
if (!attempt || attempt.status !== "pending")
|
|
20783
20918
|
return false;
|
|
20919
|
+
const attribution = cause.probeId ? { revertedBy: cause.probeId } : {};
|
|
20784
20920
|
if (!attempt.previousReleaseId) {
|
|
20785
20921
|
await replaceUpdateAttempt(layout, {
|
|
20786
20922
|
...attempt,
|
|
20787
20923
|
status: "reverted",
|
|
20788
|
-
failure: "functional served-turn proof failed, but no previous release exists"
|
|
20924
|
+
failure: cause.failure ?? "functional served-turn proof failed, but no previous release exists",
|
|
20925
|
+
...attribution
|
|
20789
20926
|
});
|
|
20790
20927
|
return false;
|
|
20791
20928
|
}
|
|
@@ -20793,7 +20930,8 @@ async function rollbackFailedSuccessor(layout, runtimeDir) {
|
|
|
20793
20930
|
await replaceUpdateAttempt(layout, {
|
|
20794
20931
|
...attempt,
|
|
20795
20932
|
status: "reverted",
|
|
20796
|
-
failure: "functional served-turn proof failed before confirmation"
|
|
20933
|
+
failure: cause.failure ?? "functional served-turn proof failed before confirmation",
|
|
20934
|
+
...attribution
|
|
20797
20935
|
});
|
|
20798
20936
|
if (runtimeDir)
|
|
20799
20937
|
await queueUpdateRollbackAlert(runtimeDir, attempt.releaseId);
|
|
@@ -20950,12 +21088,12 @@ async function runUpdateCommand(args) {
|
|
|
20950
21088
|
init_self_update();
|
|
20951
21089
|
|
|
20952
21090
|
// apps/body/dist/daemon-failure.js
|
|
20953
|
-
import { mkdir as
|
|
20954
|
-
import { dirname as dirname13, resolve as
|
|
21091
|
+
import { mkdir as mkdir17, readFile as readFile12, rename as rename5, rm as rm7, writeFile as writeFile13 } from "node:fs/promises";
|
|
21092
|
+
import { dirname as dirname13, resolve as resolve25 } from "node:path";
|
|
20955
21093
|
var DAEMON_FAILURE_LIMIT = 3;
|
|
20956
21094
|
var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
20957
21095
|
function daemonFailurePath(runtimeDir) {
|
|
20958
|
-
return
|
|
21096
|
+
return resolve25(runtimeDir, "daemon-distress.json");
|
|
20959
21097
|
}
|
|
20960
21098
|
async function readFailureRecord(runtimeDir) {
|
|
20961
21099
|
try {
|
|
@@ -20971,8 +21109,8 @@ async function readFailureRecord(runtimeDir) {
|
|
|
20971
21109
|
async function writeFailureRecord(runtimeDir, record2) {
|
|
20972
21110
|
const path = daemonFailurePath(runtimeDir);
|
|
20973
21111
|
const staged = `${path}.${process.pid}.tmp`;
|
|
20974
|
-
await
|
|
20975
|
-
await
|
|
21112
|
+
await mkdir17(dirname13(path), { recursive: true, mode: 448 });
|
|
21113
|
+
await writeFile13(staged, `${JSON.stringify(record2, null, 2)}
|
|
20976
21114
|
`, { mode: 384 });
|
|
20977
21115
|
await rename5(staged, path);
|
|
20978
21116
|
}
|
|
@@ -20994,12 +21132,34 @@ async function clearDaemonStartFailures(runtimeDir) {
|
|
|
20994
21132
|
}
|
|
20995
21133
|
|
|
20996
21134
|
// apps/body/dist/update-functional-probe.js
|
|
20997
|
-
import { mkdir as
|
|
21135
|
+
import { mkdir as mkdir18, rm as rm8 } from "node:fs/promises";
|
|
20998
21136
|
import { homedir as homedir10 } from "node:os";
|
|
20999
|
-
import { resolve as
|
|
21137
|
+
import { resolve as resolve26 } from "node:path";
|
|
21000
21138
|
var UPDATE_PROBE_SESSION_TIMEOUT_MS = 1e4;
|
|
21001
21139
|
var UPDATE_PROBE_SESSION_OPEN_TIMEOUT_MS = 2e4;
|
|
21002
21140
|
var UPDATE_PROBE_TURN_TIMEOUT_MS = 45e3;
|
|
21141
|
+
var ACP_ERROR_CODE = /\bACP error (-\d+):/;
|
|
21142
|
+
var ACP_PROMPT_INACTIVITY = /\bACP session\/prompt timed out after \d+ms of inactivity\b/;
|
|
21143
|
+
function isServerInternalCode(code) {
|
|
21144
|
+
return code === -32603 || code <= -32e3 && code >= -32099;
|
|
21145
|
+
}
|
|
21146
|
+
function classifyAcpTurnFailure(error) {
|
|
21147
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : void 0;
|
|
21148
|
+
if (!message)
|
|
21149
|
+
return void 0;
|
|
21150
|
+
if (ACP_PROMPT_INACTIVITY.test(message))
|
|
21151
|
+
return { kind: "prompt-inactivity" };
|
|
21152
|
+
const code = Number(ACP_ERROR_CODE.exec(message)?.[1]);
|
|
21153
|
+
if (Number.isFinite(code) && isServerInternalCode(code))
|
|
21154
|
+
return { kind: "server-internal", code };
|
|
21155
|
+
return void 0;
|
|
21156
|
+
}
|
|
21157
|
+
function sameAcpTurnFailure(one, other) {
|
|
21158
|
+
if (one.kind === "server-internal") {
|
|
21159
|
+
return other.kind === "server-internal" && one.code === other.code;
|
|
21160
|
+
}
|
|
21161
|
+
return other.kind === one.kind;
|
|
21162
|
+
}
|
|
21003
21163
|
var UpdateFunctionalProbeError = class extends Error {
|
|
21004
21164
|
reason;
|
|
21005
21165
|
code = "BEELINE_UPDATE_FUNCTIONAL_PROBE_FAILED";
|
|
@@ -21042,11 +21202,11 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21042
21202
|
if (input.sandboxRequired && !input.config.bwrapPath) {
|
|
21043
21203
|
throw new UpdateFunctionalProbeError("sandbox-unavailable", "the configured bubblewrap boundary did not pass its startup self-test");
|
|
21044
21204
|
}
|
|
21045
|
-
const root = input.probeRoot ??
|
|
21046
|
-
const cwd =
|
|
21047
|
-
const homeRoot =
|
|
21205
|
+
const root = input.probeRoot ?? resolve26(input.runtimeDir, "update-functional-probe");
|
|
21206
|
+
const cwd = resolve26(root, "checkout");
|
|
21207
|
+
const homeRoot = resolve26(root, "agent-home");
|
|
21048
21208
|
await rm8(root, { recursive: true, force: true });
|
|
21049
|
-
await
|
|
21209
|
+
await mkdir18(cwd, { recursive: true, mode: 448 });
|
|
21050
21210
|
let client;
|
|
21051
21211
|
try {
|
|
21052
21212
|
const agentEnv = {
|
|
@@ -21071,11 +21231,12 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21071
21231
|
args: agentArgsWithModelSelection(selectedAgent, input.config.modelSelection)
|
|
21072
21232
|
};
|
|
21073
21233
|
let modelAnswer = {};
|
|
21234
|
+
let turnCompleted = true;
|
|
21074
21235
|
if (input.config.bwrapPath) {
|
|
21075
21236
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
21076
21237
|
const operatorHome = input.config.operatorHome ?? homedir10();
|
|
21077
21238
|
const homeStateDirs = harnessHomeStateDirs(command, agentEnv.HOME ?? operatorHome);
|
|
21078
|
-
await Promise.all(homeStateDirs.map((dir) =>
|
|
21239
|
+
await Promise.all(homeStateDirs.map((dir) => mkdir18(dir, { recursive: true })));
|
|
21079
21240
|
spawnCommand = wrapAgentCommand({
|
|
21080
21241
|
bwrapPath: input.config.bwrapPath,
|
|
21081
21242
|
spec: {
|
|
@@ -21132,7 +21293,11 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21132
21293
|
...refusal ? { providerRefusal: refusal } : {}
|
|
21133
21294
|
});
|
|
21134
21295
|
}
|
|
21135
|
-
const current = await input.compareWithCurrentRelease(
|
|
21296
|
+
const current = await input.compareWithCurrentRelease({
|
|
21297
|
+
kind: "provider-refusal",
|
|
21298
|
+
reason: refusal.reason,
|
|
21299
|
+
refusal
|
|
21300
|
+
});
|
|
21136
21301
|
if (current.kind !== "refused" || current.status !== refusal.status) {
|
|
21137
21302
|
throw new UpdateFunctionalProbeError("turn-failed", `${detail}; ${describeCurrentReleaseOutcome(current)}`, { providerRefusal: refusal });
|
|
21138
21303
|
}
|
|
@@ -21147,7 +21312,26 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21147
21312
|
} catch (error) {
|
|
21148
21313
|
if (error instanceof UpdateFunctionalProbeError)
|
|
21149
21314
|
throw error;
|
|
21150
|
-
|
|
21315
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
21316
|
+
const failure = classifyAcpTurnFailure(error);
|
|
21317
|
+
if (!failure || !input.compareWithCurrentRelease) {
|
|
21318
|
+
throw new UpdateFunctionalProbeError("turn-failed", detail, { cause: error });
|
|
21319
|
+
}
|
|
21320
|
+
const current = await input.compareWithCurrentRelease({
|
|
21321
|
+
kind: "acp-turn-failure",
|
|
21322
|
+
reason: detail,
|
|
21323
|
+
failure
|
|
21324
|
+
});
|
|
21325
|
+
const currentFailure = current.kind === "unavailable" ? classifyAcpTurnFailure(current.reason) : void 0;
|
|
21326
|
+
if (!currentFailure || !sameAcpTurnFailure(failure, currentFailure)) {
|
|
21327
|
+
throw new UpdateFunctionalProbeError("turn-failed", `${detail}; ${describeCurrentReleaseOutcome(current)}`, { cause: error });
|
|
21328
|
+
}
|
|
21329
|
+
console.warn(`[body] update probe: the probe turn failed the same way on this release and the current release (${detail}); that failure is not this bundle's doing, so the probe passes as inconclusive`);
|
|
21330
|
+
turnCompleted = false;
|
|
21331
|
+
modelAnswer = {
|
|
21332
|
+
modelAnswer: "unavailable",
|
|
21333
|
+
modelAnswerReason: `${detail} (the current release fails the same way)`
|
|
21334
|
+
};
|
|
21151
21335
|
}
|
|
21152
21336
|
} catch (error) {
|
|
21153
21337
|
if (error instanceof UpdateFunctionalProbeError)
|
|
@@ -21158,7 +21342,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21158
21342
|
harness,
|
|
21159
21343
|
sandboxed: Boolean(input.config.bwrapPath),
|
|
21160
21344
|
sessionStarted: true,
|
|
21161
|
-
turnCompleted
|
|
21345
|
+
turnCompleted,
|
|
21162
21346
|
nativeTools: [],
|
|
21163
21347
|
...modelAnswer
|
|
21164
21348
|
};
|
|
@@ -21172,7 +21356,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
21172
21356
|
import { spawn as spawn7 } from "node:child_process";
|
|
21173
21357
|
import { dirname as dirname14, join as join8 } from "node:path";
|
|
21174
21358
|
init_self_update();
|
|
21175
|
-
var CURRENT_RELEASE_PROBE_TIMEOUT_MS =
|
|
21359
|
+
var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
|
|
21176
21360
|
var UPDATE_PROBE_COMMAND = "update-probe";
|
|
21177
21361
|
function parseReport(line) {
|
|
21178
21362
|
let parsed;
|
|
@@ -21211,7 +21395,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
21211
21395
|
return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
|
|
21212
21396
|
}
|
|
21213
21397
|
const timeoutMs = input.timeoutMs ?? CURRENT_RELEASE_PROBE_TIMEOUT_MS;
|
|
21214
|
-
return new Promise((
|
|
21398
|
+
return new Promise((resolve29) => {
|
|
21215
21399
|
const child = spawn7(input.execPath ?? process.execPath, [entrypoint, UPDATE_PROBE_COMMAND, "--config", input.runtimeConfigPath], { env: input.env ?? process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
21216
21400
|
let stdout6 = "";
|
|
21217
21401
|
let stderr = "";
|
|
@@ -21221,7 +21405,7 @@ async function probeReleaseInSubprocess(input) {
|
|
|
21221
21405
|
return;
|
|
21222
21406
|
settled = true;
|
|
21223
21407
|
clearTimeout(timer);
|
|
21224
|
-
|
|
21408
|
+
resolve29(outcome);
|
|
21225
21409
|
};
|
|
21226
21410
|
const timer = setTimeout(() => {
|
|
21227
21411
|
child.kill("SIGKILL");
|
|
@@ -21300,8 +21484,8 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
21300
21484
|
}
|
|
21301
21485
|
|
|
21302
21486
|
// apps/body/dist/release-status.js
|
|
21303
|
-
import { readFile as readFile13, readdir as readdir5, rename as rename6, writeFile as
|
|
21304
|
-
import { resolve as
|
|
21487
|
+
import { readFile as readFile13, readdir as readdir5, rename as rename6, writeFile as writeFile14 } from "node:fs/promises";
|
|
21488
|
+
import { resolve as resolve27 } from "node:path";
|
|
21305
21489
|
var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
|
|
21306
21490
|
var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
|
|
21307
21491
|
var SOURCE_SHA = /^[0-9a-f]{7,64}$/;
|
|
@@ -21318,9 +21502,9 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
21318
21502
|
pid: options.pid ?? process.pid,
|
|
21319
21503
|
readyAt: (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString()
|
|
21320
21504
|
};
|
|
21321
|
-
const target =
|
|
21505
|
+
const target = resolve27(runtimeDir, DAEMON_RELEASE_STATUS_FILE);
|
|
21322
21506
|
const temporary = `${target}.${status.pid}.tmp`;
|
|
21323
|
-
await
|
|
21507
|
+
await writeFile14(temporary, `${JSON.stringify(status, null, 2)}
|
|
21324
21508
|
`, { mode: 384 });
|
|
21325
21509
|
await rename6(temporary, target);
|
|
21326
21510
|
return status;
|
|
@@ -21378,7 +21562,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21378
21562
|
runtime = activated.runtime;
|
|
21379
21563
|
const daemonApi = activated.client;
|
|
21380
21564
|
const agent = runtimeAgentCommand(runtime);
|
|
21381
|
-
await
|
|
21565
|
+
await writeFile15(resolve28(dirname15(configPath), "daemon.pid"), `${process.pid}
|
|
21382
21566
|
`, { mode: 384 });
|
|
21383
21567
|
const env = {
|
|
21384
21568
|
...process.env,
|
|
@@ -21386,7 +21570,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21386
21570
|
BUZZ_DEV_MCP_BIN: runtime.mcpBinary
|
|
21387
21571
|
};
|
|
21388
21572
|
const config = loadBodyConfig({
|
|
21389
|
-
workspaceRoot:
|
|
21573
|
+
workspaceRoot: resolve28(dirname15(configPath), "workspace"),
|
|
21390
21574
|
llmEnvFile: runtime.llmEnvFile,
|
|
21391
21575
|
env,
|
|
21392
21576
|
agent
|
|
@@ -21500,8 +21684,8 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21500
21684
|
releaseId: loadedRelease ?? "unknown",
|
|
21501
21685
|
sandboxRequired: runtime.sandbox !== "off",
|
|
21502
21686
|
...currentReleaseId ? {
|
|
21503
|
-
compareWithCurrentRelease: async (
|
|
21504
|
-
console.warn(`[thin-core] successor probe
|
|
21687
|
+
compareWithCurrentRelease: async (appeal) => {
|
|
21688
|
+
console.warn(`[thin-core] successor probe got no answer from the provider (${appeal.reason}); probing the current release ${currentReleaseId} for the same outcome`);
|
|
21505
21689
|
await extendSystemdStartTimeout(CURRENT_RELEASE_PROBE_TIMEOUT_MS + 15e3);
|
|
21506
21690
|
return probeReleaseInSubprocess({
|
|
21507
21691
|
layout,
|
|
@@ -21547,7 +21731,12 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21547
21731
|
console.log(`[beeline] agent ${runtime.agent.publicKey} removed; runtime archived at ${archivedRuntime}`);
|
|
21548
21732
|
}
|
|
21549
21733
|
} catch (error) {
|
|
21550
|
-
const rolledBack = successorRolledBack || layout && pendingSuccessor && !ready &&
|
|
21734
|
+
const rolledBack = successorRolledBack || layout && pendingSuccessor && !ready && // Named, so a sibling daemon's journal can say whose failure reverted
|
|
21735
|
+
// the attempt it shares with this one.
|
|
21736
|
+
await rollbackFailedSuccessor(layout, runtimeDir, {
|
|
21737
|
+
probeId: runtime.agent.publicKey,
|
|
21738
|
+
failure: attemptFailureText(error)
|
|
21739
|
+
});
|
|
21551
21740
|
if (rolledBack) {
|
|
21552
21741
|
console.error("[thin-core] successor failed before READY; previous release restored once");
|
|
21553
21742
|
const alertRoom = runtime.rooms[0]?.channelId;
|
|
@@ -21556,7 +21745,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
21556
21745
|
throw error;
|
|
21557
21746
|
} finally {
|
|
21558
21747
|
await notifier.stopping(stoppingStatus).catch(() => void 0);
|
|
21559
|
-
const pidPath =
|
|
21748
|
+
const pidPath = resolve28(dirname15(configPath), "daemon.pid");
|
|
21560
21749
|
const recorded = Number((await readFile14(pidPath, "utf8").catch(() => "")).trim());
|
|
21561
21750
|
if (recorded === process.pid) {
|
|
21562
21751
|
await unlink3(pidPath).catch(() => void 0);
|
|
@@ -21577,6 +21766,21 @@ async function main() {
|
|
|
21577
21766
|
console.log(JSON.stringify(await runManagedUpdateWorker()));
|
|
21578
21767
|
return;
|
|
21579
21768
|
}
|
|
21769
|
+
if (command === "corner-read-token") {
|
|
21770
|
+
const configFlag = args.indexOf("--config");
|
|
21771
|
+
const roomFlag = args.indexOf("--room");
|
|
21772
|
+
const configPath = configFlag >= 0 ? args[configFlag + 1] : void 0;
|
|
21773
|
+
const roomId = roomFlag >= 0 ? args[roomFlag + 1] : void 0;
|
|
21774
|
+
if (!configPath || !roomId)
|
|
21775
|
+
throw new Error("corner-read-token requires --config and --room");
|
|
21776
|
+
const activated = await activateDaemonTransport(resolve28(configPath));
|
|
21777
|
+
if (!activated)
|
|
21778
|
+
throw new Error("corner-read-token requires monolith transport");
|
|
21779
|
+
const credential = await activated.client.execute("getRoomGitHubToken", { roomId });
|
|
21780
|
+
process.stdout.write(`${credential.token}
|
|
21781
|
+
`);
|
|
21782
|
+
return;
|
|
21783
|
+
}
|
|
21580
21784
|
if (command === "connect") {
|
|
21581
21785
|
const subscribeFlag = args.indexOf("--subscribe");
|
|
21582
21786
|
const subscribe = subscribeFlag >= 0 ? parseConnectSubscriptions(args[subscribeFlag + 1]) : [];
|
|
@@ -21631,7 +21835,7 @@ async function main() {
|
|
|
21631
21835
|
}
|
|
21632
21836
|
if (!configPath)
|
|
21633
21837
|
throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
|
|
21634
|
-
await runStoredDaemon(
|
|
21838
|
+
await runStoredDaemon(resolve28(configPath));
|
|
21635
21839
|
return;
|
|
21636
21840
|
}
|
|
21637
21841
|
if (command === "update") {
|