@cmmd-center/forge 0.13.73 → 0.13.75

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/bin.cjs CHANGED
@@ -66275,7 +66275,7 @@ function normalizeNumberish(value) {
66275
66275
  }
66276
66276
  //#endregion
66277
66277
  //#region package.json
66278
- var version$1 = "0.13.73";
66278
+ var version$1 = "0.13.75";
66279
66279
  //#endregion
66280
66280
  //#region src/sentry.ts
66281
66281
  const SERVER_APP_NAME = "forge-server";
@@ -68360,7 +68360,8 @@ const OAuthTokenExchangeInput = require_Schema$1.Struct({
68360
68360
  const CommandOAuthTokenInput = require_Schema$1.Struct({
68361
68361
  grant_type: require_Schema$1.String,
68362
68362
  device_code: require_Schema$1.String,
68363
- client_id: require_Schema$1.String
68363
+ client_id: require_Schema$1.String,
68364
+ pop_public_key: require_Schema$1.optionalKey(require_Schema$1.String)
68364
68365
  });
68365
68366
  const CommandPasswordTokenInput = require_Schema$1.Struct({
68366
68367
  email: require_Schema$1.String,
@@ -69003,7 +69004,8 @@ const authCmmdOAuthTokenRouteLayer = add$1("POST", "/api/auth/cmmd-oauth/token",
69003
69004
  return yield* proxyCmmdOAuthRequest("/api/mcp-server/oauth/token", {
69004
69005
  client_id: payload.client_id,
69005
69006
  grant_type: payload.grant_type,
69006
- device_code: payload.device_code
69007
+ device_code: payload.device_code,
69008
+ ...payload.pop_public_key ? { pop_public_key: payload.pop_public_key } : {}
69007
69009
  });
69008
69010
  }).pipe(require_Schema$1.catchTag("AuthError", (error) => respondToAuthError(error))));
69009
69011
  /**
@@ -241692,17 +241694,30 @@ function isPromiseLike(value) {
241692
241694
  * outlives the delete re-acquires the hold on its next tick; that was
241693
241695
  * previously measured leaking 37 renewals over 18 minutes, pinning a sprite
241694
241696
  * running — and billing — 33 minutes after its work had ended.
241695
- * 2. Stopping the interval only cancels FUTURE ticks. A PUT already on the wire
241696
- * must be JOINED before the DELETE, or it lands afterwards and recreates the
241697
- * hold for another full expiry window. fly.io's reference worker cancels and
241698
- * awaits its heartbeat for the same reason.
241697
+ * 2. Cancellation must be CONFIRMED before the final DELETE is trusted. A PUT
241698
+ * already on the wire has to settle first, or the DELETE can land mid-PUT
241699
+ * and the PUT recreate the hold for another full expiry window; fly.io's
241700
+ * reference worker cancels and awaits its heartbeat for the same reason.
241701
+ * The join is bounded on the shutdown path
241702
+ * (SPRITE_TASK_HOLD_RELEASE_JOIN_TIMEOUT_MS) and the bound decides the
241703
+ * shape: every PUT settled within it, with no earlier PUT rejection left
241704
+ * unanswered by a clean refresh, confirms cancellation and one DELETE
241705
+ * finishes the hold; the bound firing first means cancellation cannot be
241706
+ * confirmed, so the release sweeps, DELETE, verify with a bounded GET, and
241707
+ * re-DELETE while the server still shows the hold, capped at
241708
+ * SPRITE_TASK_HOLD_SWEEP_ROUNDS rounds. Every hold gets at least one
241709
+ * DELETE, a resurrected hold is cleaned and swept again, and only a hold
241710
+ * positively present after the cap is reported unreleased at warn instead
241711
+ * of hanging SIGTERM open.
241699
241712
  * 3. `release` can arrive while `acquire` is still awaiting its own PUT —
241700
241713
  * `releaseAll` runs from runtime drain and the shutdown finalizer,
241701
241714
  * concurrently with the provider event stream. The hold is registered before
241702
- * that await (so a duplicate turn.started cannot double-acquire), so release
241703
- * can remove the map entry first; `acquire` must then NOT install a
241704
- * refresher. One attached to an unmapped hold is unreachable by release,
241705
- * releaseThread and releaseAll alike, and re-PUTs every 60 s for the life of
241715
+ * that await (so a duplicate turn.started cannot double-acquire), and while
241716
+ * a release runs the hold stays mapped (joining, then deleting), so the
241717
+ * shutdown finalizer's bounded `releaseAll` can take a parked hold over;
241718
+ * `acquire` must then NOT install a refresher on the old hold, and a fresh
241719
+ * acquire replaces a released hold in the map. One refresher attached to a
241720
+ * hold no release path can reach would re-PUT every 60 s for the life of
241706
241721
  * the process — an unbounded pin.
241707
241722
  *
241708
241723
  * All three are pinned by tests.
@@ -241726,6 +241741,30 @@ const SPRITE_TASK_HOLD_REFRESH_MS = 6e4;
241726
241741
  */
241727
241742
  const SPRITE_TASK_HOLD_REQUEST_TIMEOUT_MS = 1e4;
241728
241743
  /**
241744
+ * Shutdown bounds for the release the server finalizer issues. Both are one
241745
+ * request deadline. With a transport that honors its abort, every PUT still on
241746
+ * the wire settles within its own 10 s deadline, so a join sized at one
241747
+ * deadline always completes, cancellation is confirmed, and a single DELETE is
241748
+ * issued; the DELETE answers within its own deadline too.
241749
+ *
241750
+ * When the join bound fires, cancellation is unconfirmed and the release
241751
+ * sweeps: DELETE, verify with a bounded GET, and re-DELETE if the hold
241752
+ * survived, capped at SPRITE_TASK_HOLD_SWEEP_ROUNDS rounds. Worst case a
241753
+ * shutdown release costs join + 2 x (delete + verify), about 50 s, after
241754
+ * which the process exits and any hold left behind expires on its own within
241755
+ * 5 minutes. Drain passes no bounds. It keeps the full join, and its tick is
241756
+ * already capped by the heartbeat timeout.
241757
+ */
241758
+ const SPRITE_TASK_HOLD_RELEASE_JOIN_TIMEOUT_MS = SPRITE_TASK_HOLD_REQUEST_TIMEOUT_MS;
241759
+ const SPRITE_TASK_HOLD_RELEASE_DELETE_TIMEOUT_MS = SPRITE_TASK_HOLD_REQUEST_TIMEOUT_MS;
241760
+ /**
241761
+ * How many delete-plus-verify rounds an unconfirmed release sweeps before it
241762
+ * gives up and reports the hold unreleased. Two is one retry past the first
241763
+ * delete: enough to clean a timed-out PUT that commits late, cheap enough
241764
+ * that a truly wedged socket cannot hold SIGTERM open much past a minute.
241765
+ */
241766
+ const SPRITE_TASK_HOLD_SWEEP_ROUNDS = 2;
241767
+ /**
241729
241768
  * Resolve the hold configuration from the process environment.
241730
241769
  *
241731
241770
  * Returns null on every runtime that is not a project sprite — desktop-local and
@@ -241747,6 +241786,20 @@ function resolveSpriteTaskHoldConfig(env = process.env) {
241747
241786
  function spriteTaskHoldName(namePrefix, turnId) {
241748
241787
  return `${namePrefix}${turnId}`;
241749
241788
  }
241789
+ const noTimer = () => {};
241790
+ /**
241791
+ * Resolve with `promise`, but stop waiting after `timeoutMs`. Rejections pass
241792
+ * through untouched, and the caller decides what a timeout means. The
241793
+ * underlying operation keeps running either way.
241794
+ */
241795
+ function boundedAwait(promise, timeoutMs) {
241796
+ if (timeoutMs === void 0) return promise;
241797
+ let clearTimer = noTimer;
241798
+ return Promise.race([promise, new Promise((resolve) => {
241799
+ const timer = setTimeout(resolve, timeoutMs);
241800
+ clearTimer = () => clearTimeout(timer);
241801
+ })]).finally(() => clearTimer());
241802
+ }
241750
241803
  const DEFAULT_TIMER = {
241751
241804
  setInterval: (handler, ms) => setInterval(handler, ms),
241752
241805
  clearInterval: (handle) => {
@@ -241782,7 +241835,8 @@ var SpriteTaskHoldManager = class {
241782
241835
  * whose turn may never start. When the budget is spent the hold releases itself.
241783
241836
  */
241784
241837
  async acquire(turnId, threadId = null, options = {}) {
241785
- if (this.#holds.has(turnId)) return;
241838
+ const existing = this.#holds.get(turnId);
241839
+ if (existing !== void 0 && !existing.released) return;
241786
241840
  let refreshesLeft = options.maxRefreshes ?? Number.POSITIVE_INFINITY;
241787
241841
  const name = spriteTaskHoldName(this.#config.namePrefix, turnId);
241788
241842
  const hold = {
@@ -241790,15 +241844,21 @@ var SpriteTaskHoldManager = class {
241790
241844
  threadId,
241791
241845
  refresher: null,
241792
241846
  inFlight: /* @__PURE__ */ new Set(),
241793
- released: false
241847
+ released: false,
241848
+ phase: "idle",
241849
+ releaseAttempt: null,
241850
+ deletion: null,
241851
+ uncertainPut: false
241794
241852
  };
241795
241853
  this.#holds.set(turnId, hold);
241796
241854
  const put = this.#transport.put(name, 300);
241797
- const tracked = put.then(() => {}, () => {});
241855
+ const tracked = put.then(() => "succeeded", () => "failed");
241798
241856
  hold.inFlight.add(tracked);
241799
241857
  try {
241800
241858
  await put;
241859
+ hold.uncertainPut = false;
241801
241860
  } catch (cause) {
241861
+ hold.uncertainPut = true;
241802
241862
  hold.inFlight.delete(tracked);
241803
241863
  this.#onError(`failed to acquire sprite task hold for turn ${turnId}`, cause);
241804
241864
  if (hold.released || this.#holds.get(turnId) !== hold) return;
@@ -241812,28 +241872,189 @@ var SpriteTaskHoldManager = class {
241812
241872
  return;
241813
241873
  }
241814
241874
  refreshesLeft -= 1;
241815
- const refresh = this.#transport.put(name, 300).catch((cause) => this.#onError(`failed to refresh sprite task hold for turn ${turnId}`, cause));
241875
+ const refresh = this.#transport.put(name, 300).then(() => {
241876
+ hold.uncertainPut = false;
241877
+ return "succeeded";
241878
+ }, (cause) => {
241879
+ hold.uncertainPut = true;
241880
+ this.#onError(`failed to refresh sprite task hold for turn ${turnId}`, cause);
241881
+ return "failed";
241882
+ });
241816
241883
  hold.inFlight.add(refresh);
241817
241884
  refresh.finally(() => hold.inFlight.delete(refresh));
241818
241885
  }, SPRITE_TASK_HOLD_REFRESH_MS);
241819
241886
  }
241820
- async release(turnId) {
241887
+ /**
241888
+ * Release one hold.
241889
+ *
241890
+ * Cancellation must be confirmed before a single DELETE is trusted: every
241891
+ * PUT on the wire has to settle successfully, or the DELETE can land mid-PUT
241892
+ * and the PUT re-create the hold behind it. With a join bound (shutdown),
241893
+ * PUTs that do not settle within the bound, or settle as rejections, make
241894
+ * the attempt sweep instead: DELETE, verify, re-DELETE while the server
241895
+ * still shows the hold, capped at two rounds. The fate outlives the PUT's
241896
+ * settlement: a PUT that rejected before the release began, with no
241897
+ * successful refresh after it, sweeps too. Without a bound (drain,
241898
+ * per-turn release) the join is patient and never gives up, though a PUT
241899
+ * that rejects still routes the release through the sweep.
241900
+ *
241901
+ * While an attempt runs, the hold stays in the map in its joining or
241902
+ * deleting phase, so shutdown can see it. A bounded (shutdown) caller takes
241903
+ * a parked hold over with its own bounded pass; a hold already in its
241904
+ * deleting phase is skipped, because its single deletion is already in
241905
+ * flight. Unbounded duplicate callers join the running attempt instead.
241906
+ */
241907
+ async release(turnId, options = {}) {
241821
241908
  const hold = this.#holds.get(turnId);
241822
- if (!hold) return;
241909
+ if (!hold) return "released";
241910
+ if (hold.phase === "deleting") return "released";
241911
+ const bounded = options.joinTimeoutMs !== void 0;
241912
+ if (hold.releaseAttempt !== null) {
241913
+ if (!bounded) return hold.releaseAttempt;
241914
+ return this.#concludeRelease(hold, turnId, options);
241915
+ }
241823
241916
  hold.released = true;
241824
241917
  if (hold.refresher !== null) {
241825
241918
  this.#timer.clearInterval(hold.refresher);
241826
241919
  hold.refresher = null;
241827
241920
  }
241828
- this.#holds.delete(turnId);
241829
- if (hold.inFlight.size > 0) await Promise.all(hold.inFlight);
241921
+ hold.phase = "joining";
241922
+ const attempt = (async () => {
241923
+ const outcome = await this.#concludeRelease(hold, turnId, options);
241924
+ if (outcome === "unreleased") {
241925
+ hold.phase = "idle";
241926
+ this.#removeIfCurrent(turnId, hold);
241927
+ }
241928
+ return outcome;
241929
+ })();
241930
+ hold.releaseAttempt = attempt;
241931
+ try {
241932
+ return await attempt;
241933
+ } finally {
241934
+ if (hold.releaseAttempt === attempt) hold.releaseAttempt = null;
241935
+ }
241936
+ }
241937
+ /**
241938
+ * Drive one release attempt to its outcome. On the confirmed path (every
241939
+ * PUT on the wire settled within the join bound) a single DELETE finishes
241940
+ * the hold. On the unconfirmed path cancellation is unknown, so the hold
241941
+ * is swept: DELETE, verify, and re-DELETE while the server still shows it,
241942
+ * capped. Shared by the first attempt and a shutdown takeover: whichever
241943
+ * caller first reaches its verdict installs the hold's single deletion
241944
+ * promise and the rest join it, so the DELETE or sweep is issued once and
241945
+ * concurrent callers report the same outcome.
241946
+ */
241947
+ async #concludeRelease(hold, turnId, options) {
241948
+ const verdict = await this.#confirmCancellation(hold, options.joinTimeoutMs);
241949
+ if (hold.deletion !== null) return hold.deletion;
241950
+ hold.phase = "deleting";
241951
+ const deletion = verdict === "confirmed" ? this.#deleteConfirmed(hold, turnId, options) : this.#sweepUnconfirmed(hold, turnId, options);
241952
+ hold.deletion = deletion;
241953
+ return deletion;
241954
+ }
241955
+ /**
241956
+ * The confirmed-path deletion: every PUT on the wire settled cleanly, so
241957
+ * one DELETE finishes the hold. A rejected DELETE is logged, never thrown;
241958
+ * the hold still leaves the map and expires on its own server-side.
241959
+ */
241960
+ async #deleteConfirmed(hold, turnId, options) {
241961
+ await this.#issueDelete(hold, options.deleteTimeoutMs, turnId);
241962
+ this.#removeIfCurrent(turnId, hold);
241963
+ return "released";
241964
+ }
241965
+ /**
241966
+ * Best-effort cleanup for a hold whose cancellation is uncertain: the join
241967
+ * bound fired with a PUT unsettled, or a PUT rejected after possibly being
241968
+ * processed server-side. The hold is owed its delete either way. Each round
241969
+ * is a bounded DELETE followed by a bounded GET; a verify that still shows
241970
+ * the hold (the timed-out PUT committed after our delete, or the delete
241971
+ * never landed) triggers the next round. Verification is best-effort too:
241972
+ * "absent" proves cleanup, "unknown" proves nothing and cannot by itself
241973
+ * report the hold unreleased, so after the cap an unverifiable hold is
241974
+ * reported released-with-its-delete while a positively present one is
241975
+ * reported unreleased at warn. Either way the hold expires on its own
241976
+ * within 300 s. Only `#concludeRelease` starts this, after it has already
241977
+ * moved the hold into its deleting phase.
241978
+ */
241979
+ async #sweepUnconfirmed(hold, turnId, options) {
241980
+ for (let round = 1; round <= SPRITE_TASK_HOLD_SWEEP_ROUNDS; round += 1) {
241981
+ await this.#issueDelete(hold, options.deleteTimeoutMs, turnId);
241982
+ const state = await this.#verifyHold(hold, options.deleteTimeoutMs, turnId);
241983
+ const last = round === SPRITE_TASK_HOLD_SWEEP_ROUNDS;
241984
+ if (state === "absent") {
241985
+ this.#removeIfCurrent(turnId, hold);
241986
+ return "released";
241987
+ }
241988
+ if (state === "present") {
241989
+ this.#onError(`sprite task hold for turn ${turnId} was still present after delete (sweep ${round}/${SPRITE_TASK_HOLD_SWEEP_ROUNDS})`, "a refresh PUT that ignored its abort appears to have committed after the delete");
241990
+ if (last) {
241991
+ this.#onError(`sprite task hold for turn ${turnId} was left unreleased: still present after ${SPRITE_TASK_HOLD_SWEEP_ROUNDS} delete+verify sweeps, expires on its own`, "hold survived the full shutdown sweep");
241992
+ this.#removeIfCurrent(turnId, hold);
241993
+ return "unreleased";
241994
+ }
241995
+ continue;
241996
+ }
241997
+ this.#onError(`sprite task hold for turn ${turnId} could not be verified after delete (sweep ${round}/${SPRITE_TASK_HOLD_SWEEP_ROUNDS})`, "hold state unverifiable");
241998
+ if (last) {
241999
+ this.#removeIfCurrent(turnId, hold);
242000
+ return "released";
242001
+ }
242002
+ }
242003
+ return "released";
242004
+ }
242005
+ /**
242006
+ * Ask the transport whether the hold still exists. No transport `get`, a
242007
+ * rejection, or a bound that fires all come back "unknown": the sweep has
242008
+ * no evidence, and never invents it.
242009
+ */
242010
+ async #verifyHold(hold, timeoutMs, turnId) {
242011
+ const get = this.#transport.get;
242012
+ if (!get) return "unknown";
242013
+ try {
242014
+ return await boundedAwait(get(hold.name), timeoutMs);
242015
+ } catch (cause) {
242016
+ this.#onError(`failed to verify sprite task hold for turn ${turnId}`, cause);
242017
+ return "unknown";
242018
+ }
242019
+ }
242020
+ /**
242021
+ * Wait for every PUT on the wire to settle and report whether cancellation
242022
+ * is confirmed. Only a clean success confirms: a PUT that REJECTED is
242023
+ * uncertain, because the server may have processed the request before the
242024
+ * failure surfaced, and a DELETE trusted after it could be raced by the
242025
+ * hold it re-created. `inFlight` forgets each PUT once it settles, so a
242026
+ * rejection that settled before the release even started is read from
242027
+ * `uncertainPut` instead, and stays uncertain until some later PUT
242028
+ * succeeds. With no bound the wait is patient; unbounded callers
242029
+ * (drain, per-turn release) trade shutdown speed for the certainty.
242030
+ */
242031
+ async #confirmCancellation(hold, timeoutMs) {
242032
+ if (hold.inFlight.size === 0) return hold.uncertainPut ? "uncertain" : "confirmed";
242033
+ const settled = Promise.all(hold.inFlight).then((fates) => fates.every((fate) => fate === "succeeded") && !hold.uncertainPut ? "confirmed" : "uncertain");
242034
+ if (timeoutMs === void 0) return settled;
242035
+ let clearTimer = noTimer;
242036
+ return Promise.race([settled, new Promise((resolve) => {
242037
+ const timer = setTimeout(() => resolve("uncertain"), timeoutMs);
242038
+ clearTimer = () => clearTimeout(timer);
242039
+ })]).finally(() => clearTimer());
242040
+ }
242041
+ /** Issue the DELETE, reporting (never throwing) a failure. */
242042
+ async #issueDelete(hold, deleteTimeoutMs, turnId) {
241830
242043
  try {
241831
- await this.#transport.delete(hold.name);
242044
+ await boundedAwait(this.#transport.delete(hold.name), deleteTimeoutMs);
241832
242045
  } catch (cause) {
241833
242046
  this.#onError(`failed to release sprite task hold for turn ${turnId}`, cause);
241834
242047
  }
241835
242048
  }
241836
242049
  /**
242050
+ * Drop the map entry only if this attempt's hold still owns the id: a newer
242051
+ * acquire may have replaced it while the release was awaiting, and deleting
242052
+ * by key alone would evict the replacement.
242053
+ */
242054
+ #removeIfCurrent(turnId, hold) {
242055
+ if (this.#holds.get(turnId) === hold) this.#holds.delete(turnId);
242056
+ }
242057
+ /**
241837
242058
  * Release every hold belonging to one thread.
241838
242059
  *
241839
242060
  * `session.exited` names only the thread whose provider process died, and a
@@ -241848,9 +242069,22 @@ var SpriteTaskHoldManager = class {
241848
242069
  /**
241849
242070
  * Release everything. Runtime drain and server shutdown must call this, or a
241850
242071
  * drained sprite keeps billing until each hold expires.
242072
+ *
242073
+ * Shutdown passes `SPRITE_TASK_HOLD_RELEASE_JOIN_TIMEOUT_MS` /
242074
+ * `SPRITE_TASK_HOLD_RELEASE_DELETE_TIMEOUT_MS` so a socket that never
242075
+ * settles cannot hang the process open past its own termination, and gets a
242076
+ * per-hold report back: every hold gets its DELETE, and only holds the
242077
+ * sweep still saw present after the full delete+verify cap come back
242078
+ * unreleased, left to their own 300 s expiry. Drain passes no bounds and
242079
+ * keeps the patient join.
241851
242080
  */
241852
- async releaseAll() {
241853
- await Promise.all([...this.#holds.keys()].map((turnId) => this.release(turnId)));
242081
+ async releaseAll(options = {}) {
242082
+ const turnIds = [...this.#holds.keys()];
242083
+ const outcomes = await Promise.all(turnIds.map(async (turnId) => [turnId, await this.release(turnId, options)]));
242084
+ return {
242085
+ released: outcomes.filter(([, outcome]) => outcome === "released").map(([turnId]) => turnId),
242086
+ unreleased: outcomes.filter(([, outcome]) => outcome === "unreleased").map(([turnId]) => turnId)
242087
+ };
241854
242088
  }
241855
242089
  };
241856
242090
  /**
@@ -241881,7 +242115,25 @@ function makeSpriteTaskHoldTransport(config, fetchImpl = fetch) {
241881
242115
  headers: { "content-type": "application/json" },
241882
242116
  body: JSON.stringify({ expire: `${expireSeconds}s` })
241883
242117
  }),
241884
- delete: (name) => call(`/${encodeURIComponent(name)}`, { method: "DELETE" })
242118
+ delete: (name) => call(`/${encodeURIComponent(name)}`, { method: "DELETE" }),
242119
+ get: async (name) => {
242120
+ const controller = new AbortController();
242121
+ const deadline = setTimeout(() => controller.abort(), SPRITE_TASK_HOLD_REQUEST_TIMEOUT_MS);
242122
+ try {
242123
+ const response = await fetchImpl(`http://sprite/v1/tasks/${encodeURIComponent(name)}`, {
242124
+ method: "GET",
242125
+ signal: controller.signal,
242126
+ unix: config.socketPath
242127
+ });
242128
+ if (response.ok) return "present";
242129
+ if (response.status === 404) return "absent";
242130
+ return "unknown";
242131
+ } catch {
242132
+ return "unknown";
242133
+ } finally {
242134
+ clearTimeout(deadline);
242135
+ }
242136
+ }
241885
242137
  };
241886
242138
  }
241887
242139
  /**
@@ -286476,10 +286728,10 @@ const AgentBrowserManagerLive = require_Schema$1.effect(BrowserManager, require_
286476
286728
  mediaSourceFactory: displayCaptureRuntime.mediaSourceFactory,
286477
286729
  taskHold: displayTaskHoldManager ? {
286478
286730
  acquire: (holdId) => displayTaskHoldManager.acquire(holdId),
286479
- release: (holdId) => displayTaskHoldManager.release(holdId)
286731
+ release: (holdId) => displayTaskHoldManager.release(holdId).then(() => {})
286480
286732
  } : void 0
286481
286733
  });
286482
- yield* require_Schema$1.addFinalizer(() => require_Schema$1.promise(() => displayTaskHoldManager?.releaseAll() ?? Promise.resolve()));
286734
+ yield* require_Schema$1.addFinalizer(() => require_Schema$1.promise(() => displayTaskHoldManager?.releaseAll().then(() => {}) ?? Promise.resolve()));
286483
286735
  const baseBackendOptions = displayCaptureRuntime.backendOptions;
286484
286736
  const sessionInitialUrls = /* @__PURE__ */ new Map();
286485
286737
  let runtimeBuild = null;
@@ -294456,6 +294708,19 @@ const make$6 = require_Schema$1.gen(function* () {
294456
294708
  const manager = makeSpriteTaskHoldManager(process.env, (message, cause) => {
294457
294709
  require_Schema$1.runFork(require_Schema$1.logWarning(message, { cause: cause instanceof Error ? cause.message : cause }));
294458
294710
  });
294711
+ /**
294712
+ * Run a manager call, or nothing on runtimes that are not sprites. One
294713
+ * null-guard for every caller: the releaseAll service and the shutdown
294714
+ * finalizer alike.
294715
+ */
294716
+ const onManager = (run) => require_Schema$1.promise(async () => {
294717
+ if (manager === null) return;
294718
+ await run(manager);
294719
+ });
294720
+ yield* require_Schema$1.addFinalizer(() => onManager((taskHolds) => taskHolds.releaseAll({
294721
+ joinTimeoutMs: SPRITE_TASK_HOLD_RELEASE_JOIN_TIMEOUT_MS,
294722
+ deleteTimeoutMs: SPRITE_TASK_HOLD_RELEASE_DELETE_TIMEOUT_MS
294723
+ })));
294459
294724
  const launchCallers = /* @__PURE__ */ new Map();
294460
294725
  const start = require_Schema$1.fn("start")(function* () {
294461
294726
  if (manager === null) return;
@@ -294472,12 +294737,12 @@ const make$6 = require_Schema$1.gen(function* () {
294472
294737
  if (event.type === "turn.completed") {
294473
294738
  const turnId = event.turnId;
294474
294739
  if (turnId === void 0) return require_Schema$1.void_;
294475
- return require_Schema$1.promise(() => manager.release(String(turnId)));
294740
+ return require_Schema$1.promise(() => manager.release(String(turnId)).then(() => {}));
294476
294741
  }
294477
294742
  if (event.type === "turn.aborted") {
294478
294743
  const turnId = event.turnId;
294479
294744
  if (turnId === void 0) return require_Schema$1.void_;
294480
- return require_Schema$1.promise(() => manager.release(String(turnId)));
294745
+ return require_Schema$1.promise(() => manager.release(String(turnId)).then(() => {}));
294481
294746
  }
294482
294747
  if (event.type === "session.exited") {
294483
294748
  launchCallers.delete(String(event.threadId));
@@ -294504,7 +294769,7 @@ const make$6 = require_Schema$1.gen(function* () {
294504
294769
  start,
294505
294770
  holdLaunch,
294506
294771
  releaseLaunch,
294507
- releaseAll: require_Schema$1.promise(() => manager === null ? Promise.resolve() : manager.releaseAll())
294772
+ releaseAll: onManager((taskHolds) => taskHolds.releaseAll())
294508
294773
  };
294509
294774
  });
294510
294775
  const SpriteTaskHoldReactorLive = require_Schema$1.effect(SpriteTaskHoldReactor, make$6);
@@ -298649,7 +298914,7 @@ function resolveBuildCommitFromEnv(env) {
298649
298914
  * environment descriptor down instead of reporting an honest "unknown".
298650
298915
  */
298651
298916
  function readBakedBuildCommit() {
298652
- return "9beb25327a2591f7938669b9014396e64c2bb674";
298917
+ return "56e2269e0c33f44c636004fc33f6c402fc8e59f4";
298653
298918
  }
298654
298919
  async function resolveServerBuildCommit(input) {
298655
298920
  if (isFullCommitSha(input.baked)) return input.baked;