byollm 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -126
- package/dist/bin.js +1 -1
- package/dist/{chunk-FUKJDD7M.js → chunk-K7QYAF7V.js} +262 -58
- package/dist/chunk-K7QYAF7V.js.map +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-FUKJDD7M.js.map +0 -1
|
@@ -613,11 +613,41 @@ var DaemonConfig = z.object({
|
|
|
613
613
|
* The trade this switch represents is written down rather than
|
|
614
614
|
* discovered: an auto-updating daemon means whoever controls the npm
|
|
615
615
|
* publish controls the fleet. The controls on that are 2FA at publish,
|
|
616
|
-
* exact-version installs (never a tag),
|
|
617
|
-
*
|
|
618
|
-
*
|
|
616
|
+
* exact-version installs (never a tag), forward-only versions, offers
|
|
617
|
+
* from {@link updateAuthority} alone, SLSA provenance checked before the
|
|
618
|
+
* new binary runs, and the canary and rollback in `update.ts`. Staged
|
|
619
|
+
* cohorts are NOT among them yet: nothing in this file or on the wire
|
|
620
|
+
* spreads an offer over time, so every machine the authority offers a
|
|
621
|
+
* version to takes it on its next heartbeat. It is the Chrome trade,
|
|
622
|
+
* taken deliberately.
|
|
619
623
|
*/
|
|
620
624
|
autoUpdate: z.boolean().default(false),
|
|
625
|
+
/**
|
|
626
|
+
* The one origin whose update offers this daemon takes — B360.
|
|
627
|
+
*
|
|
628
|
+
* Unset means the reference hub (`DEFAULT_ORIGIN` in `cli.ts`), and it is
|
|
629
|
+
* resolved there rather than defaulted here on purpose: `byollm offer`
|
|
630
|
+
* writes the PARSED config back, so a schema default would be baked into
|
|
631
|
+
* every owner's file — and an older daemon, which is exactly what a
|
|
632
|
+
* rollback installs, refuses a key its strict schema has never seen.
|
|
633
|
+
*
|
|
634
|
+
* Every other paired origin's offer is ignored and said once. The
|
|
635
|
+
* authority's own offers count only over a pairing that pinned a control
|
|
636
|
+
* plane; a direct-mode pairing never updates the daemon.
|
|
637
|
+
*/
|
|
638
|
+
updateAuthority: z.string().refine(
|
|
639
|
+
(value) => {
|
|
640
|
+
try {
|
|
641
|
+
normalizeOrigin(value);
|
|
642
|
+
return true;
|
|
643
|
+
} catch {
|
|
644
|
+
return false;
|
|
645
|
+
}
|
|
646
|
+
},
|
|
647
|
+
{
|
|
648
|
+
message: "an origin byollm can reach, the way `byollm connect` takes one (https://hub.byollm.cloud)"
|
|
649
|
+
}
|
|
650
|
+
).optional(),
|
|
621
651
|
/**
|
|
622
652
|
* The memory floor this device refuses model work below — B090.
|
|
623
653
|
*
|
|
@@ -1152,37 +1182,58 @@ ${plan.say}
|
|
|
1152
1182
|
}
|
|
1153
1183
|
|
|
1154
1184
|
// src/update.ts
|
|
1185
|
+
import { compareVersions } from "@byollm/protocol";
|
|
1155
1186
|
function exactVersion(value) {
|
|
1156
1187
|
return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(value) ? value : void 0;
|
|
1157
1188
|
}
|
|
1158
1189
|
async function update(from, to, deps) {
|
|
1159
1190
|
const target = exactVersion(to);
|
|
1160
1191
|
if (target === void 0) {
|
|
1161
|
-
const
|
|
1162
|
-
deps.report(
|
|
1163
|
-
return { kind: "refused", why
|
|
1192
|
+
const why = `refusing to install "${to}" \u2014 the updater installs exact versions only`;
|
|
1193
|
+
deps.report(why);
|
|
1194
|
+
return { kind: "refused", why };
|
|
1164
1195
|
}
|
|
1165
|
-
if (
|
|
1196
|
+
if (exactVersion(from) === void 0) {
|
|
1197
|
+
const why = `refusing to update from "${from}" \u2014 no version to roll back to`;
|
|
1198
|
+
deps.report(why);
|
|
1199
|
+
return { kind: "refused", why };
|
|
1200
|
+
}
|
|
1201
|
+
const order = compareVersions(target, from);
|
|
1202
|
+
if (order === 0) {
|
|
1166
1203
|
return { kind: "refused", why: `already on ${from}` };
|
|
1167
1204
|
}
|
|
1168
|
-
if (
|
|
1169
|
-
const
|
|
1170
|
-
deps.report(
|
|
1171
|
-
return { kind: "refused", why
|
|
1205
|
+
if (order === void 0 || order < 0) {
|
|
1206
|
+
const why = order === void 0 ? `refusing to install ${target} \u2014 cannot tell whether it is newer than ${from}` : `refusing to install ${target} \u2014 it is older than ${from}, and the updater never downgrades`;
|
|
1207
|
+
deps.report(why);
|
|
1208
|
+
return { kind: "refused", why };
|
|
1172
1209
|
}
|
|
1173
1210
|
await deps.drain();
|
|
1174
1211
|
if (!await deps.install(target)) {
|
|
1175
1212
|
await deps.reregister();
|
|
1176
|
-
const
|
|
1177
|
-
deps.report(
|
|
1178
|
-
return { kind: "refused", why
|
|
1213
|
+
const why = `could not install ${target} \u2014 staying on ${from}`;
|
|
1214
|
+
deps.report(why);
|
|
1215
|
+
return { kind: "refused", why };
|
|
1216
|
+
}
|
|
1217
|
+
const proof = await deps.verify(target);
|
|
1218
|
+
if (!proof.verified) {
|
|
1219
|
+
return rollBack(
|
|
1220
|
+
from,
|
|
1221
|
+
`${target} failed its provenance check: ${proof.why}`,
|
|
1222
|
+
deps
|
|
1223
|
+
);
|
|
1179
1224
|
}
|
|
1180
1225
|
await deps.reregister();
|
|
1181
1226
|
const reported = await deps.installedVersion();
|
|
1182
1227
|
if (reported === target) {
|
|
1183
1228
|
return { kind: "updated", to: target };
|
|
1184
1229
|
}
|
|
1185
|
-
|
|
1230
|
+
return rollBack(
|
|
1231
|
+
from,
|
|
1232
|
+
reported === void 0 ? `${target} did not answer after installing` : `installed ${target} but the binary reports ${reported}`,
|
|
1233
|
+
deps
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
async function rollBack(from, why, deps) {
|
|
1186
1237
|
if (!await deps.install(from)) {
|
|
1187
1238
|
const stranded = `${why}; rolling back to ${from} also failed`;
|
|
1188
1239
|
deps.report(stranded);
|
|
@@ -1198,6 +1249,115 @@ async function update(from, to, deps) {
|
|
|
1198
1249
|
deps.report(`${why}; rolled back to ${from}`);
|
|
1199
1250
|
return { kind: "rolled-back", to: from, why };
|
|
1200
1251
|
}
|
|
1252
|
+
function offerInbox(input) {
|
|
1253
|
+
let offered;
|
|
1254
|
+
const refused = /* @__PURE__ */ new Set();
|
|
1255
|
+
return {
|
|
1256
|
+
receive: (origin, version) => {
|
|
1257
|
+
const why = origin !== input.authority ? `updates are taken only from ${input.authority}` : input.hasControlPlane(origin) ? void 0 : "it is a direct-mode pairing, and those never update this daemon";
|
|
1258
|
+
if (why === void 0) {
|
|
1259
|
+
offered = version;
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
if (refused.has(origin)) return;
|
|
1263
|
+
refused.add(origin);
|
|
1264
|
+
input.report(`ignoring an offer of ${version} from ${origin} \u2014 ${why}`);
|
|
1265
|
+
},
|
|
1266
|
+
current: () => offered
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// src/provenance.ts
|
|
1271
|
+
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
1272
|
+
var RELEASE_REPOSITORY = "https://github.com/oftomorrowinc/byollm";
|
|
1273
|
+
var SLSA_V1 = "https://slsa.dev/provenance/v1";
|
|
1274
|
+
async function verifyProvenance(version, options = {}) {
|
|
1275
|
+
const get = options.fetch ?? ((url) => fetch(url));
|
|
1276
|
+
const registry = options.registry ?? NPM_REGISTRY;
|
|
1277
|
+
const no = (why) => ({ verified: false, why });
|
|
1278
|
+
const integrity = await readJson(get, `${registry}/byollm/${version}`);
|
|
1279
|
+
if (!integrity.ok)
|
|
1280
|
+
return no(`could not read the registry entry: ${integrity.why}`);
|
|
1281
|
+
const expected = sha512Hex(
|
|
1282
|
+
integrity.body?.dist?.integrity
|
|
1283
|
+
);
|
|
1284
|
+
if (expected === void 0) {
|
|
1285
|
+
return no("the registry entry has no sha512 integrity to check against");
|
|
1286
|
+
}
|
|
1287
|
+
const listed = await readJson(
|
|
1288
|
+
get,
|
|
1289
|
+
`${registry}/-/npm/v1/attestations/byollm@${version}`
|
|
1290
|
+
);
|
|
1291
|
+
if (!listed.ok) return no(`could not read the attestations: ${listed.why}`);
|
|
1292
|
+
const attestations = listed.body?.attestations;
|
|
1293
|
+
if (!Array.isArray(attestations))
|
|
1294
|
+
return no("the registry lists no attestations");
|
|
1295
|
+
const slsa = attestations.filter(
|
|
1296
|
+
(entry) => entry?.predicateType === SLSA_V1
|
|
1297
|
+
);
|
|
1298
|
+
if (slsa.length === 0) return no("there is no SLSA provenance for it");
|
|
1299
|
+
for (const entry of slsa) {
|
|
1300
|
+
const statement = decodeStatement(entry);
|
|
1301
|
+
if (statement === void 0) return no("its provenance could not be read");
|
|
1302
|
+
const why = checkStatement(statement, version, expected);
|
|
1303
|
+
if (why !== void 0) return no(why);
|
|
1304
|
+
}
|
|
1305
|
+
return { verified: true };
|
|
1306
|
+
}
|
|
1307
|
+
function checkStatement(statement, version, expected) {
|
|
1308
|
+
const workflow = statement.predicate?.buildDefinition?.externalParameters?.workflow;
|
|
1309
|
+
if (workflow?.repository !== RELEASE_REPOSITORY) {
|
|
1310
|
+
return `it was built by ${named(workflow?.repository)}, not ${RELEASE_REPOSITORY}`;
|
|
1311
|
+
}
|
|
1312
|
+
if (workflow.ref !== `refs/tags/v${version}`) {
|
|
1313
|
+
return `it was built from ${named(workflow.ref)}, not refs/tags/v${version}`;
|
|
1314
|
+
}
|
|
1315
|
+
const subjects = Array.isArray(
|
|
1316
|
+
statement.subject
|
|
1317
|
+
) ? statement.subject : [];
|
|
1318
|
+
const ours = subjects.find((s) => s.name === `pkg:npm/byollm@${version}`);
|
|
1319
|
+
if (ours === void 0)
|
|
1320
|
+
return `its provenance does not name byollm@${version}`;
|
|
1321
|
+
if (ours.digest?.sha512 !== expected) {
|
|
1322
|
+
return "its provenance names a different tarball than the one npm installed";
|
|
1323
|
+
}
|
|
1324
|
+
return void 0;
|
|
1325
|
+
}
|
|
1326
|
+
async function readJson(get, url) {
|
|
1327
|
+
try {
|
|
1328
|
+
const response = await get(url);
|
|
1329
|
+
if (!response.ok)
|
|
1330
|
+
return { ok: false, why: `HTTP ${String(response.status)}` };
|
|
1331
|
+
return { ok: true, body: await response.json() };
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
return {
|
|
1334
|
+
ok: false,
|
|
1335
|
+
why: error instanceof Error ? error.message : "unknown error"
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
function decodeStatement(entry) {
|
|
1340
|
+
const payload = entry?.bundle?.dsseEnvelope?.payload;
|
|
1341
|
+
if (typeof payload !== "string") return void 0;
|
|
1342
|
+
try {
|
|
1343
|
+
const parsed = JSON.parse(
|
|
1344
|
+
Buffer.from(payload, "base64").toString("utf8")
|
|
1345
|
+
);
|
|
1346
|
+
return typeof parsed === "object" && parsed !== null ? parsed : void 0;
|
|
1347
|
+
} catch {
|
|
1348
|
+
return void 0;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
function sha512Hex(integrity) {
|
|
1352
|
+
if (typeof integrity !== "string") return void 0;
|
|
1353
|
+
const match = /^sha512-([A-Za-z0-9+/]+={0,2})$/.exec(integrity.trim());
|
|
1354
|
+
if (match?.[1] === void 0) return void 0;
|
|
1355
|
+
const bytes2 = Buffer.from(match[1], "base64");
|
|
1356
|
+
return bytes2.length === 64 ? bytes2.toString("hex") : void 0;
|
|
1357
|
+
}
|
|
1358
|
+
function named(value) {
|
|
1359
|
+
return typeof value === "string" ? value : "an unnamed workflow";
|
|
1360
|
+
}
|
|
1201
1361
|
|
|
1202
1362
|
// src/update-deps.ts
|
|
1203
1363
|
function realUpdateDeps(input) {
|
|
@@ -1209,6 +1369,8 @@ function realUpdateDeps(input) {
|
|
|
1209
1369
|
"npm",
|
|
1210
1370
|
"install",
|
|
1211
1371
|
"--global",
|
|
1372
|
+
"--ignore-scripts",
|
|
1373
|
+
`--registry=${NPM_REGISTRY}`,
|
|
1212
1374
|
`byollm@${version}`
|
|
1213
1375
|
]);
|
|
1214
1376
|
if (result.code !== 0) {
|
|
@@ -1218,6 +1380,7 @@ function realUpdateDeps(input) {
|
|
|
1218
1380
|
}
|
|
1219
1381
|
return result.code === 0;
|
|
1220
1382
|
},
|
|
1383
|
+
verify: input.verify ?? ((version) => verifyProvenance(version)),
|
|
1221
1384
|
reregister: async () => (await input.run([binary, "start"])).code === 0,
|
|
1222
1385
|
installedVersion: async () => {
|
|
1223
1386
|
const result = await input.run([binary, "--version"]);
|
|
@@ -1548,6 +1711,7 @@ var FIXED_ARGV = Object.freeze([
|
|
|
1548
1711
|
"--strict-mcp-config",
|
|
1549
1712
|
"--mcp-config",
|
|
1550
1713
|
'{"mcpServers":{}}',
|
|
1714
|
+
"--restricted",
|
|
1551
1715
|
"--no-session-persistence"
|
|
1552
1716
|
]);
|
|
1553
1717
|
var ENV_ALLOWLIST = Object.freeze([
|
|
@@ -2346,7 +2510,7 @@ var CLAUDE_ALIASES = [
|
|
|
2346
2510
|
{ id: "sonnet", note: "balanced" },
|
|
2347
2511
|
{ id: "fable", note: "fastest" }
|
|
2348
2512
|
];
|
|
2349
|
-
async function
|
|
2513
|
+
async function readJson2(path) {
|
|
2350
2514
|
try {
|
|
2351
2515
|
return JSON.parse(await readFile6(path, "utf8"));
|
|
2352
2516
|
} catch {
|
|
@@ -2371,7 +2535,7 @@ function codexSuggestions(cache) {
|
|
|
2371
2535
|
}));
|
|
2372
2536
|
}
|
|
2373
2537
|
async function claudeSuggestions(home) {
|
|
2374
|
-
const settings = await
|
|
2538
|
+
const settings = await readJson2(join3(home, ".claude", "settings.json"));
|
|
2375
2539
|
const configured = typeof settings === "object" && settings !== null ? settings.model : void 0;
|
|
2376
2540
|
const out = [];
|
|
2377
2541
|
if (typeof configured === "string" && configured !== "") {
|
|
@@ -2388,7 +2552,7 @@ async function claudeSuggestions(home) {
|
|
|
2388
2552
|
async function modelSuggestions(cli, home = homedir()) {
|
|
2389
2553
|
if (cli === "codex-cli") {
|
|
2390
2554
|
return codexSuggestions(
|
|
2391
|
-
await
|
|
2555
|
+
await readJson2(join3(home, ".codex", "models_cache.json"))
|
|
2392
2556
|
);
|
|
2393
2557
|
}
|
|
2394
2558
|
if (cli === "claude-cli") return claudeSuggestions(home);
|
|
@@ -3076,14 +3240,14 @@ async function candidates(input) {
|
|
|
3076
3240
|
let model = cli.model;
|
|
3077
3241
|
let namedByOwner = false;
|
|
3078
3242
|
if (model === void 0) {
|
|
3079
|
-
const
|
|
3243
|
+
const named2 = await modelByHand({
|
|
3080
3244
|
cli,
|
|
3081
3245
|
io: input.io,
|
|
3082
3246
|
verifier: input.verifier,
|
|
3083
3247
|
...input.suggest === void 0 ? {} : { suggest: input.suggest }
|
|
3084
3248
|
});
|
|
3085
|
-
if (
|
|
3086
|
-
model =
|
|
3249
|
+
if (named2 === void 0) continue;
|
|
3250
|
+
model = named2;
|
|
3087
3251
|
namedByOwner = true;
|
|
3088
3252
|
}
|
|
3089
3253
|
const proof = await input.verifier(cli.id, model);
|
|
@@ -4813,7 +4977,7 @@ function isNotFound2(error) {
|
|
|
4813
4977
|
}
|
|
4814
4978
|
|
|
4815
4979
|
// src/console-agent.ts
|
|
4816
|
-
import { Buffer } from "buffer";
|
|
4980
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
4817
4981
|
import {
|
|
4818
4982
|
ConsoleFrame,
|
|
4819
4983
|
CONSOLE_FRAME_VERSION,
|
|
@@ -4973,7 +5137,7 @@ function consoleSession(deps) {
|
|
|
4973
5137
|
case "stdin":
|
|
4974
5138
|
if (!started) return;
|
|
4975
5139
|
fromBrowser += 1;
|
|
4976
|
-
deps.shell.write(
|
|
5140
|
+
deps.shell.write(Buffer2.from(consoleDataBytes(frame.data)));
|
|
4977
5141
|
return;
|
|
4978
5142
|
case "resize":
|
|
4979
5143
|
if (!started) return;
|
|
@@ -4992,7 +5156,7 @@ function consoleSession(deps) {
|
|
|
4992
5156
|
}
|
|
4993
5157
|
|
|
4994
5158
|
// src/pty-shell.ts
|
|
4995
|
-
import { Buffer as
|
|
5159
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
4996
5160
|
var NO_PTY_MESSAGE = "byollm console-agent needs node-pty, which is a hosted-box feature and is not installed here.\nIf you are self-hosting a box, install it beside byollm: npm i -g node-pty";
|
|
4997
5161
|
var NoPtyError = class extends Error {
|
|
4998
5162
|
constructor() {
|
|
@@ -5032,7 +5196,7 @@ async function openPtyShell(options) {
|
|
|
5032
5196
|
let exited;
|
|
5033
5197
|
let announce;
|
|
5034
5198
|
child.onData((data) => {
|
|
5035
|
-
const chunk =
|
|
5199
|
+
const chunk = Buffer3.from(data, "utf8");
|
|
5036
5200
|
if (deliver !== void 0) {
|
|
5037
5201
|
deliver(chunk);
|
|
5038
5202
|
return;
|
|
@@ -7550,11 +7714,14 @@ var Runner = class {
|
|
|
7550
7714
|
jobId: job.id,
|
|
7551
7715
|
senderKeyId: keyId2(publicIdentityOf2(keys).identity),
|
|
7552
7716
|
recipientKeyId: keyId2(this.#pinFor(job).identity),
|
|
7553
|
-
// This runner's clock, not the process's — cloud_008 §31.
|
|
7554
|
-
// `Date.now()
|
|
7555
|
-
//
|
|
7556
|
-
//
|
|
7557
|
-
//
|
|
7717
|
+
// This runner's clock, not the process's — cloud_008 §31. This was a
|
|
7718
|
+
// `Date.now()`, in the one place that stamps a deadline somebody else
|
|
7719
|
+
// enforces: a test that moves time moved every other clock here and
|
|
7720
|
+
// not this one, so a sealed result carried an expiry from a different
|
|
7721
|
+
// timeline than the lease it answered. The retirement window had the
|
|
7722
|
+
// same two clocks until it was found the same way; `drain` is the one
|
|
7723
|
+
// read left on the process clock, because it waits out real time
|
|
7724
|
+
// beside a real sleep.
|
|
7558
7725
|
deadlineAt: this.#now() + ENVELOPE_MAX_AGE_MS,
|
|
7559
7726
|
direction: "result"
|
|
7560
7727
|
}
|
|
@@ -7861,7 +8028,7 @@ var Runner = class {
|
|
|
7861
8028
|
for (const id of [...this.#sites.keys()]) {
|
|
7862
8029
|
if (id in sites) continue;
|
|
7863
8030
|
const until2 = this.#retiring.get(id);
|
|
7864
|
-
if (until2 !== void 0 &&
|
|
8031
|
+
if (until2 !== void 0 && this.#now() < until2) continue;
|
|
7865
8032
|
this.#retiring.delete(id);
|
|
7866
8033
|
this.#sites.delete(id);
|
|
7867
8034
|
for (const [leaseId, held] of this.#active) {
|
|
@@ -7943,7 +8110,7 @@ var Runner = class {
|
|
|
7943
8110
|
if (!previous) return false;
|
|
7944
8111
|
this.#known.set(id, site);
|
|
7945
8112
|
this.#sites.set(id, site);
|
|
7946
|
-
const ceiling =
|
|
8113
|
+
const ceiling = this.#now() + RETIREMENT_WINDOW_MS;
|
|
7947
8114
|
const proposed = offered.retiringUntil ?? ceiling;
|
|
7948
8115
|
this.#retiring.set(walk.from, Math.min(proposed, ceiling));
|
|
7949
8116
|
this.#options.onEvent?.({
|
|
@@ -8975,18 +9142,18 @@ function consoleSpecArg(args) {
|
|
|
8975
9142
|
var UNRESTRICTED = "--unrestricted-shell";
|
|
8976
9143
|
function consoleShellChoice(args) {
|
|
8977
9144
|
const at = args.indexOf("--shell");
|
|
8978
|
-
const
|
|
9145
|
+
const named2 = at === -1 ? void 0 : args[at + 1];
|
|
8979
9146
|
const escaped = args.includes(UNRESTRICTED);
|
|
8980
|
-
if (at !== -1 && (
|
|
9147
|
+
if (at !== -1 && (named2 === void 0 || named2.startsWith("--"))) {
|
|
8981
9148
|
return { ok: false, why: "`--shell` needs a path to the shell to run." };
|
|
8982
9149
|
}
|
|
8983
|
-
if (
|
|
9150
|
+
if (named2 !== void 0 && escaped) {
|
|
8984
9151
|
return {
|
|
8985
9152
|
ok: false,
|
|
8986
9153
|
why: `\`--shell\` and \`${UNRESTRICTED}\` disagree about what to run.`
|
|
8987
9154
|
};
|
|
8988
9155
|
}
|
|
8989
|
-
if (
|
|
9156
|
+
if (named2 !== void 0) return { ok: true, command: named2, fenced: true };
|
|
8990
9157
|
if (escaped) return { ok: true, command: "/bin/sh", fenced: false };
|
|
8991
9158
|
return {
|
|
8992
9159
|
ok: false,
|
|
@@ -9120,9 +9287,9 @@ async function commandConsoleAgent(paths, args, io) {
|
|
|
9120
9287
|
}
|
|
9121
9288
|
var DEFAULT_ORIGIN = "https://hub.byollm.cloud";
|
|
9122
9289
|
function connectTarget(args) {
|
|
9123
|
-
const
|
|
9290
|
+
const named2 = args.indexOf("--name");
|
|
9124
9291
|
const positional = args.filter(
|
|
9125
|
-
(arg, at) => !arg.startsWith("-") && (
|
|
9292
|
+
(arg, at) => !arg.startsWith("-") && (named2 === -1 || at !== named2 && at !== named2 + 1)
|
|
9126
9293
|
);
|
|
9127
9294
|
return positional[0] ?? DEFAULT_ORIGIN;
|
|
9128
9295
|
}
|
|
@@ -9191,10 +9358,14 @@ async function commandModel(paths, args, io) {
|
|
|
9191
9358
|
const shown = await showModel(paths.config, service, io);
|
|
9192
9359
|
return shown.code;
|
|
9193
9360
|
}
|
|
9361
|
+
const loaded = await loadConfig(paths.config).catch(() => void 0);
|
|
9362
|
+
const configured = loaded?.config.services[service];
|
|
9194
9363
|
const set = await setModel(
|
|
9195
9364
|
{ configPath: paths.config, service, model },
|
|
9196
9365
|
io,
|
|
9197
|
-
backendVerifier(
|
|
9366
|
+
backendVerifier(
|
|
9367
|
+
(id) => backendFor({ type: id, baseUrl: configured?.baseUrl })
|
|
9368
|
+
),
|
|
9198
9369
|
/**
|
|
9199
9370
|
* The memory guard on the owner's own command — B106.
|
|
9200
9371
|
*
|
|
@@ -9206,12 +9377,11 @@ async function commandModel(paths, args, io) {
|
|
|
9206
9377
|
* job — `minAvailableMemoryBytes`, one value, one meaning, whoever asked.
|
|
9207
9378
|
*/
|
|
9208
9379
|
async (backendId) => {
|
|
9209
|
-
const loaded = await loadConfig(paths.config).catch(() => void 0);
|
|
9210
9380
|
if (loaded === void 0) return { ask: false };
|
|
9211
9381
|
const { memory, pressure } = await readHostMemory();
|
|
9212
9382
|
return modelLoadQuestion({
|
|
9213
9383
|
backendId,
|
|
9214
|
-
baseUrl:
|
|
9384
|
+
baseUrl: configured?.baseUrl,
|
|
9215
9385
|
model,
|
|
9216
9386
|
memory,
|
|
9217
9387
|
pressure,
|
|
@@ -9223,9 +9393,9 @@ async function commandModel(paths, args, io) {
|
|
|
9223
9393
|
return set.code;
|
|
9224
9394
|
}
|
|
9225
9395
|
async function commandConnect(paths, args, io, signal) {
|
|
9226
|
-
const
|
|
9227
|
-
const name =
|
|
9228
|
-
if (
|
|
9396
|
+
const named2 = args.indexOf("--name");
|
|
9397
|
+
const name = named2 === -1 ? void 0 : args[named2 + 1];
|
|
9398
|
+
if (named2 !== -1 && (name === void 0 || name.startsWith("-"))) {
|
|
9229
9399
|
io.err("usage: byollm connect [<url>] [--name <name>]\n");
|
|
9230
9400
|
return 2;
|
|
9231
9401
|
}
|
|
@@ -9563,7 +9733,16 @@ async function runLoop(paths, origins, io, signal, supervised = !process.stdout.
|
|
|
9563
9733
|
);
|
|
9564
9734
|
if (signal?.aborted === true) controller.abort();
|
|
9565
9735
|
const runners = [];
|
|
9566
|
-
|
|
9736
|
+
const inbox = loaded.config.autoUpdate ? offerInbox({
|
|
9737
|
+
authority: normalizeOrigin(
|
|
9738
|
+
loaded.config.updateAuthority ?? DEFAULT_ORIGIN
|
|
9739
|
+
),
|
|
9740
|
+
hasControlPlane: (origin) => pairings.get(origin)?.controlPlanePublic !== void 0,
|
|
9741
|
+
report: (line) => {
|
|
9742
|
+
io.err(`update: ${line}
|
|
9743
|
+
`);
|
|
9744
|
+
}
|
|
9745
|
+
}) : void 0;
|
|
9567
9746
|
for (const origin of origins) {
|
|
9568
9747
|
const pairing = pairings.get(origin);
|
|
9569
9748
|
if (!pairing) {
|
|
@@ -9662,7 +9841,8 @@ async function runLoop(paths, origins, io, signal, supervised = !process.stdout.
|
|
|
9662
9841
|
},
|
|
9663
9842
|
onEvent: (event) => {
|
|
9664
9843
|
report(origin, event, io);
|
|
9665
|
-
if (event.type === "update-offered")
|
|
9844
|
+
if (event.type === "update-offered")
|
|
9845
|
+
inbox?.receive(origin, event.version);
|
|
9666
9846
|
if (event.type === "heartbeat") {
|
|
9667
9847
|
void recordSites(pairings, origin, runner.sites, {
|
|
9668
9848
|
known: runner.known
|
|
@@ -9717,11 +9897,11 @@ Which sites may send work is enabled from your dashboard. Ctrl-C to stop.
|
|
|
9717
9897
|
`
|
|
9718
9898
|
);
|
|
9719
9899
|
await ingress.applyRetention(Date.now());
|
|
9720
|
-
const updated =
|
|
9900
|
+
const updated = inbox ? watchForUpdate({
|
|
9721
9901
|
runners,
|
|
9722
9902
|
io,
|
|
9723
9903
|
signal: controller.signal,
|
|
9724
|
-
offered:
|
|
9904
|
+
offered: inbox.current
|
|
9725
9905
|
}) : new Promise(() => void 0);
|
|
9726
9906
|
const tookUpdate = await Promise.race([
|
|
9727
9907
|
Promise.all(runners.map((runner) => runner.run(controller.signal))).then(
|
|
@@ -9747,6 +9927,7 @@ async function watchForUpdate(input) {
|
|
|
9747
9927
|
const outcome = await update(DAEMON_VERSION, version, {
|
|
9748
9928
|
...realUpdateDeps({
|
|
9749
9929
|
run: input.run ?? spawnCommand,
|
|
9930
|
+
...input.verify === void 0 ? {} : { verify: input.verify },
|
|
9750
9931
|
drain: async () => {
|
|
9751
9932
|
await Promise.all(
|
|
9752
9933
|
input.runners.map(
|
|
@@ -9910,7 +10091,7 @@ function describeAge(ms) {
|
|
|
9910
10091
|
return seconds < 120 ? `${String(seconds)} seconds` : `${String(Math.round(seconds / 60))} minutes`;
|
|
9911
10092
|
}
|
|
9912
10093
|
async function commandStatus(paths, io, service) {
|
|
9913
|
-
const { loaded, ingress, budgets, spend, spentGrants } = await context(paths);
|
|
10094
|
+
const { loaded, configured, ingress, budgets, spend, spentGrants } = await context(paths);
|
|
9914
10095
|
const pairings = new Pairings(paths.pairings);
|
|
9915
10096
|
await pairings.load();
|
|
9916
10097
|
reportSkipped(pairings, io);
|
|
@@ -9931,10 +10112,17 @@ async function commandStatus(paths, io, service) {
|
|
|
9931
10112
|
const plan = servicePlan(serviceTarget(paths, service));
|
|
9932
10113
|
const supervision = await serviceState(plan, service.run);
|
|
9933
10114
|
const revoked = await revokedMark(paths.health);
|
|
10115
|
+
const notSetUp = !configured && beat === void 0;
|
|
9934
10116
|
io.out(
|
|
9935
|
-
`state: ${revoked !== void 0 ? "REVOKED" : supervision.state === "installed" || stale ? "NOT RUNNING" : failing ? "NOT REPORTING" : "running"}
|
|
10117
|
+
`state: ${revoked !== void 0 ? "REVOKED" : supervision.state === "installed" || stale ? "NOT RUNNING" : failing ? "NOT REPORTING" : notSetUp ? "NOT SET UP" : "running"}
|
|
9936
10118
|
`
|
|
9937
10119
|
);
|
|
10120
|
+
if (revoked === void 0 && !stale && !failing && notSetUp) {
|
|
10121
|
+
io.out(
|
|
10122
|
+
` no config at ${paths.config}, and nothing has run here yet.
|
|
10123
|
+
${NOT_SET_UP_HINT}`
|
|
10124
|
+
);
|
|
10125
|
+
}
|
|
9938
10126
|
if (revoked !== void 0) {
|
|
9939
10127
|
io.out(
|
|
9940
10128
|
` ${REVOKED_SENTENCE}.
|
|
@@ -10000,8 +10188,10 @@ async function commandStatus(paths, io, service) {
|
|
|
10000
10188
|
io.out("\nservices\n");
|
|
10001
10189
|
const recorded = await readServiceStates(paths.serviceStates);
|
|
10002
10190
|
const deviceName = await labelFor(paths, void 0);
|
|
10003
|
-
const declared = Object.entries(loaded.config.services);
|
|
10004
|
-
if (
|
|
10191
|
+
const declared = configured ? Object.entries(loaded.config.services) : [];
|
|
10192
|
+
if (!configured) {
|
|
10193
|
+
io.out(" (none \u2014 run `byollm setup`)\n");
|
|
10194
|
+
} else if (declared.length === 0) {
|
|
10005
10195
|
io.out(" (none configured)\n");
|
|
10006
10196
|
}
|
|
10007
10197
|
for (const [name, service2] of declared) {
|
|
@@ -10506,7 +10696,16 @@ ${summarise(outcome).join("\n")}
|
|
|
10506
10696
|
return signal?.aborted === true ? 1 : 0;
|
|
10507
10697
|
}
|
|
10508
10698
|
async function commandServices(paths, io, service) {
|
|
10509
|
-
const { loaded, ingress, budgets, spend, spentGrants } = await context(paths);
|
|
10699
|
+
const { loaded, configured, ingress, budgets, spend, spentGrants } = await context(paths);
|
|
10700
|
+
if (!configured) {
|
|
10701
|
+
io.out(
|
|
10702
|
+
`services
|
|
10703
|
+
(none \u2014 no config at ${paths.config})
|
|
10704
|
+
|
|
10705
|
+
` + NOT_SET_UP_HINT
|
|
10706
|
+
);
|
|
10707
|
+
return 1;
|
|
10708
|
+
}
|
|
10510
10709
|
const pairings = new Pairings(paths.pairings);
|
|
10511
10710
|
await pairings.load();
|
|
10512
10711
|
const hasRelay = pairings.list().some((pairing) => pairing.controlPlanePublic !== void 0);
|
|
@@ -10602,6 +10801,10 @@ with the device's page, and after installing a new CLI run
|
|
|
10602
10801
|
}
|
|
10603
10802
|
async function context(paths) {
|
|
10604
10803
|
const loaded = await loadConfig(paths.config);
|
|
10804
|
+
const configured = await access(paths.config).then(
|
|
10805
|
+
() => true,
|
|
10806
|
+
() => false
|
|
10807
|
+
);
|
|
10605
10808
|
const ingress = new IngressLog({
|
|
10606
10809
|
path: paths.ingressLog,
|
|
10607
10810
|
communityPromptDays: loaded.config.ingress.communityPromptDays,
|
|
@@ -10613,8 +10816,9 @@ async function context(paths) {
|
|
|
10613
10816
|
const spentGrants = new SpentGrants(paths.spentGrants);
|
|
10614
10817
|
spentGrants.load(Date.now());
|
|
10615
10818
|
await spend.load(Date.now());
|
|
10616
|
-
return { loaded, ingress, budgets, spend, spentGrants };
|
|
10819
|
+
return { loaded, configured, ingress, budgets, spend, spentGrants };
|
|
10617
10820
|
}
|
|
10821
|
+
var NOT_SET_UP_HINT = "Run `byollm setup` to find what this computer already has.\n";
|
|
10618
10822
|
async function confirmInteractively(question) {
|
|
10619
10823
|
if (!process.stdin.isTTY) {
|
|
10620
10824
|
process.stderr.write(
|
|
@@ -10680,7 +10884,7 @@ async function exists(path) {
|
|
|
10680
10884
|
}
|
|
10681
10885
|
|
|
10682
10886
|
// src/index.ts
|
|
10683
|
-
var DAEMON_VERSION = "0.1.
|
|
10887
|
+
var DAEMON_VERSION = "0.1.2";
|
|
10684
10888
|
function daemonVersion() {
|
|
10685
10889
|
return {
|
|
10686
10890
|
daemon: DAEMON_VERSION,
|
|
@@ -10697,6 +10901,8 @@ ${v.platform}-${v.arch}, node ${v.node}
|
|
|
10697
10901
|
}
|
|
10698
10902
|
|
|
10699
10903
|
export {
|
|
10904
|
+
UnusableOrigin,
|
|
10905
|
+
normalizeOrigin,
|
|
10700
10906
|
checkBaseUrl,
|
|
10701
10907
|
BASE_URL_REFUSAL_MESSAGES,
|
|
10702
10908
|
DaemonConfig,
|
|
@@ -10710,8 +10916,6 @@ export {
|
|
|
10710
10916
|
createBackend,
|
|
10711
10917
|
SpendLedger,
|
|
10712
10918
|
estimateCents,
|
|
10713
|
-
UnusableOrigin,
|
|
10714
|
-
normalizeOrigin,
|
|
10715
10919
|
Budgets,
|
|
10716
10920
|
ClientError,
|
|
10717
10921
|
ProtocolClient,
|
|
@@ -10739,4 +10943,4 @@ export {
|
|
|
10739
10943
|
runCli,
|
|
10740
10944
|
main
|
|
10741
10945
|
};
|
|
10742
|
-
//# sourceMappingURL=chunk-
|
|
10946
|
+
//# sourceMappingURL=chunk-K7QYAF7V.js.map
|