@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 +294 -29
- package/dist/bin.mjs +294 -29
- package/dist/client/assets/{DiffPanel-BEf3EXPK.js → DiffPanel-BuASe_Qh.js} +3 -3
- package/dist/client/assets/{DiffPanel.logic-Bw1O_6UU.js → DiffPanel.logic-D4uCCekM.js} +2 -2
- package/dist/client/assets/DiffPanelShell-BNlM5rgR.js +2534 -0
- package/dist/client/assets/{DiffWorkerPoolProvider-C5Ln-c7Y.js → DiffWorkerPoolProvider-DoEMfBXZ.js} +9 -9
- package/dist/client/assets/PullRequestCodePanel-Cuxhtgiu.js +5 -0
- package/dist/client/assets/{Virtualizer-B4jYnrUE.js → Virtualizer-D7RZbEUD.js} +2 -2
- package/dist/client/assets/index-AOjJdR-y.js +153 -0
- package/dist/client/index.html +4 -4
- package/dist/forge-build.json +1 -1
- package/package.json +1 -1
- package/dist/client/assets/DiffPanelShell-BoAQcVta.js +0 -2533
- package/dist/client/assets/PullRequestCodePanel-Bx3me2lj.js +0 -5
- package/dist/client/assets/index-C2Y_gZoG.js +0 -153
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.
|
|
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.
|
|
241696
|
-
*
|
|
241697
|
-
* hold for another full expiry window
|
|
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),
|
|
241703
|
-
*
|
|
241704
|
-
*
|
|
241705
|
-
*
|
|
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
|
-
|
|
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).
|
|
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
|
-
|
|
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
|
-
|
|
241829
|
-
|
|
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
|
-
|
|
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:
|
|
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 "
|
|
298917
|
+
return "56e2269e0c33f44c636004fc33f6c402fc8e59f4";
|
|
298653
298918
|
}
|
|
298654
298919
|
async function resolveServerBuildCommit(input) {
|
|
298655
298920
|
if (isFullCommitSha(input.baked)) return input.baked;
|