byollm 0.1.0-alpha.74 → 0.1.0-alpha.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-YFCNYJLR.js → chunk-MSRBBLRQ.js} +165 -49
- package/dist/chunk-MSRBBLRQ.js.map +1 -0
- package/dist/index.d.ts +13 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-YFCNYJLR.js.map +0 -1
package/README.md
CHANGED
package/dist/bin.js
CHANGED
|
@@ -53,6 +53,32 @@ function asHttpOrigin(candidate) {
|
|
|
53
53
|
// src/cli.ts
|
|
54
54
|
import { access } from "fs/promises";
|
|
55
55
|
|
|
56
|
+
// src/emphasis.ts
|
|
57
|
+
var REVERSE = "\x1B[7m";
|
|
58
|
+
var BOLD = "\x1B[1m";
|
|
59
|
+
var RESET = "\x1B[0m";
|
|
60
|
+
function emphasisAllowed(context2) {
|
|
61
|
+
if (context2.env["NO_COLOR"] !== void 0) return false;
|
|
62
|
+
if (context2.env["FORCE_COLOR"] !== void 0) return true;
|
|
63
|
+
return context2.tty;
|
|
64
|
+
}
|
|
65
|
+
function emphasise(value, context2) {
|
|
66
|
+
return emphasisAllowed(context2) ? `${REVERSE}${BOLD} ${value} ${RESET}` : value;
|
|
67
|
+
}
|
|
68
|
+
function terminalContext() {
|
|
69
|
+
return {
|
|
70
|
+
// `@types/node` declares `isTTY` as `boolean`, and Node sets it to
|
|
71
|
+
// `undefined` when the stream is not a terminal. So this comparison is
|
|
72
|
+
// load-bearing even though the type says it cannot be — the linter is
|
|
73
|
+
// reasoning from a declaration that is wrong about its own runtime, and
|
|
74
|
+
// deleting it puts `undefined` into a field typed `boolean`. The same
|
|
75
|
+
// note stands over `setup.ts`, which met this first.
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-boolean-literal-compare
|
|
77
|
+
tty: process.stdout.isTTY === true,
|
|
78
|
+
env: process.env
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
56
82
|
// src/model.ts
|
|
57
83
|
import { readFile, writeFile } from "fs/promises";
|
|
58
84
|
|
|
@@ -218,8 +244,8 @@ function until(message, now) {
|
|
|
218
244
|
if (Number.isNaN(parsed)) return void 0;
|
|
219
245
|
return parsed > now ? parsed : void 0;
|
|
220
246
|
}
|
|
221
|
-
function quotaBlock(message, now) {
|
|
222
|
-
if (!
|
|
247
|
+
function quotaBlock(message, now, corpus = OBSERVED) {
|
|
248
|
+
if (!corpus.some((seen) => seen.pattern.test(message))) return void 0;
|
|
223
249
|
const at = until(message, now);
|
|
224
250
|
return { detail: message, ...at === void 0 ? {} : { until: at } };
|
|
225
251
|
}
|
|
@@ -234,7 +260,6 @@ async function runProcessJob(job) {
|
|
|
234
260
|
ok: false,
|
|
235
261
|
code: "backend-error",
|
|
236
262
|
message: "no time limit was set for this call",
|
|
237
|
-
retryable: false,
|
|
238
263
|
durationMs: 0
|
|
239
264
|
};
|
|
240
265
|
}
|
|
@@ -253,7 +278,6 @@ function spawnIn(job, scratch) {
|
|
|
253
278
|
ok: false,
|
|
254
279
|
code: "canceled",
|
|
255
280
|
message: "the job was canceled before it started",
|
|
256
|
-
retryable: false,
|
|
257
281
|
durationMs: Date.now() - started
|
|
258
282
|
});
|
|
259
283
|
return;
|
|
@@ -316,7 +340,6 @@ function spawnIn(job, scratch) {
|
|
|
316
340
|
ok: false,
|
|
317
341
|
code: "backend-unreachable",
|
|
318
342
|
message: `could not start ${displayName}: ${error.message}`,
|
|
319
|
-
retryable: false,
|
|
320
343
|
durationMs: Date.now() - started
|
|
321
344
|
});
|
|
322
345
|
});
|
|
@@ -328,7 +351,6 @@ function spawnIn(job, scratch) {
|
|
|
328
351
|
ok: false,
|
|
329
352
|
code: "canceled",
|
|
330
353
|
message: "the job was canceled",
|
|
331
|
-
retryable: false,
|
|
332
354
|
durationMs
|
|
333
355
|
});
|
|
334
356
|
return;
|
|
@@ -338,7 +360,6 @@ function spawnIn(job, scratch) {
|
|
|
338
360
|
ok: false,
|
|
339
361
|
code: "timeout",
|
|
340
362
|
message: `the model did not answer within ${String(request.timeoutMs)}ms`,
|
|
341
|
-
retryable: true,
|
|
342
363
|
durationMs
|
|
343
364
|
});
|
|
344
365
|
return;
|
|
@@ -348,7 +369,6 @@ function spawnIn(job, scratch) {
|
|
|
348
369
|
ok: false,
|
|
349
370
|
code: "output-too-large",
|
|
350
371
|
message: `the model produced more than ${String(request.maxOutputBytes)} bytes`,
|
|
351
|
-
retryable: false,
|
|
352
372
|
durationMs
|
|
353
373
|
});
|
|
354
374
|
return;
|
|
@@ -356,13 +376,20 @@ function spawnIn(job, scratch) {
|
|
|
356
376
|
if (code !== 0) {
|
|
357
377
|
const said = `${stdout}
|
|
358
378
|
${stderr}`;
|
|
359
|
-
const blocked = quotaBlock(said, Date.now());
|
|
379
|
+
const blocked = quotaBlock(said, (job.now ?? Date.now)(), job.corpus);
|
|
360
380
|
const authFailed = blocked === void 0 && isAuthFailure(said);
|
|
361
381
|
finish({
|
|
362
382
|
ok: false,
|
|
363
383
|
code: blocked !== void 0 ? "quota-exhausted" : authFailed ? "unauthorized" : "backend-error",
|
|
364
384
|
...blocked?.until === void 0 ? {} : { until: blocked.until },
|
|
365
|
-
message: blocked !== void 0 ?
|
|
385
|
+
message: blocked !== void 0 ? (
|
|
386
|
+
/* The CLI's own words, as the Codex path already carries —
|
|
387
|
+
M2, 2026-09-04. This said only "out of quota for now",
|
|
388
|
+
throwing away the sentence that names the time, on the one
|
|
389
|
+
surface entitled to it. Owner-only: the class is all a site
|
|
390
|
+
ever sees. */
|
|
391
|
+
`${displayName} is out of quota: ${firstLine(blocked.detail)}`
|
|
392
|
+
) : authFailed ? `${displayName} is not signed in` : stderr.trim() !== "" ? `${displayName} failed: ${firstLine(stderr)}` : (
|
|
366
393
|
/* Nothing on stderr does not mean nothing was said. An
|
|
367
394
|
agentic CLI writes its errors to stdout — that is where
|
|
368
395
|
"Failed to authenticate" arrived — and reporting a bare
|
|
@@ -371,7 +398,6 @@ ${stderr}`;
|
|
|
371
398
|
goes to the site on success. */
|
|
372
399
|
stdout.trim() !== "" ? `${displayName} failed: ${firstLine(stdout)}` : `${displayName} exited with status ${String(code)}`
|
|
373
400
|
),
|
|
374
|
-
retryable: false,
|
|
375
401
|
durationMs
|
|
376
402
|
});
|
|
377
403
|
return;
|
|
@@ -658,16 +684,20 @@ function failureMessage(event) {
|
|
|
658
684
|
const error = record(event["error"]);
|
|
659
685
|
return diagnostic(event["message"]) ?? diagnostic(error?.["message"]) ?? "codex reported an error";
|
|
660
686
|
}
|
|
661
|
-
function classifyFailure(message) {
|
|
662
|
-
|
|
663
|
-
|
|
687
|
+
function classifyFailure(message, now, corpus) {
|
|
688
|
+
const blocked = quotaBlock(message, now, corpus);
|
|
689
|
+
if (blocked !== void 0) {
|
|
690
|
+
return {
|
|
691
|
+
code: "quota-exhausted",
|
|
692
|
+
...blocked.until === void 0 ? {} : { until: blocked.until }
|
|
693
|
+
};
|
|
664
694
|
}
|
|
665
695
|
if (isAuthFailure(message)) {
|
|
666
|
-
return { code: "unauthorized"
|
|
696
|
+
return { code: "unauthorized" };
|
|
667
697
|
}
|
|
668
|
-
return { code: "backend-error"
|
|
698
|
+
return { code: "backend-error" };
|
|
669
699
|
}
|
|
670
|
-
function parseCodexOutput(output) {
|
|
700
|
+
function parseCodexOutput(output, now = Date.now(), corpus) {
|
|
671
701
|
const messages = [];
|
|
672
702
|
for (const line of output.split(/\r?\n/u)) {
|
|
673
703
|
if (line.trim() === "") continue;
|
|
@@ -689,7 +719,7 @@ function parseCodexOutput(output) {
|
|
|
689
719
|
}
|
|
690
720
|
if (type === "error" || type === "turn.failed") {
|
|
691
721
|
const detail = failureMessage(event);
|
|
692
|
-
const classified = classifyFailure(detail);
|
|
722
|
+
const classified = classifyFailure(detail, now, corpus);
|
|
693
723
|
return {
|
|
694
724
|
ok: false,
|
|
695
725
|
...classified,
|
|
@@ -703,8 +733,7 @@ function parseCodexOutput(output) {
|
|
|
703
733
|
return {
|
|
704
734
|
ok: false,
|
|
705
735
|
code: "backend-error",
|
|
706
|
-
message: "the codex CLI ended without a terminal event"
|
|
707
|
-
retryable: false
|
|
736
|
+
message: "the codex CLI ended without a terminal event"
|
|
708
737
|
};
|
|
709
738
|
}
|
|
710
739
|
var CodexCliBackend = class {
|
|
@@ -953,7 +982,6 @@ var OpenAiHttpBackend = class {
|
|
|
953
982
|
ok: false,
|
|
954
983
|
code: "backend-error",
|
|
955
984
|
message: "no time limit was set for this call",
|
|
956
|
-
retryable: false,
|
|
957
985
|
durationMs: 0
|
|
958
986
|
};
|
|
959
987
|
}
|
|
@@ -978,7 +1006,6 @@ var OpenAiHttpBackend = class {
|
|
|
978
1006
|
return this.#fail(
|
|
979
1007
|
"unauthorized",
|
|
980
1008
|
"the model server rejected our credentials",
|
|
981
|
-
false,
|
|
982
1009
|
started
|
|
983
1010
|
);
|
|
984
1011
|
}
|
|
@@ -986,7 +1013,6 @@ var OpenAiHttpBackend = class {
|
|
|
986
1013
|
return this.#fail(
|
|
987
1014
|
"model-not-found",
|
|
988
1015
|
`the model server does not know "${request.model}"`,
|
|
989
|
-
false,
|
|
990
1016
|
started
|
|
991
1017
|
);
|
|
992
1018
|
}
|
|
@@ -994,7 +1020,6 @@ var OpenAiHttpBackend = class {
|
|
|
994
1020
|
return this.#fail(
|
|
995
1021
|
"backend-error",
|
|
996
1022
|
`the model server returned HTTP ${String(response.status)}`,
|
|
997
|
-
response.status >= 500,
|
|
998
1023
|
started
|
|
999
1024
|
);
|
|
1000
1025
|
}
|
|
@@ -1003,7 +1028,6 @@ var OpenAiHttpBackend = class {
|
|
|
1003
1028
|
return this.#fail(
|
|
1004
1029
|
"output-too-large",
|
|
1005
1030
|
`the model produced more than ${String(request.maxOutputBytes)} bytes`,
|
|
1006
|
-
false,
|
|
1007
1031
|
started
|
|
1008
1032
|
);
|
|
1009
1033
|
}
|
|
@@ -1012,37 +1036,43 @@ var OpenAiHttpBackend = class {
|
|
|
1012
1036
|
return this.#fail(
|
|
1013
1037
|
"backend-error",
|
|
1014
1038
|
"the model server's response was not in OpenAI chat-completion shape",
|
|
1015
|
-
false,
|
|
1016
1039
|
started
|
|
1017
1040
|
);
|
|
1018
1041
|
}
|
|
1019
1042
|
return { ok: true, text: content, durationMs: Date.now() - started };
|
|
1020
1043
|
} catch (error) {
|
|
1021
1044
|
if (request.signal.aborted) {
|
|
1022
|
-
return this.#fail("canceled", "the job was canceled",
|
|
1045
|
+
return this.#fail("canceled", "the job was canceled", started);
|
|
1023
1046
|
}
|
|
1024
1047
|
if (isAbort(error)) {
|
|
1025
1048
|
return this.#fail(
|
|
1026
1049
|
"timeout",
|
|
1027
1050
|
`the model did not answer within ${String(request.timeoutMs)}ms`,
|
|
1028
|
-
true,
|
|
1029
1051
|
started
|
|
1030
1052
|
);
|
|
1031
1053
|
}
|
|
1032
1054
|
return this.#fail(
|
|
1033
1055
|
"backend-unreachable",
|
|
1034
1056
|
describeFetchError(error, this.#baseUrl.origin),
|
|
1035
|
-
true,
|
|
1036
1057
|
started
|
|
1037
1058
|
);
|
|
1038
1059
|
}
|
|
1039
1060
|
}
|
|
1040
|
-
|
|
1061
|
+
/*
|
|
1062
|
+
* No `retryable` argument any more — ruled 2026-09-04.
|
|
1063
|
+
*
|
|
1064
|
+
* This adapter used to decide it per failure, and it was the only one whose
|
|
1065
|
+
* rule was defensible: `true` for unreachable and for a 5xx. That is
|
|
1066
|
+
* exactly why removing it matters. The decision now lives once, in the
|
|
1067
|
+
* site-facing class table, and it was the *disagreement* between three
|
|
1068
|
+
* adapters that let a value only quota produced become readable as a fact
|
|
1069
|
+
* about somebody's account.
|
|
1070
|
+
*/
|
|
1071
|
+
#fail(code, message, started) {
|
|
1041
1072
|
return {
|
|
1042
1073
|
ok: false,
|
|
1043
1074
|
code,
|
|
1044
1075
|
message,
|
|
1045
|
-
retryable,
|
|
1046
1076
|
durationMs: Date.now() - started
|
|
1047
1077
|
};
|
|
1048
1078
|
}
|
|
@@ -2435,7 +2465,20 @@ var REVOKED_RETURN = "the installed service returns by itself once you do \u2014
|
|
|
2435
2465
|
function revokedRemedy(origin, returnsByItself = true) {
|
|
2436
2466
|
return ` re-pair: byollm connect${origin === void 0 ? "" : ` ${origin}`}
|
|
2437
2467
|
` + (returnsByItself ? ` ${REVOKED_RETURN}.
|
|
2438
|
-
` :
|
|
2468
|
+
` : (
|
|
2469
|
+
/* The restart step, on the one branch that needs one — rider closed
|
|
2470
|
+
2026-09-04.
|
|
2471
|
+
|
|
2472
|
+
The original rider asked for `byollm install` back in the remedy.
|
|
2473
|
+
It is not the answer: a supervised daemon polls its mark and
|
|
2474
|
+
promotes itself, and a reinstall was work nobody needed to do. But
|
|
2475
|
+
the branch where nothing self-returns was left with a re-pair step
|
|
2476
|
+
and no next step at all — somebody running the daemon in their own
|
|
2477
|
+
terminal, whose process has already exited by the time they read
|
|
2478
|
+
this. Their restart is the command they typed, not an install. */
|
|
2479
|
+
` then: byollm run
|
|
2480
|
+
`
|
|
2481
|
+
));
|
|
2439
2482
|
}
|
|
2440
2483
|
async function revokedMark(healthPath) {
|
|
2441
2484
|
return (await readHealth(healthPath))?.revoked;
|
|
@@ -3460,33 +3503,44 @@ var SERVICE_UNAVAILABLE = "a device service is unavailable \u2014 its owner has
|
|
|
3460
3503
|
var FOR_SITE = Object.freeze({
|
|
3461
3504
|
"backend-unreachable": {
|
|
3462
3505
|
code: "service_unavailable",
|
|
3463
|
-
message: SERVICE_UNAVAILABLE
|
|
3506
|
+
message: SERVICE_UNAVAILABLE,
|
|
3507
|
+
retryable: true
|
|
3464
3508
|
},
|
|
3465
3509
|
"backend-error": {
|
|
3466
3510
|
code: "service_unavailable",
|
|
3467
|
-
message: SERVICE_UNAVAILABLE
|
|
3511
|
+
message: SERVICE_UNAVAILABLE,
|
|
3512
|
+
retryable: true
|
|
3468
3513
|
},
|
|
3469
3514
|
"model-not-found": {
|
|
3470
3515
|
code: "service_unavailable",
|
|
3471
|
-
message: SERVICE_UNAVAILABLE
|
|
3516
|
+
message: SERVICE_UNAVAILABLE,
|
|
3517
|
+
retryable: true
|
|
3472
3518
|
},
|
|
3473
3519
|
"quota-exhausted": {
|
|
3474
3520
|
code: "service_unavailable",
|
|
3475
|
-
message: SERVICE_UNAVAILABLE
|
|
3521
|
+
message: SERVICE_UNAVAILABLE,
|
|
3522
|
+
retryable: true
|
|
3476
3523
|
},
|
|
3477
3524
|
unauthorized: {
|
|
3478
3525
|
code: "service_unavailable",
|
|
3479
|
-
message: SERVICE_UNAVAILABLE
|
|
3526
|
+
message: SERVICE_UNAVAILABLE,
|
|
3527
|
+
retryable: true
|
|
3480
3528
|
},
|
|
3481
3529
|
timeout: {
|
|
3482
3530
|
code: "timeout",
|
|
3483
|
-
message: "the device did not answer in time"
|
|
3531
|
+
message: "the device did not answer in time",
|
|
3532
|
+
retryable: true
|
|
3484
3533
|
},
|
|
3485
3534
|
"output-too-large": {
|
|
3486
3535
|
code: "output-too-large",
|
|
3487
|
-
message: "the answer was too large to return"
|
|
3536
|
+
message: "the answer was too large to return",
|
|
3537
|
+
retryable: false
|
|
3488
3538
|
},
|
|
3489
|
-
canceled: {
|
|
3539
|
+
canceled: {
|
|
3540
|
+
code: "canceled",
|
|
3541
|
+
message: "the job was canceled",
|
|
3542
|
+
retryable: false
|
|
3543
|
+
}
|
|
3490
3544
|
});
|
|
3491
3545
|
function outcomeForSite(code) {
|
|
3492
3546
|
return FOR_SITE[code];
|
|
@@ -3601,6 +3655,18 @@ var Runner = class {
|
|
|
3601
3655
|
* separately.
|
|
3602
3656
|
*/
|
|
3603
3657
|
#blocked = /* @__PURE__ */ new Map();
|
|
3658
|
+
/**
|
|
3659
|
+
* The blocked services' own reports, kept so a rebuild can restore them.
|
|
3660
|
+
*
|
|
3661
|
+
* `serviceStates` is rebuilt from scratch on every detection pass and a
|
|
3662
|
+
* blocked service never reaches the probe that would fill its entry, so
|
|
3663
|
+
* without this the state survives one pass and disappears — and `byollm
|
|
3664
|
+
* status`, which is a different process reading the file, could never say a
|
|
3665
|
+
* service was blocked.
|
|
3666
|
+
*/
|
|
3667
|
+
#blockedReport = /* @__PURE__ */ new Map();
|
|
3668
|
+
/** What was last handed to the writer, so an unchanged pass writes nothing. */
|
|
3669
|
+
#lastWritten;
|
|
3604
3670
|
/**
|
|
3605
3671
|
* The key grants are checked against — from the pairing, or adopted later.
|
|
3606
3672
|
*
|
|
@@ -3716,8 +3782,14 @@ var Runner = class {
|
|
|
3716
3782
|
if (this.#unauthenticated.has(route.service)) continue;
|
|
3717
3783
|
const blockedUntil = this.#blocked.get(route.service);
|
|
3718
3784
|
if (this.#blocked.has(route.service)) {
|
|
3719
|
-
if (blockedUntil !== void 0 && this.#now() < blockedUntil)
|
|
3785
|
+
if (blockedUntil !== void 0 && this.#now() < blockedUntil) {
|
|
3786
|
+
const kept = this.#blockedReport.get(route.service);
|
|
3787
|
+
if (kept !== void 0) this.serviceStates.set(route.service, kept);
|
|
3788
|
+
continue;
|
|
3789
|
+
}
|
|
3720
3790
|
this.#blocked.delete(route.service);
|
|
3791
|
+
this.#blockedReport.delete(route.service);
|
|
3792
|
+
this.serviceStates.delete(route.service);
|
|
3721
3793
|
}
|
|
3722
3794
|
let usable = probed.get(route.service);
|
|
3723
3795
|
if (usable === void 0) {
|
|
@@ -3780,6 +3852,7 @@ var Runner = class {
|
|
|
3780
3852
|
});
|
|
3781
3853
|
}
|
|
3782
3854
|
this.#capabilities = capabilities;
|
|
3855
|
+
this.#writeServiceStates();
|
|
3783
3856
|
return capabilities;
|
|
3784
3857
|
}
|
|
3785
3858
|
#backendFor(route) {
|
|
@@ -4115,6 +4188,9 @@ var Runner = class {
|
|
|
4115
4188
|
outcome: "error",
|
|
4116
4189
|
code: "no-capability",
|
|
4117
4190
|
message: "this device has no route for that job kind",
|
|
4191
|
+
/* Not retryable, and not from the class table: this is the runner's
|
|
4192
|
+
own refusal rather than a backend failure. A device with no route
|
|
4193
|
+
for a kind will not grow one by being asked again. */
|
|
4118
4194
|
retryable: false
|
|
4119
4195
|
};
|
|
4120
4196
|
}
|
|
@@ -4159,6 +4235,12 @@ var Runner = class {
|
|
|
4159
4235
|
});
|
|
4160
4236
|
if (!result.ok && result.code === "unauthorized") {
|
|
4161
4237
|
this.#unauthenticated.add(route.service);
|
|
4238
|
+
this.#noteServiceState(route.service, {
|
|
4239
|
+
state: {
|
|
4240
|
+
kind: "signed-out",
|
|
4241
|
+
detail: result.message
|
|
4242
|
+
}
|
|
4243
|
+
});
|
|
4162
4244
|
this.#options.onEvent?.({
|
|
4163
4245
|
type: "service-not-signed-in",
|
|
4164
4246
|
service: route.service,
|
|
@@ -4167,7 +4249,7 @@ var Runner = class {
|
|
|
4167
4249
|
}
|
|
4168
4250
|
if (!result.ok && result.code === "quota-exhausted") {
|
|
4169
4251
|
this.#blocked.set(route.service, result.until);
|
|
4170
|
-
this
|
|
4252
|
+
const report2 = this.#noteServiceState(route.service, {
|
|
4171
4253
|
...this.serviceStates.get(route.service),
|
|
4172
4254
|
state: {
|
|
4173
4255
|
kind: "blocked",
|
|
@@ -4175,6 +4257,7 @@ var Runner = class {
|
|
|
4175
4257
|
...result.until === void 0 ? {} : { until: result.until }
|
|
4176
4258
|
}
|
|
4177
4259
|
});
|
|
4260
|
+
this.#blockedReport.set(route.service, report2);
|
|
4178
4261
|
this.#options.onEvent?.({
|
|
4179
4262
|
type: "service-out-of-quota",
|
|
4180
4263
|
service: route.service,
|
|
@@ -4200,13 +4283,15 @@ var Runner = class {
|
|
|
4200
4283
|
* named its backend, so every failure leaked what every success
|
|
4201
4284
|
* is careful to hide.
|
|
4202
4285
|
*
|
|
4203
|
-
* `retryable`
|
|
4204
|
-
*
|
|
4286
|
+
* `retryable` comes from the class, not from this result —
|
|
4287
|
+
* ruled 2026-09-04. Taking it from the backend let one path
|
|
4288
|
+
* inside `service_unavailable` report `true` and made the pair
|
|
4289
|
+
* readable as "rate-limited". A flag a site can read is a channel
|
|
4290
|
+
* whether or not anybody meant it as one.
|
|
4205
4291
|
*/
|
|
4206
4292
|
{
|
|
4207
4293
|
outcome: "error",
|
|
4208
|
-
...outcomeForSite(result.code)
|
|
4209
|
-
retryable: result.retryable
|
|
4294
|
+
...outcomeForSite(result.code)
|
|
4210
4295
|
}
|
|
4211
4296
|
);
|
|
4212
4297
|
await this.#options.ingress.recordOutcome({
|
|
@@ -4282,6 +4367,34 @@ var Runner = class {
|
|
|
4282
4367
|
await sleep(heartbeatMs * (0.85 + Math.random() * 0.3), signal);
|
|
4283
4368
|
}
|
|
4284
4369
|
}
|
|
4370
|
+
/**
|
|
4371
|
+
* Record a service's state, and tell whoever writes the file — S-2.
|
|
4372
|
+
*
|
|
4373
|
+
* One door, because the bug was two doors and only one of them wrote. The
|
|
4374
|
+
* quota path wrote on block and not on lift; the sign-out path never wrote
|
|
4375
|
+
* at all. Both are changes `byollm status` would report differently, and
|
|
4376
|
+
* status is a different process whose only source is that file.
|
|
4377
|
+
*/
|
|
4378
|
+
#noteServiceState(service, report2) {
|
|
4379
|
+
this.serviceStates.set(service, report2);
|
|
4380
|
+
this.#writeServiceStates();
|
|
4381
|
+
return report2;
|
|
4382
|
+
}
|
|
4383
|
+
/**
|
|
4384
|
+
* Hand the current map to whoever persists it.
|
|
4385
|
+
*
|
|
4386
|
+
* Not awaited, and the rejection is swallowed on purpose: a job must not
|
|
4387
|
+
* fail — nor the runner die on an unhandled rejection — because a status
|
|
4388
|
+
* note could not be written. The note is evidence about the job, not part
|
|
4389
|
+
* of it.
|
|
4390
|
+
*/
|
|
4391
|
+
#writeServiceStates() {
|
|
4392
|
+
const now = JSON.stringify([...this.serviceStates]);
|
|
4393
|
+
if (now === this.#lastWritten) return;
|
|
4394
|
+
this.#lastWritten = now;
|
|
4395
|
+
const noted = this.#options.onServiceStates?.(this.serviceStates);
|
|
4396
|
+
if (noted !== void 0) void noted.catch(() => void 0);
|
|
4397
|
+
}
|
|
4285
4398
|
/**
|
|
4286
4399
|
* Note a refusal that means the relationship is over.
|
|
4287
4400
|
*
|
|
@@ -5850,7 +5963,7 @@ Connecting to ${origin}
|
|
|
5850
5963
|
`
|
|
5851
5964
|
Your steps:
|
|
5852
5965
|
1) Open: ${info.verificationUrl}
|
|
5853
|
-
2) Enter code: ${info.userCode} (expires in ${String(minutes)} minutes)
|
|
5966
|
+
2) Enter code: ${emphasise(info.userCode, terminalContext())} (expires in ${String(minutes)} minutes)
|
|
5854
5967
|
3) Check the screen shows this device's fingerprint, then approve:
|
|
5855
5968
|
|
|
5856
5969
|
${fingerprint3(deviceIdentity.identity)}
|
|
@@ -6077,6 +6190,9 @@ async function runLoop(paths, origins, io, signal, supervised = !process.stdout.
|
|
|
6077
6190
|
// write a count from one attempt, which says nothing about how the
|
|
6078
6191
|
// daemon that actually runs is getting on.
|
|
6079
6192
|
healthPath: paths.health,
|
|
6193
|
+
// Written whenever it changes, not only at start — S2. `byollm status`
|
|
6194
|
+
// is a different process and this file is the whole of what reaches it.
|
|
6195
|
+
onServiceStates: (states) => writeServiceStates(paths.serviceStates, states),
|
|
6080
6196
|
identity: {
|
|
6081
6197
|
keys: () => identity.load(Date.now()),
|
|
6082
6198
|
// What was on disk. The runner replaces it from each heartbeat and
|
|
@@ -6913,7 +7029,7 @@ async function exists(path) {
|
|
|
6913
7029
|
}
|
|
6914
7030
|
|
|
6915
7031
|
// src/index.ts
|
|
6916
|
-
var DAEMON_VERSION = "0.1.0-alpha.
|
|
7032
|
+
var DAEMON_VERSION = "0.1.0-alpha.76";
|
|
6917
7033
|
function daemonVersion() {
|
|
6918
7034
|
return {
|
|
6919
7035
|
daemon: DAEMON_VERSION,
|
|
@@ -6965,4 +7081,4 @@ export {
|
|
|
6965
7081
|
runCli,
|
|
6966
7082
|
main
|
|
6967
7083
|
};
|
|
6968
|
-
//# sourceMappingURL=chunk-
|
|
7084
|
+
//# sourceMappingURL=chunk-MSRBBLRQ.js.map
|