usebeeline 0.1.3 → 0.1.5
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 +1433 -662
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -9554,11 +9554,11 @@ var init_squire_broker_link = __esm({
|
|
|
9554
9554
|
|
|
9555
9555
|
// apps/body/dist/squire-host.js
|
|
9556
9556
|
import { spawn as spawn3 } from "node:child_process";
|
|
9557
|
-
import { accessSync, constants as fsConstants, existsSync as existsSync2, mkdirSync } from "node:fs";
|
|
9557
|
+
import { accessSync, constants as fsConstants, existsSync as existsSync2, mkdirSync, realpathSync, statSync, writeFileSync } from "node:fs";
|
|
9558
9558
|
import { createRequire as createRequire2 } from "node:module";
|
|
9559
9559
|
import { createConnection as createConnection2 } from "node:net";
|
|
9560
9560
|
import { homedir as homedir2 } from "node:os";
|
|
9561
|
-
import { dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
9561
|
+
import { basename, dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
9562
9562
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
9563
9563
|
function squireHostPaths(home) {
|
|
9564
9564
|
const dir = join2(resolve2(home), ".trusty-squire");
|
|
@@ -9584,6 +9584,22 @@ function ensureSquireHostDir(home) {
|
|
|
9584
9584
|
mkdirSync(paths.profileDir, { recursive: true, mode: 448 });
|
|
9585
9585
|
return paths;
|
|
9586
9586
|
}
|
|
9587
|
+
function writeSquireBrokerUnitMarker(home) {
|
|
9588
|
+
const paths = ensureSquireHostDir(home);
|
|
9589
|
+
const profile = realpathSync.native(paths.profileDir);
|
|
9590
|
+
const parent = dirname2(profile);
|
|
9591
|
+
const { dev, ino } = statSync(parent);
|
|
9592
|
+
const path = join2(parent, SQUIRE_BROKER_UNIT_MARKER_FILE);
|
|
9593
|
+
const marker = {
|
|
9594
|
+
version: 1,
|
|
9595
|
+
socket: paths.brokerSocket,
|
|
9596
|
+
profile: { dev, ino, name: basename(profile) },
|
|
9597
|
+
accountBinding: null
|
|
9598
|
+
};
|
|
9599
|
+
writeFileSync(path, `${JSON.stringify(marker, null, 2)}
|
|
9600
|
+
`, { mode: 384 });
|
|
9601
|
+
return path;
|
|
9602
|
+
}
|
|
9587
9603
|
function squireHostDirWritable(socketPath) {
|
|
9588
9604
|
try {
|
|
9589
9605
|
accessSync(dirname2(socketPath), fsConstants.W_OK);
|
|
@@ -9678,7 +9694,14 @@ function spawnSquireServer(env, locateNpx, args) {
|
|
|
9678
9694
|
function runSquireBroker(env = process.env) {
|
|
9679
9695
|
const home = env.HOME?.trim() || homedir2();
|
|
9680
9696
|
const paths = ensureSquireHostDir(home);
|
|
9681
|
-
spawnSquireServer({
|
|
9697
|
+
spawnSquireServer({
|
|
9698
|
+
...env,
|
|
9699
|
+
...squireHostRewriteEnv(home),
|
|
9700
|
+
TRUSTY_SQUIRE_BROKER_SOCKET: paths.brokerSocket,
|
|
9701
|
+
// Squire's daemon refuses to start under the managed marker unless the
|
|
9702
|
+
// unit started it; launchd sets no INVOCATION_ID, so say so explicitly.
|
|
9703
|
+
TRUSTY_SQUIRE_BROKER_UNIT: "1"
|
|
9704
|
+
}, true, SQUIRE_BROKER_ARGS);
|
|
9682
9705
|
}
|
|
9683
9706
|
async function runSquireFacade(env = process.env) {
|
|
9684
9707
|
const socket = env.TRUSTY_SQUIRE_BROKER_SOCKET ?? squireHostPaths(env.HOME?.trim() || homedir2()).brokerSocket;
|
|
@@ -9695,7 +9718,7 @@ async function runSquireFacade(env = process.env) {
|
|
|
9695
9718
|
});
|
|
9696
9719
|
process.exit(ok ? 0 : 1);
|
|
9697
9720
|
}
|
|
9698
|
-
var SQUIRE_BROKER_UNAVAILABLE, TRUSTY_SQUIRE_BROKER_UNIT_NAME, SQUIRE_FACADE_FLAG, SQUIRE_BROKER_FLAG, SQUIRE_SERVER_ARGS, SQUIRE_BROKER_ARGS;
|
|
9721
|
+
var SQUIRE_BROKER_UNAVAILABLE, TRUSTY_SQUIRE_BROKER_UNIT_NAME, SQUIRE_FACADE_FLAG, SQUIRE_BROKER_FLAG, SQUIRE_SERVER_ARGS, SQUIRE_BROKER_ARGS, SQUIRE_BROKER_UNIT_MARKER_FILE;
|
|
9699
9722
|
var init_squire_host = __esm({
|
|
9700
9723
|
"apps/body/dist/squire-host.js"() {
|
|
9701
9724
|
"use strict";
|
|
@@ -9706,12 +9729,13 @@ var init_squire_host = __esm({
|
|
|
9706
9729
|
SQUIRE_BROKER_FLAG = "--squire-broker";
|
|
9707
9730
|
SQUIRE_SERVER_ARGS = ["-y", "@trusty-squire/mcp@latest", "server"];
|
|
9708
9731
|
SQUIRE_BROKER_ARGS = ["-y", "@trusty-squire/mcp@latest", "broker"];
|
|
9732
|
+
SQUIRE_BROKER_UNIT_MARKER_FILE = ".trusty-squire-broker-unit.json";
|
|
9709
9733
|
}
|
|
9710
9734
|
});
|
|
9711
9735
|
|
|
9712
9736
|
// apps/body/dist/systemd.js
|
|
9713
9737
|
import { execFile as execFile2 } from "node:child_process";
|
|
9714
|
-
import { mkdir as mkdir2, readFile as readFile3, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
9738
|
+
import { mkdir as mkdir2, readFile as readFile3, rename as rename2, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
9715
9739
|
import { homedir as homedir3 } from "node:os";
|
|
9716
9740
|
import { dirname as dirname3, resolve as resolve3 } from "node:path";
|
|
9717
9741
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
@@ -9740,6 +9764,7 @@ CPUWeight=1000
|
|
|
9740
9764
|
IOWeight=1000
|
|
9741
9765
|
Nice=-5
|
|
9742
9766
|
OOMScoreAdjust=-1000
|
|
9767
|
+
OOMPolicy=continue
|
|
9743
9768
|
TimeoutStartSec=90s
|
|
9744
9769
|
TimeoutStopSec=90s
|
|
9745
9770
|
KillMode=control-group
|
|
@@ -9779,7 +9804,7 @@ async function installTrustySquireBrokerService(options = {}) {
|
|
|
9779
9804
|
const env = options.env ?? process.env;
|
|
9780
9805
|
assertCanonicalInstalledLauncher(env, options.invocationPath);
|
|
9781
9806
|
const home = env.HOME?.trim() || homedir3();
|
|
9782
|
-
|
|
9807
|
+
writeSquireBrokerUnitMarker(home);
|
|
9783
9808
|
const path = systemdBrokerUnitPath(env);
|
|
9784
9809
|
const content = trustySquireBrokerUnit();
|
|
9785
9810
|
const existing = await readFile3(path, "utf8").catch(() => "");
|
|
@@ -9812,6 +9837,26 @@ async function convergeTrustySquireBrokerService(options) {
|
|
|
9812
9837
|
return false;
|
|
9813
9838
|
}
|
|
9814
9839
|
}
|
|
9840
|
+
async function convergeAgentServiceUnit(options) {
|
|
9841
|
+
const env = options.env ?? process.env;
|
|
9842
|
+
try {
|
|
9843
|
+
assertCanonicalInstalledLauncher(env, resolve3(options.libDir, "lib", "beeline", "beeline-cli.mjs"));
|
|
9844
|
+
const path = systemdUserUnitPath(env);
|
|
9845
|
+
const content = agentServiceUnit();
|
|
9846
|
+
const existing = await readFile3(path, "utf8").catch(() => "");
|
|
9847
|
+
if (existing === content)
|
|
9848
|
+
return false;
|
|
9849
|
+
await mkdir2(dirname3(path), { recursive: true, mode: 448 });
|
|
9850
|
+
await writeFile2(path, content, { mode: 384 });
|
|
9851
|
+
const run2 = options.run ?? runSystemctl;
|
|
9852
|
+
await run2(["daemon-reload"]);
|
|
9853
|
+
options.log?.("[beeline] agent systemd unit updated; it applies on the next daemon restart");
|
|
9854
|
+
return true;
|
|
9855
|
+
} catch (error) {
|
|
9856
|
+
options.log?.(`[beeline] agent systemd unit not converged: ${error instanceof Error ? error.message : String(error)}`);
|
|
9857
|
+
return false;
|
|
9858
|
+
}
|
|
9859
|
+
}
|
|
9815
9860
|
async function installAgentService(publicKey, options = {}) {
|
|
9816
9861
|
if (!/^[0-9a-f]{64}$/i.test(publicKey))
|
|
9817
9862
|
throw new Error("agent public key must be 64 hex");
|
|
@@ -9844,6 +9889,23 @@ async function installAgentService(publicKey, options = {}) {
|
|
|
9844
9889
|
} while (Date.now() < deadline);
|
|
9845
9890
|
throw new Error(`systemd did not replace ${service}'s MainPID before the restart deadline`);
|
|
9846
9891
|
}
|
|
9892
|
+
async function rewriteAgentServiceUnit(options) {
|
|
9893
|
+
const env = options.env ?? process.env;
|
|
9894
|
+
assertCanonicalInstalledLauncher(env, options.invocationPath);
|
|
9895
|
+
const path = systemdUserUnitPath(env);
|
|
9896
|
+
const content = agentServiceUnit();
|
|
9897
|
+
const run2 = options.run ?? runSystemctl;
|
|
9898
|
+
return options.lock(async () => {
|
|
9899
|
+
if (await readFile3(path, "utf8").catch(() => "") === content)
|
|
9900
|
+
return false;
|
|
9901
|
+
await mkdir2(dirname3(path), { recursive: true, mode: 448 });
|
|
9902
|
+
const staged = `${path}.${process.pid}.tmp`;
|
|
9903
|
+
await writeFile2(staged, content, { mode: 384 });
|
|
9904
|
+
await rename2(staged, path);
|
|
9905
|
+
await run2(["daemon-reload"]);
|
|
9906
|
+
return true;
|
|
9907
|
+
});
|
|
9908
|
+
}
|
|
9847
9909
|
async function serviceStatus(run2, service) {
|
|
9848
9910
|
const status = await run2([
|
|
9849
9911
|
"show",
|
|
@@ -9947,8 +10009,10 @@ async function notify(fields) {
|
|
|
9947
10009
|
async function extendSystemdStartTimeout(ms) {
|
|
9948
10010
|
await notify([`EXTEND_TIMEOUT_USEC=${Math.max(0, Math.round(ms)) * 1e3}`]).catch(() => void 0);
|
|
9949
10011
|
}
|
|
9950
|
-
function startLocalWatchdog(notifier, status, intervalMs = 6e4) {
|
|
9951
|
-
|
|
10012
|
+
function startLocalWatchdog(notifier, status, intervalMs = 6e4, env = process.env) {
|
|
10013
|
+
if (!env.WATCHDOG_USEC)
|
|
10014
|
+
return () => void 0;
|
|
10015
|
+
const timer = setInterval(() => void notifier.progress(status()).catch((error) => console.error("[thin-core] watchdog notification failed:", error)), intervalMs);
|
|
9952
10016
|
timer.unref?.();
|
|
9953
10017
|
return () => clearInterval(timer);
|
|
9954
10018
|
}
|
|
@@ -9989,8 +10053,8 @@ var init_systemd = __esm({
|
|
|
9989
10053
|
|
|
9990
10054
|
// apps/body/dist/launchd.js
|
|
9991
10055
|
import { execFile as execFile3 } from "node:child_process";
|
|
9992
|
-
import { realpathSync } from "node:fs";
|
|
9993
|
-
import { chmod as chmod2, mkdir as mkdir3, readFile as readFile4, readdir as readdir2, rename as
|
|
10056
|
+
import { realpathSync as realpathSync2 } from "node:fs";
|
|
10057
|
+
import { chmod as chmod2, mkdir as mkdir3, readFile as readFile4, readdir as readdir2, rename as rename3, rm, stat as stat3, writeFile as writeFile3 } from "node:fs/promises";
|
|
9994
10058
|
import { homedir as homedir4 } from "node:os";
|
|
9995
10059
|
import { dirname as dirname4, resolve as resolve4 } from "node:path";
|
|
9996
10060
|
import { setTimeout as sleep2 } from "node:timers/promises";
|
|
@@ -10003,7 +10067,7 @@ function launchdHome(env) {
|
|
|
10003
10067
|
}
|
|
10004
10068
|
function nodeBinDirectory() {
|
|
10005
10069
|
try {
|
|
10006
|
-
return dirname4(
|
|
10070
|
+
return dirname4(realpathSync2(process.execPath));
|
|
10007
10071
|
} catch {
|
|
10008
10072
|
return dirname4(process.execPath);
|
|
10009
10073
|
}
|
|
@@ -10158,7 +10222,7 @@ async function writeManagedFile(path, content, mode) {
|
|
|
10158
10222
|
const pending = `${path}.${process.pid}.pending`;
|
|
10159
10223
|
await writeFile3(pending, content, { mode });
|
|
10160
10224
|
await chmod2(pending, mode);
|
|
10161
|
-
await
|
|
10225
|
+
await rename3(pending, path);
|
|
10162
10226
|
return true;
|
|
10163
10227
|
}
|
|
10164
10228
|
function launchctlFailureText(error) {
|
|
@@ -10320,7 +10384,7 @@ async function installLaunchdTrustySquireBrokerService(options = {}) {
|
|
|
10320
10384
|
const env = options.env ?? process.env;
|
|
10321
10385
|
assertCanonicalInstalledLauncher2(env, options.invocationPath);
|
|
10322
10386
|
const home = launchdHome(env);
|
|
10323
|
-
|
|
10387
|
+
writeSquireBrokerUnitMarker(home);
|
|
10324
10388
|
await mkdir3(resolve4(home, "Library", "Logs", "Beeline"), { recursive: true, mode: 448 });
|
|
10325
10389
|
const plistPath = launchdBrokerPlistPath(env);
|
|
10326
10390
|
const changed = await writeManagedFile(plistPath, launchdBrokerPlist(env), 384);
|
|
@@ -10409,7 +10473,7 @@ __export(self_update_exports, {
|
|
|
10409
10473
|
});
|
|
10410
10474
|
import { createHash } from "node:crypto";
|
|
10411
10475
|
import { constants as fsConstants2 } from "node:fs";
|
|
10412
|
-
import { access, chmod as chmod3, lstat, mkdir as mkdir4, open, readFile as readFile5, rename as
|
|
10476
|
+
import { access, chmod as chmod3, lstat, mkdir as mkdir4, open, readFile as readFile5, rename as rename4, rm as rm2, symlink, writeFile as writeFile4 } from "node:fs/promises";
|
|
10413
10477
|
import { spawn as spawn4 } from "node:child_process";
|
|
10414
10478
|
import { homedir as homedir5 } from "node:os";
|
|
10415
10479
|
import { dirname as dirname5, join as join3, resolve as resolve5 } from "node:path";
|
|
@@ -10712,7 +10776,7 @@ async function replaceFile(path, contents, mode) {
|
|
|
10712
10776
|
const temp = `${path}.new-${process.pid}`;
|
|
10713
10777
|
await writeFile4(temp, contents, { mode });
|
|
10714
10778
|
await chmod3(temp, mode);
|
|
10715
|
-
await
|
|
10779
|
+
await rename4(temp, path);
|
|
10716
10780
|
}
|
|
10717
10781
|
async function activateRelease(layout, releaseId) {
|
|
10718
10782
|
const releaseDir = join3(layout.releasesRoot, releaseId);
|
|
@@ -10728,10 +10792,10 @@ async function activateRelease(layout, releaseId) {
|
|
|
10728
10792
|
try {
|
|
10729
10793
|
await access(legacyDir, fsConstants2.F_OK);
|
|
10730
10794
|
previousReleaseId = `${legacyId}-${Date.now()}`;
|
|
10731
|
-
await
|
|
10795
|
+
await rename4(layout.libDir, join3(layout.releasesRoot, previousReleaseId));
|
|
10732
10796
|
await normalizeLegacyBundleShape(join3(layout.releasesRoot, previousReleaseId));
|
|
10733
10797
|
} catch {
|
|
10734
|
-
await
|
|
10798
|
+
await rename4(layout.libDir, legacyDir);
|
|
10735
10799
|
await normalizeLegacyBundleShape(legacyDir);
|
|
10736
10800
|
previousReleaseId = legacyId;
|
|
10737
10801
|
}
|
|
@@ -10739,7 +10803,7 @@ async function activateRelease(layout, releaseId) {
|
|
|
10739
10803
|
const tempLink = `${layout.libDir}.new-${process.pid}`;
|
|
10740
10804
|
await rm2(tempLink, { force: true });
|
|
10741
10805
|
await symlink(join3("beeline-releases", releaseId), tempLink);
|
|
10742
|
-
await
|
|
10806
|
+
await rename4(tempLink, layout.libDir);
|
|
10743
10807
|
await fsyncDir(dirname5(layout.libDir));
|
|
10744
10808
|
await writeBinForwarders(layout, releaseDir);
|
|
10745
10809
|
return { previousReleaseId };
|
|
@@ -10764,7 +10828,7 @@ async function normalizeLegacyBundleShape(bundleDir) {
|
|
|
10764
10828
|
continue;
|
|
10765
10829
|
} catch {
|
|
10766
10830
|
}
|
|
10767
|
-
await
|
|
10831
|
+
await rename4(join3(bundleDir, name), join3(innerLib, name)).catch(() => void 0);
|
|
10768
10832
|
}
|
|
10769
10833
|
}
|
|
10770
10834
|
async function writeBinForwarders(layout, activeBundleRoot) {
|
|
@@ -10815,7 +10879,7 @@ async function rollbackToPreviousRelease(layout, previousReleaseId) {
|
|
|
10815
10879
|
const tempLink = `${layout.libDir}.rollback-${process.pid}`;
|
|
10816
10880
|
await rm2(tempLink, { force: true });
|
|
10817
10881
|
await symlink(join3("beeline-releases", previousReleaseId), tempLink);
|
|
10818
|
-
await
|
|
10882
|
+
await rename4(tempLink, layout.libDir);
|
|
10819
10883
|
await fsyncDir(dirname5(layout.libDir));
|
|
10820
10884
|
}
|
|
10821
10885
|
function updateAttemptPath(layout) {
|
|
@@ -10838,7 +10902,7 @@ async function writeUpdateAttempt(layout, record6) {
|
|
|
10838
10902
|
const staged = `${path}.${process.pid}.tmp`;
|
|
10839
10903
|
await writeFile4(staged, `${JSON.stringify(record6, null, 2)}
|
|
10840
10904
|
`, { mode: 384 });
|
|
10841
|
-
await
|
|
10905
|
+
await rename4(staged, path);
|
|
10842
10906
|
}
|
|
10843
10907
|
async function replaceUpdateAttempt(layout, record6) {
|
|
10844
10908
|
await writeUpdateAttempt(layout, record6);
|
|
@@ -10925,7 +10989,6 @@ var init_self_update = __esm({
|
|
|
10925
10989
|
fetchImpl;
|
|
10926
10990
|
log;
|
|
10927
10991
|
stageOnly;
|
|
10928
|
-
timer;
|
|
10929
10992
|
nextCheckAllowedAt = 0;
|
|
10930
10993
|
disposed = false;
|
|
10931
10994
|
applying = false;
|
|
@@ -10942,9 +11005,7 @@ var init_self_update = __esm({
|
|
|
10942
11005
|
};
|
|
10943
11006
|
this.options = {
|
|
10944
11007
|
layout: options.layout,
|
|
10945
|
-
tickMs: options.tickMs ?? numberEnv2("BEELINE_UPDATE_TICK_MS", 6e4),
|
|
10946
11008
|
checkIntervalMs: options.checkIntervalMs ?? numberEnv2("BEELINE_UPDATE_INTERVAL_MS", 6 * 60 * 6e4),
|
|
10947
|
-
initialDelayMs: options.initialDelayMs ?? numberEnv2("BEELINE_UPDATE_INITIAL_DELAY_MS", 2 * 6e4),
|
|
10948
11009
|
idleTimeoutMs: options.idleTimeoutMs ?? numberEnv2("BEELINE_UPDATE_IDLE_TIMEOUT_MS", 30 * 6e4),
|
|
10949
11010
|
idlePollMs: options.idlePollMs ?? 5e3,
|
|
10950
11011
|
env,
|
|
@@ -10956,20 +11017,8 @@ var init_self_update = __esm({
|
|
|
10956
11017
|
this.log = options.logger ?? ((line) => console.log(line));
|
|
10957
11018
|
this.stageOnly = options.stageOnly ?? false;
|
|
10958
11019
|
}
|
|
10959
|
-
start() {
|
|
10960
|
-
if (this.timer || this.disposed)
|
|
10961
|
-
return;
|
|
10962
|
-
this.nextCheckAllowedAt = this.options.now() + this.options.initialDelayMs;
|
|
10963
|
-
this.timer = setInterval(() => {
|
|
10964
|
-
void this.tick();
|
|
10965
|
-
}, this.options.tickMs);
|
|
10966
|
-
this.timer.unref?.();
|
|
10967
|
-
}
|
|
10968
11020
|
dispose() {
|
|
10969
11021
|
this.disposed = true;
|
|
10970
|
-
if (this.timer)
|
|
10971
|
-
clearInterval(this.timer);
|
|
10972
|
-
this.timer = void 0;
|
|
10973
11022
|
}
|
|
10974
11023
|
busy() {
|
|
10975
11024
|
return !this.isIdle();
|
|
@@ -11087,6 +11136,11 @@ var init_self_update = __esm({
|
|
|
11087
11136
|
env: this.options.env,
|
|
11088
11137
|
log: this.log
|
|
11089
11138
|
});
|
|
11139
|
+
await convergeAgentServiceUnit({
|
|
11140
|
+
libDir: this.options.layout.libDir,
|
|
11141
|
+
env: this.options.env,
|
|
11142
|
+
log: this.log
|
|
11143
|
+
});
|
|
11090
11144
|
} else if (process.platform === "darwin" && this.options.env.BEELINE_LAUNCHD_USER !== "0") {
|
|
11091
11145
|
await convergeLaunchdTrustySquireBrokerService({
|
|
11092
11146
|
libDir: this.options.layout.libDir,
|
|
@@ -11251,10 +11305,10 @@ var init_cursor_models = __esm({
|
|
|
11251
11305
|
// apps/body/dist/cursor-acp-bridge.js
|
|
11252
11306
|
import { spawn as spawn6 } from "node:child_process";
|
|
11253
11307
|
import { existsSync as existsSync3 } from "node:fs";
|
|
11254
|
-
import { chmod as chmod4, lstat as lstat2, mkdir as mkdir6, rename as
|
|
11308
|
+
import { chmod as chmod4, lstat as lstat2, mkdir as mkdir6, rename as rename5, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
|
|
11255
11309
|
import { createRequire as createRequire3 } from "node:module";
|
|
11256
11310
|
import { createInterface as createInterface3 } from "node:readline";
|
|
11257
|
-
import { basename, dirname as dirname7, resolve as resolvePath } from "node:path";
|
|
11311
|
+
import { basename as basename2, dirname as dirname7, resolve as resolvePath } from "node:path";
|
|
11258
11312
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
11259
11313
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
11260
11314
|
function harnessIdentityLabel(agent) {
|
|
@@ -11320,11 +11374,11 @@ async function writeIsolatedCursorFile(path, content) {
|
|
|
11320
11374
|
if (!parentStats.isDirectory() || parentStats.isSymbolicLink()) {
|
|
11321
11375
|
throw new Error(`isolated cursor parent is not a real directory: ${parent}`);
|
|
11322
11376
|
}
|
|
11323
|
-
const temporary = resolvePath(parent, `.${
|
|
11377
|
+
const temporary = resolvePath(parent, `.${basename2(path)}.${process.pid}.${randomUUID2()}.tmp`);
|
|
11324
11378
|
try {
|
|
11325
11379
|
await writeFile5(temporary, content, { mode: 384, flag: "wx" });
|
|
11326
11380
|
await chmod4(temporary, 384);
|
|
11327
|
-
await
|
|
11381
|
+
await rename5(temporary, path);
|
|
11328
11382
|
} finally {
|
|
11329
11383
|
await unlink3(temporary).catch(() => void 0);
|
|
11330
11384
|
}
|
|
@@ -25219,7 +25273,7 @@ var import_picocolors3 = __toESM(require_picocolors(), 1);
|
|
|
25219
25273
|
// apps/body/dist/config.js
|
|
25220
25274
|
init_agent_command();
|
|
25221
25275
|
import { accessSync as accessSync3, constants as constants2, existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
|
|
25222
|
-
import { basename as
|
|
25276
|
+
import { basename as basename3, dirname as dirname8, resolve as resolve8 } from "node:path";
|
|
25223
25277
|
function firstExisting2(paths) {
|
|
25224
25278
|
for (const p of paths) {
|
|
25225
25279
|
if (p && existsSync5(p))
|
|
@@ -25229,7 +25283,7 @@ function firstExisting2(paths) {
|
|
|
25229
25283
|
}
|
|
25230
25284
|
function commandInRunningBundle(command) {
|
|
25231
25285
|
const entrypoint = process.argv[1];
|
|
25232
|
-
if (!entrypoint ||
|
|
25286
|
+
if (!entrypoint || basename3(entrypoint) !== "beeline-cli.mjs")
|
|
25233
25287
|
return void 0;
|
|
25234
25288
|
const entrypointDir = dirname8(resolve8(entrypoint));
|
|
25235
25289
|
const candidates = [
|
|
@@ -26630,7 +26684,7 @@ function isAllowedAgentModelConfigCategory(category, id) {
|
|
|
26630
26684
|
|
|
26631
26685
|
// apps/body/dist/model-config.js
|
|
26632
26686
|
import { lstatSync, readFileSync as readFileSync3 } from "node:fs";
|
|
26633
|
-
import { basename as
|
|
26687
|
+
import { basename as basename4, resolve as resolve9 } from "node:path";
|
|
26634
26688
|
|
|
26635
26689
|
// packages/api-contract/dist/daemon-operations.js
|
|
26636
26690
|
function isAgentCommand(value) {
|
|
@@ -26668,6 +26722,12 @@ var ARTIFACT_EXTENSIONS_BY_MIME = {
|
|
|
26668
26722
|
"application/json": [".json"],
|
|
26669
26723
|
"text/csv": [".csv"],
|
|
26670
26724
|
"application/zip": [".zip"],
|
|
26725
|
+
"video/mp4": [".mp4", ".m4v"],
|
|
26726
|
+
"video/quicktime": [".mov"],
|
|
26727
|
+
"video/webm": [".webm"],
|
|
26728
|
+
"audio/mpeg": [".mp3"],
|
|
26729
|
+
"audio/wav": [".wav"],
|
|
26730
|
+
"audio/mp4": [".m4a"],
|
|
26671
26731
|
"application/octet-stream": []
|
|
26672
26732
|
};
|
|
26673
26733
|
var ARTIFACT_MIME_BY_EXTENSION = Object.fromEntries(Object.entries(ARTIFACT_EXTENSIONS_BY_MIME).flatMap(([mime, extensions]) => extensions.map((extension2) => [extension2, mime])));
|
|
@@ -27244,7 +27304,7 @@ function isGrokAgentCommand(agent) {
|
|
|
27244
27304
|
return true;
|
|
27245
27305
|
if (agent.kind && agent.kind !== "custom")
|
|
27246
27306
|
return false;
|
|
27247
|
-
return /^grok(?:\.[a-z0-9]+)?$/i.test(
|
|
27307
|
+
return /^grok(?:\.[a-z0-9]+)?$/i.test(basename4(agent.command));
|
|
27248
27308
|
}
|
|
27249
27309
|
function agentArgsWithModelSelection(agent, selection) {
|
|
27250
27310
|
const original = [...agent.args];
|
|
@@ -27787,6 +27847,72 @@ function matchProfile(agentCommand) {
|
|
|
27787
27847
|
return void 0;
|
|
27788
27848
|
}
|
|
27789
27849
|
|
|
27850
|
+
// apps/body/dist/oom-kill.js
|
|
27851
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
27852
|
+
import { join as join5 } from "node:path";
|
|
27853
|
+
var CGROUP_V2_ROOT = "/sys/fs/cgroup";
|
|
27854
|
+
function parseOomKillCount(contents) {
|
|
27855
|
+
for (const line of contents.split("\n")) {
|
|
27856
|
+
const [key, raw] = line.trim().split(/\s+/, 2);
|
|
27857
|
+
if (key !== "oom_kill")
|
|
27858
|
+
continue;
|
|
27859
|
+
const value = Number(raw);
|
|
27860
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
27861
|
+
}
|
|
27862
|
+
return null;
|
|
27863
|
+
}
|
|
27864
|
+
function unifiedCgroupPath(procSelfCgroup) {
|
|
27865
|
+
const line = procSelfCgroup.split("\n").map((value) => value.trim()).find((value) => value.startsWith("0::"));
|
|
27866
|
+
const path = line?.slice(3).trim();
|
|
27867
|
+
return path && path.startsWith("/") ? path : null;
|
|
27868
|
+
}
|
|
27869
|
+
function cgroupOomKillProbe(options = {}) {
|
|
27870
|
+
const readProc = options.procSelfCgroup ?? (() => readFile9("/proc/self/cgroup", "utf8"));
|
|
27871
|
+
const root = options.cgroupRoot ?? CGROUP_V2_ROOT;
|
|
27872
|
+
let directory;
|
|
27873
|
+
return {
|
|
27874
|
+
async read() {
|
|
27875
|
+
try {
|
|
27876
|
+
if (directory === void 0) {
|
|
27877
|
+
const path = unifiedCgroupPath(await readProc());
|
|
27878
|
+
directory = path ? join5(root, path) : null;
|
|
27879
|
+
}
|
|
27880
|
+
if (!directory)
|
|
27881
|
+
return null;
|
|
27882
|
+
return parseOomKillCount(await readFile9(join5(directory, "memory.events"), "utf8"));
|
|
27883
|
+
} catch {
|
|
27884
|
+
return null;
|
|
27885
|
+
}
|
|
27886
|
+
}
|
|
27887
|
+
};
|
|
27888
|
+
}
|
|
27889
|
+
var OomKillTracker = class {
|
|
27890
|
+
probe;
|
|
27891
|
+
#last = null;
|
|
27892
|
+
#banked = 0;
|
|
27893
|
+
constructor(probe) {
|
|
27894
|
+
this.probe = probe;
|
|
27895
|
+
}
|
|
27896
|
+
/** Record the current count so the next kill is measured against it. */
|
|
27897
|
+
async prime() {
|
|
27898
|
+
const current = await this.probe.read();
|
|
27899
|
+
if (current !== null)
|
|
27900
|
+
this.#last = current;
|
|
27901
|
+
}
|
|
27902
|
+
async consume() {
|
|
27903
|
+
const current = await this.probe.read();
|
|
27904
|
+
if (current === null)
|
|
27905
|
+
return false;
|
|
27906
|
+
if (this.#last !== null && current > this.#last)
|
|
27907
|
+
this.#banked += current - this.#last;
|
|
27908
|
+
this.#last = current;
|
|
27909
|
+
if (this.#banked === 0)
|
|
27910
|
+
return false;
|
|
27911
|
+
this.#banked -= 1;
|
|
27912
|
+
return true;
|
|
27913
|
+
}
|
|
27914
|
+
};
|
|
27915
|
+
|
|
27790
27916
|
// apps/body/dist/acp.js
|
|
27791
27917
|
var STDERR_TAIL_MAX_CHARS2 = 2e3;
|
|
27792
27918
|
function braceDelta(line) {
|
|
@@ -28122,6 +28248,9 @@ var AcpClient = class extends EventEmitter {
|
|
|
28122
28248
|
permissionHandler;
|
|
28123
28249
|
permissionAllowlist;
|
|
28124
28250
|
commandsHandler;
|
|
28251
|
+
oomKills;
|
|
28252
|
+
/** A deliberate stop owns its SIGKILL; that exit is never labelled OOM. */
|
|
28253
|
+
stopping = false;
|
|
28125
28254
|
constructor(opts) {
|
|
28126
28255
|
super();
|
|
28127
28256
|
const command = opts.agentCommand ?? opts.agentBinary;
|
|
@@ -28139,10 +28268,13 @@ var AcpClient = class extends EventEmitter {
|
|
|
28139
28268
|
this.permissionHandler = opts.permissionHandler;
|
|
28140
28269
|
this.permissionAllowlist = opts.permissionAllowlist;
|
|
28141
28270
|
this.commandsHandler = opts.onCommands;
|
|
28271
|
+
this.oomKills = opts.oomKills ?? new OomKillTracker(cgroupOomKillProbe());
|
|
28142
28272
|
}
|
|
28143
28273
|
async start(timeoutMs = 6e4) {
|
|
28144
28274
|
if (this.alive)
|
|
28145
28275
|
return;
|
|
28276
|
+
await this.oomKills.prime().catch(() => void 0);
|
|
28277
|
+
this.stopping = false;
|
|
28146
28278
|
this.child = await withAdapterInstallLock(() => spawn10(this.agentCommand, this.agentArgs, {
|
|
28147
28279
|
// agentEnv is the child's whole environment: buildAgentEnv's allowlist is
|
|
28148
28280
|
// a real boundary, not a decorative one layered over a full inherit.
|
|
@@ -28164,19 +28296,7 @@ var AcpClient = class extends EventEmitter {
|
|
|
28164
28296
|
this.child.stdout.setEncoding("utf8");
|
|
28165
28297
|
this.child.stdout.on("data", (chunk) => this.onData(chunk));
|
|
28166
28298
|
this.child.on("exit", (code, signal) => {
|
|
28167
|
-
this.
|
|
28168
|
-
const meaningful = flattenHarnessCause(this.stderrTail);
|
|
28169
|
-
const stderrSuffix = meaningful ? `: ${meaningful}` : "";
|
|
28170
|
-
for (const [, p] of this.pending) {
|
|
28171
|
-
this.clearTimer(p);
|
|
28172
|
-
p.reject(new Error(`ACP agent ${this.agentLabel} exited code=${code} signal=${signal}${stderrSuffix}`));
|
|
28173
|
-
}
|
|
28174
|
-
this.pending.clear();
|
|
28175
|
-
this.activeRunIds.clear();
|
|
28176
|
-
this.activePromptSessions.clear();
|
|
28177
|
-
this.toolCallMetadata.clear();
|
|
28178
|
-
this.sessionCommands.clear();
|
|
28179
|
-
this.emit("exit", { code, signal });
|
|
28299
|
+
void this.handleChildExit(code, signal);
|
|
28180
28300
|
});
|
|
28181
28301
|
this.child.on("error", (err) => {
|
|
28182
28302
|
this.alive = false;
|
|
@@ -28202,12 +28322,36 @@ var AcpClient = class extends EventEmitter {
|
|
|
28202
28322
|
if (!isPiAcpHarness(this.agentLabel))
|
|
28203
28323
|
this.notify("notifications/initialized", {});
|
|
28204
28324
|
}
|
|
28325
|
+
/**
|
|
28326
|
+
* One child exit: reject every in-flight request so the turn fails and is
|
|
28327
|
+
* reported instead of hanging, then publish the exit. A SIGKILL is checked
|
|
28328
|
+
* against the daemon cgroup's OOM counter so the rejection can name the real
|
|
28329
|
+
* cause instead of a bare signal.
|
|
28330
|
+
*/
|
|
28331
|
+
async handleChildExit(code, signal) {
|
|
28332
|
+
this.alive = false;
|
|
28333
|
+
const oomKilled = signal === "SIGKILL" && !this.stopping && await this.oomKills.consume().catch(() => false);
|
|
28334
|
+
const exitText = oomKilled ? `ACP agent ${this.agentLabel} was killed by the kernel OOM killer (signal=SIGKILL)` : `ACP agent ${this.agentLabel} exited code=${code} signal=${signal}`;
|
|
28335
|
+
const meaningful = flattenHarnessCause(this.stderrTail);
|
|
28336
|
+
const stderrSuffix = meaningful ? `: ${meaningful}` : "";
|
|
28337
|
+
for (const [, p] of this.pending) {
|
|
28338
|
+
this.clearTimer(p);
|
|
28339
|
+
p.reject(new Error(`${exitText}${stderrSuffix}`));
|
|
28340
|
+
}
|
|
28341
|
+
this.pending.clear();
|
|
28342
|
+
this.activeRunIds.clear();
|
|
28343
|
+
this.activePromptSessions.clear();
|
|
28344
|
+
this.toolCallMetadata.clear();
|
|
28345
|
+
this.sessionCommands.clear();
|
|
28346
|
+
this.emit("exit", { code, signal });
|
|
28347
|
+
}
|
|
28205
28348
|
async stop() {
|
|
28206
28349
|
if (!this.alive)
|
|
28207
28350
|
return;
|
|
28208
28351
|
const child = this.child;
|
|
28209
28352
|
if (!child)
|
|
28210
28353
|
return;
|
|
28354
|
+
this.stopping = true;
|
|
28211
28355
|
try {
|
|
28212
28356
|
if (this.child?.stdin.writable) {
|
|
28213
28357
|
this.notify("shutdown", {});
|
|
@@ -28852,7 +28996,7 @@ async function applyRuntimeModelPreflight(config, agent, selection, validate = v
|
|
|
28852
28996
|
|
|
28853
28997
|
// apps/body/dist/model-catalog-sync.js
|
|
28854
28998
|
import { createHash as createHash3 } from "node:crypto";
|
|
28855
|
-
import { readFile as
|
|
28999
|
+
import { readFile as readFile10, writeFile as writeFile6 } from "node:fs/promises";
|
|
28856
29000
|
import { resolve as resolve11 } from "node:path";
|
|
28857
29001
|
var MODEL_CATALOG_PROBE_TIMEOUT_MS = 3e4;
|
|
28858
29002
|
var MODEL_CATALOG_HASH_FILE = "model-catalog.sha256";
|
|
@@ -28890,7 +29034,7 @@ async function syncAgentModelCatalog(input) {
|
|
|
28890
29034
|
const { catalog } = await withTimeout(fetchCatalog(input.agent, input.agentEnv, input.startupUnavailable ? void 0 : selection), input.timeoutMs ?? MODEL_CATALOG_PROBE_TIMEOUT_MS, "model catalog probe");
|
|
28891
29035
|
const effectiveCatalog = input.startupUnavailable ? catalog : withEffectiveCurrentValues(catalog, selection);
|
|
28892
29036
|
const hash = modelCatalogHash(effectiveCatalog, selection, input.startupUnavailable);
|
|
28893
|
-
const previous = await
|
|
29037
|
+
const previous = await readFile10(hashPath, "utf8").catch(() => "");
|
|
28894
29038
|
if (!input.force && previous.trim() === hash)
|
|
28895
29039
|
return "unchanged";
|
|
28896
29040
|
await input.api.execute("postAgentModelCatalog", {
|
|
@@ -28917,7 +29061,7 @@ import { execFile as execFile6 } from "node:child_process";
|
|
|
28917
29061
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
28918
29062
|
import { rm as rm4 } from "node:fs/promises";
|
|
28919
29063
|
import { tmpdir as tmpdir2, userInfo } from "node:os";
|
|
28920
|
-
import { join as
|
|
29064
|
+
import { join as join6 } from "node:path";
|
|
28921
29065
|
var COMMAND_TIMEOUT_MS = 2 * 6e4;
|
|
28922
29066
|
var OUTPUT_LIMIT = 32 * 1024;
|
|
28923
29067
|
var LOGIN_URL = /https:\/\/login\.tailscale\.com\/[A-Za-z0-9_/-]+/u;
|
|
@@ -29004,7 +29148,7 @@ async function ensureInstalled(run2, onProgress, platform) {
|
|
|
29004
29148
|
}
|
|
29005
29149
|
};
|
|
29006
29150
|
}
|
|
29007
|
-
const script =
|
|
29151
|
+
const script = join6(tmpdir2(), `beeline-tailscale-install-${process.pid}-${randomUUID4()}.sh`);
|
|
29008
29152
|
const steps2 = [
|
|
29009
29153
|
step2("Tailscale installed", "running", {
|
|
29010
29154
|
command: "curl -fsSL https://tailscale.com/install.sh"
|
|
@@ -29124,10 +29268,10 @@ ${up.stderr}`;
|
|
|
29124
29268
|
import { createHash as createHash4, randomBytes as randomBytes6 } from "node:crypto";
|
|
29125
29269
|
import { lookup } from "node:dns/promises";
|
|
29126
29270
|
import { createRequire as createRequire4 } from "node:module";
|
|
29127
|
-
import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync, writeFileSync } from "node:fs";
|
|
29271
|
+
import { chmodSync, existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
29128
29272
|
import { createConnection as createConnection3, createServer as createServer2, isIPv4, isIPv6 } from "node:net";
|
|
29129
29273
|
import { homedir as homedir10 } from "node:os";
|
|
29130
|
-
import { dirname as dirname9, join as
|
|
29274
|
+
import { dirname as dirname9, join as join7 } from "node:path";
|
|
29131
29275
|
import { createInterface as createInterface5 } from "node:readline";
|
|
29132
29276
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
29133
29277
|
|
|
@@ -29262,12 +29406,12 @@ async function assertNotOwnMachine(url, remoteIsOwnMachine, resolveHost) {
|
|
|
29262
29406
|
return url;
|
|
29263
29407
|
}
|
|
29264
29408
|
function registryMcpStateRoot(home = homedir10()) {
|
|
29265
|
-
return
|
|
29409
|
+
return join7(home, ".beeline", "registry-mcp");
|
|
29266
29410
|
}
|
|
29267
29411
|
function registryMcpStatePath(connectorId, home = homedir10()) {
|
|
29268
29412
|
if (!/^[0-9a-f-]{20,}$/i.test(connectorId))
|
|
29269
29413
|
throw new Error("Registry connector id is invalid");
|
|
29270
|
-
return
|
|
29414
|
+
return join7(registryMcpStateRoot(home), `${connectorId}.json`);
|
|
29271
29415
|
}
|
|
29272
29416
|
function readState(path) {
|
|
29273
29417
|
try {
|
|
@@ -29279,7 +29423,7 @@ function readState(path) {
|
|
|
29279
29423
|
}
|
|
29280
29424
|
function writeState(path, state) {
|
|
29281
29425
|
mkdirSync2(dirname9(path), { recursive: true, mode: 448 });
|
|
29282
|
-
|
|
29426
|
+
writeFileSync2(path, `${JSON.stringify(state)}
|
|
29283
29427
|
`, { mode: 384 });
|
|
29284
29428
|
}
|
|
29285
29429
|
function challengeParameter(header, key) {
|
|
@@ -29653,7 +29797,7 @@ function jsonRpcToolName(line) {
|
|
|
29653
29797
|
}
|
|
29654
29798
|
}
|
|
29655
29799
|
function brokerSocketPath(home = homedir10()) {
|
|
29656
|
-
return
|
|
29800
|
+
return join7(home, ".beeline", "registry-mcp-broker", `${process.pid}.sock`);
|
|
29657
29801
|
}
|
|
29658
29802
|
var RegistryMcpHostBroker = class {
|
|
29659
29803
|
home;
|
|
@@ -30218,13 +30362,13 @@ function describe(error) {
|
|
|
30218
30362
|
}
|
|
30219
30363
|
|
|
30220
30364
|
// apps/body/dist/institutional-memory-shadow-worker.js
|
|
30221
|
-
import { mkdtemp as mkdtemp2, readFile as
|
|
30365
|
+
import { mkdtemp as mkdtemp2, readFile as readFile11, rm as rm5 } from "node:fs/promises";
|
|
30222
30366
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
30223
|
-
import { join as
|
|
30367
|
+
import { join as join9, resolve as resolve12 } from "node:path";
|
|
30224
30368
|
|
|
30225
30369
|
// apps/body/dist/attachment-delivery.js
|
|
30226
30370
|
import { mkdir as mkdir7, writeFile as writeFile7 } from "node:fs/promises";
|
|
30227
|
-
import { basename as
|
|
30371
|
+
import { basename as basename5, extname, join as join8 } from "node:path";
|
|
30228
30372
|
var MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;
|
|
30229
30373
|
var EXPIRED_REASON = "expired: these attachment bytes are past their retention window";
|
|
30230
30374
|
var FETCH_TIMEOUT_MS = 3e4;
|
|
@@ -30254,7 +30398,7 @@ async function fetchBoundedBytes(url, fetchImpl = fetch) {
|
|
|
30254
30398
|
}
|
|
30255
30399
|
var MAX_INLINE_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
30256
30400
|
function safeFileName(attachment, index, taken) {
|
|
30257
|
-
const raw =
|
|
30401
|
+
const raw = basename5(attachment.name ?? "").replace(/[^\w.-]+/g, "_").replace(/^\.+/, "");
|
|
30258
30402
|
let name = raw || `attachment-${index + 1}`;
|
|
30259
30403
|
if (taken.has(name)) {
|
|
30260
30404
|
const ext = extname(name);
|
|
@@ -30283,7 +30427,7 @@ async function deliverAttachments(attachments, dir, fetchImpl = fetch) {
|
|
|
30283
30427
|
return { attachment, reason: EXPIRED_REASON };
|
|
30284
30428
|
if (!fetched.ok)
|
|
30285
30429
|
throw new Error(`HTTP ${fetched.status}`);
|
|
30286
|
-
const path =
|
|
30430
|
+
const path = join8(dir, safeFileName(attachment, index, taken));
|
|
30287
30431
|
await writeFile7(path, fetched.bytes);
|
|
30288
30432
|
const bytes = fetched.bytes;
|
|
30289
30433
|
const mimeType = attachment.mimeType ?? fetched.mimeType;
|
|
@@ -30422,7 +30566,7 @@ async function readInstitutionalMemoryAttachments(job, dir, acceptsImages, fetch
|
|
|
30422
30566
|
for (const message of job.messages) {
|
|
30423
30567
|
if (!message.attachments?.length)
|
|
30424
30568
|
continue;
|
|
30425
|
-
const delivered = await deliverAttachments(message.attachments,
|
|
30569
|
+
const delivered = await deliverAttachments(message.attachments, join9(dir, message.id), fetchImpl);
|
|
30426
30570
|
for (const entry of delivered) {
|
|
30427
30571
|
const { attachment } = entry;
|
|
30428
30572
|
const mimeType = attachment.mimeType ?? entry.image?.mimeType;
|
|
@@ -30447,7 +30591,7 @@ async function readInstitutionalMemoryAttachments(job, dir, acceptsImages, fetch
|
|
|
30447
30591
|
evidence.push({ ...base, notRead: "the attachment text budget is used up" });
|
|
30448
30592
|
continue;
|
|
30449
30593
|
}
|
|
30450
|
-
const text2 = clipText(await
|
|
30594
|
+
const text2 = clipText(await readFile11(entry.path, "utf8"), textBudget);
|
|
30451
30595
|
textBudget -= Buffer.byteLength(text2, "utf8");
|
|
30452
30596
|
evidence.push({ ...base, text: text2 });
|
|
30453
30597
|
} else {
|
|
@@ -30561,7 +30705,7 @@ async function extractInstitutionalMemoryShadowJob(job, options, signal) {
|
|
|
30561
30705
|
if (options.modelSelection) {
|
|
30562
30706
|
await applyAgentModelSelection(client, opened.sessionId, parseAdvertisedConfigOptions(opened.raw, options.modelSelection.model), options.modelSelection);
|
|
30563
30707
|
}
|
|
30564
|
-
const attachments = await readInstitutionalMemoryAttachments(job,
|
|
30708
|
+
const attachments = await readInstitutionalMemoryAttachments(job, join9(scratch, "attachments"), client.canPromptWithImages(), options.fetch);
|
|
30565
30709
|
prompt = institutionalMemoryExtractionPrompt(job, attachments.evidence);
|
|
30566
30710
|
const result = await client.sessionPrompt(opened.sessionId, promptWithImages(prompt, attachments.images));
|
|
30567
30711
|
const proposal = parseExtractionText(result.agentText, job.triggerKind);
|
|
@@ -30704,9 +30848,9 @@ function helperVersionHeader(value) {
|
|
|
30704
30848
|
|
|
30705
30849
|
// apps/body/dist/host-read-budget.js
|
|
30706
30850
|
import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
|
|
30707
|
-
import { mkdir as mkdir8, open as open3, readFile as
|
|
30851
|
+
import { mkdir as mkdir8, open as open3, readFile as readFile12, readdir as readdir3, stat as stat5, unlink as unlink4, writeFile as writeFile8 } from "node:fs/promises";
|
|
30708
30852
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
30709
|
-
import { join as
|
|
30853
|
+
import { join as join10 } from "node:path";
|
|
30710
30854
|
var READ_SLOTS = 6;
|
|
30711
30855
|
var BACKGROUND_SLOTS = 4;
|
|
30712
30856
|
var MAX_WAITERS = 256;
|
|
@@ -30737,7 +30881,7 @@ var HostReadBudget = class {
|
|
|
30737
30881
|
const uid = process.getuid?.() ?? "unknown";
|
|
30738
30882
|
const origin = new URL(baseUrl).origin;
|
|
30739
30883
|
const key = createHash5("sha256").update(origin).digest("hex").slice(0, 16);
|
|
30740
|
-
this.directory =
|
|
30884
|
+
this.directory = join10(root, `beeline-read-budget-${uid}-${key}`);
|
|
30741
30885
|
}
|
|
30742
30886
|
metrics() {
|
|
30743
30887
|
return { waiting: this.waiting, active: this.active, totalWaitMs: this.totalWaitMs };
|
|
@@ -30745,7 +30889,7 @@ var HostReadBudget = class {
|
|
|
30745
30889
|
async acquire(priority, deadlineAt) {
|
|
30746
30890
|
await mkdir8(this.directory, { recursive: true, mode: 448 });
|
|
30747
30891
|
const ticket = `wait-${priority === "urgent" ? "0" : "1"}-${String(Date.now()).padStart(13, "0")}-${randomUUID5()}`;
|
|
30748
|
-
const ticketPath =
|
|
30892
|
+
const ticketPath = join10(this.directory, ticket);
|
|
30749
30893
|
const tickets = (await readdir3(this.directory)).filter((name) => name.startsWith("wait-"));
|
|
30750
30894
|
if (tickets.length >= MAX_WAITERS)
|
|
30751
30895
|
throw new ReadBudgetFullError();
|
|
@@ -30757,14 +30901,14 @@ var HostReadBudget = class {
|
|
|
30757
30901
|
const queue = (await readdir3(this.directory)).filter((name) => name.startsWith("wait-")).sort();
|
|
30758
30902
|
for (const name of queue.slice(0, READ_SLOTS)) {
|
|
30759
30903
|
if (name !== ticket)
|
|
30760
|
-
await this.reapStaleTicket(
|
|
30904
|
+
await this.reapStaleTicket(join10(this.directory, name));
|
|
30761
30905
|
}
|
|
30762
30906
|
const liveQueue = (await readdir3(this.directory)).filter((name) => name.startsWith("wait-")).sort();
|
|
30763
30907
|
const rank = liveQueue.indexOf(ticket);
|
|
30764
30908
|
const available = priority === "urgent" ? READ_SLOTS : BACKGROUND_SLOTS;
|
|
30765
30909
|
if (rank >= 0 && rank < available) {
|
|
30766
30910
|
for (let slot = 0; slot < available; slot += 1) {
|
|
30767
|
-
const slotPath =
|
|
30911
|
+
const slotPath = join10(this.directory, `slot-${slot}`);
|
|
30768
30912
|
try {
|
|
30769
30913
|
const handle2 = await open3(slotPath, "wx", 384);
|
|
30770
30914
|
try {
|
|
@@ -30814,7 +30958,7 @@ var HostReadBudget = class {
|
|
|
30814
30958
|
const details = await stat5(path).catch(() => void 0);
|
|
30815
30959
|
if (!details || Date.now() - details.mtimeMs < 2e3)
|
|
30816
30960
|
return;
|
|
30817
|
-
const owner = await
|
|
30961
|
+
const owner = await readFile12(path, "utf8").then((value) => {
|
|
30818
30962
|
try {
|
|
30819
30963
|
return JSON.parse(value);
|
|
30820
30964
|
} catch {
|
|
@@ -30829,13 +30973,13 @@ var HostReadBudget = class {
|
|
|
30829
30973
|
const details = await stat5(path).catch(() => void 0);
|
|
30830
30974
|
if (!details || Date.now() - details.mtimeMs < 2e3)
|
|
30831
30975
|
return;
|
|
30832
|
-
const pid = Number(await
|
|
30976
|
+
const pid = Number(await readFile12(path, "utf8").catch(() => "0"));
|
|
30833
30977
|
if (pid > 0 && ownerAlive(pid) && Date.now() - details.mtimeMs < STALE_SLOT_MS)
|
|
30834
30978
|
return;
|
|
30835
30979
|
await unlink4(path).catch(() => void 0);
|
|
30836
30980
|
}
|
|
30837
30981
|
async takeRateToken(deadlineAt) {
|
|
30838
|
-
const lock =
|
|
30982
|
+
const lock = join10(this.directory, "rate.lock");
|
|
30839
30983
|
let handle2;
|
|
30840
30984
|
try {
|
|
30841
30985
|
handle2 = await open3(lock, "wx", 384);
|
|
@@ -30846,8 +30990,8 @@ var HostReadBudget = class {
|
|
|
30846
30990
|
return false;
|
|
30847
30991
|
}
|
|
30848
30992
|
try {
|
|
30849
|
-
const path =
|
|
30850
|
-
const next = Number(await
|
|
30993
|
+
const path = join10(this.directory, "next-admission");
|
|
30994
|
+
const next = Number(await readFile12(path, "utf8").catch(() => "0")) || 0;
|
|
30851
30995
|
const now2 = Date.now();
|
|
30852
30996
|
if (next > now2 || now2 >= deadlineAt)
|
|
30853
30997
|
return false;
|
|
@@ -30860,6 +31004,251 @@ var HostReadBudget = class {
|
|
|
30860
31004
|
}
|
|
30861
31005
|
};
|
|
30862
31006
|
|
|
31007
|
+
// apps/body/dist/live-link.js
|
|
31008
|
+
var LIVE_LINK_TIMING = Object.freeze({
|
|
31009
|
+
handshakeTimeoutMs: 3e4,
|
|
31010
|
+
pongTimeoutMs: 15e3,
|
|
31011
|
+
backoffBaseMs: 1e3,
|
|
31012
|
+
backoffMaxMs: 3e4,
|
|
31013
|
+
stableSocketMs: 3e4,
|
|
31014
|
+
stableCloseJitterMs: 1e4,
|
|
31015
|
+
keepAliveDelayMs: 5 * 6e4
|
|
31016
|
+
});
|
|
31017
|
+
var NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
31018
|
+
"ECONNRESET",
|
|
31019
|
+
"ECONNREFUSED",
|
|
31020
|
+
"ENOTFOUND",
|
|
31021
|
+
"EAI_AGAIN",
|
|
31022
|
+
"ETIMEDOUT",
|
|
31023
|
+
"EHOSTUNREACH",
|
|
31024
|
+
"ENETUNREACH",
|
|
31025
|
+
"EPIPE",
|
|
31026
|
+
"ECONNABORTED"
|
|
31027
|
+
]);
|
|
31028
|
+
function isNetworkFailure(error) {
|
|
31029
|
+
const seen = /* @__PURE__ */ new Set();
|
|
31030
|
+
const visit = (value) => {
|
|
31031
|
+
if (!value || typeof value !== "object" || seen.has(value))
|
|
31032
|
+
return false;
|
|
31033
|
+
seen.add(value);
|
|
31034
|
+
const code = value.code;
|
|
31035
|
+
if (typeof code === "string" && (NETWORK_ERROR_CODES.has(code) || code.startsWith("UND_ERR_")))
|
|
31036
|
+
return true;
|
|
31037
|
+
if (value instanceof AggregateError && value.errors.length > 0 && value.errors.every(visit))
|
|
31038
|
+
return true;
|
|
31039
|
+
return visit(value.cause);
|
|
31040
|
+
};
|
|
31041
|
+
return visit(error);
|
|
31042
|
+
}
|
|
31043
|
+
function retryAfterMs(value) {
|
|
31044
|
+
if (!value)
|
|
31045
|
+
return void 0;
|
|
31046
|
+
const seconds = Number(value);
|
|
31047
|
+
const delay = Number.isFinite(seconds) && seconds >= 0 ? seconds * 1e3 : Date.parse(value) - Date.now();
|
|
31048
|
+
return Number.isFinite(delay) && delay >= 0 ? Math.min(delay, 6e4) : void 0;
|
|
31049
|
+
}
|
|
31050
|
+
var LiveLink = class {
|
|
31051
|
+
options;
|
|
31052
|
+
#state = "disconnected";
|
|
31053
|
+
#socket;
|
|
31054
|
+
#openedAt;
|
|
31055
|
+
#failedConnects = 0;
|
|
31056
|
+
#retryAfterMs = 0;
|
|
31057
|
+
#reconnect;
|
|
31058
|
+
#pongDeadline;
|
|
31059
|
+
#wanted = false;
|
|
31060
|
+
#updateAnnounced = false;
|
|
31061
|
+
#reconnects = 0;
|
|
31062
|
+
#openListeners = /* @__PURE__ */ new Set();
|
|
31063
|
+
#timing;
|
|
31064
|
+
#random;
|
|
31065
|
+
#now;
|
|
31066
|
+
constructor(options) {
|
|
31067
|
+
this.options = options;
|
|
31068
|
+
this.#timing = { ...LIVE_LINK_TIMING, ...options.timing };
|
|
31069
|
+
this.#random = options.random ?? Math.random;
|
|
31070
|
+
this.#now = options.now ?? Date.now;
|
|
31071
|
+
}
|
|
31072
|
+
get state() {
|
|
31073
|
+
return this.#state;
|
|
31074
|
+
}
|
|
31075
|
+
get reconnects() {
|
|
31076
|
+
return this.#reconnects;
|
|
31077
|
+
}
|
|
31078
|
+
/** A suspect socket is still open for writes until its pong deadline. */
|
|
31079
|
+
isOpen() {
|
|
31080
|
+
return this.#state === "open" || this.#state === "suspect";
|
|
31081
|
+
}
|
|
31082
|
+
/** Called on every open, after the link's own open handling. */
|
|
31083
|
+
onOpen(listener) {
|
|
31084
|
+
this.#openListeners.add(listener);
|
|
31085
|
+
return () => this.#openListeners.delete(listener);
|
|
31086
|
+
}
|
|
31087
|
+
start() {
|
|
31088
|
+
if (this.#state === "update-required")
|
|
31089
|
+
return;
|
|
31090
|
+
this.#wanted = true;
|
|
31091
|
+
if (!this.#socket && !this.#reconnect)
|
|
31092
|
+
this.#connect();
|
|
31093
|
+
}
|
|
31094
|
+
stop() {
|
|
31095
|
+
this.#wanted = false;
|
|
31096
|
+
this.#clearTimers();
|
|
31097
|
+
const socket = this.#socket;
|
|
31098
|
+
this.#socket = void 0;
|
|
31099
|
+
if (this.#state !== "update-required")
|
|
31100
|
+
this.#state = "disconnected";
|
|
31101
|
+
socket?.close();
|
|
31102
|
+
}
|
|
31103
|
+
send(data) {
|
|
31104
|
+
if (!this.isOpen() || this.#socket?.readyState !== wrapper_default.OPEN)
|
|
31105
|
+
return false;
|
|
31106
|
+
this.#socket.send(data);
|
|
31107
|
+
return true;
|
|
31108
|
+
}
|
|
31109
|
+
/**
|
|
31110
|
+
* Something suggests the socket may be dead (a network-class HTTP failure,
|
|
31111
|
+
* an admitted fetch past its deadline, a failed reconcile). Ask the socket
|
|
31112
|
+
* itself: one ping, and no pong within the deadline drops it. A socket that
|
|
31113
|
+
* is not open is already on its way to a new one.
|
|
31114
|
+
*/
|
|
31115
|
+
suspect() {
|
|
31116
|
+
const socket = this.#socket;
|
|
31117
|
+
if (this.#state !== "open" || !socket)
|
|
31118
|
+
return;
|
|
31119
|
+
this.#state = "suspect";
|
|
31120
|
+
try {
|
|
31121
|
+
socket.ping?.();
|
|
31122
|
+
} catch {
|
|
31123
|
+
}
|
|
31124
|
+
this.#pongDeadline = setTimeout(() => {
|
|
31125
|
+
this.#pongDeadline = void 0;
|
|
31126
|
+
if (this.#socket === socket && this.#state === "suspect")
|
|
31127
|
+
socket.terminate();
|
|
31128
|
+
}, this.#timing.pongTimeoutMs);
|
|
31129
|
+
this.#pongDeadline.unref?.();
|
|
31130
|
+
}
|
|
31131
|
+
/** The server requires a newer helper: stop for good and say so once. */
|
|
31132
|
+
requireUpdate(minVersion) {
|
|
31133
|
+
this.#markUpdateRequired();
|
|
31134
|
+
if (this.#updateAnnounced)
|
|
31135
|
+
return;
|
|
31136
|
+
this.#updateAnnounced = true;
|
|
31137
|
+
this.options.onUpdateRequired(minVersion);
|
|
31138
|
+
}
|
|
31139
|
+
#markUpdateRequired() {
|
|
31140
|
+
this.#state = "update-required";
|
|
31141
|
+
this.#clearTimers();
|
|
31142
|
+
const socket = this.#socket;
|
|
31143
|
+
this.#socket = void 0;
|
|
31144
|
+
socket?.close();
|
|
31145
|
+
}
|
|
31146
|
+
#clearTimers() {
|
|
31147
|
+
clearTimeout(this.#reconnect);
|
|
31148
|
+
this.#reconnect = void 0;
|
|
31149
|
+
clearTimeout(this.#pongDeadline);
|
|
31150
|
+
this.#pongDeadline = void 0;
|
|
31151
|
+
}
|
|
31152
|
+
#connect() {
|
|
31153
|
+
const socket = this.options.factory(this.options.url(), this.options.protocols(), {
|
|
31154
|
+
handshakeTimeout: this.#timing.handshakeTimeoutMs
|
|
31155
|
+
});
|
|
31156
|
+
this.#socket = socket;
|
|
31157
|
+
this.#state = "connecting";
|
|
31158
|
+
this.#openedAt = void 0;
|
|
31159
|
+
socket.on?.("upgrade", (response) => {
|
|
31160
|
+
response.socket?.setKeepAlive?.(true, this.#timing.keepAliveDelayMs);
|
|
31161
|
+
});
|
|
31162
|
+
socket.on?.("unexpected-response", (_request, response) => {
|
|
31163
|
+
if (response.statusCode !== 426) {
|
|
31164
|
+
this.#retryAfterMs = retryAfterMs(headerValue(response.headers?.["retry-after"])) ?? 0;
|
|
31165
|
+
socket.terminate();
|
|
31166
|
+
return;
|
|
31167
|
+
}
|
|
31168
|
+
this.#state = "update-required";
|
|
31169
|
+
this.#clearTimers();
|
|
31170
|
+
let body = "";
|
|
31171
|
+
response.on("data", (chunk) => {
|
|
31172
|
+
if (body.length < 1024)
|
|
31173
|
+
body += chunk.toString("utf8").slice(0, 1024 - body.length);
|
|
31174
|
+
});
|
|
31175
|
+
response.on("end", () => {
|
|
31176
|
+
try {
|
|
31177
|
+
const refusal = JSON.parse(body);
|
|
31178
|
+
if (refusal.error === "update_required" && typeof refusal.minVersion === "string")
|
|
31179
|
+
this.requireUpdate(refusal.minVersion);
|
|
31180
|
+
} catch {
|
|
31181
|
+
}
|
|
31182
|
+
});
|
|
31183
|
+
response.on("close", () => socket.terminate());
|
|
31184
|
+
});
|
|
31185
|
+
socket.on?.("pong", () => {
|
|
31186
|
+
if (this.#socket !== socket || this.#state !== "suspect")
|
|
31187
|
+
return;
|
|
31188
|
+
clearTimeout(this.#pongDeadline);
|
|
31189
|
+
this.#pongDeadline = void 0;
|
|
31190
|
+
this.#state = "open";
|
|
31191
|
+
});
|
|
31192
|
+
socket.onopen = () => {
|
|
31193
|
+
if (this.#socket !== socket)
|
|
31194
|
+
return;
|
|
31195
|
+
this.#state = "open";
|
|
31196
|
+
this.#openedAt = this.#now();
|
|
31197
|
+
this.options.onOpen();
|
|
31198
|
+
for (const listener of [...this.#openListeners]) {
|
|
31199
|
+
try {
|
|
31200
|
+
listener();
|
|
31201
|
+
} catch (error) {
|
|
31202
|
+
console.error("[live-link] open listener failed", error);
|
|
31203
|
+
}
|
|
31204
|
+
}
|
|
31205
|
+
};
|
|
31206
|
+
socket.onmessage = (message) => {
|
|
31207
|
+
if (this.#socket === socket)
|
|
31208
|
+
this.options.onMessage(String(message.data));
|
|
31209
|
+
};
|
|
31210
|
+
socket.onerror = () => void 0;
|
|
31211
|
+
socket.onclose = () => {
|
|
31212
|
+
if (this.#socket !== socket)
|
|
31213
|
+
return;
|
|
31214
|
+
this.#socket = void 0;
|
|
31215
|
+
clearTimeout(this.#pongDeadline);
|
|
31216
|
+
this.#pongDeadline = void 0;
|
|
31217
|
+
const openedAt = this.#openedAt;
|
|
31218
|
+
this.#openedAt = void 0;
|
|
31219
|
+
if (this.#state !== "update-required")
|
|
31220
|
+
this.#state = "disconnected";
|
|
31221
|
+
this.options.onClose();
|
|
31222
|
+
if (this.#state === "update-required" || !this.#wanted)
|
|
31223
|
+
return;
|
|
31224
|
+
this.#scheduleReconnect(openedAt);
|
|
31225
|
+
};
|
|
31226
|
+
}
|
|
31227
|
+
#scheduleReconnect(openedAt) {
|
|
31228
|
+
let delay;
|
|
31229
|
+
if (openedAt !== void 0 && this.#now() - openedAt >= this.#timing.stableSocketMs) {
|
|
31230
|
+
this.#failedConnects = 0;
|
|
31231
|
+
delay = this.#random() * this.#timing.stableCloseJitterMs;
|
|
31232
|
+
} else {
|
|
31233
|
+
const ceiling = Math.min(this.#timing.backoffMaxMs, this.#timing.backoffBaseMs * 2 ** this.#failedConnects);
|
|
31234
|
+
this.#failedConnects += 1;
|
|
31235
|
+
delay = this.#random() * ceiling;
|
|
31236
|
+
}
|
|
31237
|
+
delay = Math.floor(Math.max(delay, this.#retryAfterMs));
|
|
31238
|
+
this.#retryAfterMs = 0;
|
|
31239
|
+
this.#reconnects += 1;
|
|
31240
|
+
this.#reconnect = setTimeout(() => {
|
|
31241
|
+
this.#reconnect = void 0;
|
|
31242
|
+
if (this.#wanted && !this.#socket && this.#state !== "update-required")
|
|
31243
|
+
this.#connect();
|
|
31244
|
+
}, delay);
|
|
31245
|
+
this.#reconnect.unref?.();
|
|
31246
|
+
}
|
|
31247
|
+
};
|
|
31248
|
+
function headerValue(value) {
|
|
31249
|
+
return Array.isArray(value) ? value[0] : value;
|
|
31250
|
+
}
|
|
31251
|
+
|
|
30863
31252
|
// apps/body/dist/daemon-api-client.js
|
|
30864
31253
|
init_runtime();
|
|
30865
31254
|
var DaemonApiError = class extends Error {
|
|
@@ -30908,32 +31297,19 @@ async function responseError(response) {
|
|
|
30908
31297
|
}
|
|
30909
31298
|
return new DaemonApiError(`monolith daemon request failed (${response.status}: ${code})`, response.status, response.status === 408 || response.status === 429 || response.status >= 500, code, retryAfterMs(response.headers.get("retry-after")), minVersion);
|
|
30910
31299
|
}
|
|
30911
|
-
function retryAfterMs(value) {
|
|
30912
|
-
if (!value)
|
|
30913
|
-
return void 0;
|
|
30914
|
-
const seconds = Number(value);
|
|
30915
|
-
const delay = Number.isFinite(seconds) && seconds >= 0 ? seconds * 1e3 : Date.parse(value) - Date.now();
|
|
30916
|
-
return Number.isFinite(delay) && delay >= 0 ? Math.min(delay, 6e4) : void 0;
|
|
30917
|
-
}
|
|
30918
31300
|
var REQUEST_DEADLINE_MS = 3e4;
|
|
30919
|
-
var STABLE_SOCKET_MS = 3e4;
|
|
30920
31301
|
var DaemonApiClient = class {
|
|
30921
31302
|
baseUrl;
|
|
30922
31303
|
daemonToken;
|
|
30923
31304
|
agentId;
|
|
30924
31305
|
fetchImpl;
|
|
30925
|
-
webSocketFactory;
|
|
30926
31306
|
presenceLifecycleId = randomUUID6();
|
|
30927
|
-
|
|
30928
|
-
|
|
30929
|
-
liveReconnectDelayMs = 1e3;
|
|
30930
|
-
liveOpenedAt = 0;
|
|
31307
|
+
/** The one live socket; it reconnects by itself for as long as it is wanted. */
|
|
31308
|
+
link;
|
|
30931
31309
|
inFlight = 0;
|
|
30932
31310
|
requestCount = 0;
|
|
30933
31311
|
timeoutCount = 0;
|
|
30934
|
-
reconnectCount = 0;
|
|
30935
31312
|
subscriptionCount = 0;
|
|
30936
|
-
discoveryWakeSupported = false;
|
|
30937
31313
|
readBudget;
|
|
30938
31314
|
liveRooms = /* @__PURE__ */ new Map();
|
|
30939
31315
|
roomsChangedListener;
|
|
@@ -30944,17 +31320,28 @@ var DaemonApiClient = class {
|
|
|
30944
31320
|
cornerRestartListener;
|
|
30945
31321
|
helperReleaseListener;
|
|
30946
31322
|
forceUpdateListener;
|
|
30947
|
-
forceUpdatePending = false;
|
|
30948
31323
|
helperIdentity = {
|
|
30949
31324
|
releaseVersion: "v0.0.0"
|
|
30950
31325
|
};
|
|
30951
|
-
constructor(baseUrl, daemonToken, agentId, fetchImpl = fetch, webSocketFactory = (url, protocols) => new wrapper_default(url, protocols), readBudget) {
|
|
31326
|
+
constructor(baseUrl, daemonToken, agentId, fetchImpl = fetch, webSocketFactory = (url, protocols, options) => new wrapper_default(url, protocols, options), readBudget, linkTiming) {
|
|
30952
31327
|
this.baseUrl = baseUrl;
|
|
30953
31328
|
this.daemonToken = daemonToken;
|
|
30954
31329
|
this.agentId = agentId;
|
|
30955
31330
|
this.fetchImpl = fetchImpl;
|
|
30956
|
-
this.webSocketFactory = webSocketFactory;
|
|
30957
31331
|
this.readBudget = readBudget ?? (fetchImpl === fetch ? new HostReadBudget(baseUrl) : void 0);
|
|
31332
|
+
this.link = new LiveLink({
|
|
31333
|
+
url: () => this.liveUrl(),
|
|
31334
|
+
protocols: () => [`bearer.${this.daemonToken}`],
|
|
31335
|
+
factory: webSocketFactory,
|
|
31336
|
+
onOpen: () => this.liveOpened(),
|
|
31337
|
+
onMessage: (data) => this.liveMessage(data),
|
|
31338
|
+
onClose: () => {
|
|
31339
|
+
for (const room of this.liveRooms.values())
|
|
31340
|
+
room.onState?.(false);
|
|
31341
|
+
},
|
|
31342
|
+
onUpdateRequired: (minVersion) => this.forceUpdateListener?.(minVersion),
|
|
31343
|
+
...linkTiming ? { timing: linkTiming } : {}
|
|
31344
|
+
});
|
|
30958
31345
|
}
|
|
30959
31346
|
/** Connection material for the daemon-owned MCP proxy and corner credentials. */
|
|
30960
31347
|
connection() {
|
|
@@ -30980,24 +31367,15 @@ var DaemonApiClient = class {
|
|
|
30980
31367
|
inFlight: this.inFlight,
|
|
30981
31368
|
requests: this.requestCount,
|
|
30982
31369
|
timeouts: this.timeoutCount,
|
|
30983
|
-
reconnects: this.
|
|
31370
|
+
reconnects: this.link.reconnects,
|
|
30984
31371
|
subscriptionsSent: this.subscriptionCount,
|
|
30985
31372
|
readQueueDepth: budget?.waiting ?? 0,
|
|
30986
31373
|
readQueueWaitMs: budget?.totalWaitMs ?? 0
|
|
30987
31374
|
};
|
|
30988
31375
|
}
|
|
30989
|
-
/**
|
|
30990
|
-
|
|
30991
|
-
return this.
|
|
30992
|
-
}
|
|
30993
|
-
requestForceUpdate(minVersion) {
|
|
30994
|
-
if (this.forceUpdatePending)
|
|
30995
|
-
return;
|
|
30996
|
-
this.forceUpdatePending = true;
|
|
30997
|
-
clearTimeout(this.liveReconnect);
|
|
30998
|
-
this.liveReconnect = void 0;
|
|
30999
|
-
this.forceUpdateListener?.(minVersion);
|
|
31000
|
-
this.liveSocket?.close();
|
|
31376
|
+
/** Called on every live socket open, after resubscription and the wakes. */
|
|
31377
|
+
onLiveOpen(listener) {
|
|
31378
|
+
return this.link.onOpen(listener);
|
|
31001
31379
|
}
|
|
31002
31380
|
/** Add one Room to this agent's shared live socket. */
|
|
31003
31381
|
liveSubscribe(roomId, cursor3, onItems, onState, presence, onCommands) {
|
|
@@ -31020,18 +31398,12 @@ var DaemonApiClient = class {
|
|
|
31020
31398
|
});
|
|
31021
31399
|
}
|
|
31022
31400
|
this.ensureLiveSocket();
|
|
31023
|
-
|
|
31024
|
-
this.sendLiveSubscription(roomId);
|
|
31401
|
+
this.sendLiveSubscription(roomId);
|
|
31025
31402
|
return () => {
|
|
31026
31403
|
this.liveRooms.delete(roomId);
|
|
31027
|
-
|
|
31028
|
-
|
|
31029
|
-
|
|
31030
|
-
if (!this.liveRooms.size && !this.roomsChangedListener) {
|
|
31031
|
-
clearTimeout(this.liveReconnect);
|
|
31032
|
-
this.liveSocket?.close();
|
|
31033
|
-
this.liveSocket = void 0;
|
|
31034
|
-
}
|
|
31404
|
+
this.link.send(JSON.stringify({ type: "unsubscribe", roomId }));
|
|
31405
|
+
if (!this.liveRooms.size && !this.roomsChangedListener)
|
|
31406
|
+
this.link.stop();
|
|
31035
31407
|
};
|
|
31036
31408
|
}
|
|
31037
31409
|
/** Register the one listener invoked when the server reports this agent's
|
|
@@ -31072,17 +31444,9 @@ var DaemonApiClient = class {
|
|
|
31072
31444
|
if (room && cursor3)
|
|
31073
31445
|
room.cursor = cursor3;
|
|
31074
31446
|
}
|
|
31075
|
-
/** Retry an uncertain discovery read through socket reconnect backoff. */
|
|
31076
|
-
reconnectLive() {
|
|
31077
|
-
this.liveSocket?.close();
|
|
31078
|
-
}
|
|
31079
31447
|
/** Release the long-lived socket when the helper itself is shutting down. */
|
|
31080
31448
|
closeLive() {
|
|
31081
|
-
|
|
31082
|
-
this.liveReconnect = void 0;
|
|
31083
|
-
const socket = this.liveSocket;
|
|
31084
|
-
this.liveSocket = void 0;
|
|
31085
|
-
socket?.close();
|
|
31449
|
+
this.link.stop();
|
|
31086
31450
|
}
|
|
31087
31451
|
async execute(name, input) {
|
|
31088
31452
|
const candidate = input;
|
|
@@ -31116,7 +31480,7 @@ var DaemonApiClient = class {
|
|
|
31116
31480
|
if (!response.ok) {
|
|
31117
31481
|
const error = await responseError(response);
|
|
31118
31482
|
if (error.status === 426 && error.code === "update_required" && error.minVersion)
|
|
31119
|
-
this.
|
|
31483
|
+
this.link.requireUpdate(error.minVersion);
|
|
31120
31484
|
throw error;
|
|
31121
31485
|
}
|
|
31122
31486
|
output = await response.json();
|
|
@@ -31126,8 +31490,12 @@ var DaemonApiClient = class {
|
|
|
31126
31490
|
}
|
|
31127
31491
|
if (controller.signal.aborted) {
|
|
31128
31492
|
this.timeoutCount += 1;
|
|
31493
|
+
if (admitted)
|
|
31494
|
+
this.link.suspect();
|
|
31129
31495
|
throw new DaemonApiError(`monolith daemon ${String(name)} timed out`, 408, true, "deadline_exceeded");
|
|
31130
31496
|
}
|
|
31497
|
+
if (isNetworkFailure(error))
|
|
31498
|
+
this.link.suspect();
|
|
31131
31499
|
throw error;
|
|
31132
31500
|
} finally {
|
|
31133
31501
|
clearTimeout(deadline);
|
|
@@ -31138,171 +31506,121 @@ var DaemonApiClient = class {
|
|
|
31138
31506
|
return output;
|
|
31139
31507
|
}
|
|
31140
31508
|
ensureLiveSocket() {
|
|
31141
|
-
if (this.
|
|
31142
|
-
|
|
31509
|
+
if (this.liveRooms.size || this.roomsChangedListener)
|
|
31510
|
+
this.link.start();
|
|
31511
|
+
}
|
|
31512
|
+
liveUrl() {
|
|
31143
31513
|
const liveUrl = new URL("/v1/phone/live", this.baseUrl);
|
|
31144
31514
|
liveUrl.protocol = liveUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
31145
31515
|
liveUrl.searchParams.set("helperVersion", this.helperIdentity.releaseVersion);
|
|
31146
31516
|
if (this.helperIdentity.sourceSha)
|
|
31147
31517
|
liveUrl.searchParams.set("sourceSha", this.helperIdentity.sourceSha);
|
|
31148
|
-
|
|
31149
|
-
|
|
31150
|
-
|
|
31151
|
-
this.
|
|
31152
|
-
|
|
31153
|
-
|
|
31154
|
-
|
|
31155
|
-
|
|
31156
|
-
|
|
31157
|
-
|
|
31158
|
-
|
|
31159
|
-
|
|
31160
|
-
|
|
31161
|
-
|
|
31162
|
-
|
|
31163
|
-
|
|
31164
|
-
|
|
31165
|
-
|
|
31166
|
-
|
|
31167
|
-
|
|
31168
|
-
|
|
31169
|
-
|
|
31170
|
-
|
|
31171
|
-
|
|
31172
|
-
|
|
31173
|
-
|
|
31174
|
-
|
|
31175
|
-
|
|
31176
|
-
|
|
31518
|
+
return liveUrl.toString();
|
|
31519
|
+
}
|
|
31520
|
+
liveOpened() {
|
|
31521
|
+
for (const roomId of this.liveRooms.keys())
|
|
31522
|
+
this.sendLiveSubscription(roomId);
|
|
31523
|
+
this.roomsChangedListener?.();
|
|
31524
|
+
this.connectorAssignmentListener?.();
|
|
31525
|
+
this.memoryJobListener?.();
|
|
31526
|
+
}
|
|
31527
|
+
liveMessage(data) {
|
|
31528
|
+
let value;
|
|
31529
|
+
try {
|
|
31530
|
+
value = JSON.parse(data);
|
|
31531
|
+
} catch {
|
|
31532
|
+
return;
|
|
31533
|
+
}
|
|
31534
|
+
if (!value || typeof value !== "object")
|
|
31535
|
+
return;
|
|
31536
|
+
const event = value;
|
|
31537
|
+
if (event.type === "force-update" && typeof event.minVersion === "string") {
|
|
31538
|
+
this.link.requireUpdate(event.minVersion);
|
|
31539
|
+
return;
|
|
31540
|
+
}
|
|
31541
|
+
if (event.type === "helper-release" && typeof event.version === "string" && typeof event.sha === "string") {
|
|
31542
|
+
this.helperReleaseListener?.({ version: event.version, sha: event.sha });
|
|
31543
|
+
return;
|
|
31544
|
+
}
|
|
31545
|
+
if (event.type === "rooms-changed") {
|
|
31546
|
+
this.roomsChangedListener?.(membershipChange(event));
|
|
31547
|
+
return;
|
|
31548
|
+
}
|
|
31549
|
+
if (event.type === "discovery-wake" && (event.reason === "listener-resync" || event.reason === "database-recovered")) {
|
|
31177
31550
|
this.roomsChangedListener?.();
|
|
31551
|
+
return;
|
|
31552
|
+
}
|
|
31553
|
+
if (event.type === "corner-complete" && typeof event.roomId === "string") {
|
|
31554
|
+
this.cornerCompleteListener?.(event.roomId);
|
|
31555
|
+
return;
|
|
31556
|
+
}
|
|
31557
|
+
if (event.type === "corner-restart" && typeof event.roomId === "string") {
|
|
31558
|
+
this.cornerRestartListener?.(event.roomId);
|
|
31559
|
+
return;
|
|
31560
|
+
}
|
|
31561
|
+
if (event.type === "connector-assignment") {
|
|
31178
31562
|
this.connectorAssignmentListener?.();
|
|
31563
|
+
return;
|
|
31564
|
+
}
|
|
31565
|
+
if (event.type === "memory-job") {
|
|
31179
31566
|
this.memoryJobListener?.();
|
|
31180
|
-
|
|
31181
|
-
|
|
31182
|
-
|
|
31183
|
-
|
|
31184
|
-
|
|
31185
|
-
|
|
31186
|
-
|
|
31187
|
-
|
|
31188
|
-
|
|
31189
|
-
|
|
31190
|
-
|
|
31191
|
-
|
|
31192
|
-
|
|
31193
|
-
|
|
31194
|
-
|
|
31195
|
-
|
|
31196
|
-
|
|
31197
|
-
if (capabilities?.discoveryWake === true)
|
|
31198
|
-
this.discoveryWakeSupported = true;
|
|
31199
|
-
return;
|
|
31200
|
-
}
|
|
31201
|
-
if (event.type === "helper-release" && typeof event.version === "string" && typeof event.sha === "string") {
|
|
31202
|
-
this.helperReleaseListener?.({ version: event.version, sha: event.sha });
|
|
31203
|
-
return;
|
|
31204
|
-
}
|
|
31205
|
-
if (event.type === "rooms-changed") {
|
|
31206
|
-
this.roomsChangedListener?.(membershipChange(event));
|
|
31207
|
-
return;
|
|
31208
|
-
}
|
|
31209
|
-
if (event.type === "discovery-wake" && (event.reason === "listener-resync" || event.reason === "database-recovered")) {
|
|
31210
|
-
this.roomsChangedListener?.();
|
|
31211
|
-
return;
|
|
31212
|
-
}
|
|
31213
|
-
if (event.type === "corner-complete" && typeof event.roomId === "string") {
|
|
31214
|
-
this.cornerCompleteListener?.(event.roomId);
|
|
31215
|
-
return;
|
|
31216
|
-
}
|
|
31217
|
-
if (event.type === "corner-restart" && typeof event.roomId === "string") {
|
|
31218
|
-
this.cornerRestartListener?.(event.roomId);
|
|
31219
|
-
return;
|
|
31220
|
-
}
|
|
31221
|
-
if (event.type === "connector-assignment") {
|
|
31222
|
-
this.connectorAssignmentListener?.();
|
|
31223
|
-
return;
|
|
31224
|
-
}
|
|
31225
|
-
if (event.type === "memory-job") {
|
|
31226
|
-
this.memoryJobListener?.();
|
|
31227
|
-
return;
|
|
31228
|
-
}
|
|
31229
|
-
if (event.type === "config-changed") {
|
|
31230
|
-
this.configChangedListener?.();
|
|
31231
|
-
return;
|
|
31232
|
-
}
|
|
31233
|
-
if (event.type === "subscribed" && typeof event.roomId === "string") {
|
|
31234
|
-
const capabilities = event.capabilities;
|
|
31235
|
-
if (capabilities?.discoveryWake === true)
|
|
31236
|
-
this.discoveryWakeSupported = true;
|
|
31237
|
-
this.liveRooms.get(event.roomId)?.onState?.(true, {
|
|
31238
|
-
pushIntake: capabilities?.pushIntake === true,
|
|
31239
|
-
connectionPresence: capabilities?.connectionPresence === true
|
|
31240
|
-
});
|
|
31241
|
-
return;
|
|
31242
|
-
}
|
|
31243
|
-
if (event.type === "commands" && typeof event.roomId === "string" && event.commandProtocol === 1 && Array.isArray(event.commands)) {
|
|
31244
|
-
const room2 = this.liveRooms.get(event.roomId);
|
|
31245
|
-
if (!room2)
|
|
31246
|
-
return;
|
|
31247
|
-
const commands = event.commands.filter((command) => {
|
|
31248
|
-
if (!isAgentCommand(command) || command.roomId !== event.roomId || command.agentId !== this.agentId || room2.pushedCommandIds.has(command.id))
|
|
31249
|
-
return false;
|
|
31250
|
-
room2.pushedCommandIds.add(command.id);
|
|
31251
|
-
return true;
|
|
31252
|
-
});
|
|
31253
|
-
while (room2.pushedCommandIds.size > 1e4)
|
|
31254
|
-
room2.pushedCommandIds.delete(room2.pushedCommandIds.values().next().value);
|
|
31255
|
-
if (commands.length)
|
|
31256
|
-
room2.onCommands?.(commands);
|
|
31257
|
-
return;
|
|
31258
|
-
}
|
|
31259
|
-
if (event.type !== "inbox" || typeof event.roomId !== "string" || !Array.isArray(event.items))
|
|
31260
|
-
return;
|
|
31261
|
-
const room = this.liveRooms.get(event.roomId);
|
|
31262
|
-
if (!room)
|
|
31567
|
+
return;
|
|
31568
|
+
}
|
|
31569
|
+
if (event.type === "config-changed") {
|
|
31570
|
+
this.configChangedListener?.();
|
|
31571
|
+
return;
|
|
31572
|
+
}
|
|
31573
|
+
if (event.type === "subscribed" && typeof event.roomId === "string") {
|
|
31574
|
+
const capabilities = event.capabilities;
|
|
31575
|
+
this.liveRooms.get(event.roomId)?.onState?.(true, {
|
|
31576
|
+
pushIntake: capabilities?.pushIntake === true,
|
|
31577
|
+
connectionPresence: capabilities?.connectionPresence === true
|
|
31578
|
+
});
|
|
31579
|
+
return;
|
|
31580
|
+
}
|
|
31581
|
+
if (event.type === "commands" && typeof event.roomId === "string" && event.commandProtocol === 1 && Array.isArray(event.commands)) {
|
|
31582
|
+
const room2 = this.liveRooms.get(event.roomId);
|
|
31583
|
+
if (!room2)
|
|
31263
31584
|
return;
|
|
31264
|
-
const
|
|
31265
|
-
|
|
31266
|
-
|
|
31267
|
-
|
|
31268
|
-
|
|
31269
|
-
|
|
31270
|
-
|
|
31271
|
-
|
|
31272
|
-
|
|
31273
|
-
|
|
31585
|
+
const commands = event.commands.filter((command) => {
|
|
31586
|
+
if (!isAgentCommand(command) || command.roomId !== event.roomId || command.agentId !== this.agentId || room2.pushedCommandIds.has(command.id))
|
|
31587
|
+
return false;
|
|
31588
|
+
room2.pushedCommandIds.add(command.id);
|
|
31589
|
+
return true;
|
|
31590
|
+
});
|
|
31591
|
+
while (room2.pushedCommandIds.size > 1e4)
|
|
31592
|
+
room2.pushedCommandIds.delete(room2.pushedCommandIds.values().next().value);
|
|
31593
|
+
if (commands.length)
|
|
31594
|
+
room2.onCommands?.(commands);
|
|
31595
|
+
return;
|
|
31596
|
+
}
|
|
31597
|
+
if (event.type !== "inbox" || typeof event.roomId !== "string" || !Array.isArray(event.items))
|
|
31598
|
+
return;
|
|
31599
|
+
const room = this.liveRooms.get(event.roomId);
|
|
31600
|
+
if (!room)
|
|
31601
|
+
return;
|
|
31602
|
+
const items = [];
|
|
31603
|
+
for (const candidate of event.items) {
|
|
31604
|
+
if (!candidate || typeof candidate !== "object")
|
|
31605
|
+
continue;
|
|
31606
|
+
const id = candidate.id;
|
|
31607
|
+
if (typeof id === "string") {
|
|
31608
|
+
if (!room.pushedIds.has(id))
|
|
31609
|
+
items.push(candidate);
|
|
31610
|
+
room.pushedIds.add(id);
|
|
31274
31611
|
}
|
|
31275
|
-
|
|
31276
|
-
|
|
31277
|
-
|
|
31278
|
-
|
|
31279
|
-
|
|
31280
|
-
const reconnect = () => {
|
|
31281
|
-
if (this.liveSocket !== socket)
|
|
31282
|
-
return;
|
|
31283
|
-
this.liveSocket = void 0;
|
|
31284
|
-
this.discoveryWakeSupported = false;
|
|
31285
|
-
for (const room of this.liveRooms.values())
|
|
31286
|
-
room.onState?.(false);
|
|
31287
|
-
if (this.forceUpdatePending)
|
|
31288
|
-
return;
|
|
31289
|
-
if (!this.liveRooms.size && !this.roomsChangedListener)
|
|
31290
|
-
return;
|
|
31291
|
-
const delay = this.liveReconnectDelayMs;
|
|
31292
|
-
this.liveReconnectDelayMs = Date.now() - this.liveOpenedAt >= STABLE_SOCKET_MS ? 1e3 : Math.min(delay * 2, 3e4);
|
|
31293
|
-
this.reconnectCount += 1;
|
|
31294
|
-
this.liveReconnect = setTimeout(() => this.ensureLiveSocket(), Math.floor(Math.random() * delay));
|
|
31295
|
-
this.liveReconnect.unref?.();
|
|
31296
|
-
};
|
|
31297
|
-
socket.onerror = () => void 0;
|
|
31298
|
-
socket.onclose = reconnect;
|
|
31612
|
+
}
|
|
31613
|
+
while (room.pushedIds.size > 1e4)
|
|
31614
|
+
room.pushedIds.delete(room.pushedIds.values().next().value);
|
|
31615
|
+
if (items.length)
|
|
31616
|
+
room.onItems?.(items, typeof event.cursor === "string" ? event.cursor : void 0);
|
|
31299
31617
|
}
|
|
31300
31618
|
sendLiveSubscription(roomId) {
|
|
31301
31619
|
const room = this.liveRooms.get(roomId);
|
|
31302
|
-
if (!room || this.
|
|
31620
|
+
if (!room || !this.link.isOpen())
|
|
31303
31621
|
return;
|
|
31304
31622
|
this.subscriptionCount += 1;
|
|
31305
|
-
this.
|
|
31623
|
+
this.link.send(JSON.stringify({
|
|
31306
31624
|
type: "subscribe",
|
|
31307
31625
|
roomId,
|
|
31308
31626
|
lifecycleId: this.presenceLifecycleId,
|
|
@@ -31363,7 +31681,7 @@ import { promisify as promisify8 } from "node:util";
|
|
|
31363
31681
|
// apps/body/dist/grant-runner.js
|
|
31364
31682
|
import { execFile as execFile8 } from "node:child_process";
|
|
31365
31683
|
import { createHash as createHash6, randomBytes as randomBytes7, randomUUID as randomUUID7 } from "node:crypto";
|
|
31366
|
-
import { chmod as chmod6, mkdir as mkdir10, readFile as
|
|
31684
|
+
import { chmod as chmod6, mkdir as mkdir10, readFile as readFile14, readdir as readdir4, rename as rename6, rm as rm6, rmdir, stat as stat6, writeFile as writeFile10 } from "node:fs/promises";
|
|
31367
31685
|
import { createServer as createServer3 } from "node:http";
|
|
31368
31686
|
import { dirname as dirname12, resolve as resolve16 } from "node:path";
|
|
31369
31687
|
|
|
@@ -31612,9 +31930,9 @@ function surfaceAllows(surface, capability) {
|
|
|
31612
31930
|
init_agent_command();
|
|
31613
31931
|
init_cursor_acp_bridge();
|
|
31614
31932
|
import { execFile as execFile7, spawnSync } from "node:child_process";
|
|
31615
|
-
import { lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as
|
|
31933
|
+
import { lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
31616
31934
|
import { homedir as homedir11 } from "node:os";
|
|
31617
|
-
import { basename as
|
|
31935
|
+
import { basename as basename6, dirname as dirname10, isAbsolute as isAbsolute2, relative, resolve as resolve14 } from "node:path";
|
|
31618
31936
|
var DEFAULT_SANDBOX_POLICY = "bwrap";
|
|
31619
31937
|
function isSandboxPolicy(value) {
|
|
31620
31938
|
return value === "bwrap" || value === "off";
|
|
@@ -31709,7 +32027,7 @@ function siblingAgentMaskPaths(ownRuntimeDir, listAgentDirs = (agentsRoot) => {
|
|
|
31709
32027
|
}) {
|
|
31710
32028
|
const own = resolve14(ownRuntimeDir);
|
|
31711
32029
|
const agentsRoot = dirname10(own);
|
|
31712
|
-
const ownName =
|
|
32030
|
+
const ownName = basename6(own).toLowerCase();
|
|
31713
32031
|
return listAgentDirs(agentsRoot).filter((name) => name.toLowerCase() !== ownName).map((name) => ({ path: resolve14(agentsRoot, name), kind: "dir" })).sort((a2, b) => a2.path.localeCompare(b.path));
|
|
31714
32032
|
}
|
|
31715
32033
|
var DEFAULT_SANDBOX_DEVICES = ["/dev/kvm"];
|
|
@@ -31935,7 +32253,7 @@ function recordInstallFailure(stateDir, at) {
|
|
|
31935
32253
|
if (!stateDir)
|
|
31936
32254
|
return;
|
|
31937
32255
|
try {
|
|
31938
|
-
|
|
32256
|
+
writeFileSync3(installFailureMarker(stateDir), `${at}
|
|
31939
32257
|
`, "utf8");
|
|
31940
32258
|
} catch {
|
|
31941
32259
|
}
|
|
@@ -32058,7 +32376,7 @@ async function ensureBwrapSandbox(options = {}) {
|
|
|
32058
32376
|
}
|
|
32059
32377
|
|
|
32060
32378
|
// apps/body/dist/provider-key-store.js
|
|
32061
|
-
import { chmod as chmod5, mkdir as mkdir9, readFile as
|
|
32379
|
+
import { chmod as chmod5, mkdir as mkdir9, readFile as readFile13, writeFile as writeFile9 } from "node:fs/promises";
|
|
32062
32380
|
import { homedir as homedir12 } from "node:os";
|
|
32063
32381
|
import { dirname as dirname11, resolve as resolve15 } from "node:path";
|
|
32064
32382
|
var PROVIDER_KEY_ENV_VARS = {
|
|
@@ -32075,7 +32393,7 @@ function providerKeyStorePath(env = process.env) {
|
|
|
32075
32393
|
}
|
|
32076
32394
|
async function readProviderKeyStore(env = process.env) {
|
|
32077
32395
|
const path = providerKeyStorePath(env);
|
|
32078
|
-
const raw = await
|
|
32396
|
+
const raw = await readFile13(path, "utf8").catch(() => void 0);
|
|
32079
32397
|
if (!raw)
|
|
32080
32398
|
return {};
|
|
32081
32399
|
try {
|
|
@@ -32127,7 +32445,7 @@ function operatorSecretsPath(env = process.env) {
|
|
|
32127
32445
|
return resolve16(dirname12(providerKeyStorePath(env)), "secrets.json");
|
|
32128
32446
|
}
|
|
32129
32447
|
async function readOperatorSecrets(env = process.env) {
|
|
32130
|
-
const raw = await
|
|
32448
|
+
const raw = await readFile14(operatorSecretsPath(env), "utf8").catch(() => void 0);
|
|
32131
32449
|
if (!raw)
|
|
32132
32450
|
return {};
|
|
32133
32451
|
try {
|
|
@@ -32339,7 +32657,7 @@ ${ROOM_WRITE_REFUSED_NOTE}` : outcome.output, secrets), cap);
|
|
|
32339
32657
|
return;
|
|
32340
32658
|
let bytes;
|
|
32341
32659
|
for (const candidate of candidates) {
|
|
32342
|
-
bytes = await
|
|
32660
|
+
bytes = await readFile14(candidate).catch(() => void 0);
|
|
32343
32661
|
if (bytes)
|
|
32344
32662
|
break;
|
|
32345
32663
|
}
|
|
@@ -32541,10 +32859,10 @@ function captureConnectionUsage(recorder, turn, calls) {
|
|
|
32541
32859
|
}
|
|
32542
32860
|
|
|
32543
32861
|
// apps/body/dist/turn-usage.js
|
|
32544
|
-
import { readFile as
|
|
32862
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
32545
32863
|
|
|
32546
32864
|
// apps/body/dist/pi-turn-record.js
|
|
32547
|
-
import { readdir as readdir5, readFile as
|
|
32865
|
+
import { readdir as readdir5, readFile as readFile15 } from "node:fs/promises";
|
|
32548
32866
|
import { resolve as resolve17 } from "node:path";
|
|
32549
32867
|
function summarizeProviderError(errorMessage2) {
|
|
32550
32868
|
const trimmed = errorMessage2.trim();
|
|
@@ -32572,7 +32890,7 @@ async function piSessionFilePath(agentEnv, sessionId) {
|
|
|
32572
32890
|
}
|
|
32573
32891
|
async function sessionFileFromMap(home, sessionId) {
|
|
32574
32892
|
try {
|
|
32575
|
-
const raw = await
|
|
32893
|
+
const raw = await readFile15(resolve17(home, ".pi", "pi-acp", "session-map.json"), "utf8");
|
|
32576
32894
|
const map = JSON.parse(raw);
|
|
32577
32895
|
const file = map.sessions?.[sessionId]?.sessionFile;
|
|
32578
32896
|
return typeof file === "string" && file ? file : void 0;
|
|
@@ -32614,7 +32932,7 @@ async function readPiTurnRecord(input) {
|
|
|
32614
32932
|
return void 0;
|
|
32615
32933
|
let raw;
|
|
32616
32934
|
try {
|
|
32617
|
-
raw = await
|
|
32935
|
+
raw = await readFile15(file, "utf8");
|
|
32618
32936
|
} catch {
|
|
32619
32937
|
return void 0;
|
|
32620
32938
|
}
|
|
@@ -32675,7 +32993,7 @@ async function readHarnessTurnUsage(input) {
|
|
|
32675
32993
|
return void 0;
|
|
32676
32994
|
let raw;
|
|
32677
32995
|
try {
|
|
32678
|
-
raw = await
|
|
32996
|
+
raw = await readFile16(file, "utf8");
|
|
32679
32997
|
} catch {
|
|
32680
32998
|
return void 0;
|
|
32681
32999
|
}
|
|
@@ -32715,15 +33033,15 @@ async function readHarnessTurnUsage(input) {
|
|
|
32715
33033
|
// apps/body/dist/server-command-intake.js
|
|
32716
33034
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
32717
33035
|
import { mkdir as mkdir11, writeFile as writeFile11 } from "node:fs/promises";
|
|
32718
|
-
import { writeFileSync as
|
|
33036
|
+
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
32719
33037
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
32720
|
-
import { dirname as dirname13, join as
|
|
33038
|
+
import { dirname as dirname13, join as join11 } from "node:path";
|
|
32721
33039
|
var CommandExecutionContext = class {
|
|
32722
33040
|
generationId = randomUUID8();
|
|
32723
33041
|
path;
|
|
32724
33042
|
current;
|
|
32725
33043
|
constructor(root) {
|
|
32726
|
-
this.path =
|
|
33044
|
+
this.path = join11(root ?? tmpdir5(), `beeline-command-${this.generationId}.json`);
|
|
32727
33045
|
}
|
|
32728
33046
|
async enter(command) {
|
|
32729
33047
|
this.current = command;
|
|
@@ -32744,7 +33062,7 @@ var CommandExecutionContext = class {
|
|
|
32744
33062
|
const command = this.current;
|
|
32745
33063
|
if (!command)
|
|
32746
33064
|
return;
|
|
32747
|
-
|
|
33065
|
+
writeFileSync4(this.path, JSON.stringify({
|
|
32748
33066
|
roomId: command.roomId,
|
|
32749
33067
|
requestId: command.turnRequestId,
|
|
32750
33068
|
taskId: command.rootCommandId,
|
|
@@ -32831,6 +33149,7 @@ async function runServerCommandIntake(options) {
|
|
|
32831
33149
|
requestReconciliation();
|
|
32832
33150
|
hasSubscribed = true;
|
|
32833
33151
|
}, options.presence, notify2);
|
|
33152
|
+
let failed = false;
|
|
32834
33153
|
try {
|
|
32835
33154
|
while (!signal?.aborted) {
|
|
32836
33155
|
if (reconciliationError)
|
|
@@ -32908,22 +33227,36 @@ async function runServerCommandIntake(options) {
|
|
|
32908
33227
|
if (reconcile)
|
|
32909
33228
|
requestReconciliation();
|
|
32910
33229
|
}
|
|
33230
|
+
} catch (error) {
|
|
33231
|
+
failed = true;
|
|
33232
|
+
throw error;
|
|
32911
33233
|
} finally {
|
|
32912
33234
|
stopped = true;
|
|
32913
33235
|
off?.();
|
|
32914
33236
|
options.onWake?.(void 0);
|
|
32915
|
-
|
|
32916
|
-
|
|
32917
|
-
|
|
33237
|
+
const current = context.current;
|
|
33238
|
+
const stopCurrent = () => {
|
|
33239
|
+
if (current)
|
|
33240
|
+
options.stop(current.turnRequestId);
|
|
33241
|
+
};
|
|
33242
|
+
if (!failed || signal?.aborted)
|
|
33243
|
+
stopCurrent();
|
|
33244
|
+
else
|
|
33245
|
+
signal?.addEventListener("abort", stopCurrent, { once: true });
|
|
33246
|
+
try {
|
|
33247
|
+
await busy;
|
|
33248
|
+
} finally {
|
|
33249
|
+
signal?.removeEventListener("abort", stopCurrent);
|
|
33250
|
+
}
|
|
32918
33251
|
}
|
|
32919
33252
|
}
|
|
32920
33253
|
|
|
32921
33254
|
// apps/body/dist/monolith-corner-turn.js
|
|
32922
33255
|
import { execFile as execFile11 } from "node:child_process";
|
|
32923
33256
|
import { createHash as createHash10 } from "node:crypto";
|
|
32924
|
-
import { mkdir as mkdir20, readFile as
|
|
33257
|
+
import { mkdir as mkdir20, readFile as readFile22, writeFile as writeFile16 } from "node:fs/promises";
|
|
32925
33258
|
import { homedir as homedir15, hostname as hostname2 } from "node:os";
|
|
32926
|
-
import { dirname as dirname18, join as
|
|
33259
|
+
import { dirname as dirname18, join as join17, resolve as resolve28 } from "node:path";
|
|
32927
33260
|
import { promisify as promisify7 } from "node:util";
|
|
32928
33261
|
|
|
32929
33262
|
// apps/body/dist/agent-home.js
|
|
@@ -33726,9 +34059,9 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
33726
34059
|
|
|
33727
34060
|
// apps/body/dist/agent-home.js
|
|
33728
34061
|
import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
|
|
33729
|
-
import { chmod as chmod7, copyFile, lstat as lstat3, mkdir as mkdir13, readFile as
|
|
34062
|
+
import { chmod as chmod7, copyFile, lstat as lstat3, mkdir as mkdir13, readFile as readFile18, readlink, readdir as readdir6, realpath, rename as rename7, rm as rm7, symlink as symlink2, unlink as unlink5, writeFile as writeFile13 } from "node:fs/promises";
|
|
33730
34063
|
import { homedir as homedir13 } from "node:os";
|
|
33731
|
-
import { basename as
|
|
34064
|
+
import { basename as basename7, dirname as dirname14, join as join13, relative as relative2, resolve as resolve21, sep } from "node:path";
|
|
33732
34065
|
|
|
33733
34066
|
// apps/body/dist/draw-avatar-skill.js
|
|
33734
34067
|
var DRAW_AVATAR_SKILL_NAME = "draw-avatar";
|
|
@@ -33852,14 +34185,235 @@ function isAgentPairingCode(value) {
|
|
|
33852
34185
|
// packages/api-contract/dist/phone.js
|
|
33853
34186
|
init_agent_access();
|
|
33854
34187
|
|
|
34188
|
+
// packages/api-contract/dist/message-search.js
|
|
34189
|
+
var MESSAGE_SEARCH_FILLER_WORDS = [
|
|
34190
|
+
// Articles and determiners
|
|
34191
|
+
"a",
|
|
34192
|
+
"an",
|
|
34193
|
+
"the",
|
|
34194
|
+
"this",
|
|
34195
|
+
"that",
|
|
34196
|
+
"these",
|
|
34197
|
+
"those",
|
|
34198
|
+
"some",
|
|
34199
|
+
"any",
|
|
34200
|
+
"each",
|
|
34201
|
+
"every",
|
|
34202
|
+
"all",
|
|
34203
|
+
"both",
|
|
34204
|
+
"either",
|
|
34205
|
+
"neither",
|
|
34206
|
+
"much",
|
|
34207
|
+
"many",
|
|
34208
|
+
"more",
|
|
34209
|
+
"most",
|
|
34210
|
+
"such",
|
|
34211
|
+
"other",
|
|
34212
|
+
"another",
|
|
34213
|
+
"own",
|
|
34214
|
+
"same",
|
|
34215
|
+
"no",
|
|
34216
|
+
"not",
|
|
34217
|
+
"only",
|
|
34218
|
+
"very",
|
|
34219
|
+
// Pronouns
|
|
34220
|
+
"i",
|
|
34221
|
+
"me",
|
|
34222
|
+
"my",
|
|
34223
|
+
"mine",
|
|
34224
|
+
"myself",
|
|
34225
|
+
"you",
|
|
34226
|
+
"your",
|
|
34227
|
+
"yours",
|
|
34228
|
+
"yourself",
|
|
34229
|
+
"he",
|
|
34230
|
+
"him",
|
|
34231
|
+
"his",
|
|
34232
|
+
"himself",
|
|
34233
|
+
"she",
|
|
34234
|
+
"her",
|
|
34235
|
+
"hers",
|
|
34236
|
+
"herself",
|
|
34237
|
+
"it",
|
|
34238
|
+
"its",
|
|
34239
|
+
"itself",
|
|
34240
|
+
"we",
|
|
34241
|
+
"us",
|
|
34242
|
+
"our",
|
|
34243
|
+
"ours",
|
|
34244
|
+
"ourselves",
|
|
34245
|
+
"they",
|
|
34246
|
+
"them",
|
|
34247
|
+
"their",
|
|
34248
|
+
"theirs",
|
|
34249
|
+
"themselves",
|
|
34250
|
+
"who",
|
|
34251
|
+
"whom",
|
|
34252
|
+
"whose",
|
|
34253
|
+
"which",
|
|
34254
|
+
"what",
|
|
34255
|
+
"someone",
|
|
34256
|
+
"something",
|
|
34257
|
+
"anyone",
|
|
34258
|
+
"anything",
|
|
34259
|
+
"everyone",
|
|
34260
|
+
"everything",
|
|
34261
|
+
// Auxiliaries
|
|
34262
|
+
"am",
|
|
34263
|
+
"is",
|
|
34264
|
+
"are",
|
|
34265
|
+
"was",
|
|
34266
|
+
"were",
|
|
34267
|
+
"be",
|
|
34268
|
+
"been",
|
|
34269
|
+
"being",
|
|
34270
|
+
"have",
|
|
34271
|
+
"has",
|
|
34272
|
+
"had",
|
|
34273
|
+
"having",
|
|
34274
|
+
"do",
|
|
34275
|
+
"does",
|
|
34276
|
+
"did",
|
|
34277
|
+
"doing",
|
|
34278
|
+
"done",
|
|
34279
|
+
"will",
|
|
34280
|
+
"would",
|
|
34281
|
+
"shall",
|
|
34282
|
+
"should",
|
|
34283
|
+
"can",
|
|
34284
|
+
"could",
|
|
34285
|
+
"might",
|
|
34286
|
+
"must",
|
|
34287
|
+
"get",
|
|
34288
|
+
"gets",
|
|
34289
|
+
"got",
|
|
34290
|
+
// Contraction pieces
|
|
34291
|
+
"s",
|
|
34292
|
+
"t",
|
|
34293
|
+
"d",
|
|
34294
|
+
"ll",
|
|
34295
|
+
"m",
|
|
34296
|
+
"re",
|
|
34297
|
+
"ve",
|
|
34298
|
+
"don",
|
|
34299
|
+
"doesn",
|
|
34300
|
+
"didn",
|
|
34301
|
+
"isn",
|
|
34302
|
+
"aren",
|
|
34303
|
+
"wasn",
|
|
34304
|
+
"weren",
|
|
34305
|
+
"haven",
|
|
34306
|
+
"hasn",
|
|
34307
|
+
"hadn",
|
|
34308
|
+
"won",
|
|
34309
|
+
"wouldn",
|
|
34310
|
+
"couldn",
|
|
34311
|
+
"shouldn",
|
|
34312
|
+
"cannot",
|
|
34313
|
+
// Conjunctions
|
|
34314
|
+
"and",
|
|
34315
|
+
"or",
|
|
34316
|
+
"but",
|
|
34317
|
+
"nor",
|
|
34318
|
+
"so",
|
|
34319
|
+
"yet",
|
|
34320
|
+
"if",
|
|
34321
|
+
"then",
|
|
34322
|
+
"than",
|
|
34323
|
+
"because",
|
|
34324
|
+
"as",
|
|
34325
|
+
"while",
|
|
34326
|
+
"though",
|
|
34327
|
+
"although",
|
|
34328
|
+
"unless",
|
|
34329
|
+
"until",
|
|
34330
|
+
"whether",
|
|
34331
|
+
"also",
|
|
34332
|
+
// Prepositions
|
|
34333
|
+
"of",
|
|
34334
|
+
"to",
|
|
34335
|
+
"in",
|
|
34336
|
+
"on",
|
|
34337
|
+
"at",
|
|
34338
|
+
"by",
|
|
34339
|
+
"for",
|
|
34340
|
+
"with",
|
|
34341
|
+
"from",
|
|
34342
|
+
"into",
|
|
34343
|
+
"onto",
|
|
34344
|
+
"about",
|
|
34345
|
+
"above",
|
|
34346
|
+
"below",
|
|
34347
|
+
"over",
|
|
34348
|
+
"under",
|
|
34349
|
+
"after",
|
|
34350
|
+
"before",
|
|
34351
|
+
"between",
|
|
34352
|
+
"through",
|
|
34353
|
+
"during",
|
|
34354
|
+
"without",
|
|
34355
|
+
"within",
|
|
34356
|
+
"again",
|
|
34357
|
+
"against",
|
|
34358
|
+
"upon",
|
|
34359
|
+
"via",
|
|
34360
|
+
"per",
|
|
34361
|
+
"around",
|
|
34362
|
+
// Adverbs
|
|
34363
|
+
"here",
|
|
34364
|
+
"there",
|
|
34365
|
+
"where",
|
|
34366
|
+
"when",
|
|
34367
|
+
"why",
|
|
34368
|
+
"how",
|
|
34369
|
+
"now",
|
|
34370
|
+
"just",
|
|
34371
|
+
"too",
|
|
34372
|
+
"still",
|
|
34373
|
+
"even",
|
|
34374
|
+
"ever",
|
|
34375
|
+
"never",
|
|
34376
|
+
"always",
|
|
34377
|
+
"really",
|
|
34378
|
+
"maybe",
|
|
34379
|
+
"already",
|
|
34380
|
+
"soon",
|
|
34381
|
+
// Chat filler
|
|
34382
|
+
"ok",
|
|
34383
|
+
"okay",
|
|
34384
|
+
"yes",
|
|
34385
|
+
"yeah",
|
|
34386
|
+
"yep",
|
|
34387
|
+
"yup",
|
|
34388
|
+
"nope",
|
|
34389
|
+
"hi",
|
|
34390
|
+
"hey",
|
|
34391
|
+
"hello",
|
|
34392
|
+
"thanks",
|
|
34393
|
+
"thank",
|
|
34394
|
+
"thx",
|
|
34395
|
+
"please",
|
|
34396
|
+
"pls",
|
|
34397
|
+
"like",
|
|
34398
|
+
"gonna",
|
|
34399
|
+
"wanna",
|
|
34400
|
+
"kinda",
|
|
34401
|
+
"lol",
|
|
34402
|
+
"oh",
|
|
34403
|
+
"ah",
|
|
34404
|
+
"um",
|
|
34405
|
+
"uh",
|
|
34406
|
+
"hmm",
|
|
34407
|
+
"oops",
|
|
34408
|
+
"anyway"
|
|
34409
|
+
];
|
|
34410
|
+
var FILLER_WORDS = new Set(MESSAGE_SEARCH_FILLER_WORDS);
|
|
34411
|
+
|
|
33855
34412
|
// apps/body/dist/beeline-skill.js
|
|
33856
34413
|
var USING_BEELINE_SKILL_NAME = "using-beeline";
|
|
33857
34414
|
var BEELINE_TRIAGE_SKILL_NAME = "beeline-triage";
|
|
33858
34415
|
var BEELINE_REVIEW_SKILL_NAME = "beeline-review";
|
|
33859
34416
|
var BEELINE_SPEC_SKILL_NAME = "beeline-spec";
|
|
33860
|
-
function isConfiguredReviewer(agentHandle, reviewerHandle) {
|
|
33861
|
-
return Boolean(agentHandle && reviewerHandle && agentHandle.replace(/^@/, "") === reviewerHandle.replace(/^@/, ""));
|
|
33862
|
-
}
|
|
33863
34417
|
var BEELINE_ROOM_MECHANICS = [
|
|
33864
34418
|
"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.",
|
|
33865
34419
|
"To create a file you can send, 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 post_artifact 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), or with html/bytes content directly; it is uploaded and attached to your reply, and title and mime default from the file when you post by path. write_scratch_file produces the file, not a picture. To put a real photograph in an artifact, call beeline-agent fetch_image with the photo URL; it writes the bytes to your session scratch and returns the path, mime, and size \u2014 read them, base64-encode, and embed as a data: URL. The validator still refuses every http(s) image reference, and drawing an SVG stand-in is not a photograph.",
|
|
@@ -34024,7 +34578,7 @@ Only the author may report final_authorization as passed, after pr_checks_status
|
|
|
34024
34578
|
|
|
34025
34579
|
Then take exactly one action:
|
|
34026
34580
|
|
|
34027
|
-
- FAIL: reply \`@author\` with the confirmed findings to fix.
|
|
34581
|
+
- FAIL: call \`record_validation_stage\` with stage \`review\`, status \`failed\`, and the reviewed head SHA, then reply \`@author\` with the confirmed findings and that reviewed head SHA to fix. The recorded review stage is how an implementer who has already fixed the findings can tell whether the review is stale.
|
|
34028
34582
|
- PASS: call \`approve_merge\` with the reviewed head SHA and assigned briefRevision (omit the revision only for a legacy corner without a brief), then reply \`approved <reviewed sha>\` without tagging the author. Do not tell the author to merge.
|
|
34029
34583
|
- Approving is your last step as reviewer. The server squash-merges that exact head once checks are green, the worker's yolo is on, and no human hold stands. Neither you nor the author merges it.
|
|
34030
34584
|
`;
|
|
@@ -34194,7 +34748,7 @@ var SQUIRE_GOVERNED_TOOLS = [
|
|
|
34194
34748
|
var SQUIRE_GOVERNED_TOOL_SET = new Set(SQUIRE_GOVERNED_TOOLS);
|
|
34195
34749
|
|
|
34196
34750
|
// apps/body/dist/host-mcp-route.js
|
|
34197
|
-
import { join as
|
|
34751
|
+
import { join as join12, resolve as resolve19 } from "node:path";
|
|
34198
34752
|
var import_yaml = __toESM(require_dist(), 1);
|
|
34199
34753
|
init_squire_host();
|
|
34200
34754
|
function grantedMcpServerNames(grants) {
|
|
@@ -34249,7 +34803,7 @@ function grantedSquireHostRouteNames(granted, declarations = {}) {
|
|
|
34249
34803
|
});
|
|
34250
34804
|
}
|
|
34251
34805
|
function hostRouteEnv(hostHome) {
|
|
34252
|
-
return { XDG_CONFIG_HOME:
|
|
34806
|
+
return { XDG_CONFIG_HOME: join12(resolve19(hostHome), ".config") };
|
|
34253
34807
|
}
|
|
34254
34808
|
function rewriteHostMcpDeclaration(name, declaration, hostHome, resourceAuthFile, squireScope) {
|
|
34255
34809
|
const next = { ...declaration };
|
|
@@ -34368,7 +34922,7 @@ function mergeGooseHostRoutes(existing, routes) {
|
|
|
34368
34922
|
init_squire_host();
|
|
34369
34923
|
|
|
34370
34924
|
// apps/body/dist/openrouter-routing.js
|
|
34371
|
-
import { mkdir as mkdir12, readFile as
|
|
34925
|
+
import { mkdir as mkdir12, readFile as readFile17, writeFile as writeFile12 } from "node:fs/promises";
|
|
34372
34926
|
import { resolve as resolve20 } from "node:path";
|
|
34373
34927
|
var OPENROUTER_ENDPOINTS_BASE_URL = "https://openrouter.ai/api/v1/models";
|
|
34374
34928
|
var OPENROUTER_COMPLETIONS_URL = "https://openrouter.ai/api/v1/chat/completions";
|
|
@@ -34496,7 +35050,7 @@ function cachePath(cacheDir, model) {
|
|
|
34496
35050
|
}
|
|
34497
35051
|
async function readCache(cacheDir, model) {
|
|
34498
35052
|
try {
|
|
34499
|
-
const parsed = JSON.parse(await
|
|
35053
|
+
const parsed = JSON.parse(await readFile17(cachePath(cacheDir, model), "utf8"));
|
|
34500
35054
|
if (!parsed || typeof parsed !== "object")
|
|
34501
35055
|
return void 0;
|
|
34502
35056
|
const cached = parsed;
|
|
@@ -34539,7 +35093,7 @@ function probeCachePath(cacheDir, model) {
|
|
|
34539
35093
|
}
|
|
34540
35094
|
async function readProbeCache(cacheDir, model) {
|
|
34541
35095
|
try {
|
|
34542
|
-
const parsed = JSON.parse(await
|
|
35096
|
+
const parsed = JSON.parse(await readFile17(probeCachePath(cacheDir, model), "utf8"));
|
|
34543
35097
|
if (!parsed || typeof parsed !== "object")
|
|
34544
35098
|
return void 0;
|
|
34545
35099
|
const cached = parsed;
|
|
@@ -35090,10 +35644,10 @@ function claudeLoginExpiresAt(text2) {
|
|
|
35090
35644
|
}
|
|
35091
35645
|
}
|
|
35092
35646
|
async function hasNewerDetachedClaudeLogin(detached, source) {
|
|
35093
|
-
const detachedExpiresAt = claudeLoginExpiresAt(await
|
|
35647
|
+
const detachedExpiresAt = claudeLoginExpiresAt(await readFile18(detached, "utf8"));
|
|
35094
35648
|
if (detachedExpiresAt === void 0)
|
|
35095
35649
|
return false;
|
|
35096
|
-
const sourceExpiresAt = claudeLoginExpiresAt(await
|
|
35650
|
+
const sourceExpiresAt = claudeLoginExpiresAt(await readFile18(source, "utf8"));
|
|
35097
35651
|
return sourceExpiresAt !== void 0 && detachedExpiresAt > sourceExpiresAt;
|
|
35098
35652
|
}
|
|
35099
35653
|
async function repairRoomAgentCredentialLinks(input) {
|
|
@@ -35120,7 +35674,7 @@ async function repairRoomAgentCredentialLinks(input) {
|
|
|
35120
35674
|
continue;
|
|
35121
35675
|
}
|
|
35122
35676
|
const quarantine = `${target}.beeline-quarantine-${Date.now()}-${randomUUID9()}`;
|
|
35123
|
-
await
|
|
35677
|
+
await rename7(target, quarantine);
|
|
35124
35678
|
}
|
|
35125
35679
|
await symlink2(source, target);
|
|
35126
35680
|
}
|
|
@@ -35600,7 +36154,7 @@ async function provisionManagedSkillsDir(target, managedSkills, sharedSkills, op
|
|
|
35600
36154
|
const existing = await lstat3(target).catch(() => void 0);
|
|
35601
36155
|
if (existing)
|
|
35602
36156
|
await rm7(target, { recursive: existing.isDirectory(), force: true });
|
|
35603
|
-
await
|
|
36157
|
+
await rename7(staged, target);
|
|
35604
36158
|
} finally {
|
|
35605
36159
|
await rm7(staged, { recursive: true, force: true });
|
|
35606
36160
|
}
|
|
@@ -35621,8 +36175,8 @@ async function planManagedSkills(managedSkills, sharedSkills, optionalShares) {
|
|
|
35621
36175
|
try {
|
|
35622
36176
|
const tree = [];
|
|
35623
36177
|
await walkSafeSkillTree(shared.source, shared.source, {
|
|
35624
|
-
directory: async (rel) => void tree.push(`d ${
|
|
35625
|
-
file: async (rel, realPath) => void tree.push(`f ${
|
|
36178
|
+
directory: async (rel) => void tree.push(`d ${join13(shared.name, rel)}`),
|
|
36179
|
+
file: async (rel, realPath) => void tree.push(`f ${join13(shared.name, rel)} ${sha2563(await readFile18(realPath))}`)
|
|
35626
36180
|
});
|
|
35627
36181
|
entries.push({ kind: "shared", name: shared.name, source: shared.source });
|
|
35628
36182
|
lines.push(...tree);
|
|
@@ -35642,7 +36196,7 @@ async function materializedSkillManifest(target) {
|
|
|
35642
36196
|
const visit = async (directory, prefix) => {
|
|
35643
36197
|
for (const entry of await readdir6(directory)) {
|
|
35644
36198
|
const path = resolve21(directory, entry);
|
|
35645
|
-
const rel = prefix ?
|
|
36199
|
+
const rel = prefix ? join13(prefix, entry) : entry;
|
|
35646
36200
|
const entryStats = await lstat3(path);
|
|
35647
36201
|
if (entryStats.isSymbolicLink())
|
|
35648
36202
|
return false;
|
|
@@ -35654,7 +36208,7 @@ async function materializedSkillManifest(target) {
|
|
|
35654
36208
|
}
|
|
35655
36209
|
if (!entryStats.isFile() || entryStats.nlink !== 1)
|
|
35656
36210
|
return false;
|
|
35657
|
-
lines.push(`f ${rel} ${sha2563(await
|
|
36211
|
+
lines.push(`f ${rel} ${sha2563(await readFile18(path))}`);
|
|
35658
36212
|
}
|
|
35659
36213
|
return true;
|
|
35660
36214
|
};
|
|
@@ -35802,7 +36356,7 @@ async function walkSafeSkillTree(source, sourceRoot, visitor, rel = "") {
|
|
|
35802
36356
|
const stats = await lstat3(resolvedSource);
|
|
35803
36357
|
if (stats.isSymbolicLink())
|
|
35804
36358
|
throw new Error(`shared skill contains a symlink: ${source}`);
|
|
35805
|
-
if (BLOCKED_SHARED_FILENAMES.test(
|
|
36359
|
+
if (BLOCKED_SHARED_FILENAMES.test(basename7(source))) {
|
|
35806
36360
|
throw new Error(`shared skill contains credential or configuration material: ${source}`);
|
|
35807
36361
|
}
|
|
35808
36362
|
if (stats.isDirectory()) {
|
|
@@ -35810,7 +36364,7 @@ async function walkSafeSkillTree(source, sourceRoot, visitor, rel = "") {
|
|
|
35810
36364
|
for (const entry of await readdir6(resolvedSource)) {
|
|
35811
36365
|
if (entry === "." || entry === "..")
|
|
35812
36366
|
throw new Error("invalid shared skill entry");
|
|
35813
|
-
await walkSafeSkillTree(resolve21(source, entry), sourceRoot, visitor, rel ?
|
|
36367
|
+
await walkSafeSkillTree(resolve21(source, entry), sourceRoot, visitor, rel ? join13(rel, entry) : entry);
|
|
35814
36368
|
}
|
|
35815
36369
|
return;
|
|
35816
36370
|
}
|
|
@@ -35837,11 +36391,11 @@ async function writeIsolatedHarnessFile(path, content) {
|
|
|
35837
36391
|
if (!parentStats.isDirectory() || parentStats.isSymbolicLink()) {
|
|
35838
36392
|
throw new Error(`isolated harness parent is not a real directory: ${parent}`);
|
|
35839
36393
|
}
|
|
35840
|
-
const temporary = resolve21(parent, `.${
|
|
36394
|
+
const temporary = resolve21(parent, `.${basename7(path)}.${process.pid}.${randomUUID9()}.tmp`);
|
|
35841
36395
|
try {
|
|
35842
36396
|
await writeFile13(temporary, content, { mode: 384, flag: "wx" });
|
|
35843
36397
|
await chmod7(temporary, 384);
|
|
35844
|
-
await
|
|
36398
|
+
await rename7(temporary, path);
|
|
35845
36399
|
} finally {
|
|
35846
36400
|
await unlink5(temporary).catch(() => void 0);
|
|
35847
36401
|
}
|
|
@@ -36832,7 +37386,7 @@ function readOnlyMcpServer(config, cwd, agentMemoryDir) {
|
|
|
36832
37386
|
|
|
36833
37387
|
// apps/body/dist/codegraph.js
|
|
36834
37388
|
import { execFile as execFile10 } from "node:child_process";
|
|
36835
|
-
import { access as access2, appendFile, mkdir as mkdir15, readFile as
|
|
37389
|
+
import { access as access2, appendFile, mkdir as mkdir15, readFile as readFile19 } from "node:fs/promises";
|
|
36836
37390
|
import { dirname as dirname15, isAbsolute as isAbsolute3, resolve as resolve24 } from "node:path";
|
|
36837
37391
|
import { promisify as promisify6 } from "node:util";
|
|
36838
37392
|
var execFileAsync6 = promisify6(execFile10);
|
|
@@ -36882,7 +37436,7 @@ async function excludeIndexFromGitStatus(cwd) {
|
|
|
36882
37436
|
return;
|
|
36883
37437
|
const path = isAbsolute3(gitPath) ? gitPath : resolve24(cwd, gitPath);
|
|
36884
37438
|
await mkdir15(dirname15(path), { recursive: true });
|
|
36885
|
-
const existing = await
|
|
37439
|
+
const existing = await readFile19(path, "utf8").catch(() => "");
|
|
36886
37440
|
if (existing.split("\n").includes(".codegraph/"))
|
|
36887
37441
|
return;
|
|
36888
37442
|
await appendFile(path, `${existing && !existing.endsWith("\n") ? "\n" : ""}.codegraph/
|
|
@@ -36918,20 +37472,20 @@ init_cursor_acp_bridge();
|
|
|
36918
37472
|
// apps/body/dist/monolith-room-turn.js
|
|
36919
37473
|
import { mkdir as mkdir17, writeFile as writeFile14 } from "node:fs/promises";
|
|
36920
37474
|
import { homedir as homedir14, hostname } from "node:os";
|
|
36921
|
-
import { dirname as dirname16, join as
|
|
37475
|
+
import { dirname as dirname16, join as join15 } from "node:path";
|
|
36922
37476
|
|
|
36923
37477
|
// packages/api-contract/dist/scheduled-prompts.js
|
|
36924
37478
|
var SCHEDULE_SCHEDULER_NAME = "Beeline Scheduler";
|
|
36925
37479
|
var SCHEDULE_RAN_VERB = "ran a schedule for";
|
|
36926
37480
|
|
|
36927
37481
|
// apps/body/dist/model-context-window.js
|
|
36928
|
-
import { readFile as
|
|
36929
|
-
import { join as
|
|
37482
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
37483
|
+
import { join as join14 } from "node:path";
|
|
36930
37484
|
async function modelContextWindowTokens(model, piHome) {
|
|
36931
37485
|
if (!model || !piHome)
|
|
36932
37486
|
return void 0;
|
|
36933
37487
|
try {
|
|
36934
|
-
const catalog = JSON.parse(await
|
|
37488
|
+
const catalog = JSON.parse(await readFile20(join14(piHome, "models.json"), "utf8"));
|
|
36935
37489
|
const parts = model.split("/");
|
|
36936
37490
|
const preferredProvider = parts.length > 2 ? parts.shift() : void 0;
|
|
36937
37491
|
const modelId = parts.join("/");
|
|
@@ -37082,7 +37636,7 @@ var CORNERS = [
|
|
|
37082
37636
|
];
|
|
37083
37637
|
var EVERYWHERE = PROMPT_SURFACES;
|
|
37084
37638
|
var CORNER_AUTHOR_CONTRACT = `The current brief's spec is the scope and its checklist says what done means. Its approval quote is the human's own words and wins any conflict with the spec. The short objective is navigation-only text and cannot add, remove, or narrow a requirement.
|
|
37085
|
-
Complete every checklist item in the current spec and use the brief's file manifest. Record
|
|
37639
|
+
Complete every checklist item in the current spec and use the brief's file manifest. Record your stages with record_validation_stage for this revision and head: intent, base, tests, docs, lint_types, publication, ci, final_authorization; the configured reviewer records review. Do not call a missing stage passed.
|
|
37086
37640
|
When a human correction changes the assignment, read the latest revision and use revise_corner_brief with the complete updated brief and a change description before doing dependent work. A chat reply does not revise the assignment.
|
|
37087
37641
|
Before any code, write its end-user story in one sentence: "a person who does X sees Y".
|
|
37088
37642
|
Follow the beeline-triage skill's bugfix execution contract when the spec or its approval quote reports a defect.
|
|
@@ -37113,15 +37667,15 @@ function cornerMergeInstruction(yoloMode, reviewerHandle) {
|
|
|
37113
37667
|
return yoloMode ? `Once the pull request exists, reply with its full URL and end the turn; do not tag ${reviewer}, check, or wait for CI. Green checks wake ${reviewer}; after its PASS the server merges the pull request itself. Never merge it yourself. You are woken only to fix failing checks, requested changes, or a merge GitHub refused; push the fix, and the new head needs green checks and a fresh PASS.` : `Once the pull request exists, reply with its full URL and end the turn; do not tag ${reviewer}, check, or wait for CI. Yolo is off, so the merge gate stays closed for you: never merge; a person merges it after ${reviewer} approves.`;
|
|
37114
37668
|
}
|
|
37115
37669
|
function cornerReviewerInstruction(input) {
|
|
37116
|
-
if (!input.
|
|
37670
|
+
if (!input.isReviewer || input.openedByAgent)
|
|
37117
37671
|
return void 0;
|
|
37118
37672
|
const author = input.authorHandle ? handle(input.authorHandle) : "author";
|
|
37119
37673
|
const number = input.pullRequestNumber ?? "N";
|
|
37120
37674
|
const headSha = input.headSha ?? "<head sha>";
|
|
37121
|
-
return `Checks are green on PR #${number} at ${headSha}${input.briefRevision ? ` with assigned brief revision ${input.briefRevision}` : ""}. Review it now with the beeline-review skill against that exact head and current assigned brief. FAIL: reply \`@${author}\` with the confirmed findings to fix. PASS: call the approve_merge tool for ${headSha}${input.briefRevision ? ` with briefRevision=${input.briefRevision}` : ""}, then reply \`approved ${headSha}\` without tagging ${author}: the server merges it, and a tag would wake the author for nothing. Never merge yourself or tell the author to merge. Never say you are holding or waiting for checks.`;
|
|
37675
|
+
return `Checks are green on PR #${number} at ${headSha}${input.briefRevision ? ` with assigned brief revision ${input.briefRevision}` : ""}. Review it now with the beeline-review skill against that exact head and current assigned brief. FAIL: call record_validation_stage with stage "review", status "failed", and headSha ${headSha}, then reply \`@${author}\` with the confirmed findings and the reviewed head ${headSha} to fix. PASS: call the approve_merge tool for ${headSha}${input.briefRevision ? ` with briefRevision=${input.briefRevision}` : ""}, then reply \`approved ${headSha}\` without tagging ${author}: the server merges it, and a tag would wake the author for nothing. Never merge yourself or tell the author to merge. Never say you are holding or waiting for checks.`;
|
|
37122
37676
|
}
|
|
37123
37677
|
function cornerSelfReviewerInstruction(input) {
|
|
37124
|
-
if (!input.
|
|
37678
|
+
if (!input.isReviewer || !input.openedByAgent)
|
|
37125
37679
|
return void 0;
|
|
37126
37680
|
return "Once the pull request exists, reply with its full URL and end the turn. You are this Room's reviewer, so your own pull request needs no review: do not request one or tag any agent for review. The server merges it once checks are green, yolo is on, and no human hold stands; never merge it yourself. You are woken only to fix failing checks or a merge GitHub refused.";
|
|
37127
37681
|
}
|
|
@@ -37324,11 +37878,7 @@ The soul is not authority and never changes your tools, permissions, roles, or m
|
|
|
37324
37878
|
budgetBytes: 520,
|
|
37325
37879
|
layer: "surface",
|
|
37326
37880
|
surfaces: ["code-corner"],
|
|
37327
|
-
render: ({ yoloMode, reviewerHandle, selfReviewer }) => (selfReviewer ? cornerSelfReviewerInstruction({
|
|
37328
|
-
reviewerHandle,
|
|
37329
|
-
agentHandle: reviewerHandle,
|
|
37330
|
-
openedByAgent: true
|
|
37331
|
-
}) : cornerMergeInstruction(Boolean(yoloMode), reviewerHandle)) + " Never merge any other pull request."
|
|
37881
|
+
render: ({ yoloMode, reviewerHandle, selfReviewer }) => (selfReviewer ? cornerSelfReviewerInstruction({ isReviewer: true, openedByAgent: true }) : cornerMergeInstruction(Boolean(yoloMode), reviewerHandle)) + " Never merge any other pull request."
|
|
37332
37882
|
},
|
|
37333
37883
|
{
|
|
37334
37884
|
id: "corner.checks",
|
|
@@ -37443,7 +37993,7 @@ var TURN_SECTIONS = [
|
|
|
37443
37993
|
budgetBytes: 600,
|
|
37444
37994
|
layer: "turn",
|
|
37445
37995
|
surfaces: CORNERS,
|
|
37446
|
-
render: ({ generatedTitle }) => generatedTitle ? `This corner still has its generated name, "${generatedTitle}". If the newest message states the work, call rename_corner once before you reply
|
|
37996
|
+
render: ({ generatedTitle, brief }) => generatedTitle ? `This human-opened corner still has its generated name, "${generatedTitle}". If the newest human message states the work, call rename_corner once before you reply with a name of at most three words and a short objective${brief ? "" : ", plus a brief grounded in that message with brief.approval.sourceMessageId set to the human message id"}. A bare mention does not state the work; leave the name until a message does.` : ""
|
|
37447
37997
|
},
|
|
37448
37998
|
{
|
|
37449
37999
|
id: "turn.brief",
|
|
@@ -38228,7 +38778,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
38228
38778
|
const cached = this.deliveredAttachments.get(item.id);
|
|
38229
38779
|
if (cached)
|
|
38230
38780
|
return cached;
|
|
38231
|
-
const delivered = await deliverAttachments(item.attachments,
|
|
38781
|
+
const delivered = await deliverAttachments(item.attachments, join15(this.attachmentDir, item.id.replace(/[^\w-]/g, "_")), this.options.fetchImpl);
|
|
38232
38782
|
this.deliveredAttachments.set(item.id, withoutImageData(delivered));
|
|
38233
38783
|
return delivered;
|
|
38234
38784
|
}
|
|
@@ -38415,7 +38965,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
38415
38965
|
root: this.options.config.agentHomeRoot,
|
|
38416
38966
|
squireScope,
|
|
38417
38967
|
sharedSkills: this.options.config.sharedSkills ?? [],
|
|
38418
|
-
isReviewer:
|
|
38968
|
+
isReviewer: configuration.isReviewer === true,
|
|
38419
38969
|
grantedHostRoutes: mountedHostRoutes,
|
|
38420
38970
|
extraHostRoutes: registryHostDeclarations,
|
|
38421
38971
|
resourceAuthFile,
|
|
@@ -38444,7 +38994,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
38444
38994
|
args: this.options.config.agentArgs ?? []
|
|
38445
38995
|
}, selection);
|
|
38446
38996
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
38447
|
-
this.attachmentDir = tmpDir ?
|
|
38997
|
+
this.attachmentDir = tmpDir ? join15(tmpDir, "beeline-attachments") : void 0;
|
|
38448
38998
|
this.sessionScratchDir = tmpDir;
|
|
38449
38999
|
this.sessionStateDirs = stateDirs;
|
|
38450
39000
|
const homeStateDirs = harnessHomeStateDirs(harnessLabel, agentEnv.HOME ?? operatorHome);
|
|
@@ -38693,7 +39243,6 @@ var MonolithRoomTurnLoop = class {
|
|
|
38693
39243
|
};
|
|
38694
39244
|
this.activeTurn = active;
|
|
38695
39245
|
active.promise = this.prompt(active).catch((error) => {
|
|
38696
|
-
this.options.health.failure(1e3);
|
|
38697
39246
|
console.error(`[thin-core] monolith Room ${this.options.roomId} turn failed:`, error);
|
|
38698
39247
|
}).finally(() => {
|
|
38699
39248
|
if (this.activeTurn === active) {
|
|
@@ -39076,56 +39625,60 @@ var MonolithRoomTurnLoop = class {
|
|
|
39076
39625
|
}
|
|
39077
39626
|
}
|
|
39078
39627
|
async run() {
|
|
39079
|
-
const { api, roomId, signal } = this.options;
|
|
39628
|
+
const { api, roomId, signal, supervisor } = this.options;
|
|
39629
|
+
const intake = (progress) => runServerCommandIntake({
|
|
39630
|
+
api,
|
|
39631
|
+
roomId,
|
|
39632
|
+
agentId: this.agent.publicKey,
|
|
39633
|
+
context: this.commandContext,
|
|
39634
|
+
signal,
|
|
39635
|
+
pollMs: this.options.pollMs,
|
|
39636
|
+
presence: {
|
|
39637
|
+
...this.options.config.daemonReleaseVersion ? { releaseVersion: this.options.config.daemonReleaseVersion } : {},
|
|
39638
|
+
...this.options.config.daemonSourceSha ? { sourceSha: this.options.config.daemonSourceSha } : {},
|
|
39639
|
+
available: !this.options.config.modelUnavailable
|
|
39640
|
+
},
|
|
39641
|
+
onWake: (wake) => {
|
|
39642
|
+
this.wakeIntake = wake;
|
|
39643
|
+
},
|
|
39644
|
+
onPoll: () => {
|
|
39645
|
+
progress();
|
|
39646
|
+
this.options.health.poll();
|
|
39647
|
+
},
|
|
39648
|
+
onSubscriptionState: this.options.onSubscriptionState,
|
|
39649
|
+
onError: (error) => {
|
|
39650
|
+
this.options.onIntakeError?.(error);
|
|
39651
|
+
console.error("[thin-core] Room command failed", error);
|
|
39652
|
+
},
|
|
39653
|
+
// Marks this loop busy the instant it attempts to claim a real
|
|
39654
|
+
// turn, before the claim's own network round trip and before
|
|
39655
|
+
// context.enter()'s own file I/O - closing the window where
|
|
39656
|
+
// RoomRuntimeCoordinator.reconcile's repository-revision restart
|
|
39657
|
+
// could see a claiming-but-not-yet-`busy` Room as idle and stop it,
|
|
39658
|
+
// cancelling a turn that had already begun (or was about to) (C112).
|
|
39659
|
+
onClaiming: () => {
|
|
39660
|
+
this.busy = true;
|
|
39661
|
+
},
|
|
39662
|
+
onClaimFailed: () => {
|
|
39663
|
+
this.busy = false;
|
|
39664
|
+
},
|
|
39665
|
+
onEnter: (command) => this.squireRelay.activate(command, this.commandContext.generationId),
|
|
39666
|
+
onLeave: (command) => this.squireRelay.deactivate(command.turnRequestId, this.pausedOnGrantRequestId),
|
|
39667
|
+
stop: (requestId) => this.stopTurn(requestId),
|
|
39668
|
+
restart: () => this.options.onRestartRequested?.(),
|
|
39669
|
+
canStartTurn: this.options.canStartTurn,
|
|
39670
|
+
run: async (command) => {
|
|
39671
|
+
const item = {
|
|
39672
|
+
...command.source,
|
|
39673
|
+
id: command.turnRequestId,
|
|
39674
|
+
body: command.action === "resume" ? `Resume the paused turn. The server supplied this answer: ${command.source.body}` : command.source.body
|
|
39675
|
+
};
|
|
39676
|
+
this.startPrompt(item);
|
|
39677
|
+
await this.activeTurn?.promise;
|
|
39678
|
+
}
|
|
39679
|
+
});
|
|
39080
39680
|
try {
|
|
39081
|
-
await
|
|
39082
|
-
api,
|
|
39083
|
-
roomId,
|
|
39084
|
-
agentId: this.agent.publicKey,
|
|
39085
|
-
context: this.commandContext,
|
|
39086
|
-
signal,
|
|
39087
|
-
pollMs: this.options.pollMs,
|
|
39088
|
-
presence: {
|
|
39089
|
-
...this.options.config.daemonReleaseVersion ? { releaseVersion: this.options.config.daemonReleaseVersion } : {},
|
|
39090
|
-
...this.options.config.daemonSourceSha ? { sourceSha: this.options.config.daemonSourceSha } : {},
|
|
39091
|
-
available: !this.options.config.modelUnavailable
|
|
39092
|
-
},
|
|
39093
|
-
onWake: (wake) => {
|
|
39094
|
-
this.wakeIntake = wake;
|
|
39095
|
-
},
|
|
39096
|
-
onPoll: () => this.options.health.poll(),
|
|
39097
|
-
onSubscriptionState: this.options.onSubscriptionState,
|
|
39098
|
-
onError: (error) => {
|
|
39099
|
-
this.options.onIntakeError?.(error);
|
|
39100
|
-
console.error("[thin-core] Room command failed", error);
|
|
39101
|
-
},
|
|
39102
|
-
// Marks this loop busy the instant it attempts to claim a real
|
|
39103
|
-
// turn, before the claim's own network round trip and before
|
|
39104
|
-
// context.enter()'s own file I/O - closing the window where
|
|
39105
|
-
// RoomRuntimeCoordinator.reconcile's repository-revision restart
|
|
39106
|
-
// could see a claiming-but-not-yet-`busy` Room as idle and stop it,
|
|
39107
|
-
// cancelling a turn that had already begun (or was about to) (C112).
|
|
39108
|
-
onClaiming: () => {
|
|
39109
|
-
this.busy = true;
|
|
39110
|
-
},
|
|
39111
|
-
onClaimFailed: () => {
|
|
39112
|
-
this.busy = false;
|
|
39113
|
-
},
|
|
39114
|
-
onEnter: (command) => this.squireRelay.activate(command, this.commandContext.generationId),
|
|
39115
|
-
onLeave: (command) => this.squireRelay.deactivate(command.turnRequestId, this.pausedOnGrantRequestId),
|
|
39116
|
-
stop: (requestId) => this.stopTurn(requestId),
|
|
39117
|
-
restart: () => this.options.onRestartRequested?.(),
|
|
39118
|
-
canStartTurn: this.options.canStartTurn,
|
|
39119
|
-
run: async (command) => {
|
|
39120
|
-
const item = {
|
|
39121
|
-
...command.source,
|
|
39122
|
-
id: command.turnRequestId,
|
|
39123
|
-
body: command.action === "resume" ? `Resume the paused turn. The server supplied this answer: ${command.source.body}` : command.source.body
|
|
39124
|
-
};
|
|
39125
|
-
this.startPrompt(item);
|
|
39126
|
-
await this.activeTurn?.promise;
|
|
39127
|
-
}
|
|
39128
|
-
});
|
|
39681
|
+
await (supervisor ? supervisor.supervise(`Room ${roomId}`, signal, intake) : intake(() => void 0));
|
|
39129
39682
|
} finally {
|
|
39130
39683
|
this.squireRelay.close();
|
|
39131
39684
|
this.options.grantRunner?.unregister(roomId);
|
|
@@ -39311,8 +39864,8 @@ process.exit(result.status ?? 1);
|
|
|
39311
39864
|
// apps/body/dist/warm-node-modules.js
|
|
39312
39865
|
import { createHash as createHash9, randomUUID as randomUUID10 } from "node:crypto";
|
|
39313
39866
|
import { constants as fsConstants3 } from "node:fs";
|
|
39314
|
-
import { chmod as chmod9, copyFile as copyFile2, link, lstat as lstat4, mkdir as mkdir19, readdir as readdir8, readFile as
|
|
39315
|
-
import { dirname as dirname17, join as
|
|
39867
|
+
import { chmod as chmod9, copyFile as copyFile2, link, lstat as lstat4, mkdir as mkdir19, readdir as readdir8, readFile as readFile21, readlink as readlink2, rename as rename8, rm as rm9, stat as stat7, symlink as symlink3, utimes } from "node:fs/promises";
|
|
39868
|
+
import { dirname as dirname17, join as join16, resolve as resolve27 } from "node:path";
|
|
39316
39869
|
var STORE_FORMAT = "v1";
|
|
39317
39870
|
var STAGING_PREFIX = ".beeline-warm-";
|
|
39318
39871
|
var STAGING_SWEEP_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -39333,7 +39886,7 @@ function isPlanRefusal(value) {
|
|
|
39333
39886
|
return "failure" in value;
|
|
39334
39887
|
}
|
|
39335
39888
|
async function readWarmPlan(worktreePath) {
|
|
39336
|
-
const lockfile = await
|
|
39889
|
+
const lockfile = await readFile21(resolve27(worktreePath, "package-lock.json")).catch(() => void 0);
|
|
39337
39890
|
if (!lockfile)
|
|
39338
39891
|
return { failure: "no-lockfile" };
|
|
39339
39892
|
const packages = parseLockfilePackages(lockfile);
|
|
@@ -39398,7 +39951,7 @@ async function seedWarmNodeModules(input) {
|
|
|
39398
39951
|
for (const tree of plan.trees) {
|
|
39399
39952
|
const target = resolve27(input.worktreePath, tree);
|
|
39400
39953
|
await mkdir19(dirname17(target), { recursive: true });
|
|
39401
|
-
await
|
|
39954
|
+
await rename8(resolve27(staging, tree), target);
|
|
39402
39955
|
placed.push(target);
|
|
39403
39956
|
}
|
|
39404
39957
|
return { reason: "seeded", key: plan.key };
|
|
@@ -39443,7 +39996,7 @@ async function harvestWarmNodeModules(input) {
|
|
|
39443
39996
|
if (!await stagedTreeIsPublishable(input.worktreePath, staging, plan.key)) {
|
|
39444
39997
|
return { reason: "changed", key: plan.key };
|
|
39445
39998
|
}
|
|
39446
|
-
await
|
|
39999
|
+
await rename8(staging, entry);
|
|
39447
40000
|
await pruneWarmStore(input.storeRoot, WARM_STORE_MAX_ENTRIES);
|
|
39448
40001
|
return { reason: "stored", key: plan.key };
|
|
39449
40002
|
} catch (error) {
|
|
@@ -39458,18 +40011,18 @@ async function stagedTreeIsPublishable(worktreePath, staging, key) {
|
|
|
39458
40011
|
const settled = await readWarmPlan(worktreePath);
|
|
39459
40012
|
if (isPlanRefusal(settled) || settled.key !== key)
|
|
39460
40013
|
return false;
|
|
39461
|
-
const hidden =
|
|
40014
|
+
const hidden = join16("node_modules", ".package-lock.json");
|
|
39462
40015
|
const [copied, current] = await Promise.all([
|
|
39463
|
-
|
|
39464
|
-
|
|
40016
|
+
readFile21(resolve27(staging, hidden)).catch(() => void 0),
|
|
40017
|
+
readFile21(resolve27(worktreePath, hidden)).catch(() => void 0)
|
|
39465
40018
|
]);
|
|
39466
40019
|
if (!copied || !current || !copied.equals(current))
|
|
39467
40020
|
return false;
|
|
39468
40021
|
return (await missingInstalledPackages(worktreePath, staging)).length === 0;
|
|
39469
40022
|
}
|
|
39470
40023
|
async function missingInstalledPackages(worktreePath, treeRoot = worktreePath) {
|
|
39471
|
-
const wanted = parseLockfilePackages(await
|
|
39472
|
-
const installed = parseLockfilePackages(await
|
|
40024
|
+
const wanted = parseLockfilePackages(await readFile21(resolve27(worktreePath, "package-lock.json")).catch(() => void 0));
|
|
40025
|
+
const installed = parseLockfilePackages(await readFile21(resolve27(treeRoot, "node_modules", ".package-lock.json")).catch(() => void 0));
|
|
39473
40026
|
if (!wanted)
|
|
39474
40027
|
return ["package-lock.json is unreadable"];
|
|
39475
40028
|
if (!installed)
|
|
@@ -39496,7 +40049,7 @@ async function missingInstalledPackages(worktreePath, treeRoot = worktreePath) {
|
|
|
39496
40049
|
return missing.sort();
|
|
39497
40050
|
}
|
|
39498
40051
|
async function isInstalledPackage(path) {
|
|
39499
|
-
return stat7(
|
|
40052
|
+
return stat7(join16(path, "package.json")).then((info) => info.isFile(), () => false);
|
|
39500
40053
|
}
|
|
39501
40054
|
var INTEGRITY_READ_CONCURRENCY = 64;
|
|
39502
40055
|
async function mapWithLimit(values, limit, visit) {
|
|
@@ -39530,8 +40083,8 @@ function isContainedTreePath(value) {
|
|
|
39530
40083
|
async function cloneTree(source, target, file, topLevel = true) {
|
|
39531
40084
|
await mkdir19(target, { recursive: true, mode: 493 });
|
|
39532
40085
|
for (const entry of await readdir8(source, { withFileTypes: true })) {
|
|
39533
|
-
const from =
|
|
39534
|
-
const to =
|
|
40086
|
+
const from = join16(source, entry.name);
|
|
40087
|
+
const to = join16(target, entry.name);
|
|
39535
40088
|
if (entry.isSymbolicLink()) {
|
|
39536
40089
|
await symlink3(await readlink2(from), to);
|
|
39537
40090
|
continue;
|
|
@@ -39561,13 +40114,13 @@ async function pruneWarmStore(storeRoot, keep) {
|
|
|
39561
40114
|
const names = (await readdir8(storeRoot).catch(() => [])).filter((name) => !name.startsWith(STAGING_PREFIX));
|
|
39562
40115
|
const entries = [];
|
|
39563
40116
|
for (const name of names) {
|
|
39564
|
-
const info = await lstat4(
|
|
40117
|
+
const info = await lstat4(join16(storeRoot, name)).catch(() => void 0);
|
|
39565
40118
|
if (info?.isDirectory())
|
|
39566
40119
|
entries.push({ name, usedAt: info.mtimeMs });
|
|
39567
40120
|
}
|
|
39568
40121
|
const dropped = entries.sort((a2, b) => b.usedAt - a2.usedAt || a2.name.localeCompare(b.name)).slice(keep);
|
|
39569
40122
|
for (const entry of dropped) {
|
|
39570
|
-
await rm9(
|
|
40123
|
+
await rm9(join16(storeRoot, entry.name), { recursive: true, force: true }).catch(() => void 0);
|
|
39571
40124
|
}
|
|
39572
40125
|
return dropped.map((entry) => entry.name);
|
|
39573
40126
|
}
|
|
@@ -39576,7 +40129,7 @@ async function sweepStaleStaging(storeRoot, now2) {
|
|
|
39576
40129
|
for (const name of entries) {
|
|
39577
40130
|
if (!name.startsWith(STAGING_PREFIX))
|
|
39578
40131
|
continue;
|
|
39579
|
-
const path =
|
|
40132
|
+
const path = join16(storeRoot, name);
|
|
39580
40133
|
const info = await lstat4(path).catch(() => void 0);
|
|
39581
40134
|
if (!info || now2 - info.mtimeMs < STAGING_SWEEP_MS)
|
|
39582
40135
|
continue;
|
|
@@ -40092,8 +40645,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
40092
40645
|
this.yoloMode = configuration.yoloMode;
|
|
40093
40646
|
const opener = this.options.openedBy ? roster.members.find((member) => member.identityId === this.options.openedBy) : void 0;
|
|
40094
40647
|
const reviewerInput = {
|
|
40095
|
-
|
|
40096
|
-
agentHandle: self?.handle,
|
|
40648
|
+
isReviewer: configuration.isReviewer === true,
|
|
40097
40649
|
authorHandle: opener?.handle,
|
|
40098
40650
|
openedByAgent: !this.options.openedBy || this.options.openedBy === this.agent.publicKey
|
|
40099
40651
|
};
|
|
@@ -40135,7 +40687,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
40135
40687
|
root: this.options.config.agentHomeRoot,
|
|
40136
40688
|
squireScope,
|
|
40137
40689
|
sharedSkills: this.options.config.sharedSkills ?? [],
|
|
40138
|
-
isReviewer:
|
|
40690
|
+
isReviewer: Boolean(reviewerInstruction),
|
|
40139
40691
|
grantedHostRoutes: mountedHostRoutes,
|
|
40140
40692
|
extraHostRoutes: registryHostDeclarations,
|
|
40141
40693
|
resourceAuthFile,
|
|
@@ -40193,7 +40745,7 @@ var MonolithCornerTurnLoop = class {
|
|
|
40193
40745
|
args: this.options.config.agentArgs ?? []
|
|
40194
40746
|
}, selection);
|
|
40195
40747
|
const { stateDirs, tmpDir } = harnessStateDirsFromEnv(agentEnv);
|
|
40196
|
-
this.attachmentDir = tmpDir ?
|
|
40748
|
+
this.attachmentDir = tmpDir ? join17(tmpDir, "beeline-attachments") : void 0;
|
|
40197
40749
|
this.sessionScratchDir = tmpDir;
|
|
40198
40750
|
const homeStateDirs = harnessHomeStateDirs(harnessLabel, agentEnv.HOME ?? operatorHome);
|
|
40199
40751
|
await Promise.all(homeStateDirs.map((dir) => mkdir20(dir, { recursive: true })));
|
|
@@ -40594,10 +41146,10 @@ var MonolithCornerTurnLoop = class {
|
|
|
40594
41146
|
size: file.size
|
|
40595
41147
|
}));
|
|
40596
41148
|
const allAttachments = [...attachments, ...briefAttachments];
|
|
40597
|
-
const delivered = this.attachmentDir && allAttachments.length ? await deliverAttachments(allAttachments,
|
|
41149
|
+
const delivered = this.attachmentDir && allAttachments.length ? await deliverAttachments(allAttachments, join17(this.attachmentDir, requestId.replace(/[^\w-]/g, "_")), this.options.fetchImpl) : [];
|
|
40598
41150
|
const briefFileLines = await Promise.all((restored.brief?.attachments ?? []).map(async (file, index) => {
|
|
40599
41151
|
const entry = delivered.find((item) => item.attachment === briefAttachments[index]);
|
|
40600
|
-
const verified = entry?.path && createHash10("sha256").update(await
|
|
41152
|
+
const verified = entry?.path && createHash10("sha256").update(await readFile22(entry.path)).digest("hex") === file.sha256;
|
|
40601
41153
|
return `- ${file.title} (${file.purpose}; ${file.required ? "required" : "optional"}; sha256 ${file.sha256}): ${verified ? entry.path : "UNAVAILABLE OR CONTENT MISMATCH"}`;
|
|
40602
41154
|
}));
|
|
40603
41155
|
const missingRequiredBriefFile = (restored.brief?.attachments ?? []).some((file, index) => file.required && briefFileLines[index]?.includes("UNAVAILABLE OR CONTENT MISMATCH"));
|
|
@@ -41037,68 +41589,72 @@ ${deviceGrantResumePrompt(grantedDevice, result.agentText)}`);
|
|
|
41037
41589
|
});
|
|
41038
41590
|
}
|
|
41039
41591
|
async run() {
|
|
41040
|
-
const { api, cornerId, signal } = this.options;
|
|
41041
|
-
|
|
41042
|
-
|
|
41043
|
-
|
|
41044
|
-
|
|
41045
|
-
|
|
41046
|
-
|
|
41047
|
-
|
|
41048
|
-
|
|
41049
|
-
|
|
41050
|
-
|
|
41051
|
-
|
|
41052
|
-
|
|
41053
|
-
|
|
41054
|
-
|
|
41055
|
-
|
|
41056
|
-
|
|
41057
|
-
|
|
41058
|
-
|
|
41059
|
-
|
|
41060
|
-
|
|
41061
|
-
|
|
41062
|
-
|
|
41063
|
-
|
|
41064
|
-
|
|
41065
|
-
|
|
41066
|
-
|
|
41067
|
-
|
|
41068
|
-
|
|
41069
|
-
|
|
41070
|
-
|
|
41071
|
-
|
|
41072
|
-
|
|
41073
|
-
|
|
41074
|
-
|
|
41075
|
-
|
|
41076
|
-
|
|
41077
|
-
|
|
41078
|
-
|
|
41079
|
-
|
|
41080
|
-
|
|
41081
|
-
|
|
41082
|
-
|
|
41083
|
-
|
|
41084
|
-
return true;
|
|
41085
|
-
}
|
|
41086
|
-
if (!this.reconcileCloseRequested)
|
|
41087
|
-
return false;
|
|
41088
|
-
this.reconcileCloseRequested = false;
|
|
41089
|
-
const state = await api.execute("getCornerRestoreState", { cornerId });
|
|
41090
|
-
if (this.options.lane === "no_code" && state.lane !== "no_code") {
|
|
41091
|
-
this.options.onLaneChanged?.();
|
|
41092
|
-
return true;
|
|
41093
|
-
}
|
|
41094
|
-
if (!state.closeRequested)
|
|
41095
|
-
return false;
|
|
41592
|
+
const { api, cornerId, signal, supervisor } = this.options;
|
|
41593
|
+
const intake = (progress) => runServerCommandIntake({
|
|
41594
|
+
api,
|
|
41595
|
+
roomId: cornerId,
|
|
41596
|
+
agentId: this.agent.publicKey,
|
|
41597
|
+
context: this.commandContext,
|
|
41598
|
+
signal,
|
|
41599
|
+
pollMs: this.options.pollMs,
|
|
41600
|
+
presence: {
|
|
41601
|
+
...this.options.config.daemonReleaseVersion ? { releaseVersion: this.options.config.daemonReleaseVersion } : {},
|
|
41602
|
+
...this.options.config.daemonSourceSha ? { sourceSha: this.options.config.daemonSourceSha } : {},
|
|
41603
|
+
available: !this.options.config.modelUnavailable
|
|
41604
|
+
},
|
|
41605
|
+
onWake: (wake) => {
|
|
41606
|
+
this.wakeIntake = wake;
|
|
41607
|
+
},
|
|
41608
|
+
onPoll: () => {
|
|
41609
|
+
progress();
|
|
41610
|
+
this.options.onPoll();
|
|
41611
|
+
},
|
|
41612
|
+
onSubscriptionState: this.options.onSubscriptionState,
|
|
41613
|
+
onError: (error) => {
|
|
41614
|
+
this.options.onIntakeError?.(error);
|
|
41615
|
+
console.error("[thin-core] corner command failed", error);
|
|
41616
|
+
},
|
|
41617
|
+
// See monolith-room-turn.ts (C112): mark busy the instant a claim
|
|
41618
|
+
// attempt starts, before its own network round trip and before
|
|
41619
|
+
// context.enter()'s own file I/O, so a reconcile busy-check landing
|
|
41620
|
+
// anywhere in that window can never see this corner as idle when a
|
|
41621
|
+
// turn was already claimed (or about to be).
|
|
41622
|
+
onClaiming: () => {
|
|
41623
|
+
this.busy = true;
|
|
41624
|
+
},
|
|
41625
|
+
onClaimFailed: () => {
|
|
41626
|
+
this.busy = false;
|
|
41627
|
+
},
|
|
41628
|
+
onEnter: (command) => this.squireRelay.activate(command, this.commandContext.generationId),
|
|
41629
|
+
onLeave: (command) => this.squireRelay.deactivate(command.turnRequestId),
|
|
41630
|
+
stop: (requestId) => this.stopTurn(requestId),
|
|
41631
|
+
restart: () => this.options.onRestartRequested?.(),
|
|
41632
|
+
canStartTurn: this.options.canStartTurn,
|
|
41633
|
+
closed: async () => {
|
|
41634
|
+
if (this.closePushed) {
|
|
41635
|
+
this.closePushed = false;
|
|
41096
41636
|
await this.harvest;
|
|
41097
41637
|
await this.options.onCloseRequested();
|
|
41098
41638
|
return true;
|
|
41099
|
-
}
|
|
41100
|
-
|
|
41101
|
-
|
|
41639
|
+
}
|
|
41640
|
+
if (!this.reconcileCloseRequested)
|
|
41641
|
+
return false;
|
|
41642
|
+
this.reconcileCloseRequested = false;
|
|
41643
|
+
const state = await api.execute("getCornerRestoreState", { cornerId });
|
|
41644
|
+
if (this.options.lane === "no_code" && state.lane !== "no_code") {
|
|
41645
|
+
this.options.onLaneChanged?.();
|
|
41646
|
+
return true;
|
|
41647
|
+
}
|
|
41648
|
+
if (!state.closeRequested)
|
|
41649
|
+
return false;
|
|
41650
|
+
await this.harvest;
|
|
41651
|
+
await this.options.onCloseRequested();
|
|
41652
|
+
return true;
|
|
41653
|
+
},
|
|
41654
|
+
run: (command) => this.prompt(command.turnRequestId, command.source.body, command.source.attachments, command.source.authorId, command.reason === "corner_check" ? [command.source.body] : void 0, command.source.type === "message" ? command.sourceMessageId : void 0)
|
|
41655
|
+
});
|
|
41656
|
+
try {
|
|
41657
|
+
await (supervisor ? supervisor.supervise(`corner ${cornerId}`, signal, intake) : intake(() => void 0));
|
|
41102
41658
|
} finally {
|
|
41103
41659
|
this.squireRelay.close();
|
|
41104
41660
|
this.options.grantRunner?.unregister(cornerId);
|
|
@@ -41170,6 +41726,89 @@ var SurfaceHealth = class {
|
|
|
41170
41726
|
}
|
|
41171
41727
|
};
|
|
41172
41728
|
|
|
41729
|
+
// apps/body/dist/room-supervisor.js
|
|
41730
|
+
var ROOM_RETRY_DELAYS_MS = [1e3, 5e3, 3e4];
|
|
41731
|
+
var RoomSupervisor = class {
|
|
41732
|
+
delaysMs;
|
|
41733
|
+
#parked = /* @__PURE__ */ new Set();
|
|
41734
|
+
#wakes = 0;
|
|
41735
|
+
constructor(delaysMs = ROOM_RETRY_DELAYS_MS) {
|
|
41736
|
+
this.delaysMs = delaysMs;
|
|
41737
|
+
}
|
|
41738
|
+
/** The live socket opened or discovery was woken: every waiting loop retries now. */
|
|
41739
|
+
wake() {
|
|
41740
|
+
this.#wakes += 1;
|
|
41741
|
+
for (const resume of [...this.#parked])
|
|
41742
|
+
resume();
|
|
41743
|
+
}
|
|
41744
|
+
/** Wakes so far; a wait that started from an older count does not wait. */
|
|
41745
|
+
get wakes() {
|
|
41746
|
+
return this.#wakes;
|
|
41747
|
+
}
|
|
41748
|
+
/** How many timed retries follow one failure before a loop parks. */
|
|
41749
|
+
get retries() {
|
|
41750
|
+
return this.delaysMs.length;
|
|
41751
|
+
}
|
|
41752
|
+
/**
|
|
41753
|
+
* Wait before retrying failure number `failures` (1-based). Within the
|
|
41754
|
+
* bound the fixed delay applies, and a wake may cut it short; past the bound
|
|
41755
|
+
* only a wake (or the abort) ends the wait. A wake that already arrived
|
|
41756
|
+
* after `since` (a `wakes` count) ends it at once, so none is lost.
|
|
41757
|
+
*/
|
|
41758
|
+
retryDelay(failures, signal, since = this.#wakes) {
|
|
41759
|
+
const delay = this.delaysMs[failures - 1];
|
|
41760
|
+
return new Promise((resolve40) => {
|
|
41761
|
+
let timer;
|
|
41762
|
+
const done = () => {
|
|
41763
|
+
clearTimeout(timer);
|
|
41764
|
+
this.#parked.delete(done);
|
|
41765
|
+
signal?.removeEventListener("abort", done);
|
|
41766
|
+
resolve40();
|
|
41767
|
+
};
|
|
41768
|
+
this.#parked.add(done);
|
|
41769
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
41770
|
+
if (signal?.aborted || this.#wakes !== since) {
|
|
41771
|
+
done();
|
|
41772
|
+
return;
|
|
41773
|
+
}
|
|
41774
|
+
if (delay !== void 0) {
|
|
41775
|
+
timer = setTimeout(done, delay);
|
|
41776
|
+
timer.unref?.();
|
|
41777
|
+
}
|
|
41778
|
+
});
|
|
41779
|
+
}
|
|
41780
|
+
/**
|
|
41781
|
+
* Run one Room or corner intake under supervision: a failed read never ends
|
|
41782
|
+
* it. `run` resolves only when the intake itself is finished (aborted or
|
|
41783
|
+
* closed); it calls `progress` once its reads succeed again, which restores
|
|
41784
|
+
* the full retry budget. The intake rejects only after its active turn has
|
|
41785
|
+
* settled, so re-entering cannot claim the same command twice.
|
|
41786
|
+
*/
|
|
41787
|
+
async supervise(label, signal, run2) {
|
|
41788
|
+
let failures = 0;
|
|
41789
|
+
for (; ; ) {
|
|
41790
|
+
const since = this.#wakes;
|
|
41791
|
+
try {
|
|
41792
|
+
await run2(() => {
|
|
41793
|
+
failures = 0;
|
|
41794
|
+
});
|
|
41795
|
+
return;
|
|
41796
|
+
} catch (error) {
|
|
41797
|
+
if (signal?.aborted)
|
|
41798
|
+
return;
|
|
41799
|
+
failures += 1;
|
|
41800
|
+
const parked = failures > this.delaysMs.length;
|
|
41801
|
+
console.error(`[thin-core] ${label} intake failed; ${parked ? "waiting for the next live open or discovery wake" : `retry ${failures} of ${this.delaysMs.length} in ${this.delaysMs[failures - 1]}ms`}:`, error);
|
|
41802
|
+
await this.retryDelay(failures, signal, since);
|
|
41803
|
+
if (signal?.aborted)
|
|
41804
|
+
return;
|
|
41805
|
+
if (parked)
|
|
41806
|
+
failures = 0;
|
|
41807
|
+
}
|
|
41808
|
+
}
|
|
41809
|
+
}
|
|
41810
|
+
};
|
|
41811
|
+
|
|
41173
41812
|
// apps/body/dist/room-runtime.js
|
|
41174
41813
|
init_runtime();
|
|
41175
41814
|
|
|
@@ -41597,11 +42236,6 @@ var SessionScheduler = class {
|
|
|
41597
42236
|
// apps/body/dist/room-runtime.js
|
|
41598
42237
|
var REMOVAL_CONFIRMATION_READS = 2;
|
|
41599
42238
|
var ROOM_JOIN_CONCURRENCY = 4;
|
|
41600
|
-
var DEFAULT_ROOM_WATCHDOG_STALE_MS = 9e4;
|
|
41601
|
-
var DEFAULT_RECONCILE_HEARTBEAT_MS = 10 * 6e4;
|
|
41602
|
-
function defaultReconcileHeartbeatMs(random = Math.random) {
|
|
41603
|
-
return DEFAULT_RECONCILE_HEARTBEAT_MS + Math.floor(random() * 5 * 6e4);
|
|
41604
|
-
}
|
|
41605
42239
|
var DEFAULT_DRAIN_DEADLINE_MS = 30 * 6e4;
|
|
41606
42240
|
var CORNER_BRANCH_DELETE_ATTEMPTS = 3;
|
|
41607
42241
|
var CornerCredentialLookupError = class extends Error {
|
|
@@ -41609,25 +42243,6 @@ var CornerCredentialLookupError = class extends Error {
|
|
|
41609
42243
|
super("corner repository credential lookup failed", { cause });
|
|
41610
42244
|
}
|
|
41611
42245
|
};
|
|
41612
|
-
var DiscoveryWakes = class {
|
|
41613
|
-
arrived = 0;
|
|
41614
|
-
served = 0;
|
|
41615
|
-
/** Called for every agent-directed `rooms-changed` wake. */
|
|
41616
|
-
wake() {
|
|
41617
|
-
this.arrived += 1;
|
|
41618
|
-
}
|
|
41619
|
-
needsFastReconcile() {
|
|
41620
|
-
return this.arrived !== this.served;
|
|
41621
|
-
}
|
|
41622
|
-
/** Snapshot at reconcile entry: the wake count its reads will cover. */
|
|
41623
|
-
beginReconcile() {
|
|
41624
|
-
return this.arrived;
|
|
41625
|
-
}
|
|
41626
|
-
/** Clear only wakes the completed start pass actually served. */
|
|
41627
|
-
completeReconcile(covered) {
|
|
41628
|
-
this.served = Math.max(this.served, covered);
|
|
41629
|
-
}
|
|
41630
|
-
};
|
|
41631
42246
|
function shouldPostInitialCornerWorkingState(restore) {
|
|
41632
42247
|
return !restore.lifecycle?.branch && !restore.lifecycle?.pr;
|
|
41633
42248
|
}
|
|
@@ -41908,8 +42523,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
41908
42523
|
/** Parent ownership retained so a failed corner listing never authorizes removal. */
|
|
41909
42524
|
monolithCornerParents = /* @__PURE__ */ new Map();
|
|
41910
42525
|
now;
|
|
41911
|
-
watchdogStaleMs;
|
|
41912
|
-
reconcileHeartbeatMs;
|
|
41913
42526
|
drainDeadlineMs;
|
|
41914
42527
|
drainDeadlineAt;
|
|
41915
42528
|
workspaceRemovalConfirmations = 0;
|
|
@@ -41921,14 +42534,9 @@ var RoomRuntimeCoordinator = class {
|
|
|
41921
42534
|
repositoryStateFlights = /* @__PURE__ */ new Map();
|
|
41922
42535
|
tokenCache = /* @__PURE__ */ new Map();
|
|
41923
42536
|
tokenFlights = /* @__PURE__ */ new Map();
|
|
41924
|
-
confirmationPending = false;
|
|
41925
42537
|
restartRequested = false;
|
|
41926
|
-
/**
|
|
41927
|
-
|
|
41928
|
-
* survive its start-pass clearing, or a reconnect mid-reconcile waits a
|
|
41929
|
-
* heartbeat for a wake the daemon already received. A scoped membership
|
|
41930
|
-
* event applies incrementally and never touches this latch. */
|
|
41931
|
-
discoveryWakes = new DiscoveryWakes();
|
|
42538
|
+
/** Keeps Room and corner intakes alive across failed reads, without polling. */
|
|
42539
|
+
supervisor = new RoomSupervisor();
|
|
41932
42540
|
discoveryWakeListener;
|
|
41933
42541
|
interactiveIdleListener;
|
|
41934
42542
|
/** One command-grant runner per daemon; Rooms and corners register their checkouts on it. */
|
|
@@ -41975,8 +42583,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
41975
42583
|
void this.scheduler.suspendIdle().catch((error) => console.error("[body] config-change session restart failed", error));
|
|
41976
42584
|
void Promise.resolve(this.options.onConfigChanged?.()).catch((error) => console.error("[body] config-change catalog refresh failed", error));
|
|
41977
42585
|
});
|
|
41978
|
-
this.watchdogStaleMs = options.watchdogStaleMs ?? DEFAULT_ROOM_WATCHDOG_STALE_MS;
|
|
41979
|
-
this.reconcileHeartbeatMs = options.reconcileHeartbeatMs ?? defaultReconcileHeartbeatMs();
|
|
41980
42586
|
this.drainDeadlineMs = options.drainDeadlineMs ?? DEFAULT_DRAIN_DEADLINE_MS;
|
|
41981
42587
|
const fixedWorkspaceCeiling = process.env.BUZZY_BODY_MAX_SESSIONS;
|
|
41982
42588
|
this.scheduler = new SessionScheduler({
|
|
@@ -41998,12 +42604,18 @@ var RoomRuntimeCoordinator = class {
|
|
|
41998
42604
|
setInteractiveIdleListener(listener) {
|
|
41999
42605
|
this.interactiveIdleListener = listener;
|
|
42000
42606
|
}
|
|
42001
|
-
|
|
42002
|
-
|
|
42003
|
-
|
|
42607
|
+
/**
|
|
42608
|
+
* A failed reconcile makes the live socket suspect: it is pinged, and a
|
|
42609
|
+
* silent one is replaced, which works with any server version. A response
|
|
42610
|
+
* the server actually sent (or a full local read budget) says nothing about
|
|
42611
|
+
* the socket.
|
|
42612
|
+
*/
|
|
42613
|
+
suspectLink(error) {
|
|
42614
|
+
if (!(error instanceof DaemonApiError))
|
|
42615
|
+
this.options.daemonApi.link?.suspect();
|
|
42004
42616
|
}
|
|
42005
42617
|
wakeDiscovery() {
|
|
42006
|
-
this.
|
|
42618
|
+
this.supervisor.wake();
|
|
42007
42619
|
this.discoveryWakeListener?.();
|
|
42008
42620
|
}
|
|
42009
42621
|
activeRoomCount() {
|
|
@@ -42027,12 +42639,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42027
42639
|
schedulerSnapshot() {
|
|
42028
42640
|
return this.scheduler.snapshot();
|
|
42029
42641
|
}
|
|
42030
|
-
needsFastReconcile() {
|
|
42031
|
-
return this.confirmationPending || this.discoveryWakes.needsFastReconcile();
|
|
42032
|
-
}
|
|
42033
|
-
reconcileHeartbeatIntervalMs() {
|
|
42034
|
-
return this.reconcileHeartbeatMs;
|
|
42035
|
-
}
|
|
42036
42642
|
isWorkspaceIdle() {
|
|
42037
42643
|
return this.activeTurnCount() === 0;
|
|
42038
42644
|
}
|
|
@@ -42058,6 +42664,16 @@ var RoomRuntimeCoordinator = class {
|
|
|
42058
42664
|
room.controller.abort();
|
|
42059
42665
|
return true;
|
|
42060
42666
|
}
|
|
42667
|
+
/**
|
|
42668
|
+
* Undo `quiesceForUpdateIfIdle` after a managed restart failed: clear the
|
|
42669
|
+
* latch and let reconciliation start the Room loops the quiesce stopped.
|
|
42670
|
+
*/
|
|
42671
|
+
resumeServing() {
|
|
42672
|
+
if (this.stopped)
|
|
42673
|
+
return;
|
|
42674
|
+
this.restartRequested = false;
|
|
42675
|
+
this.wakeDiscovery();
|
|
42676
|
+
}
|
|
42061
42677
|
setDrainDeadlineAt(deadlineAt) {
|
|
42062
42678
|
if (Number.isFinite(deadlineAt)) {
|
|
42063
42679
|
this.drainDeadlineAt = Math.min(this.drainDeadlineAt ?? Number.POSITIVE_INFINITY, deadlineAt);
|
|
@@ -42080,9 +42696,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
42080
42696
|
async reconcile() {
|
|
42081
42697
|
if (this.stopped)
|
|
42082
42698
|
return "member";
|
|
42083
|
-
this.confirmationPending = false;
|
|
42084
42699
|
const existingRooms = new Set(this.running.keys());
|
|
42085
|
-
const coveredWakes = this.discoveryWakes.beginReconcile();
|
|
42086
42700
|
const bootstrap = await this.options.daemonApi.execute("getDaemonBootstrap", {
|
|
42087
42701
|
agentId: this.agent.publicKey
|
|
42088
42702
|
});
|
|
@@ -42091,7 +42705,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42091
42705
|
if (!bootstrap.workspaceIds.includes(this.runtime.communityId)) {
|
|
42092
42706
|
this.workspaceRemovalConfirmations += 1;
|
|
42093
42707
|
if (this.workspaceRemovalConfirmations < REMOVAL_CONFIRMATION_READS) {
|
|
42094
|
-
this.confirmationPending = true;
|
|
42095
42708
|
this.wakeDiscovery();
|
|
42096
42709
|
return "unknown";
|
|
42097
42710
|
}
|
|
@@ -42179,10 +42792,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
42179
42792
|
continue;
|
|
42180
42793
|
const confirmations = (this.roomRemovalConfirmations.get(channelId) ?? 0) + 1;
|
|
42181
42794
|
this.roomRemovalConfirmations.set(channelId, confirmations);
|
|
42182
|
-
if (confirmations < REMOVAL_CONFIRMATION_READS)
|
|
42183
|
-
this.confirmationPending = true;
|
|
42795
|
+
if (confirmations < REMOVAL_CONFIRMATION_READS)
|
|
42184
42796
|
continue;
|
|
42185
|
-
}
|
|
42186
42797
|
await this.stopRunning(channelId, running);
|
|
42187
42798
|
this.roomRemovalConfirmations.delete(channelId);
|
|
42188
42799
|
}
|
|
@@ -42207,7 +42818,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42207
42818
|
for (const [roomId, running] of this.running)
|
|
42208
42819
|
if (existingRooms.has(roomId))
|
|
42209
42820
|
running.body.requestReconciliation();
|
|
42210
|
-
this.discoveryWakes.completeReconcile(coveredWakes);
|
|
42211
42821
|
if (this.roomRemovalConfirmations.size)
|
|
42212
42822
|
this.wakeDiscovery();
|
|
42213
42823
|
return "member";
|
|
@@ -42310,7 +42920,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42310
42920
|
await this.reapCornerScratch(running.scratch);
|
|
42311
42921
|
} catch (error) {
|
|
42312
42922
|
console.error(`[thin-core] corner ${channelId} cleanup failed; will retry:`, error);
|
|
42313
|
-
this.confirmationPending = true;
|
|
42314
42923
|
}
|
|
42315
42924
|
}
|
|
42316
42925
|
roomRecord(roomId) {
|
|
@@ -42373,7 +42982,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42373
42982
|
const controller = new AbortController();
|
|
42374
42983
|
const cwd = this.roomRoot(roomId);
|
|
42375
42984
|
const grantRunnerEndpoint = await this.grantRunnerEndpoint();
|
|
42376
|
-
const startedAt = this.now();
|
|
42377
42985
|
const loop = new MonolithRoomTurnLoop({
|
|
42378
42986
|
roomId,
|
|
42379
42987
|
workspaceId: this.runtime.communityId,
|
|
@@ -42386,18 +42994,12 @@ var RoomRuntimeCoordinator = class {
|
|
|
42386
42994
|
api: this.options.daemonApi,
|
|
42387
42995
|
scheduler: this.scheduler,
|
|
42388
42996
|
signal: controller.signal,
|
|
42389
|
-
health: {
|
|
42390
|
-
poll: () => this.notePoll(roomId),
|
|
42391
|
-
failure: (retryInMs) => this.noteFailure(roomId, retryInMs),
|
|
42392
|
-
presence: () => void 0
|
|
42393
|
-
},
|
|
42997
|
+
health: { poll: () => this.notePoll(roomId) },
|
|
42394
42998
|
onSubscriptionState: (connected) => this.surfaceHealth.subscribed(roomId, connected),
|
|
42395
42999
|
onIntakeError: () => this.surfaceHealth.degraded(roomId, "Room command intake failed"),
|
|
42396
|
-
onCornerOpened: () => {
|
|
42397
|
-
this.confirmationPending = true;
|
|
42398
|
-
},
|
|
42399
43000
|
onRestartRequested: () => this.requestLifecycleRestart(),
|
|
42400
|
-
canStartTurn: () => !this.restartRequested
|
|
43001
|
+
canStartTurn: () => !this.restartRequested,
|
|
43002
|
+
supervisor: this.supervisor
|
|
42401
43003
|
});
|
|
42402
43004
|
const promise = loop.run().catch((error) => {
|
|
42403
43005
|
if (!controller.signal.aborted) {
|
|
@@ -42413,14 +43015,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
42413
43015
|
await promise;
|
|
42414
43016
|
return;
|
|
42415
43017
|
}
|
|
42416
|
-
this.running.set(roomId, {
|
|
42417
|
-
body: loop,
|
|
42418
|
-
controller,
|
|
42419
|
-
promise,
|
|
42420
|
-
lastPollAt: startedAt,
|
|
42421
|
-
backoffUntil: 0,
|
|
42422
|
-
recovering: false
|
|
42423
|
-
});
|
|
43018
|
+
this.running.set(roomId, { body: loop, controller, promise });
|
|
42424
43019
|
console.log(`[thin-core] serving monolith Room ${roomId}`);
|
|
42425
43020
|
}
|
|
42426
43021
|
/**
|
|
@@ -42546,7 +43141,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42546
43141
|
}
|
|
42547
43142
|
const controller = new AbortController();
|
|
42548
43143
|
const grantRunnerEndpoint = await this.grantRunnerEndpoint();
|
|
42549
|
-
const startedAt = this.now();
|
|
42550
43144
|
const loop = new MonolithCornerTurnLoop({
|
|
42551
43145
|
cornerId: corner.cornerId,
|
|
42552
43146
|
grantRunner: this.grantRunner,
|
|
@@ -42574,7 +43168,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42574
43168
|
scheduler: this.scheduler,
|
|
42575
43169
|
signal: controller.signal,
|
|
42576
43170
|
onPoll: () => this.notePoll(corner.cornerId),
|
|
42577
|
-
onFailure: (retryInMs) => this.noteFailure(corner.cornerId, retryInMs),
|
|
42578
43171
|
onSubscriptionState: (connected) => this.surfaceHealth.subscribed(corner.cornerId, connected),
|
|
42579
43172
|
onIntakeError: () => this.surfaceHealth.degraded(corner.cornerId, "corner command intake failed"),
|
|
42580
43173
|
onCloseRequested: () => worktree ? this.reapCornerWorktree({
|
|
@@ -42586,7 +43179,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
42586
43179
|
}) : this.reapCornerScratch({ path: workspacePath, cornerId: corner.cornerId }),
|
|
42587
43180
|
onLaneChanged: () => void this.applyCornerRestart(corner.cornerId).catch((error) => console.error("[thin-core] corner lane-change restart failed", error)),
|
|
42588
43181
|
onRestartRequested: () => this.requestLifecycleRestart(),
|
|
42589
|
-
canStartTurn: () => !this.restartRequested
|
|
43182
|
+
canStartTurn: () => !this.restartRequested,
|
|
43183
|
+
supervisor: this.supervisor
|
|
42590
43184
|
});
|
|
42591
43185
|
const promise = loop.run().catch((error) => {
|
|
42592
43186
|
if (!controller.signal.aborted) {
|
|
@@ -42607,9 +43201,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42607
43201
|
body: loop,
|
|
42608
43202
|
controller,
|
|
42609
43203
|
promise,
|
|
42610
|
-
lastPollAt: startedAt,
|
|
42611
|
-
backoffUntil: 0,
|
|
42612
|
-
recovering: false,
|
|
42613
43204
|
...worktree ? {
|
|
42614
43205
|
worktree: {
|
|
42615
43206
|
...worktree,
|
|
@@ -42937,8 +43528,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42937
43528
|
const room = this.running.get(roomId);
|
|
42938
43529
|
if (!room)
|
|
42939
43530
|
return;
|
|
42940
|
-
room.lastPollAt = this.now();
|
|
42941
|
-
room.backoffUntil = 0;
|
|
42942
43531
|
if (this.deferredRepositoryRestarts.has(roomId) && !room.body.isBusy()) {
|
|
42943
43532
|
this.deferredRepositoryRestarts.delete(roomId);
|
|
42944
43533
|
void this.stopRunning(roomId, room).then(() => this.stopped ? void 0 : this.startRoom(roomId)).catch((error) => {
|
|
@@ -42949,29 +43538,6 @@ var RoomRuntimeCoordinator = class {
|
|
|
42949
43538
|
if (this.isWorkspaceIdle())
|
|
42950
43539
|
this.interactiveIdleListener?.();
|
|
42951
43540
|
}
|
|
42952
|
-
noteFailure(roomId, retryInMs) {
|
|
42953
|
-
const room = this.running.get(roomId);
|
|
42954
|
-
if (room)
|
|
42955
|
-
room.backoffUntil = Math.max(room.backoffUntil, this.now() + retryInMs);
|
|
42956
|
-
}
|
|
42957
|
-
async watchdogTick() {
|
|
42958
|
-
if (this.stopped)
|
|
42959
|
-
return;
|
|
42960
|
-
for (const [roomId, room] of [...this.running]) {
|
|
42961
|
-
if (room.recovering || room.body.isBusy())
|
|
42962
|
-
continue;
|
|
42963
|
-
if (this.now() <= Math.max(room.lastPollAt + this.watchdogStaleMs, room.backoffUntil))
|
|
42964
|
-
continue;
|
|
42965
|
-
room.recovering = true;
|
|
42966
|
-
room.controller.abort();
|
|
42967
|
-
await room.promise.catch(() => void 0);
|
|
42968
|
-
if (room.worktree) {
|
|
42969
|
-
this.confirmationPending = true;
|
|
42970
|
-
} else if (!this.stopped && !this.running.has(roomId)) {
|
|
42971
|
-
this.startRoom(roomId);
|
|
42972
|
-
}
|
|
42973
|
-
}
|
|
42974
|
-
}
|
|
42975
43541
|
beginShutdown() {
|
|
42976
43542
|
if (this.stopped)
|
|
42977
43543
|
return;
|
|
@@ -43160,6 +43726,10 @@ var ThinDaemonCore = class {
|
|
|
43160
43726
|
quiesceForUpdateIfIdle() {
|
|
43161
43727
|
return this.roomRuntime.quiesceForUpdateIfIdle();
|
|
43162
43728
|
}
|
|
43729
|
+
/** A managed restart failed after intake closed: take turns again. */
|
|
43730
|
+
resumeServing() {
|
|
43731
|
+
this.roomRuntime.resumeServing();
|
|
43732
|
+
}
|
|
43163
43733
|
async prepareForForcedUpdateRestart() {
|
|
43164
43734
|
await this.roomRuntime.prepareForForcedUpdateRestart();
|
|
43165
43735
|
}
|
|
@@ -43192,25 +43762,35 @@ var ThinDaemonCore = class {
|
|
|
43192
43762
|
try {
|
|
43193
43763
|
if (!opts.signal?.aborted)
|
|
43194
43764
|
await opts.onEstablished?.();
|
|
43765
|
+
const supervisor = this.roomRuntime.supervisor;
|
|
43766
|
+
let failures = 0;
|
|
43195
43767
|
while (!opts.signal?.aborted) {
|
|
43196
43768
|
this.pendingDiscovery = false;
|
|
43769
|
+
const wakesBefore = supervisor.wakes;
|
|
43197
43770
|
try {
|
|
43198
43771
|
const membership = await this.roomRuntime.reconcile();
|
|
43199
43772
|
if (membership === "not-member")
|
|
43200
43773
|
return "agent-removed";
|
|
43201
43774
|
this.discoveryStatus = membership === "unknown" ? "monolith membership degraded" : "";
|
|
43775
|
+
failures = 0;
|
|
43202
43776
|
} catch (error) {
|
|
43203
43777
|
if (isAgentRemovedError(error))
|
|
43204
43778
|
return "agent-removed";
|
|
43205
|
-
|
|
43779
|
+
failures += 1;
|
|
43780
|
+
console.error(failures > supervisor.retries ? "[thin-core] discovery failed; waiting for the next live open or discovery wake:" : `[thin-core] discovery failed; retry ${failures} of ${supervisor.retries}:`, error);
|
|
43206
43781
|
this.discoveryStatus = `monolith discovery degraded: ${error instanceof Error ? error.message : String(error)}`;
|
|
43207
|
-
this.roomRuntime.
|
|
43782
|
+
this.roomRuntime.suspectLink(error);
|
|
43208
43783
|
}
|
|
43209
43784
|
if (opts.signal?.aborted)
|
|
43210
43785
|
break;
|
|
43211
43786
|
await opts.onProgress?.(this.healthStatus());
|
|
43212
|
-
if (
|
|
43787
|
+
if (failures > 0) {
|
|
43788
|
+
await supervisor.retryDelay(failures, opts.signal, wakesBefore);
|
|
43789
|
+
if (failures > supervisor.retries)
|
|
43790
|
+
failures = 0;
|
|
43791
|
+
} else if (!this.pendingDiscovery) {
|
|
43213
43792
|
await this.waitForDiscovery(opts.signal);
|
|
43793
|
+
}
|
|
43214
43794
|
}
|
|
43215
43795
|
return "aborted";
|
|
43216
43796
|
} finally {
|
|
@@ -43220,32 +43800,173 @@ var ThinDaemonCore = class {
|
|
|
43220
43800
|
}
|
|
43221
43801
|
};
|
|
43222
43802
|
|
|
43223
|
-
// apps/body/dist/
|
|
43224
|
-
|
|
43225
|
-
|
|
43226
|
-
|
|
43227
|
-
|
|
43228
|
-
|
|
43229
|
-
|
|
43803
|
+
// apps/body/dist/helper-lifecycle.js
|
|
43804
|
+
init_systemd();
|
|
43805
|
+
var HELPER_HARD_STOP_MS = 8e4;
|
|
43806
|
+
var HELPER_EXIT_CODES = {
|
|
43807
|
+
stopped: 0,
|
|
43808
|
+
"restart-requested": 0,
|
|
43809
|
+
update: 0,
|
|
43810
|
+
failed: 75,
|
|
43811
|
+
"rolled-back": 75,
|
|
43812
|
+
"force-update-failed": 75,
|
|
43813
|
+
distress: DAEMON_DISTRESS_EXIT_STATUS,
|
|
43814
|
+
"agent-removed": DELIBERATE_REMOVAL_EXIT_STATUS,
|
|
43815
|
+
"unknown-agent": UNKNOWN_AGENT_EXIT_STATUS
|
|
43816
|
+
};
|
|
43817
|
+
var HelperLifecycle = class {
|
|
43818
|
+
options;
|
|
43819
|
+
#state = { kind: "serving" };
|
|
43820
|
+
#hardStop;
|
|
43821
|
+
#exitProcess;
|
|
43822
|
+
constructor(options) {
|
|
43823
|
+
this.options = options;
|
|
43824
|
+
this.#exitProcess = options.exitProcess ?? ((code) => process.exit(code));
|
|
43825
|
+
}
|
|
43826
|
+
get state() {
|
|
43827
|
+
return this.#state;
|
|
43828
|
+
}
|
|
43829
|
+
get serving() {
|
|
43830
|
+
return this.#state.kind === "serving";
|
|
43831
|
+
}
|
|
43832
|
+
/** The reason the final stop was asked for, once one was. */
|
|
43833
|
+
get stopReason() {
|
|
43834
|
+
return this.#state.kind === "stopping" ? this.#state.reason : void 0;
|
|
43835
|
+
}
|
|
43836
|
+
/**
|
|
43837
|
+
* Close intake. An update may only start from serving; `/restart` and a
|
|
43838
|
+
* forced update also take over a waiting update. Returns whether this call
|
|
43839
|
+
* moved the helper to quiescing.
|
|
43840
|
+
*/
|
|
43841
|
+
quiesce(reason) {
|
|
43842
|
+
const state = this.#state;
|
|
43843
|
+
if (state.kind === "serving" || state.kind === "quiescing" && state.reason === "update" && reason !== "update") {
|
|
43844
|
+
this.#state = { kind: "quiescing", reason };
|
|
43845
|
+
return true;
|
|
43846
|
+
}
|
|
43847
|
+
return false;
|
|
43848
|
+
}
|
|
43849
|
+
/** A managed restart failed after intake closed: serve again. */
|
|
43850
|
+
resume() {
|
|
43851
|
+
if (this.#state.kind !== "quiescing")
|
|
43852
|
+
return false;
|
|
43853
|
+
this.#state = { kind: "serving" };
|
|
43854
|
+
return true;
|
|
43855
|
+
}
|
|
43856
|
+
/**
|
|
43857
|
+
* The managed update's idle gate: quiesce only while serving and only if
|
|
43858
|
+
* `closeIntakeIfIdle` proves no turn is running (and closes intake in the
|
|
43859
|
+
* same step). A busy helper stays serving, so the update waits.
|
|
43860
|
+
*/
|
|
43861
|
+
quiesceUpdateIfIdle(closeIntakeIfIdle) {
|
|
43862
|
+
return this.serving && closeIntakeIfIdle() && this.quiesce("update");
|
|
43863
|
+
}
|
|
43864
|
+
/** A managed restart failed after its quiesce: serve again and reopen intake. */
|
|
43865
|
+
resumeAfterFailedUpdate(reopenIntake) {
|
|
43866
|
+
const state = this.#state;
|
|
43867
|
+
if (state.kind !== "quiescing" || state.reason !== "update" || !this.resume())
|
|
43868
|
+
return false;
|
|
43869
|
+
reopenIntake();
|
|
43870
|
+
return true;
|
|
43871
|
+
}
|
|
43872
|
+
/** The final stop: abort the core, and exit no later than the hard limit. */
|
|
43873
|
+
stop(reason) {
|
|
43874
|
+
if (this.#state.kind === "stopping" || this.#state.kind === "exited")
|
|
43230
43875
|
return;
|
|
43231
|
-
|
|
43232
|
-
|
|
43233
|
-
(
|
|
43234
|
-
|
|
43235
|
-
|
|
43236
|
-
|
|
43237
|
-
|
|
43238
|
-
|
|
43239
|
-
|
|
43240
|
-
|
|
43241
|
-
|
|
43242
|
-
|
|
43243
|
-
|
|
43244
|
-
|
|
43876
|
+
this.#state = { kind: "stopping", reason };
|
|
43877
|
+
this.#hardStop = setTimeout(() => {
|
|
43878
|
+
console.error("[thin-core] shutdown deadline reached; exiting helper");
|
|
43879
|
+
this.exit(reason);
|
|
43880
|
+
}, this.options.hardStopMs ?? HELPER_HARD_STOP_MS);
|
|
43881
|
+
this.#hardStop.unref?.();
|
|
43882
|
+
this.options.controller.abort();
|
|
43883
|
+
}
|
|
43884
|
+
/** The one exit funnel: each reason maps to exactly one code. */
|
|
43885
|
+
exit(reason) {
|
|
43886
|
+
if (this.#state.kind === "exited")
|
|
43887
|
+
return;
|
|
43888
|
+
clearTimeout(this.#hardStop);
|
|
43889
|
+
const code = HELPER_EXIT_CODES[reason];
|
|
43890
|
+
this.#state = { kind: "exited", code };
|
|
43891
|
+
this.#exitProcess(code);
|
|
43892
|
+
}
|
|
43893
|
+
/** SIGTERM and SIGINT are a final stop. */
|
|
43894
|
+
installSignals(emitter = process) {
|
|
43895
|
+
const stop = () => this.stop("stopped");
|
|
43896
|
+
emitter.once("SIGINT", stop);
|
|
43897
|
+
emitter.once("SIGTERM", stop);
|
|
43898
|
+
return () => {
|
|
43899
|
+
emitter.removeListener("SIGINT", stop);
|
|
43900
|
+
emitter.removeListener("SIGTERM", stop);
|
|
43901
|
+
};
|
|
43902
|
+
}
|
|
43903
|
+
};
|
|
43904
|
+
function installUnhandledRejectionGuard(emitter = process) {
|
|
43905
|
+
const log2 = (reason) => console.error("[thin-core] unhandled rejection (kept running):", reason);
|
|
43906
|
+
emitter.on("unhandledRejection", log2);
|
|
43907
|
+
return () => emitter.removeListener("unhandledRejection", log2);
|
|
43908
|
+
}
|
|
43909
|
+
function isTransientServerFailure(error) {
|
|
43910
|
+
return isNetworkFailure(error) || error instanceof DaemonApiError && error.retryable;
|
|
43911
|
+
}
|
|
43912
|
+
function successorRollbackAllowed(error, deadlineAt, now2 = Date.now()) {
|
|
43913
|
+
return !isTransientServerFailure(error) || deadlineAt !== void 0 && now2 >= deadlineAt;
|
|
43914
|
+
}
|
|
43915
|
+
async function retryBeforeReady(work, options) {
|
|
43916
|
+
const now2 = options.now ?? Date.now;
|
|
43917
|
+
const slice = options.waitSliceMs ?? 6e4;
|
|
43918
|
+
let failures = 0;
|
|
43919
|
+
for (; ; ) {
|
|
43920
|
+
try {
|
|
43921
|
+
return await work();
|
|
43922
|
+
} catch (error) {
|
|
43923
|
+
if (!isTransientServerFailure(error) || options.signal?.aborted)
|
|
43924
|
+
throw error;
|
|
43925
|
+
if (options.deadlineAt !== void 0 && now2() >= options.deadlineAt)
|
|
43926
|
+
throw error;
|
|
43927
|
+
failures += 1;
|
|
43928
|
+
const timedRetry = ROOM_RETRY_DELAYS_MS[failures - 1];
|
|
43929
|
+
console.warn(`[thin-core] server unreachable before READY; ${timedRetry === void 0 ? "waiting for the live socket to open" : `retrying in ${timedRetry}ms or on open`}:`, error);
|
|
43930
|
+
let opened = false;
|
|
43931
|
+
let wake = () => void 0;
|
|
43932
|
+
const off = options.onLinkOpen(() => {
|
|
43933
|
+
opened = true;
|
|
43934
|
+
wake();
|
|
43935
|
+
});
|
|
43936
|
+
try {
|
|
43937
|
+
const waitStarted = now2();
|
|
43938
|
+
while (!opened && !options.signal?.aborted) {
|
|
43939
|
+
const remaining = [
|
|
43940
|
+
slice,
|
|
43941
|
+
options.deadlineAt === void 0 ? Infinity : options.deadlineAt - now2(),
|
|
43942
|
+
timedRetry === void 0 ? Infinity : timedRetry - (now2() - waitStarted)
|
|
43943
|
+
];
|
|
43944
|
+
const wait2 = Math.min(...remaining);
|
|
43945
|
+
if (wait2 <= 0)
|
|
43946
|
+
break;
|
|
43947
|
+
await options.extendStartTimeout(wait2 + 15e3);
|
|
43948
|
+
await new Promise((resolve40) => {
|
|
43949
|
+
const timer = setTimeout(done, wait2);
|
|
43950
|
+
function done() {
|
|
43951
|
+
clearTimeout(timer);
|
|
43952
|
+
options.signal?.removeEventListener("abort", done);
|
|
43953
|
+
resolve40();
|
|
43954
|
+
}
|
|
43955
|
+
wake = done;
|
|
43956
|
+
options.signal?.addEventListener("abort", done, { once: true });
|
|
43957
|
+
if (opened || options.signal?.aborted)
|
|
43958
|
+
done();
|
|
43959
|
+
});
|
|
43960
|
+
}
|
|
43961
|
+
} finally {
|
|
43962
|
+
off();
|
|
43963
|
+
}
|
|
43964
|
+
}
|
|
43965
|
+
}
|
|
43245
43966
|
}
|
|
43246
43967
|
|
|
43247
43968
|
// apps/body/dist/force-update-journal.js
|
|
43248
|
-
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, writeFileSync as
|
|
43969
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync, writeFileSync as writeFileSync5 } from "node:fs";
|
|
43249
43970
|
import { resolve as resolve30 } from "node:path";
|
|
43250
43971
|
var NAME = "force-update-interruptions.json";
|
|
43251
43972
|
function pathFor(runtimeDir) {
|
|
@@ -43274,7 +43995,7 @@ function write(runtimeDir, rows) {
|
|
|
43274
43995
|
mkdirSync4(runtimeDir, { recursive: true, mode: 448 });
|
|
43275
43996
|
const target = pathFor(runtimeDir);
|
|
43276
43997
|
const temporary = `${target}.${process.pid}.tmp`;
|
|
43277
|
-
|
|
43998
|
+
writeFileSync5(temporary, `${JSON.stringify(rows)}
|
|
43278
43999
|
`, { mode: 384 });
|
|
43279
44000
|
renameSync(temporary, target);
|
|
43280
44001
|
}
|
|
@@ -43667,7 +44388,7 @@ async function runUpdateFunctionalProbe(input) {
|
|
|
43667
44388
|
}
|
|
43668
44389
|
|
|
43669
44390
|
// apps/body/dist/update-rollback-alert.js
|
|
43670
|
-
import { mkdir as mkdir23, readFile as
|
|
44391
|
+
import { mkdir as mkdir23, readFile as readFile23, rename as rename9, unlink as unlink6, writeFile as writeFile17 } from "node:fs/promises";
|
|
43671
44392
|
import { dirname as dirname20, resolve as resolve32 } from "node:path";
|
|
43672
44393
|
var REPORT_INTERVAL_MS = 60 * 60 * 1e3;
|
|
43673
44394
|
var lastLogged = /* @__PURE__ */ new Map();
|
|
@@ -43680,7 +44401,7 @@ async function writeAlert(runtimeDir, alert) {
|
|
|
43680
44401
|
await mkdir23(dirname20(path), { recursive: true });
|
|
43681
44402
|
await writeFile17(staged, `${JSON.stringify(alert, null, 2)}
|
|
43682
44403
|
`, { mode: 384 });
|
|
43683
|
-
await
|
|
44404
|
+
await rename9(staged, path);
|
|
43684
44405
|
}
|
|
43685
44406
|
async function queueUpdateRollbackAlert(runtimeDir, releaseId, now2 = Date.now()) {
|
|
43686
44407
|
const existing = await readUpdateRollbackAlert(runtimeDir);
|
|
@@ -43690,7 +44411,7 @@ async function queueUpdateRollbackAlert(runtimeDir, releaseId, now2 = Date.now()
|
|
|
43690
44411
|
}
|
|
43691
44412
|
async function readUpdateRollbackAlert(runtimeDir) {
|
|
43692
44413
|
try {
|
|
43693
|
-
const value = JSON.parse(await
|
|
44414
|
+
const value = JSON.parse(await readFile23(updateRollbackAlertPath(runtimeDir), "utf8"));
|
|
43694
44415
|
if (value.version !== 1 || typeof value.releaseId !== "string")
|
|
43695
44416
|
return void 0;
|
|
43696
44417
|
return value;
|
|
@@ -44024,6 +44745,11 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
44024
44745
|
env: this.#env,
|
|
44025
44746
|
log: (line) => console.log(line)
|
|
44026
44747
|
});
|
|
44748
|
+
await convergeAgentServiceUnit({
|
|
44749
|
+
libDir: this.#layout.libDir,
|
|
44750
|
+
env: this.#env,
|
|
44751
|
+
log: (line) => console.log(line)
|
|
44752
|
+
});
|
|
44027
44753
|
} else if (process.platform === "darwin" && this.#env.BEELINE_LAUNCHD_USER !== "0") {
|
|
44028
44754
|
await convergeLaunchdTrustySquireBrokerService({
|
|
44029
44755
|
libDir: this.#layout.libDir,
|
|
@@ -44375,7 +45101,7 @@ init_runtime();
|
|
|
44375
45101
|
init_launchd();
|
|
44376
45102
|
init_systemd();
|
|
44377
45103
|
init_runtime();
|
|
44378
|
-
import { mkdir as mkdir25, rename as
|
|
45104
|
+
import { mkdir as mkdir25, rename as rename10 } from "node:fs/promises";
|
|
44379
45105
|
import { dirname as dirname22, resolve as resolve34 } from "node:path";
|
|
44380
45106
|
async function retireRemovedAgent(runtime, options = {}) {
|
|
44381
45107
|
const deletedRoot = resolve34(runtime.supervisorRoot, "beeline", "deleted-runtimes");
|
|
@@ -44400,12 +45126,12 @@ async function relocateAgentRuntime(runtime, target, options = {}) {
|
|
|
44400
45126
|
});
|
|
44401
45127
|
}
|
|
44402
45128
|
await mkdir25(dirname22(destination), { recursive: true, mode: 448 });
|
|
44403
|
-
await
|
|
45129
|
+
await rename10(source, destination);
|
|
44404
45130
|
return destination;
|
|
44405
45131
|
}
|
|
44406
45132
|
|
|
44407
45133
|
// apps/body/dist/start-command.js
|
|
44408
|
-
import { basename as
|
|
45134
|
+
import { basename as basename8, dirname as dirname23 } from "node:path";
|
|
44409
45135
|
var import_picocolors2 = __toESM(require_picocolors(), 1);
|
|
44410
45136
|
init_agent_command();
|
|
44411
45137
|
init_runtime();
|
|
@@ -44620,7 +45346,7 @@ async function startStoredRuntime(configPath, opts = {}, dependencyOverrides = {
|
|
|
44620
45346
|
return { status: "started", pid };
|
|
44621
45347
|
}
|
|
44622
45348
|
function agentStartId(configPath) {
|
|
44623
|
-
return
|
|
45349
|
+
return basename8(dirname23(configPath));
|
|
44624
45350
|
}
|
|
44625
45351
|
async function startRuntime(configPath, spinnerHandle) {
|
|
44626
45352
|
const report = (text2) => spinnerHandle ? spinnerHandle.message(text2) : console.log(text2);
|
|
@@ -44735,7 +45461,7 @@ async function runStartCommand(args, interactiveUi, dependencyOverrides = {}) {
|
|
|
44735
45461
|
// apps/body/dist/connect-command.js
|
|
44736
45462
|
import { spawn as spawn12 } from "node:child_process";
|
|
44737
45463
|
import { createHash as createHash13, randomUUID as randomUUID11 } from "node:crypto";
|
|
44738
|
-
import { chmod as chmod10, mkdir as mkdir26, readFile as
|
|
45464
|
+
import { chmod as chmod10, mkdir as mkdir26, readFile as readFile24, unlink as unlink7, writeFile as writeFile19 } from "node:fs/promises";
|
|
44739
45465
|
import { homedir as homedir17, hostname as hostname3 } from "node:os";
|
|
44740
45466
|
import { dirname as dirname24, resolve as resolve35 } from "node:path";
|
|
44741
45467
|
import { stdin as stdin3, stdout as stdout4 } from "node:process";
|
|
@@ -45413,7 +46139,7 @@ async function readMachineId(env = process.env) {
|
|
|
45413
46139
|
let machineId;
|
|
45414
46140
|
let machineName = hostname3();
|
|
45415
46141
|
try {
|
|
45416
|
-
const existing = await
|
|
46142
|
+
const existing = await readFile24(machineIdPath, "utf8");
|
|
45417
46143
|
machineId = existing.trim();
|
|
45418
46144
|
if (!/^[0-9a-f-]{32,}$/.test(machineId))
|
|
45419
46145
|
throw new Error("invalid persisted machine id");
|
|
@@ -45669,12 +46395,12 @@ async function runConnectFinishCommand(path) {
|
|
|
45669
46395
|
throw new Error("connect-finish may run only from the canonical installed Beeline launcher");
|
|
45670
46396
|
}
|
|
45671
46397
|
try {
|
|
45672
|
-
const grant = JSON.parse(await
|
|
46398
|
+
const grant = JSON.parse(await readFile24(resolve35(path), "utf8"));
|
|
45673
46399
|
if (!isDevicePairingGrant(grant))
|
|
45674
46400
|
throw new Error("device connection grant is invalid");
|
|
45675
46401
|
const connected = await completeDevicePairing(grant);
|
|
45676
46402
|
await unlink7(resolve35(path));
|
|
45677
|
-
const providerEnv = grant.llmEnvFile ? await
|
|
46403
|
+
const providerEnv = grant.llmEnvFile ? await readFile24(grant.llmEnvFile, "utf8").catch(() => "") : "";
|
|
45678
46404
|
const apiKey = (/^OPENROUTER_API_KEY=(\S+)/m.exec(providerEnv)?.[1] ?? "").replace(/^["']|["']$/g, "");
|
|
45679
46405
|
const model = openRouterModelId(grant.model, { OPENROUTER_API_KEY: apiKey });
|
|
45680
46406
|
if (model) {
|
|
@@ -45698,7 +46424,7 @@ async function runConnectFinishCommand(path) {
|
|
|
45698
46424
|
init_self_update();
|
|
45699
46425
|
|
|
45700
46426
|
// apps/body/dist/daemon-failure.js
|
|
45701
|
-
import { mkdir as mkdir27, readFile as
|
|
46427
|
+
import { mkdir as mkdir27, readFile as readFile25, rename as rename11, rm as rm13, writeFile as writeFile20 } from "node:fs/promises";
|
|
45702
46428
|
import { dirname as dirname25, resolve as resolve36 } from "node:path";
|
|
45703
46429
|
var DAEMON_FAILURE_LIMIT = 3;
|
|
45704
46430
|
var DAEMON_FAILURE_WINDOW_MS = 5 * 6e4;
|
|
@@ -45707,7 +46433,7 @@ function daemonFailurePath(runtimeDir) {
|
|
|
45707
46433
|
}
|
|
45708
46434
|
async function readFailureRecord(runtimeDir) {
|
|
45709
46435
|
try {
|
|
45710
|
-
const value = JSON.parse(await
|
|
46436
|
+
const value = JSON.parse(await readFile25(daemonFailurePath(runtimeDir), "utf8"));
|
|
45711
46437
|
if (value.version !== 1 || !Array.isArray(value.failures) || value.failures.some((failure) => typeof failure !== "number") || typeof value.lastError !== "string") {
|
|
45712
46438
|
return void 0;
|
|
45713
46439
|
}
|
|
@@ -45722,7 +46448,14 @@ async function writeFailureRecord(runtimeDir, record6) {
|
|
|
45722
46448
|
await mkdir27(dirname25(path), { recursive: true, mode: 448 });
|
|
45723
46449
|
await writeFile20(staged, `${JSON.stringify(record6, null, 2)}
|
|
45724
46450
|
`, { mode: 384 });
|
|
45725
|
-
await
|
|
46451
|
+
await rename11(staged, path);
|
|
46452
|
+
}
|
|
46453
|
+
function countsTowardDistress(error) {
|
|
46454
|
+
if (isNetworkFailure(error))
|
|
46455
|
+
return false;
|
|
46456
|
+
if (error instanceof DaemonApiError && (error.retryable || error.status === 401))
|
|
46457
|
+
return false;
|
|
46458
|
+
return true;
|
|
45726
46459
|
}
|
|
45727
46460
|
async function recordDaemonStartFailure(runtimeDir, error, now2 = Date.now()) {
|
|
45728
46461
|
const prior = await readFailureRecord(runtimeDir);
|
|
@@ -45737,6 +46470,11 @@ async function recordDaemonStartFailure(runtimeDir, error, now2 = Date.now()) {
|
|
|
45737
46470
|
await writeFailureRecord(runtimeDir, record6);
|
|
45738
46471
|
return { distressed, count: failures.length, path: daemonFailurePath(runtimeDir) };
|
|
45739
46472
|
}
|
|
46473
|
+
async function settleDaemonStartFailure(runtimeDir, error, now2 = Date.now()) {
|
|
46474
|
+
if (!countsTowardDistress(error))
|
|
46475
|
+
return { distressed: false };
|
|
46476
|
+
return recordDaemonStartFailure(runtimeDir, error, now2);
|
|
46477
|
+
}
|
|
45740
46478
|
async function clearDaemonStartFailures(runtimeDir) {
|
|
45741
46479
|
await rm13(daemonFailurePath(runtimeDir), { force: true });
|
|
45742
46480
|
}
|
|
@@ -45746,7 +46484,7 @@ init_systemd();
|
|
|
45746
46484
|
|
|
45747
46485
|
// apps/body/dist/current-release-probe.js
|
|
45748
46486
|
import { spawn as spawn13 } from "node:child_process";
|
|
45749
|
-
import { dirname as dirname26, join as
|
|
46487
|
+
import { dirname as dirname26, join as join18 } from "node:path";
|
|
45750
46488
|
init_runtime();
|
|
45751
46489
|
init_self_update();
|
|
45752
46490
|
var CURRENT_RELEASE_PROBE_TIMEOUT_MS = 12e4;
|
|
@@ -45790,7 +46528,7 @@ function outcomeFromReport(report) {
|
|
|
45790
46528
|
}
|
|
45791
46529
|
}
|
|
45792
46530
|
async function probeReleaseInSubprocess(input) {
|
|
45793
|
-
const bundleDir =
|
|
46531
|
+
const bundleDir = join18(input.layout.releasesRoot, input.releaseId);
|
|
45794
46532
|
const entrypoint = await resolveBundleEntrypoint(bundleDir);
|
|
45795
46533
|
if (!entrypoint) {
|
|
45796
46534
|
return { kind: "unavailable", reason: `release ${input.releaseId} has no runnable CLI entrypoint` };
|
|
@@ -45853,7 +46591,7 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
45853
46591
|
const runtime = await readRuntimeRecord(configPath);
|
|
45854
46592
|
const agent = runtimeAgentCommand(runtime);
|
|
45855
46593
|
const config = loadBodyConfig({
|
|
45856
|
-
workspaceRoot:
|
|
46594
|
+
workspaceRoot: join18(dirname26(configPath), "workspace"),
|
|
45857
46595
|
llmEnvFile: runtime.llmEnvFile,
|
|
45858
46596
|
env: { ...env, BUZZ_AGENT_BIN: agent.command, BUZZ_DEV_MCP_BIN: runtime.mcpBinary },
|
|
45859
46597
|
agent
|
|
@@ -45879,14 +46617,14 @@ async function runUpdateProbeCommand(args, options = {}) {
|
|
|
45879
46617
|
sandboxRequired: runtime.sandbox !== "off",
|
|
45880
46618
|
sandboxUnavailableDetail: sandbox.advisory,
|
|
45881
46619
|
// The successor's probe still holds `<runtimeDir>/update-functional-probe`.
|
|
45882
|
-
probeRoot:
|
|
46620
|
+
probeRoot: join18(runtimeDir, "current-release-probe")
|
|
45883
46621
|
}));
|
|
45884
46622
|
const report = outcome.kind === "served" ? { probe: "served" } : outcome.kind === "refused" ? { probe: "refused", status: outcome.status, reason: outcome.reason } : outcome.kind === "sandbox-unavailable" ? { probe: "sandbox-unavailable", reason: outcome.reason } : { probe: "failed", reason: outcome.reason };
|
|
45885
46623
|
write2(JSON.stringify(report));
|
|
45886
46624
|
}
|
|
45887
46625
|
|
|
45888
46626
|
// apps/body/dist/release-status.js
|
|
45889
|
-
import { readFile as
|
|
46627
|
+
import { readFile as readFile26, readdir as readdir10, rename as rename12, writeFile as writeFile21 } from "node:fs/promises";
|
|
45890
46628
|
import { resolve as resolve37 } from "node:path";
|
|
45891
46629
|
var DAEMON_RELEASE_STATUS_FILE = "release-status.json";
|
|
45892
46630
|
var RELEASE_VERSION = /^v\d+\.\d+\.\d+$/;
|
|
@@ -45908,7 +46646,7 @@ async function writeDaemonReleaseStatus(runtimeDir, agentPubkey, identity, optio
|
|
|
45908
46646
|
const temporary = `${target}.${status.pid}.tmp`;
|
|
45909
46647
|
await writeFile21(temporary, `${JSON.stringify(status, null, 2)}
|
|
45910
46648
|
`, { mode: 384 });
|
|
45911
|
-
await
|
|
46649
|
+
await rename12(temporary, target);
|
|
45912
46650
|
return status;
|
|
45913
46651
|
}
|
|
45914
46652
|
|
|
@@ -46028,15 +46766,16 @@ All other config via env vars (see config.ts).
|
|
|
46028
46766
|
process.exit(exitCode);
|
|
46029
46767
|
}
|
|
46030
46768
|
var daemonFailureRuntimeDir;
|
|
46769
|
+
var daemonLifecycle;
|
|
46031
46770
|
var SCRATCH_SWEEP_INTERVAL_MS = 6 * 60 * 6e4;
|
|
46032
46771
|
function runScratchSweepLogged(runtimeDir) {
|
|
46033
46772
|
void runScratchSweep(runtimeDir).catch((error) => console.error("[body] scratch sweep failed:", error));
|
|
46034
46773
|
}
|
|
46035
46774
|
var DaemonExitError = class extends Error {
|
|
46036
|
-
|
|
46037
|
-
constructor(message,
|
|
46775
|
+
reason;
|
|
46776
|
+
constructor(message, reason) {
|
|
46038
46777
|
super(message);
|
|
46039
|
-
this.
|
|
46778
|
+
this.reason = reason;
|
|
46040
46779
|
this.name = "DaemonExitError";
|
|
46041
46780
|
}
|
|
46042
46781
|
};
|
|
@@ -46117,7 +46856,9 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46117
46856
|
config.sandboxMaskPaths = [...config.sandboxMaskPaths ?? [], ...runtime.sandboxMaskPaths];
|
|
46118
46857
|
}
|
|
46119
46858
|
const controller = new AbortController();
|
|
46120
|
-
const
|
|
46859
|
+
const lifecycle = new HelperLifecycle({ controller });
|
|
46860
|
+
daemonLifecycle = lifecycle;
|
|
46861
|
+
const disposeStopSignals = lifecycle.installSignals();
|
|
46121
46862
|
const runtimeDir = dirname27(configPath);
|
|
46122
46863
|
const layout = beelineInstallLayout(process.env);
|
|
46123
46864
|
const notifier = new SystemdNotifier();
|
|
@@ -46139,15 +46880,17 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46139
46880
|
let update;
|
|
46140
46881
|
let pendingSuccessor = false;
|
|
46141
46882
|
let successorRolledBack = false;
|
|
46883
|
+
let attemptDeadlineAt;
|
|
46142
46884
|
if (layout) {
|
|
46143
46885
|
const settle = await settleUpdateAttemptOnStart(layout);
|
|
46144
46886
|
if (settle.kind === "rolled-back") {
|
|
46145
46887
|
await queueUpdateRollbackAlert(runtimeDir, settle.record.releaseId);
|
|
46146
46888
|
await drainRollbackAlert(runtime.rooms[0]?.channelId);
|
|
46147
46889
|
console.error(`[body] self-update ROLLED BACK: bundle ${describeIdentity(settle.record.to)} never confirmed healthy; restored ${settle.record.previousReleaseId ?? "previous release"}`);
|
|
46148
|
-
throw new DaemonExitError("stale unconfirmed release rolled back; supervisor must restart",
|
|
46890
|
+
throw new DaemonExitError("stale unconfirmed release rolled back; supervisor must restart", "rolled-back");
|
|
46149
46891
|
} else if (settle.kind === "pending") {
|
|
46150
46892
|
pendingSuccessor = true;
|
|
46893
|
+
attemptDeadlineAt = (await readUpdateAttempt(layout))?.confirmBy;
|
|
46151
46894
|
}
|
|
46152
46895
|
loadedRelease = await activeReleaseId(layout);
|
|
46153
46896
|
await clearUpdateRollbackAlertIfConfirmed(runtimeDir, loadedRelease);
|
|
@@ -46162,6 +46905,9 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46162
46905
|
requiredProbeIds: [...await runningRuntimeProbeIds(process.env), runtime.agent.publicKey]
|
|
46163
46906
|
});
|
|
46164
46907
|
if (pendingSuccessor && process.platform === "linux" && process.env.BEELINE_SYSTEMD_USER !== "0") {
|
|
46908
|
+
await rewriteAgentServiceUnit({ lock: (work) => withInstallLock(layout, work) }).catch((error) => {
|
|
46909
|
+
console.error(`[beeline] agent unit not converged: ${error instanceof Error ? error.message : String(error)}`);
|
|
46910
|
+
});
|
|
46165
46911
|
await installTrustySquireBrokerService().catch((error) => {
|
|
46166
46912
|
console.error(`[beeline] host Squire broker unit not converged: ${error instanceof Error ? error.message : String(error)}`);
|
|
46167
46913
|
});
|
|
@@ -46201,6 +46947,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46201
46947
|
return catalogRefresh;
|
|
46202
46948
|
};
|
|
46203
46949
|
let stoppingStatus = "daemon stopped";
|
|
46950
|
+
let exitReason;
|
|
46204
46951
|
try {
|
|
46205
46952
|
registryMcpBroker = new RegistryMcpHostBroker(
|
|
46206
46953
|
config.operatorHome,
|
|
@@ -46224,16 +46971,16 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46224
46971
|
daemonApi,
|
|
46225
46972
|
onConfigChanged: refreshCatalog,
|
|
46226
46973
|
onRestartRequested: () => {
|
|
46227
|
-
if (lifecycleRestart)
|
|
46974
|
+
if (lifecycleRestart || !lifecycle.quiesce("restart"))
|
|
46228
46975
|
return;
|
|
46229
46976
|
lifecycleRestart = (async () => {
|
|
46230
46977
|
const cancelled = await core.cancelActiveWorkForRestart();
|
|
46231
46978
|
stoppingStatus = cancelled ? "restart requested; active work cancelled" : "restart requested; no active work";
|
|
46232
|
-
await notifier.stopping(stoppingStatus);
|
|
46233
|
-
|
|
46979
|
+
await notifier.stopping(stoppingStatus).catch((error) => console.error("[thin-core] stopping notification failed:", error));
|
|
46980
|
+
lifecycle.stop("restart-requested");
|
|
46234
46981
|
})().catch((error) => {
|
|
46235
46982
|
console.error("[thin-core] requested restart failed:", error);
|
|
46236
|
-
|
|
46983
|
+
lifecycle.stop("restart-requested");
|
|
46237
46984
|
});
|
|
46238
46985
|
}
|
|
46239
46986
|
});
|
|
@@ -46242,6 +46989,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46242
46989
|
loadedVersion: loadedReleaseIdentity?.version,
|
|
46243
46990
|
runtimeDir,
|
|
46244
46991
|
interrupt: () => {
|
|
46992
|
+
lifecycle.quiesce("force-update");
|
|
46245
46993
|
core.setDrainDeadlineAt(Date.now() + 6e4);
|
|
46246
46994
|
return core.interruptForServerMinimum();
|
|
46247
46995
|
},
|
|
@@ -46260,25 +47008,25 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46260
47008
|
if (staggerMs > 0)
|
|
46261
47009
|
await new Promise((resolve40) => setTimeout(resolve40, staggerMs));
|
|
46262
47010
|
stoppingStatus = `server minimum installed; restarting onto ${desiredRelease}`;
|
|
46263
|
-
await notifier.stopping(stoppingStatus);
|
|
46264
|
-
|
|
47011
|
+
await notifier.stopping(stoppingStatus).catch((error) => console.error("[thin-core] stopping notification failed:", error));
|
|
47012
|
+
lifecycle.stop("update");
|
|
46265
47013
|
},
|
|
46266
47014
|
failed: (error) => {
|
|
46267
47015
|
console.error("[thin-core] forced helper update failed:", error);
|
|
46268
|
-
|
|
47016
|
+
lifecycle.stop("force-update-failed");
|
|
46269
47017
|
}
|
|
46270
47018
|
}) : void 0;
|
|
46271
47019
|
daemonApi.setForceUpdateListener((minVersion) => {
|
|
46272
47020
|
if (!forceUpdate) {
|
|
46273
47021
|
console.error("[thin-core] server requires a published helper, but this process has no install layout");
|
|
46274
|
-
|
|
47022
|
+
lifecycle.stop("stopped");
|
|
46275
47023
|
return;
|
|
46276
47024
|
}
|
|
46277
47025
|
forceUpdate.request(minVersion);
|
|
46278
47026
|
});
|
|
46279
47027
|
const updateDrain = update ? new ManagedUpdateDrain({
|
|
46280
47028
|
update,
|
|
46281
|
-
quiesceIfIdle: () => !forceUpdate?.active && core.quiesceForUpdateIfIdle(),
|
|
47029
|
+
quiesceIfIdle: () => !forceUpdate?.active && lifecycle.quiesceUpdateIfIdle(() => core.quiesceForUpdateIfIdle()),
|
|
46282
47030
|
activeTurnCount: () => core.activeTurnCount(),
|
|
46283
47031
|
restart: async ({ desiredRelease, drainDeadlineAt }) => {
|
|
46284
47032
|
core.setDrainDeadlineAt(drainDeadlineAt);
|
|
@@ -46286,20 +47034,29 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46286
47034
|
if (staggerMs > 0)
|
|
46287
47035
|
await new Promise((resolve40) => setTimeout(resolve40, staggerMs));
|
|
46288
47036
|
stoppingStatus = `update pending, converging; loaded_release=${loadedRelease ?? "unknown"}; desired_release=${desiredRelease}; active work drained; intake quiesced`;
|
|
46289
|
-
await notifier.stopping(stoppingStatus);
|
|
46290
|
-
|
|
47037
|
+
await notifier.stopping(stoppingStatus).catch((error) => console.error("[thin-core] stopping notification failed:", error));
|
|
47038
|
+
lifecycle.stop("update");
|
|
46291
47039
|
},
|
|
46292
47040
|
waiting: async ({ desiredRelease }) => {
|
|
46293
47041
|
await notifier.progress(`loaded_release=${loadedRelease ?? "unknown"}; update ready; active agent work is still running; handoff deferred; desired_release=${desiredRelease}`);
|
|
46294
47042
|
}
|
|
46295
47043
|
}) : void 0;
|
|
47044
|
+
const tickUpdate = async () => {
|
|
47045
|
+
try {
|
|
47046
|
+
await updateDrain?.tick();
|
|
47047
|
+
} catch (error) {
|
|
47048
|
+
console.error("[thin-core] managed restart failed; serving again:", error);
|
|
47049
|
+
lifecycle.resumeAfterFailedUpdate(() => core.resumeServing());
|
|
47050
|
+
}
|
|
47051
|
+
};
|
|
46296
47052
|
daemonApi.setHelperReleaseListener(({ version, sha }) => {
|
|
46297
47053
|
update?.notifyReleaseAvailable(`${version}:${sha}`);
|
|
46298
|
-
void
|
|
47054
|
+
void tickUpdate();
|
|
46299
47055
|
});
|
|
47056
|
+
daemonApi.onLiveOpen(() => void tickUpdate());
|
|
46300
47057
|
core.setInteractiveIdleListener(() => {
|
|
46301
47058
|
institutionalMemoryWorker?.wake();
|
|
46302
|
-
void
|
|
47059
|
+
void tickUpdate();
|
|
46303
47060
|
});
|
|
46304
47061
|
const result = await core.run({
|
|
46305
47062
|
signal: controller.signal,
|
|
@@ -46359,7 +47116,12 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46359
47116
|
console.log(`[thin-core] successor functional probe passed on exact release ${loadedRelease}: ${functionalProof?.harness ?? "unknown"} session/new + turn` + (functionalProof?.modelAnswer === "unavailable" ? ` (model answer unavailable: ${functionalProof.modelAnswerReason})` : ""));
|
|
46360
47117
|
}
|
|
46361
47118
|
try {
|
|
46362
|
-
await reportInterruptedTurns(runtimeDir, daemonApi, runtime.agent.publicKey)
|
|
47119
|
+
await retryBeforeReady(() => reportInterruptedTurns(runtimeDir, daemonApi, runtime.agent.publicKey), {
|
|
47120
|
+
onLinkOpen: (listener) => daemonApi.onLiveOpen(listener),
|
|
47121
|
+
extendStartTimeout: extendSystemdStartTimeout,
|
|
47122
|
+
...attemptDeadlineAt !== void 0 ? { deadlineAt: attemptDeadlineAt } : {},
|
|
47123
|
+
signal: controller.signal
|
|
47124
|
+
});
|
|
46363
47125
|
} catch (error) {
|
|
46364
47126
|
if (error instanceof DaemonApiError && error.status === 426 && error.code === "update_required" && forceUpdate?.pending) {
|
|
46365
47127
|
await forceUpdate.pending;
|
|
@@ -46407,18 +47169,18 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46407
47169
|
onProgress: async (status) => {
|
|
46408
47170
|
lastCoreStatus = status;
|
|
46409
47171
|
void drainRollbackAlert(core.activeRoomIds()[0] ?? runtime.rooms[0]?.channelId);
|
|
46410
|
-
await notifier.progress(`loaded_release=${loadedRelease ?? "development"}; ${status}`);
|
|
46411
|
-
await
|
|
47172
|
+
await notifier.progress(`loaded_release=${loadedRelease ?? "development"}; ${status}`).catch((error) => console.error("[thin-core] progress notification failed:", error));
|
|
47173
|
+
await tickUpdate();
|
|
46412
47174
|
}
|
|
46413
47175
|
});
|
|
46414
47176
|
if (result === "agent-removed") {
|
|
46415
47177
|
controller.abort();
|
|
46416
47178
|
const archivedRuntime = await retireRemovedAgent(runtime);
|
|
46417
|
-
|
|
47179
|
+
exitReason = "agent-removed";
|
|
46418
47180
|
console.log(`[beeline] agent ${runtime.agent.publicKey} removed; runtime archived at ${archivedRuntime}`);
|
|
46419
47181
|
}
|
|
46420
47182
|
} catch (error) {
|
|
46421
|
-
const rolledBack = successorRolledBack || layout && pendingSuccessor && !ready && // Named, so a sibling daemon's journal can say whose failure reverted
|
|
47183
|
+
const rolledBack = successorRolledBack || layout && pendingSuccessor && !ready && successorRollbackAllowed(error, attemptDeadlineAt) && // Named, so a sibling daemon's journal can say whose failure reverted
|
|
46422
47184
|
// the attempt it shares with this one.
|
|
46423
47185
|
await rollbackFailedSuccessor(layout, runtimeDir, {
|
|
46424
47186
|
probeId: runtime.agent.publicKey,
|
|
@@ -46441,6 +47203,7 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
46441
47203
|
await clearDaemonPidRecordIfPid(configPath, process.pid);
|
|
46442
47204
|
disposeStopSignals();
|
|
46443
47205
|
}
|
|
47206
|
+
return exitReason ?? lifecycle.stopReason ?? "stopped";
|
|
46444
47207
|
}
|
|
46445
47208
|
async function main() {
|
|
46446
47209
|
const args = process.argv.slice(2);
|
|
@@ -46529,6 +47292,7 @@ async function main() {
|
|
|
46529
47292
|
return;
|
|
46530
47293
|
}
|
|
46531
47294
|
if (command === "daemon") {
|
|
47295
|
+
installUnhandledRejectionGuard();
|
|
46532
47296
|
const configFlag = args.indexOf("--config");
|
|
46533
47297
|
const agentFlag = args.indexOf("--agent");
|
|
46534
47298
|
let configPath = configFlag >= 0 ? args[configFlag + 1] : void 0;
|
|
@@ -46547,11 +47311,12 @@ async function main() {
|
|
|
46547
47311
|
configPath = configs.find((candidate) => dirname27(candidate).endsWith(agentPubkey));
|
|
46548
47312
|
}
|
|
46549
47313
|
if (!configPath && agentPubkey) {
|
|
46550
|
-
throw new DaemonExitError(`unknown agent ${agentPubkey}: no durable runtime exists; refusing service restart loop`,
|
|
47314
|
+
throw new DaemonExitError(`unknown agent ${agentPubkey}: no durable runtime exists; refusing service restart loop`, "unknown-agent");
|
|
46551
47315
|
}
|
|
46552
47316
|
if (!configPath)
|
|
46553
47317
|
throw new Error("daemon requires --config <runtime.json> or --agent <pubkey>");
|
|
46554
|
-
await runStoredDaemon(resolve39(configPath));
|
|
47318
|
+
const reason = await runStoredDaemon(resolve39(configPath));
|
|
47319
|
+
daemonLifecycle?.exit(reason);
|
|
46555
47320
|
return;
|
|
46556
47321
|
}
|
|
46557
47322
|
if (command === "update") {
|
|
@@ -46591,7 +47356,8 @@ async function main() {
|
|
|
46591
47356
|
main().catch(async (err) => {
|
|
46592
47357
|
if (process.argv[2] === "daemon") {
|
|
46593
47358
|
const layout = beelineInstallLayout(process.env);
|
|
46594
|
-
|
|
47359
|
+
const attempt = layout ? await readUpdateAttempt(layout).catch(() => void 0) : void 0;
|
|
47360
|
+
if (layout && successorRollbackAllowed(err, attempt?.confirmBy) && await rollbackFailedSuccessor(layout).catch(() => false)) {
|
|
46595
47361
|
console.error("[thin-core] successor failed during startup; previous release restored once");
|
|
46596
47362
|
}
|
|
46597
47363
|
}
|
|
@@ -46603,19 +47369,24 @@ main().catch(async (err) => {
|
|
|
46603
47369
|
} else {
|
|
46604
47370
|
console.error(import_picocolors3.default.red("[body] fatal:"), err);
|
|
46605
47371
|
}
|
|
46606
|
-
|
|
46607
|
-
|
|
47372
|
+
if (process.argv[2] !== "daemon")
|
|
47373
|
+
process.exit(1);
|
|
47374
|
+
let reason = err instanceof DaemonExitError ? err.reason : "failed";
|
|
47375
|
+
if (daemonFailureRuntimeDir && reason === "failed") {
|
|
46608
47376
|
try {
|
|
46609
|
-
const failure = await
|
|
47377
|
+
const failure = await settleDaemonStartFailure(daemonFailureRuntimeDir, err);
|
|
46610
47378
|
if (failure.distressed) {
|
|
46611
|
-
|
|
47379
|
+
reason = "distress";
|
|
46612
47380
|
console.error(`[thin-core] daemon start failed ${failure.count} times; service restart stopped. operator record: ${failure.path}`);
|
|
46613
47381
|
}
|
|
46614
47382
|
} catch (recordError) {
|
|
46615
47383
|
console.error("[thin-core] could not persist daemon distress record:", recordError);
|
|
46616
47384
|
}
|
|
46617
47385
|
}
|
|
46618
|
-
|
|
47386
|
+
if (daemonLifecycle)
|
|
47387
|
+
daemonLifecycle.exit(reason);
|
|
47388
|
+
else
|
|
47389
|
+
process.exit(HELPER_EXIT_CODES[reason]);
|
|
46619
47390
|
});
|
|
46620
47391
|
/*! Bundled license information:
|
|
46621
47392
|
|