byollm 0.1.0-alpha.77 → 0.1.0-alpha.78

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  > [!WARNING]
2
- > **Alpha (`0.1.0-alpha.77`) — under active development. Don't use this yet.**
2
+ > **Alpha (`0.1.0-alpha.78`) — under active development. Don't use this yet.**
3
3
  >
4
4
  > Install it deliberately: `npx byollm@alpha`, or `npm install byollm@alpha`.
5
5
  >
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-QA5S2SQF.js";
4
+ } from "./chunk-ZROCDZDA.js";
5
5
 
6
6
  // src/bin.ts
7
7
  process.exitCode = await main(process.argv.slice(2));
@@ -3598,6 +3598,7 @@ function joinSections(sections) {
3598
3598
  }
3599
3599
 
3600
3600
  // src/runner.ts
3601
+ var AUTH_RECHECK_MS = 6e4;
3601
3602
  var DEFAULT_HEARTBEAT_MS = 1e4;
3602
3603
  function sameKey(a, b) {
3603
3604
  return a.identity === b.identity && a.encryption === b.encryption && a.encryptionSig === b.encryptionSig;
@@ -3668,6 +3669,8 @@ var Runner = class {
3668
3669
  #blockedReport = /* @__PURE__ */ new Map();
3669
3670
  /** Signed-out services' reports, kept for the same reason blocked ones are. */
3670
3671
  #withdrawnReport = /* @__PURE__ */ new Map();
3672
+ /** Earliest moment each withdrawn service may be asked again — T2-S1. */
3673
+ #authRecheckAt = /* @__PURE__ */ new Map();
3671
3674
  /** What was last handed to the writer, so an unchanged pass writes nothing. */
3672
3675
  #lastWritten;
3673
3676
  /**
@@ -3783,9 +3786,27 @@ var Runner = class {
3783
3786
  const probed = /* @__PURE__ */ new Map();
3784
3787
  for (const route of this.#options.loaded.routes) {
3785
3788
  if (this.#unauthenticated.has(route.service)) {
3786
- const kept = this.#withdrawnReport.get(route.service);
3787
- if (kept !== void 0) this.serviceStates.set(route.service, kept);
3788
- continue;
3789
+ const recheckAt = this.#authRecheckAt.get(route.service) ?? 0;
3790
+ const backend = this.#backendFor(route);
3791
+ const lifted = this.#now() >= recheckAt && backend.canary !== void 0 && (await backend.canary(route.model)).healthy;
3792
+ if (!lifted) {
3793
+ if (this.#now() >= recheckAt) {
3794
+ this.#authRecheckAt.set(
3795
+ route.service,
3796
+ this.#now() + AUTH_RECHECK_MS
3797
+ );
3798
+ }
3799
+ const kept = this.#withdrawnReport.get(route.service);
3800
+ if (kept !== void 0) this.serviceStates.set(route.service, kept);
3801
+ continue;
3802
+ }
3803
+ this.#unauthenticated.delete(route.service);
3804
+ this.#withdrawnReport.delete(route.service);
3805
+ this.#authRecheckAt.delete(route.service);
3806
+ this.#options.onEvent?.({
3807
+ type: "service-signed-in",
3808
+ service: route.service
3809
+ });
3789
3810
  }
3790
3811
  const blockedUntil = this.#blocked.get(route.service);
3791
3812
  if (this.#blocked.has(route.service)) {
@@ -4567,6 +4588,20 @@ var Runner = class {
4567
4588
  }
4568
4589
  const fetched = await this.#fetchWhenSealed(job);
4569
4590
  if (!fetched) return;
4591
+ if ("gone" in fetched) {
4592
+ this.#options.onEvent?.({
4593
+ type: "error",
4594
+ message: `${job.id} is not ours to run: ${fetched.gone}`
4595
+ });
4596
+ await this.#safely(
4597
+ () => this.#options.client.release({
4598
+ runnerId: this.#options.runnerId,
4599
+ leases: [{ jobId: job.id, leaseId: job.lease.id }],
4600
+ reason: "refused"
4601
+ })
4602
+ );
4603
+ return;
4604
+ }
4570
4605
  const payload = await this.#openPayload(job, fetched.envelope);
4571
4606
  const resolved = job.grant?.service;
4572
4607
  const route = this.#routeFor(job.kind, resolved);
@@ -4662,6 +4697,28 @@ var Runner = class {
4662
4697
  * the job up quietly — the upstream's `awaiting-payload` timer will requeue
4663
4698
  * it, and the stub was never lost.
4664
4699
  */
4700
+ /**
4701
+ * Wait for the payload, or say the job is over for this device — B038.
4702
+ *
4703
+ * The stuck-daemon loop, reported live on a real user's Windows machine: a
4704
+ * claimed job came back "unknown job", the daemon abandoned it **without
4705
+ * releasing the lease**, the hub re-offered it, and the same daemon
4706
+ * re-claimed the same id every twenty seconds forever. The log spammed
4707
+ * claim, unknown job, reclaim; the device looked wedged while fresh jobs on
4708
+ * a live site still ran fine.
4709
+ *
4710
+ * Both exits leaked. A terminal error threw straight out of `#handle` into
4711
+ * the background `catch`, and the give-up-at-deadline path returned `null`
4712
+ * into `if (!fetched) return`. Neither released anything, and the comment on
4713
+ * that `catch` explains why nobody noticed: letting the lease lapse *is*
4714
+ * the recovery the protocol is built around — for a transient failure. For
4715
+ * a permanent one it is an invitation to be offered the same job again.
4716
+ *
4717
+ * So this reports *why* it stopped instead of throwing, and the caller
4718
+ * releases. `refused` is the shape the relay already has for exactly this:
4719
+ * a permanent decline, which means the job is never offered to this device
4720
+ * again. Nothing new on the wire.
4721
+ */
4665
4722
  async #fetchWhenSealed(job) {
4666
4723
  const deadline = Math.min(job.lease.expiresAt, this.#now() + 3e4);
4667
4724
  let delay = 50;
@@ -4674,13 +4731,18 @@ var Runner = class {
4674
4731
  });
4675
4732
  } catch (error) {
4676
4733
  const notReady = error instanceof ClientError && error.kind === "not-ready";
4677
- if (!notReady) throw error;
4734
+ if (!notReady) {
4735
+ if (error instanceof ClientError && error.kind === "rejected") {
4736
+ return { gone: error.message };
4737
+ }
4738
+ throw error;
4739
+ }
4678
4740
  if (this.#now() + delay >= deadline) {
4679
4741
  this.#options.onEvent?.({
4680
4742
  type: "error",
4681
4743
  message: `gave up waiting for the payload of ${job.id}`
4682
4744
  });
4683
- return null;
4745
+ return { gone: `the payload never arrived for ${job.id}` };
4684
4746
  }
4685
4747
  await new Promise((resolve) => setTimeout(resolve, delay));
4686
4748
  delay = Math.min(delay * 2, 1e3);
@@ -6336,6 +6398,12 @@ function report(origin, event, io) {
6336
6398
  `${at} ${host} ${event.service} is not signed in \u2014 it has stopped taking work.
6337
6399
  ${event.detail}
6338
6400
  Sign in with that tool, then restart: \`byollm run\` re-checks on start.
6401
+ `
6402
+ );
6403
+ break;
6404
+ case "service-signed-in":
6405
+ io.err(
6406
+ `${at} ${host} ${event.service} is signed in again \u2014 it is taking work.
6339
6407
  `
6340
6408
  );
6341
6409
  break;
@@ -7048,7 +7116,7 @@ async function exists(path) {
7048
7116
  }
7049
7117
 
7050
7118
  // src/index.ts
7051
- var DAEMON_VERSION = "0.1.0-alpha.77";
7119
+ var DAEMON_VERSION = "0.1.0-alpha.78";
7052
7120
  function daemonVersion() {
7053
7121
  return {
7054
7122
  daemon: DAEMON_VERSION,
@@ -7100,4 +7168,4 @@ export {
7100
7168
  runCli,
7101
7169
  main
7102
7170
  };
7103
- //# sourceMappingURL=chunk-QA5S2SQF.js.map
7171
+ //# sourceMappingURL=chunk-ZROCDZDA.js.map