@cmmd-center/forge 0.13.72 → 0.13.74

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