@cmmd-center/forge 0.13.73 → 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.mjs CHANGED
@@ -65979,7 +65979,7 @@ function normalizeNumberish(value) {
65979
65979
  }
65980
65980
  //#endregion
65981
65981
  //#region package.json
65982
- var version$1 = "0.13.73";
65982
+ var version$1 = "0.13.74";
65983
65983
  //#endregion
65984
65984
  //#region src/sentry.ts
65985
65985
  const SERVER_APP_NAME = "forge-server";
@@ -241209,17 +241209,30 @@ function isPromiseLike(value) {
241209
241209
  * outlives the delete re-acquires the hold on its next tick; that was
241210
241210
  * previously measured leaking 37 renewals over 18 minutes, pinning a sprite
241211
241211
  * running — and billing — 33 minutes after its work had ended.
241212
- * 2. Stopping the interval only cancels FUTURE ticks. A PUT already on the wire
241213
- * must be JOINED before the DELETE, or it lands afterwards and recreates the
241214
- * hold for another full expiry window. fly.io's reference worker cancels and
241215
- * awaits its heartbeat for the same reason.
241212
+ * 2. Cancellation must be CONFIRMED before the final DELETE is trusted. A PUT
241213
+ * already on the wire has to settle first, or the DELETE can land mid-PUT
241214
+ * and the PUT recreate the hold for another full expiry window; fly.io's
241215
+ * reference worker cancels and awaits its heartbeat for the same reason.
241216
+ * The join is bounded on the shutdown path
241217
+ * (SPRITE_TASK_HOLD_RELEASE_JOIN_TIMEOUT_MS) and the bound decides the
241218
+ * shape: every PUT settled within it, with no earlier PUT rejection left
241219
+ * unanswered by a clean refresh, confirms cancellation and one DELETE
241220
+ * finishes the hold; the bound firing first means cancellation cannot be
241221
+ * confirmed, so the release sweeps, DELETE, verify with a bounded GET, and
241222
+ * re-DELETE while the server still shows the hold, capped at
241223
+ * SPRITE_TASK_HOLD_SWEEP_ROUNDS rounds. Every hold gets at least one
241224
+ * DELETE, a resurrected hold is cleaned and swept again, and only a hold
241225
+ * positively present after the cap is reported unreleased at warn instead
241226
+ * of hanging SIGTERM open.
241216
241227
  * 3. `release` can arrive while `acquire` is still awaiting its own PUT —
241217
241228
  * `releaseAll` runs from runtime drain and the shutdown finalizer,
241218
241229
  * concurrently with the provider event stream. The hold is registered before
241219
- * that await (so a duplicate turn.started cannot double-acquire), so release
241220
- * can remove the map entry first; `acquire` must then NOT install a
241221
- * refresher. One attached to an unmapped hold is unreachable by release,
241222
- * releaseThread and releaseAll alike, and re-PUTs every 60 s for the life of
241230
+ * that await (so a duplicate turn.started cannot double-acquire), and while
241231
+ * a release runs the hold stays mapped (joining, then deleting), so the
241232
+ * shutdown finalizer's bounded `releaseAll` can take a parked hold over;
241233
+ * `acquire` must then NOT install a refresher on the old hold, and a fresh
241234
+ * acquire replaces a released hold in the map. One refresher attached to a
241235
+ * hold no release path can reach would re-PUT every 60 s for the life of
241223
241236
  * the process — an unbounded pin.
241224
241237
  *
241225
241238
  * All three are pinned by tests.
@@ -241243,6 +241256,30 @@ const SPRITE_TASK_HOLD_REFRESH_MS = 6e4;
241243
241256
  */
241244
241257
  const SPRITE_TASK_HOLD_REQUEST_TIMEOUT_MS = 1e4;
241245
241258
  /**
241259
+ * Shutdown bounds for the release the server finalizer issues. Both are one
241260
+ * request deadline. With a transport that honors its abort, every PUT still on
241261
+ * the wire settles within its own 10 s deadline, so a join sized at one
241262
+ * deadline always completes, cancellation is confirmed, and a single DELETE is
241263
+ * issued; the DELETE answers within its own deadline too.
241264
+ *
241265
+ * When the join bound fires, cancellation is unconfirmed and the release
241266
+ * sweeps: DELETE, verify with a bounded GET, and re-DELETE if the hold
241267
+ * survived, capped at SPRITE_TASK_HOLD_SWEEP_ROUNDS rounds. Worst case a
241268
+ * shutdown release costs join + 2 x (delete + verify), about 50 s, after
241269
+ * which the process exits and any hold left behind expires on its own within
241270
+ * 5 minutes. Drain passes no bounds. It keeps the full join, and its tick is
241271
+ * already capped by the heartbeat timeout.
241272
+ */
241273
+ const SPRITE_TASK_HOLD_RELEASE_JOIN_TIMEOUT_MS = SPRITE_TASK_HOLD_REQUEST_TIMEOUT_MS;
241274
+ const SPRITE_TASK_HOLD_RELEASE_DELETE_TIMEOUT_MS = SPRITE_TASK_HOLD_REQUEST_TIMEOUT_MS;
241275
+ /**
241276
+ * How many delete-plus-verify rounds an unconfirmed release sweeps before it
241277
+ * gives up and reports the hold unreleased. Two is one retry past the first
241278
+ * delete: enough to clean a timed-out PUT that commits late, cheap enough
241279
+ * that a truly wedged socket cannot hold SIGTERM open much past a minute.
241280
+ */
241281
+ const SPRITE_TASK_HOLD_SWEEP_ROUNDS = 2;
241282
+ /**
241246
241283
  * Resolve the hold configuration from the process environment.
241247
241284
  *
241248
241285
  * Returns null on every runtime that is not a project sprite — desktop-local and
@@ -241264,6 +241301,20 @@ function resolveSpriteTaskHoldConfig(env = process.env) {
241264
241301
  function spriteTaskHoldName(namePrefix, turnId) {
241265
241302
  return `${namePrefix}${turnId}`;
241266
241303
  }
241304
+ const noTimer = () => {};
241305
+ /**
241306
+ * Resolve with `promise`, but stop waiting after `timeoutMs`. Rejections pass
241307
+ * through untouched, and the caller decides what a timeout means. The
241308
+ * underlying operation keeps running either way.
241309
+ */
241310
+ function boundedAwait(promise, timeoutMs) {
241311
+ if (timeoutMs === void 0) return promise;
241312
+ let clearTimer = noTimer;
241313
+ return Promise.race([promise, new Promise((resolve) => {
241314
+ const timer = setTimeout(resolve, timeoutMs);
241315
+ clearTimer = () => clearTimeout(timer);
241316
+ })]).finally(() => clearTimer());
241317
+ }
241267
241318
  const DEFAULT_TIMER = {
241268
241319
  setInterval: (handler, ms) => setInterval(handler, ms),
241269
241320
  clearInterval: (handle) => {
@@ -241299,7 +241350,8 @@ var SpriteTaskHoldManager = class {
241299
241350
  * whose turn may never start. When the budget is spent the hold releases itself.
241300
241351
  */
241301
241352
  async acquire(turnId, threadId = null, options = {}) {
241302
- if (this.#holds.has(turnId)) return;
241353
+ const existing = this.#holds.get(turnId);
241354
+ if (existing !== void 0 && !existing.released) return;
241303
241355
  let refreshesLeft = options.maxRefreshes ?? Number.POSITIVE_INFINITY;
241304
241356
  const name = spriteTaskHoldName(this.#config.namePrefix, turnId);
241305
241357
  const hold = {
@@ -241307,15 +241359,21 @@ var SpriteTaskHoldManager = class {
241307
241359
  threadId,
241308
241360
  refresher: null,
241309
241361
  inFlight: /* @__PURE__ */ new Set(),
241310
- released: false
241362
+ released: false,
241363
+ phase: "idle",
241364
+ releaseAttempt: null,
241365
+ deletion: null,
241366
+ uncertainPut: false
241311
241367
  };
241312
241368
  this.#holds.set(turnId, hold);
241313
241369
  const put = this.#transport.put(name, 300);
241314
- const tracked = put.then(() => {}, () => {});
241370
+ const tracked = put.then(() => "succeeded", () => "failed");
241315
241371
  hold.inFlight.add(tracked);
241316
241372
  try {
241317
241373
  await put;
241374
+ hold.uncertainPut = false;
241318
241375
  } catch (cause) {
241376
+ hold.uncertainPut = true;
241319
241377
  hold.inFlight.delete(tracked);
241320
241378
  this.#onError(`failed to acquire sprite task hold for turn ${turnId}`, cause);
241321
241379
  if (hold.released || this.#holds.get(turnId) !== hold) return;
@@ -241329,28 +241387,189 @@ var SpriteTaskHoldManager = class {
241329
241387
  return;
241330
241388
  }
241331
241389
  refreshesLeft -= 1;
241332
- const refresh = this.#transport.put(name, 300).catch((cause) => this.#onError(`failed to refresh sprite task hold for turn ${turnId}`, cause));
241390
+ const refresh = this.#transport.put(name, 300).then(() => {
241391
+ hold.uncertainPut = false;
241392
+ return "succeeded";
241393
+ }, (cause) => {
241394
+ hold.uncertainPut = true;
241395
+ this.#onError(`failed to refresh sprite task hold for turn ${turnId}`, cause);
241396
+ return "failed";
241397
+ });
241333
241398
  hold.inFlight.add(refresh);
241334
241399
  refresh.finally(() => hold.inFlight.delete(refresh));
241335
241400
  }, SPRITE_TASK_HOLD_REFRESH_MS);
241336
241401
  }
241337
- async release(turnId) {
241402
+ /**
241403
+ * Release one hold.
241404
+ *
241405
+ * Cancellation must be confirmed before a single DELETE is trusted: every
241406
+ * PUT on the wire has to settle successfully, or the DELETE can land mid-PUT
241407
+ * and the PUT re-create the hold behind it. With a join bound (shutdown),
241408
+ * PUTs that do not settle within the bound, or settle as rejections, make
241409
+ * the attempt sweep instead: DELETE, verify, re-DELETE while the server
241410
+ * still shows the hold, capped at two rounds. The fate outlives the PUT's
241411
+ * settlement: a PUT that rejected before the release began, with no
241412
+ * successful refresh after it, sweeps too. Without a bound (drain,
241413
+ * per-turn release) the join is patient and never gives up, though a PUT
241414
+ * that rejects still routes the release through the sweep.
241415
+ *
241416
+ * While an attempt runs, the hold stays in the map in its joining or
241417
+ * deleting phase, so shutdown can see it. A bounded (shutdown) caller takes
241418
+ * a parked hold over with its own bounded pass; a hold already in its
241419
+ * deleting phase is skipped, because its single deletion is already in
241420
+ * flight. Unbounded duplicate callers join the running attempt instead.
241421
+ */
241422
+ async release(turnId, options = {}) {
241338
241423
  const hold = this.#holds.get(turnId);
241339
- if (!hold) return;
241424
+ if (!hold) return "released";
241425
+ if (hold.phase === "deleting") return "released";
241426
+ const bounded = options.joinTimeoutMs !== void 0;
241427
+ if (hold.releaseAttempt !== null) {
241428
+ if (!bounded) return hold.releaseAttempt;
241429
+ return this.#concludeRelease(hold, turnId, options);
241430
+ }
241340
241431
  hold.released = true;
241341
241432
  if (hold.refresher !== null) {
241342
241433
  this.#timer.clearInterval(hold.refresher);
241343
241434
  hold.refresher = null;
241344
241435
  }
241345
- this.#holds.delete(turnId);
241346
- if (hold.inFlight.size > 0) await Promise.all(hold.inFlight);
241436
+ hold.phase = "joining";
241437
+ const attempt = (async () => {
241438
+ const outcome = await this.#concludeRelease(hold, turnId, options);
241439
+ if (outcome === "unreleased") {
241440
+ hold.phase = "idle";
241441
+ this.#removeIfCurrent(turnId, hold);
241442
+ }
241443
+ return outcome;
241444
+ })();
241445
+ hold.releaseAttempt = attempt;
241347
241446
  try {
241348
- await this.#transport.delete(hold.name);
241447
+ return await attempt;
241448
+ } finally {
241449
+ if (hold.releaseAttempt === attempt) hold.releaseAttempt = null;
241450
+ }
241451
+ }
241452
+ /**
241453
+ * Drive one release attempt to its outcome. On the confirmed path (every
241454
+ * PUT on the wire settled within the join bound) a single DELETE finishes
241455
+ * the hold. On the unconfirmed path cancellation is unknown, so the hold
241456
+ * is swept: DELETE, verify, and re-DELETE while the server still shows it,
241457
+ * capped. Shared by the first attempt and a shutdown takeover: whichever
241458
+ * caller first reaches its verdict installs the hold's single deletion
241459
+ * promise and the rest join it, so the DELETE or sweep is issued once and
241460
+ * concurrent callers report the same outcome.
241461
+ */
241462
+ async #concludeRelease(hold, turnId, options) {
241463
+ const verdict = await this.#confirmCancellation(hold, options.joinTimeoutMs);
241464
+ if (hold.deletion !== null) return hold.deletion;
241465
+ hold.phase = "deleting";
241466
+ const deletion = verdict === "confirmed" ? this.#deleteConfirmed(hold, turnId, options) : this.#sweepUnconfirmed(hold, turnId, options);
241467
+ hold.deletion = deletion;
241468
+ return deletion;
241469
+ }
241470
+ /**
241471
+ * The confirmed-path deletion: every PUT on the wire settled cleanly, so
241472
+ * one DELETE finishes the hold. A rejected DELETE is logged, never thrown;
241473
+ * the hold still leaves the map and expires on its own server-side.
241474
+ */
241475
+ async #deleteConfirmed(hold, turnId, options) {
241476
+ await this.#issueDelete(hold, options.deleteTimeoutMs, turnId);
241477
+ this.#removeIfCurrent(turnId, hold);
241478
+ return "released";
241479
+ }
241480
+ /**
241481
+ * Best-effort cleanup for a hold whose cancellation is uncertain: the join
241482
+ * bound fired with a PUT unsettled, or a PUT rejected after possibly being
241483
+ * processed server-side. The hold is owed its delete either way. Each round
241484
+ * is a bounded DELETE followed by a bounded GET; a verify that still shows
241485
+ * the hold (the timed-out PUT committed after our delete, or the delete
241486
+ * never landed) triggers the next round. Verification is best-effort too:
241487
+ * "absent" proves cleanup, "unknown" proves nothing and cannot by itself
241488
+ * report the hold unreleased, so after the cap an unverifiable hold is
241489
+ * reported released-with-its-delete while a positively present one is
241490
+ * reported unreleased at warn. Either way the hold expires on its own
241491
+ * within 300 s. Only `#concludeRelease` starts this, after it has already
241492
+ * moved the hold into its deleting phase.
241493
+ */
241494
+ async #sweepUnconfirmed(hold, turnId, options) {
241495
+ for (let round = 1; round <= SPRITE_TASK_HOLD_SWEEP_ROUNDS; round += 1) {
241496
+ await this.#issueDelete(hold, options.deleteTimeoutMs, turnId);
241497
+ const state = await this.#verifyHold(hold, options.deleteTimeoutMs, turnId);
241498
+ const last = round === SPRITE_TASK_HOLD_SWEEP_ROUNDS;
241499
+ if (state === "absent") {
241500
+ this.#removeIfCurrent(turnId, hold);
241501
+ return "released";
241502
+ }
241503
+ if (state === "present") {
241504
+ 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");
241505
+ if (last) {
241506
+ 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");
241507
+ this.#removeIfCurrent(turnId, hold);
241508
+ return "unreleased";
241509
+ }
241510
+ continue;
241511
+ }
241512
+ this.#onError(`sprite task hold for turn ${turnId} could not be verified after delete (sweep ${round}/${SPRITE_TASK_HOLD_SWEEP_ROUNDS})`, "hold state unverifiable");
241513
+ if (last) {
241514
+ this.#removeIfCurrent(turnId, hold);
241515
+ return "released";
241516
+ }
241517
+ }
241518
+ return "released";
241519
+ }
241520
+ /**
241521
+ * Ask the transport whether the hold still exists. No transport `get`, a
241522
+ * rejection, or a bound that fires all come back "unknown": the sweep has
241523
+ * no evidence, and never invents it.
241524
+ */
241525
+ async #verifyHold(hold, timeoutMs, turnId) {
241526
+ const get = this.#transport.get;
241527
+ if (!get) return "unknown";
241528
+ try {
241529
+ return await boundedAwait(get(hold.name), timeoutMs);
241530
+ } catch (cause) {
241531
+ this.#onError(`failed to verify sprite task hold for turn ${turnId}`, cause);
241532
+ return "unknown";
241533
+ }
241534
+ }
241535
+ /**
241536
+ * Wait for every PUT on the wire to settle and report whether cancellation
241537
+ * is confirmed. Only a clean success confirms: a PUT that REJECTED is
241538
+ * uncertain, because the server may have processed the request before the
241539
+ * failure surfaced, and a DELETE trusted after it could be raced by the
241540
+ * hold it re-created. `inFlight` forgets each PUT once it settles, so a
241541
+ * rejection that settled before the release even started is read from
241542
+ * `uncertainPut` instead, and stays uncertain until some later PUT
241543
+ * succeeds. With no bound the wait is patient; unbounded callers
241544
+ * (drain, per-turn release) trade shutdown speed for the certainty.
241545
+ */
241546
+ async #confirmCancellation(hold, timeoutMs) {
241547
+ if (hold.inFlight.size === 0) return hold.uncertainPut ? "uncertain" : "confirmed";
241548
+ const settled = Promise.all(hold.inFlight).then((fates) => fates.every((fate) => fate === "succeeded") && !hold.uncertainPut ? "confirmed" : "uncertain");
241549
+ if (timeoutMs === void 0) return settled;
241550
+ let clearTimer = noTimer;
241551
+ return Promise.race([settled, new Promise((resolve) => {
241552
+ const timer = setTimeout(() => resolve("uncertain"), timeoutMs);
241553
+ clearTimer = () => clearTimeout(timer);
241554
+ })]).finally(() => clearTimer());
241555
+ }
241556
+ /** Issue the DELETE, reporting (never throwing) a failure. */
241557
+ async #issueDelete(hold, deleteTimeoutMs, turnId) {
241558
+ try {
241559
+ await boundedAwait(this.#transport.delete(hold.name), deleteTimeoutMs);
241349
241560
  } catch (cause) {
241350
241561
  this.#onError(`failed to release sprite task hold for turn ${turnId}`, cause);
241351
241562
  }
241352
241563
  }
241353
241564
  /**
241565
+ * Drop the map entry only if this attempt's hold still owns the id: a newer
241566
+ * acquire may have replaced it while the release was awaiting, and deleting
241567
+ * by key alone would evict the replacement.
241568
+ */
241569
+ #removeIfCurrent(turnId, hold) {
241570
+ if (this.#holds.get(turnId) === hold) this.#holds.delete(turnId);
241571
+ }
241572
+ /**
241354
241573
  * Release every hold belonging to one thread.
241355
241574
  *
241356
241575
  * `session.exited` names only the thread whose provider process died, and a
@@ -241365,9 +241584,22 @@ var SpriteTaskHoldManager = class {
241365
241584
  /**
241366
241585
  * Release everything. Runtime drain and server shutdown must call this, or a
241367
241586
  * drained sprite keeps billing until each hold expires.
241587
+ *
241588
+ * Shutdown passes `SPRITE_TASK_HOLD_RELEASE_JOIN_TIMEOUT_MS` /
241589
+ * `SPRITE_TASK_HOLD_RELEASE_DELETE_TIMEOUT_MS` so a socket that never
241590
+ * settles cannot hang the process open past its own termination, and gets a
241591
+ * per-hold report back: every hold gets its DELETE, and only holds the
241592
+ * sweep still saw present after the full delete+verify cap come back
241593
+ * unreleased, left to their own 300 s expiry. Drain passes no bounds and
241594
+ * keeps the patient join.
241368
241595
  */
241369
- async releaseAll() {
241370
- await Promise.all([...this.#holds.keys()].map((turnId) => this.release(turnId)));
241596
+ async releaseAll(options = {}) {
241597
+ const turnIds = [...this.#holds.keys()];
241598
+ const outcomes = await Promise.all(turnIds.map(async (turnId) => [turnId, await this.release(turnId, options)]));
241599
+ return {
241600
+ released: outcomes.filter(([, outcome]) => outcome === "released").map(([turnId]) => turnId),
241601
+ unreleased: outcomes.filter(([, outcome]) => outcome === "unreleased").map(([turnId]) => turnId)
241602
+ };
241371
241603
  }
241372
241604
  };
241373
241605
  /**
@@ -241398,7 +241630,25 @@ function makeSpriteTaskHoldTransport(config, fetchImpl = fetch) {
241398
241630
  headers: { "content-type": "application/json" },
241399
241631
  body: JSON.stringify({ expire: `${expireSeconds}s` })
241400
241632
  }),
241401
- delete: (name) => call(`/${encodeURIComponent(name)}`, { method: "DELETE" })
241633
+ delete: (name) => call(`/${encodeURIComponent(name)}`, { method: "DELETE" }),
241634
+ get: async (name) => {
241635
+ const controller = new AbortController();
241636
+ const deadline = setTimeout(() => controller.abort(), SPRITE_TASK_HOLD_REQUEST_TIMEOUT_MS);
241637
+ try {
241638
+ const response = await fetchImpl(`http://sprite/v1/tasks/${encodeURIComponent(name)}`, {
241639
+ method: "GET",
241640
+ signal: controller.signal,
241641
+ unix: config.socketPath
241642
+ });
241643
+ if (response.ok) return "present";
241644
+ if (response.status === 404) return "absent";
241645
+ return "unknown";
241646
+ } catch {
241647
+ return "unknown";
241648
+ } finally {
241649
+ clearTimeout(deadline);
241650
+ }
241651
+ }
241402
241652
  };
241403
241653
  }
241404
241654
  /**
@@ -285989,10 +286239,10 @@ const AgentBrowserManagerLive = effect(BrowserManager, gen(function* () {
285989
286239
  mediaSourceFactory: displayCaptureRuntime.mediaSourceFactory,
285990
286240
  taskHold: displayTaskHoldManager ? {
285991
286241
  acquire: (holdId) => displayTaskHoldManager.acquire(holdId),
285992
- release: (holdId) => displayTaskHoldManager.release(holdId)
286242
+ release: (holdId) => displayTaskHoldManager.release(holdId).then(() => {})
285993
286243
  } : void 0
285994
286244
  });
285995
- yield* addFinalizer$2(() => promise(() => displayTaskHoldManager?.releaseAll() ?? Promise.resolve()));
286245
+ yield* addFinalizer$2(() => promise(() => displayTaskHoldManager?.releaseAll().then(() => {}) ?? Promise.resolve()));
285996
286246
  const baseBackendOptions = displayCaptureRuntime.backendOptions;
285997
286247
  const sessionInitialUrls = /* @__PURE__ */ new Map();
285998
286248
  let runtimeBuild = null;
@@ -293932,6 +294182,19 @@ const SpriteTaskHoldReactorLive = effect(SpriteTaskHoldReactor, gen(function* ()
293932
294182
  const manager = makeSpriteTaskHoldManager(process.env, (message, cause) => {
293933
294183
  runFork(logWarning$1(message, { cause: cause instanceof Error ? cause.message : cause }));
293934
294184
  });
294185
+ /**
294186
+ * Run a manager call, or nothing on runtimes that are not sprites. One
294187
+ * null-guard for every caller: the releaseAll service and the shutdown
294188
+ * finalizer alike.
294189
+ */
294190
+ const onManager = (run) => promise(async () => {
294191
+ if (manager === null) return;
294192
+ await run(manager);
294193
+ });
294194
+ yield* addFinalizer$2(() => onManager((taskHolds) => taskHolds.releaseAll({
294195
+ joinTimeoutMs: SPRITE_TASK_HOLD_RELEASE_JOIN_TIMEOUT_MS,
294196
+ deleteTimeoutMs: SPRITE_TASK_HOLD_RELEASE_DELETE_TIMEOUT_MS
294197
+ })));
293935
294198
  const launchCallers = /* @__PURE__ */ new Map();
293936
294199
  const start = fn$1("start")(function* () {
293937
294200
  if (manager === null) return;
@@ -293948,12 +294211,12 @@ const SpriteTaskHoldReactorLive = effect(SpriteTaskHoldReactor, gen(function* ()
293948
294211
  if (event.type === "turn.completed") {
293949
294212
  const turnId = event.turnId;
293950
294213
  if (turnId === void 0) return void_$1;
293951
- return promise(() => manager.release(String(turnId)));
294214
+ return promise(() => manager.release(String(turnId)).then(() => {}));
293952
294215
  }
293953
294216
  if (event.type === "turn.aborted") {
293954
294217
  const turnId = event.turnId;
293955
294218
  if (turnId === void 0) return void_$1;
293956
- return promise(() => manager.release(String(turnId)));
294219
+ return promise(() => manager.release(String(turnId)).then(() => {}));
293957
294220
  }
293958
294221
  if (event.type === "session.exited") {
293959
294222
  launchCallers.delete(String(event.threadId));
@@ -293980,7 +294243,7 @@ const SpriteTaskHoldReactorLive = effect(SpriteTaskHoldReactor, gen(function* ()
293980
294243
  start,
293981
294244
  holdLaunch,
293982
294245
  releaseLaunch,
293983
- releaseAll: promise(() => manager === null ? Promise.resolve() : manager.releaseAll())
294246
+ releaseAll: onManager((taskHolds) => taskHolds.releaseAll())
293984
294247
  };
293985
294248
  }));
293986
294249
  //#endregion
@@ -298094,7 +298357,7 @@ function resolveBuildCommitFromEnv(env) {
298094
298357
  * environment descriptor down instead of reporting an honest "unknown".
298095
298358
  */
298096
298359
  function readBakedBuildCommit() {
298097
- return "9beb25327a2591f7938669b9014396e64c2bb674";
298360
+ return "d1c5c1c87c650d1d49b596cbbe4bcc3ff14c7bfe";
298098
298361
  }
298099
298362
  async function resolveServerBuildCommit(input) {
298100
298363
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -1,4 +1,4 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{Ha as t,Mi as n,Ua as r,Wa as i}from"./Stream-mUTFnSY9.js";import{Al as a,Fn as o,Gc as s,Hr as c,Jc as l,Qr as u,Rr as d,Sr as f,Tn as p,Uc as m,Xr as h,_r as g,d as _,fn as v,fr as y,gr as b,i as x,is as S,jn as C,l as w,m as T,ms as E,n as D,qc as O,qt as k,r as A,u as j,za as M,zr as N}from"./DiffPanelShell-BoAQcVta.js";import{hn as P}from"./CompositeItem-B_Qce_Zi.js";import{a as F,c as I,f as L,i as R,l as z,m as B,n as V,o as H,p as U,r as W,s as G,t as K}from"./Virtualizer-B4jYnrUE.js";import{Dn as q,at as J,it as ee}from"./src-IM0FnQax.js";import{a as te,c as ne,d as re,h as ie,i as ae,l as oe,m as se,n as ce,o as Y,p as le,r as ue,s as de,t as fe,u as pe}from"./DiffPanel.logic-Bw1O_6UU.js";var X=e(i(),1),me=typeof window>`u`?X.useEffect:X.useLayoutEffect;function he({fileDiff:e,options:t,editorOptions:n,lineAnnotations:r,selectedLines:i,prerenderedHTML:a,metrics:o,hasGutterRenderUtility:s,hasCustomHeader:c,disableWorkerPool:l,edit:u}){let d=V(),f=i!==void 0,p=(0,X.useContext)(x),m=j(),h=(0,X.useRef)(null),g=_(n=>{if(n!=null){if(h.current!=null)throw Error(`useFileDiffInstance: An instance should not already exist when a node is created`);d==null?h.current=new re(Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),l?void 0:p,!0):h.current=new pe(Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),d,o,l?void 0:p,!0),h.current.hydrate({fileDiff:e,fileContainer:n,lineAnnotations:r,prerenderedHTML:a})}else{if(h.current==null)throw Error(`useFileDiffInstance: A FileDiff instance should exist when unmounting`);h.current.cleanUp(),h.current=null}});return me(()=>{let{current:n}=h;if(n==null)return;let a=Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),o=a!==void 0&&!k(n.options,a);n.setOptions(a),n.render({forceRender:o,fileDiff:e,lineAnnotations:r}),i!==void 0&&n.setSelectedLines(i)}),me(()=>{if(u&&h.current!=null){if(m===void 0)throw Error(`FileDiff: EditContext is not attached`);let e=m(n??{});if(e==null)throw Error(`FileDiff: EditProvider.createEditor must return an editor instance`);try{return e.edit(h.current)}catch(t){throw e.cleanUp(),t}}},[u]),{ref:g,getHoveredLine:(0,X.useCallback)(()=>h.current?.getHoveredLine(),[])}}function Z({options:e,controlledSelection:t,hasCustomHeader:n,hasGutterRenderUtility:r}){return t||r||n?{...e,controlledSelection:t,renderCustomHeader:n?w:e?.renderCustomHeader,renderGutterUtility:r?w:e?.renderGutterUtility}:e}var Q=r();function ge({fileDiff:e,options:t,editorOptions:n,metrics:r,lineAnnotations:i,selectedLines:a,className:o,style:s,prerenderedHTML:c,renderAnnotation:l,renderCustomHeader:u,renderHeaderPrefix:d,renderHeaderFilenameSuffix:f,renderHeaderMetadata:p,renderGutterUtility:m,disableWorkerPool:h=!1,edit:g=!1}){let{ref:_,getHoveredLine:y}=he({fileDiff:e,options:t,editorOptions:n,metrics:r,lineAnnotations:i,selectedLines:a,prerenderedHTML:c,hasGutterRenderUtility:m!=null,hasCustomHeader:u!=null,disableWorkerPool:h,edit:g});return(0,Q.jsx)(v,{ref:_,className:o,style:s,children:W(oe({fileDiff:e,renderCustomHeader:u,renderHeaderPrefix:d,renderHeaderFilenameSuffix:f,renderHeaderMetadata:p,renderAnnotation:l,renderGutterUtility:m,lineAnnotations:i,getHoveredLine:y}),c)})}var $=t();function _e(e){return e.fromTurnCount===0?q(ee)({threadId:e.threadId,toTurnCount:e.toTurnCount}).pipe(n(e=>({kind:`fullThreadDiff`,input:e}))):q(J)({threadId:e.threadId,fromTurnCount:e.fromTurnCount,toTurnCount:e.toTurnCount}).pipe(n(e=>({kind:`turnDiff`,input:e})))}function ve(e){return e instanceof Error?e.message:typeof e==`string`?e:``}function ye(e){let t=ve(e).trim();if(t.length===0)return`Failed to load checkpoint diff.`;let n=t.toLowerCase();if(n.includes(`not a git repository`))return`Turn diffs are unavailable because this project is not a git repository.`;if(n.includes(`checkpoint unavailable for thread`)||n.includes(`checkpoint invariant violation`)){let e=t.indexOf(`:`);if(e>=0){let n=t.slice(e+1).trim();if(n.length>0)return n}}return t}function be(e){let t=ve(e).toLowerCase();return t.includes(`exceeds current turn count`)||t.includes(`checkpoint is unavailable for turn`)||t.includes(`filesystem checkpoint is unavailable`)}function xe(e){let t=_e(e);return O({queryKey:M.checkpointDiff(e),queryFn:async({signal:n})=>{if(!e.environmentId||!e.threadId||t._tag===`None`)throw Error(`Checkpoint diff is unavailable.`);let r=c(e.environmentId);try{return t.value.kind===`fullThreadDiff`?await r.orchestration.getFullThreadDiff(t.value.input,{signal:n}):await r.orchestration.getTurnDiff(t.value.input,{signal:n})}catch(e){throw Error(ye(e),{cause:e})}},enabled:(e.enabled??!0)&&!!e.environmentId&&!!e.threadId&&t._tag===`Some`,staleTime:1/0,retry:(e,t)=>be(t)?e<12:e<3,retryDelay:(e,t)=>be(t)?Math.min(5e3,250*2**(e-1)):Math.min(1e3,100*2**(e-1))})}function Se(e){if(!(!e.canScrollLeft&&!e.canScrollRight))return{maskImage:`linear-gradient(to right, ${e.canScrollLeft?`transparent 24px, black 72px`:`black`}, ${e.canScrollRight?`black calc(100% - 72px), transparent calc(100% - 24px)`:`black`})`}}function Ce(e){return e instanceof Error?e.message:e?`Failed to load checkpoint diff.`:null}function we(e){return{environmentId:e.environmentId??null,threadId:e.threadId,fromTurnCount:e.range?.fromTurnCount??null,toTurnCount:e.range?.toTurnCount??null,cacheScope:e.selectedTurnId?`turn:${e.selectedTurnId}`:e.conversationCacheScope,enabled:e.enabled}}function Te(){let e=(0,$.c)(8),t=(0,X.useRef)(null),[n,r]=(0,X.useState)(!1),[i,a]=(0,X.useState)(!1),o;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(o=()=>{let e=t.current;if(!e){r(!1),a(!1);return}let n=de({scrollLeft:e.scrollLeft,scrollWidth:e.scrollWidth,clientWidth:e.clientWidth});r(n.canScrollLeft),a(n.canScrollRight)},e[0]=o):o=e[0];let s=o,c;e[1]===Symbol.for(`react.memo_cache_sentinel`)?(c=e=>{t.current?.scrollBy({left:e,behavior:`smooth`})},e[1]=c):c=e[1];let l=c,u;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(u=e=>{let n=t.current;n&&ne({scrollWidth:n.scrollWidth,clientWidth:n.clientWidth,deltaX:e.deltaX,deltaY:e.deltaY})&&(e.preventDefault(),n.scrollBy({left:e.deltaY,behavior:`auto`}))},e[2]=u):u=e[2];let d=u,f,p;e[3]===Symbol.for(`react.memo_cache_sentinel`)?(f=()=>{let e=t.current;if(!e)return;let n=window.requestAnimationFrame(s),r=()=>s();e.addEventListener(`scroll`,r,{passive:!0});let i=new ResizeObserver(()=>s());return i.observe(e),()=>{window.cancelAnimationFrame(n),e.removeEventListener(`scroll`,r),i.disconnect()}},p=[s],e[3]=f,e[4]=p):(f=e[3],p=e[4]),(0,X.useEffect)(f,p);let m;return e[5]!==n||e[6]!==i?(m={ref:t,canScrollLeft:n,canScrollRight:i,scrollBy:l,onWheel:d,remeasure:s},e[5]=n,e[6]=i,e[7]=m):m=e[7],m}function Ee(e,t){let n=(0,$.c)(5),r;n[0]===e.current?r=n[1]:(r=()=>{(e.current?.querySelector(`[data-turn-chip-selected='true']`))?.scrollIntoView({block:`nearest`,inline:`nearest`,behavior:`smooth`})},n[0]=e.current,n[1]=r);let i;n[2]!==e||n[3]!==t?(i=[e,t],n[2]=e,n[3]=t,n[4]=i):i=n[4],(0,X.useEffect)(r,i)}var De=`
1
+ import{r as e}from"./rolldown-runtime-hePW80VL.js";import{Ha as t,Mi as n,Ua as r,Wa as i}from"./Stream-mUTFnSY9.js";import{Al as a,Fn as o,Gc as s,Hr as c,Jc as l,Qr as u,Rr as d,Sr as f,Tn as p,Uc as m,Xr as h,_r as g,d as _,fn as v,fr as y,gr as b,i as x,is as S,jn as C,l as w,m as T,ms as E,n as D,qc as O,qt as k,r as A,u as j,za as M,zr as N}from"./DiffPanelShell-CTLS82pj.js";import{hn as P}from"./CompositeItem-B_Qce_Zi.js";import{a as F,c as I,f as L,i as R,l as z,m as B,n as V,o as H,p as U,r as W,s as G,t as K}from"./Virtualizer-DsHt9iaj.js";import{Dn as q,at as J,it as ee}from"./src-IM0FnQax.js";import{a as te,c as ne,d as re,h as ie,i as ae,l as oe,m as se,n as ce,o as Y,p as le,r as ue,s as de,t as fe,u as pe}from"./DiffPanel.logic-DF8NdwcA.js";var X=e(i(),1),me=typeof window>`u`?X.useEffect:X.useLayoutEffect;function he({fileDiff:e,options:t,editorOptions:n,lineAnnotations:r,selectedLines:i,prerenderedHTML:a,metrics:o,hasGutterRenderUtility:s,hasCustomHeader:c,disableWorkerPool:l,edit:u}){let d=V(),f=i!==void 0,p=(0,X.useContext)(x),m=j(),h=(0,X.useRef)(null),g=_(n=>{if(n!=null){if(h.current!=null)throw Error(`useFileDiffInstance: An instance should not already exist when a node is created`);d==null?h.current=new re(Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),l?void 0:p,!0):h.current=new pe(Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),d,o,l?void 0:p,!0),h.current.hydrate({fileDiff:e,fileContainer:n,lineAnnotations:r,prerenderedHTML:a})}else{if(h.current==null)throw Error(`useFileDiffInstance: A FileDiff instance should exist when unmounting`);h.current.cleanUp(),h.current=null}});return me(()=>{let{current:n}=h;if(n==null)return;let a=Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),o=a!==void 0&&!k(n.options,a);n.setOptions(a),n.render({forceRender:o,fileDiff:e,lineAnnotations:r}),i!==void 0&&n.setSelectedLines(i)}),me(()=>{if(u&&h.current!=null){if(m===void 0)throw Error(`FileDiff: EditContext is not attached`);let e=m(n??{});if(e==null)throw Error(`FileDiff: EditProvider.createEditor must return an editor instance`);try{return e.edit(h.current)}catch(t){throw e.cleanUp(),t}}},[u]),{ref:g,getHoveredLine:(0,X.useCallback)(()=>h.current?.getHoveredLine(),[])}}function Z({options:e,controlledSelection:t,hasCustomHeader:n,hasGutterRenderUtility:r}){return t||r||n?{...e,controlledSelection:t,renderCustomHeader:n?w:e?.renderCustomHeader,renderGutterUtility:r?w:e?.renderGutterUtility}:e}var Q=r();function ge({fileDiff:e,options:t,editorOptions:n,metrics:r,lineAnnotations:i,selectedLines:a,className:o,style:s,prerenderedHTML:c,renderAnnotation:l,renderCustomHeader:u,renderHeaderPrefix:d,renderHeaderFilenameSuffix:f,renderHeaderMetadata:p,renderGutterUtility:m,disableWorkerPool:h=!1,edit:g=!1}){let{ref:_,getHoveredLine:y}=he({fileDiff:e,options:t,editorOptions:n,metrics:r,lineAnnotations:i,selectedLines:a,prerenderedHTML:c,hasGutterRenderUtility:m!=null,hasCustomHeader:u!=null,disableWorkerPool:h,edit:g});return(0,Q.jsx)(v,{ref:_,className:o,style:s,children:W(oe({fileDiff:e,renderCustomHeader:u,renderHeaderPrefix:d,renderHeaderFilenameSuffix:f,renderHeaderMetadata:p,renderAnnotation:l,renderGutterUtility:m,lineAnnotations:i,getHoveredLine:y}),c)})}var $=t();function _e(e){return e.fromTurnCount===0?q(ee)({threadId:e.threadId,toTurnCount:e.toTurnCount}).pipe(n(e=>({kind:`fullThreadDiff`,input:e}))):q(J)({threadId:e.threadId,fromTurnCount:e.fromTurnCount,toTurnCount:e.toTurnCount}).pipe(n(e=>({kind:`turnDiff`,input:e})))}function ve(e){return e instanceof Error?e.message:typeof e==`string`?e:``}function ye(e){let t=ve(e).trim();if(t.length===0)return`Failed to load checkpoint diff.`;let n=t.toLowerCase();if(n.includes(`not a git repository`))return`Turn diffs are unavailable because this project is not a git repository.`;if(n.includes(`checkpoint unavailable for thread`)||n.includes(`checkpoint invariant violation`)){let e=t.indexOf(`:`);if(e>=0){let n=t.slice(e+1).trim();if(n.length>0)return n}}return t}function be(e){let t=ve(e).toLowerCase();return t.includes(`exceeds current turn count`)||t.includes(`checkpoint is unavailable for turn`)||t.includes(`filesystem checkpoint is unavailable`)}function xe(e){let t=_e(e);return O({queryKey:M.checkpointDiff(e),queryFn:async({signal:n})=>{if(!e.environmentId||!e.threadId||t._tag===`None`)throw Error(`Checkpoint diff is unavailable.`);let r=c(e.environmentId);try{return t.value.kind===`fullThreadDiff`?await r.orchestration.getFullThreadDiff(t.value.input,{signal:n}):await r.orchestration.getTurnDiff(t.value.input,{signal:n})}catch(e){throw Error(ye(e),{cause:e})}},enabled:(e.enabled??!0)&&!!e.environmentId&&!!e.threadId&&t._tag===`Some`,staleTime:1/0,retry:(e,t)=>be(t)?e<12:e<3,retryDelay:(e,t)=>be(t)?Math.min(5e3,250*2**(e-1)):Math.min(1e3,100*2**(e-1))})}function Se(e){if(!(!e.canScrollLeft&&!e.canScrollRight))return{maskImage:`linear-gradient(to right, ${e.canScrollLeft?`transparent 24px, black 72px`:`black`}, ${e.canScrollRight?`black calc(100% - 72px), transparent calc(100% - 24px)`:`black`})`}}function Ce(e){return e instanceof Error?e.message:e?`Failed to load checkpoint diff.`:null}function we(e){return{environmentId:e.environmentId??null,threadId:e.threadId,fromTurnCount:e.range?.fromTurnCount??null,toTurnCount:e.range?.toTurnCount??null,cacheScope:e.selectedTurnId?`turn:${e.selectedTurnId}`:e.conversationCacheScope,enabled:e.enabled}}function Te(){let e=(0,$.c)(8),t=(0,X.useRef)(null),[n,r]=(0,X.useState)(!1),[i,a]=(0,X.useState)(!1),o;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(o=()=>{let e=t.current;if(!e){r(!1),a(!1);return}let n=de({scrollLeft:e.scrollLeft,scrollWidth:e.scrollWidth,clientWidth:e.clientWidth});r(n.canScrollLeft),a(n.canScrollRight)},e[0]=o):o=e[0];let s=o,c;e[1]===Symbol.for(`react.memo_cache_sentinel`)?(c=e=>{t.current?.scrollBy({left:e,behavior:`smooth`})},e[1]=c):c=e[1];let l=c,u;e[2]===Symbol.for(`react.memo_cache_sentinel`)?(u=e=>{let n=t.current;n&&ne({scrollWidth:n.scrollWidth,clientWidth:n.clientWidth,deltaX:e.deltaX,deltaY:e.deltaY})&&(e.preventDefault(),n.scrollBy({left:e.deltaY,behavior:`auto`}))},e[2]=u):u=e[2];let d=u,f,p;e[3]===Symbol.for(`react.memo_cache_sentinel`)?(f=()=>{let e=t.current;if(!e)return;let n=window.requestAnimationFrame(s),r=()=>s();e.addEventListener(`scroll`,r,{passive:!0});let i=new ResizeObserver(()=>s());return i.observe(e),()=>{window.cancelAnimationFrame(n),e.removeEventListener(`scroll`,r),i.disconnect()}},p=[s],e[3]=f,e[4]=p):(f=e[3],p=e[4]),(0,X.useEffect)(f,p);let m;return e[5]!==n||e[6]!==i?(m={ref:t,canScrollLeft:n,canScrollRight:i,scrollBy:l,onWheel:d,remeasure:s},e[5]=n,e[6]=i,e[7]=m):m=e[7],m}function Ee(e,t){let n=(0,$.c)(5),r;n[0]===e.current?r=n[1]:(r=()=>{(e.current?.querySelector(`[data-turn-chip-selected='true']`))?.scrollIntoView({block:`nearest`,inline:`nearest`,behavior:`smooth`})},n[0]=e.current,n[1]=r);let i;n[2]!==e||n[3]!==t?(i=[e,t],n[2]=e,n[3]=t,n[4]=i):i=n[4],(0,X.useEffect)(r,i)}var De=`
2
2
  [data-diffs-header],
3
3
  [data-diff],
4
4
  [data-file],
@@ -61,4 +61,4 @@ import{r as e}from"./rolldown-runtime-hePW80VL.js";import{Ha as t,Mi as n,Ua as
61
61
  text-decoration-color: currentColor;
62
62
  }
63
63
  `;function Oe(e){let t=(0,$.c)(44),{mode:n}=e,r=n===void 0?`inline`:n,{resolvedTheme:i}=b(),a=g(),[c,l]=(0,X.useState)(`stacked`),[u,d]=(0,X.useState)(a.diffWordWrap),h=(0,X.useRef)(null),_=(0,X.useRef)(!1),v=Te(),{activeCwd:y,activeThread:x,bodyState:S,diffOpen:C,inferredCheckpointTurnCountByTurnId:w,orderedTurnDiffSummaries:T,renderableFiles:E,renderablePatch:D,selectedFilePath:O,selectedTurn:k,selectedTurnId:j}=Le(i),M,P;t[0]!==C||t[1]!==a.diffWordWrap?(M=()=>{C&&!_.current&&d(a.diffWordWrap),_.current=C},P=[C,a.diffWordWrap],t[0]=C,t[1]=a.diffWordWrap,t[2]=M,t[3]=P):(M=t[2],P=t[3]),(0,X.useEffect)(M,P);let F;t[4]===O?F=t[5]:(F=()=>{!O||!h.current||Array.from(h.current.querySelectorAll(`[data-diff-file-path]`)).find(e=>e.dataset.diffFilePath===O)?.scrollIntoView({block:`nearest`})},t[4]=O,t[5]=F);let I;t[6]!==E||t[7]!==O?(I=[O,E],t[6]=E,t[7]=O,t[8]=I):I=t[8],(0,X.useEffect)(F,I);let L;t[9]===y?L=t[10]:(L=e=>{let t=f();if(!t)return;let n=y?p(e,y):e;N(t,n).catch(ke)},t[9]=y,t[10]=L);let R=L,z;t[11]===x?z=t[12]:(z=e=>{x&&o.getState().openDiff(s(m(x.environmentId,x.id)),e)},t[11]=x,t[12]=z);let B=z,V;t[13]===x?V=t[14]:(V=()=>{x&&o.getState().openDiff(s(m(x.environmentId,x.id)))},t[13]=x,t[14]=V);let H=V,U;t[15]===v.remeasure?U=t[16]:(U=()=>{let e=window.requestAnimationFrame(v.remeasure);return()=>window.cancelAnimationFrame(e)},t[15]=v.remeasure,t[16]=U);let W;t[17]!==T||t[18]!==j||t[19]!==v.remeasure?(W=[T,j,v.remeasure],t[17]=T,t[18]=j,t[19]=v.remeasure,t[20]=W):W=t[20],(0,X.useEffect)(U,W),Ee(v.ref,k?.turnId??j);let G;t[21]!==c||t[22]!==u||t[23]!==w||t[24]!==T||t[25]!==B||t[26]!==H||t[27]!==k||t[28]!==j||t[29]!==a||t[30]!==v?(G=(0,Q.jsx)(Ae,{diffRenderMode:c,diffWordWrap:u,inferredCheckpointTurnCountByTurnId:w,orderedTurnDiffSummaries:T,selectTurn:B,selectWholeConversation:H,selectedTurn:k,selectedTurnId:j,setDiffRenderMode:l,setDiffWordWrap:d,settings:a,turnStrip:v}),t[21]=c,t[22]=u,t[23]=w,t[24]=T,t[25]=B,t[26]=H,t[27]=k,t[28]=j,t[29]=a,t[30]=v,t[31]=G):G=t[31];let K=G,q;t[32]!==S||t[33]!==c||t[34]!==u||t[35]!==R||t[36]!==E||t[37]!==D||t[38]!==i?(q=(0,Q.jsx)(je,{bodyState:S,diffRenderMode:c,diffWordWrap:u,openDiffFileInEditor:R,patchViewportRef:h,renderableFiles:E,renderablePatch:D,resolvedTheme:i}),t[32]=S,t[33]=c,t[34]=u,t[35]=R,t[36]=E,t[37]=D,t[38]=i,t[39]=q):q=t[39];let J;return t[40]!==K||t[41]!==r||t[42]!==q?(J=(0,Q.jsx)(A,{mode:r,header:K,children:q}),t[40]=K,t[41]=r,t[42]=q,t[43]=J):J=t[43],J}function ke(e){console.warn(`Failed to open diff file in editor.`,e)}function Ae(e){let t=(0,$.c)(59),{diffRenderMode:n,diffWordWrap:r,inferredCheckpointTurnCountByTurnId:i,orderedTurnDiffSummaries:a,selectTurn:o,selectWholeConversation:s,selectedTurn:c,selectedTurnId:l,setDiffRenderMode:u,setDiffWordWrap:d,settings:f,turnStrip:p}=e,m,h;t[0]===p?(m=t[1],h=t[2]):(m=(0,Q.jsx)(Be,{direction:`left`,strip:p}),h=(0,Q.jsx)(Be,{direction:`right`,strip:p}),t[0]=p,t[1]=m,t[2]=h);let g=p.ref,_;t[3]!==p.canScrollLeft||t[4]!==p.canScrollRight?(_=Se({canScrollLeft:p.canScrollLeft,canScrollRight:p.canScrollRight}),t[3]=p.canScrollLeft,t[4]=p.canScrollRight,t[5]=_):_=t[5];let v=p.onWheel,y=l===null,b=l===null?`border-border bg-accent text-accent-foreground`:`border-border/70 bg-background/70 text-muted-foreground/80 hover:border-border hover:text-foreground/80`,x;t[6]===b?x=t[7]:(x=P(`rounded-md border px-2 py-1 text-left transition-colors`,b),t[6]=b,t[7]=x);let S;t[8]===Symbol.for(`react.memo_cache_sentinel`)?(S=(0,Q.jsx)(`div`,{className:`text-[10px] leading-tight font-medium`,children:`All turns`}),t[8]=S):S=t[8];let C;t[9]===x?C=t[10]:(C=(0,Q.jsx)(`div`,{className:x,children:S}),t[9]=x,t[10]=C);let w;t[11]!==s||t[12]!==C||t[13]!==y?(w=(0,Q.jsx)(`button`,{type:`button`,className:`shrink-0 rounded-md`,onClick:s,"data-turn-chip-selected":y,children:C}),t[11]=s,t[12]=C,t[13]=y,t[14]=w):w=t[14];let T;if(t[15]!==i||t[16]!==a||t[17]!==o||t[18]!==c?.turnId||t[19]!==f){let e;t[21]!==i||t[22]!==o||t[23]!==c?.turnId||t[24]!==f?(e=e=>(0,Q.jsx)(Ve,{summary:e,selected:e.turnId===c?.turnId,turnCount:e.checkpointTurnCount??i[e.turnId],timestampFormat:f.timestampFormat,onSelect:o},e.turnId),t[21]=i,t[22]=o,t[23]=c?.turnId,t[24]=f,t[25]=e):e=t[25],T=a.map(e),t[15]=i,t[16]=a,t[17]=o,t[18]=c?.turnId,t[19]=f,t[20]=T}else T=t[20];let E;t[26]!==w||t[27]!==T||t[28]!==_||t[29]!==p.onWheel||t[30]!==p.ref?(E=(0,Q.jsxs)(`div`,{ref:g,className:`turn-chip-strip flex gap-1 overflow-x-auto px-8 py-0.5`,style:_,onWheel:v,children:[w,T]}),t[26]=w,t[27]=T,t[28]=_,t[29]=p.onWheel,t[30]=p.ref,t[31]=E):E=t[31];let D;t[32]!==m||t[33]!==E||t[34]!==h?(D=(0,Q.jsxs)(`div`,{className:`relative min-w-0 flex-1 [-webkit-app-region:no-drag]`,children:[m,h,E]}),t[32]=m,t[33]=E,t[34]=h,t[35]=D):D=t[35];let O;t[36]===n?O=t[37]:(O=[n],t[36]=n,t[37]=O);let k;t[38]===u?k=t[39]:(k=e=>{let t=e[0];(t===`stacked`||t===`split`)&&u(t)},t[38]=u,t[39]=k);let A;t[40]===Symbol.for(`react.memo_cache_sentinel`)?(A=(0,Q.jsx)(R,{"aria-label":`Stacked diff view`,value:`stacked`,children:(0,Q.jsx)(se,{className:`size-3`})}),t[40]=A):A=t[40];let j;t[41]===Symbol.for(`react.memo_cache_sentinel`)?(j=(0,Q.jsx)(R,{"aria-label":`Split diff view`,value:`split`,children:(0,Q.jsx)(ie,{className:`size-3`})}),t[41]=j):j=t[41];let M;t[42]!==O||t[43]!==k?(M=(0,Q.jsxs)(F,{className:`shrink-0`,variant:`outline`,size:`xs`,value:O,onValueChange:k,children:[A,j]}),t[42]=O,t[43]=k,t[44]=M):M=t[44];let N=r?`Disable diff line wrapping`:`Enable diff line wrapping`,I=r?`Disable line wrapping`:`Enable line wrapping`,L;t[45]===d?L=t[46]:(L=e=>{d(!!e)},t[45]=d,t[46]=L);let z;t[47]===Symbol.for(`react.memo_cache_sentinel`)?(z=(0,Q.jsx)(le,{className:`size-3`}),t[47]=z):z=t[47];let B;t[48]!==r||t[49]!==N||t[50]!==I||t[51]!==L?(B=(0,Q.jsx)(R,{"aria-label":N,title:I,variant:`outline`,size:`xs`,pressed:r,onPressedChange:L,children:z}),t[48]=r,t[49]=N,t[50]=I,t[51]=L,t[52]=B):B=t[52];let V;t[53]!==M||t[54]!==B?(V=(0,Q.jsxs)(`div`,{className:`flex shrink-0 items-center gap-1 [-webkit-app-region:no-drag]`,children:[M,B]}),t[53]=M,t[54]=B,t[55]=V):V=t[55];let H;return t[56]!==D||t[57]!==V?(H=(0,Q.jsxs)(Q.Fragment,{children:[D,V]}),t[56]=D,t[57]=V,t[58]=H):H=t[58],H}function je(e){let t=(0,$.c)(18),{bodyState:n,diffRenderMode:r,diffWordWrap:i,openDiffFileInEditor:a,patchViewportRef:o,renderableFiles:s,renderablePatch:c,resolvedTheme:l}=e;if(n.kind===`no-thread`){let e;return t[0]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,Q.jsx)(Ne,{children:`Select a thread to inspect turn diffs.`}),t[0]=e):e=t[0],e}if(n.kind===`not-git-repo`){let e;return t[1]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,Q.jsx)(Ne,{children:`Turn diffs are unavailable because this project is not a git repository.`}),t[1]=e):e=t[1],e}if(n.kind===`no-completed-turns`){let e;return t[2]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,Q.jsx)(Ne,{children:`No completed turns yet.`}),t[2]=e):e=t[2],e}let u;t[3]!==n.error||t[4]!==c?(u=n.error&&!c&&(0,Q.jsx)(`div`,{className:`px-3`,children:(0,Q.jsx)(`p`,{className:`mb-2 text-[11px] text-destructive-foreground`,children:n.error})}),t[3]=n.error,t[4]=c,t[5]=u):u=t[5];let d;t[6]!==n||t[7]!==r||t[8]!==i||t[9]!==a||t[10]!==s||t[11]!==c||t[12]!==l?(d=c?c.kind===`files`?(0,Q.jsx)(K,{className:`diff-render-surface h-full min-h-0 overflow-auto px-2 pb-2`,config:{overscrollSize:600,intersectionObserverMargin:1200},children:s.map(e=>{let t=Y(e),n=`${fe(e)}:${l}`;return(0,Q.jsx)(`div`,{"data-diff-file-path":t,className:`diff-render-file mb-2 rounded-md first:mt-2 last:mb-0`,onClickCapture:e=>{(e.nativeEvent.composedPath?.()??[]).some(Me)&&a(t)},children:(0,Q.jsx)(ge,{fileDiff:e,options:{diffStyle:r===`split`?`split`:`unified`,lineDiffType:`none`,overflow:i?`wrap`:`scroll`,theme:T(l),themeType:l,unsafeCSS:De}})},n)})}):(0,Q.jsx)(`div`,{className:`h-full overflow-auto p-2`,children:(0,Q.jsxs)(`div`,{className:`space-y-2`,children:[(0,Q.jsx)(`p`,{className:`text-[11px] text-muted-foreground/75`,children:c.reason}),(0,Q.jsx)(`pre`,{className:P(`max-h-[72vh] rounded-md border border-border/70 bg-background/70 p-3 font-mono text-[11px] leading-relaxed text-muted-foreground/90`,i?`overflow-auto whitespace-pre-wrap wrap-break-word`:`overflow-auto`),children:c.text})]})}):(0,Q.jsx)(Re,{bodyState:n}),t[6]=n,t[7]=r,t[8]=i,t[9]=a,t[10]=s,t[11]=c,t[12]=l,t[13]=d):d=t[13];let f;return t[14]!==o||t[15]!==u||t[16]!==d?(f=(0,Q.jsx)(Q.Fragment,{children:(0,Q.jsxs)(`div`,{ref:o,className:`diff-panel-viewport min-h-0 min-w-0 flex-1 overflow-hidden`,children:[u,d]})}),t[14]=o,t[15]=u,t[16]=d,t[17]=f):f=t[17],f}function Me(e){return e instanceof Element&&e.hasAttribute(`data-title`)}function Ne(e){let t=(0,$.c)(2),{children:n}=e,r;return t[0]===n?r=t[1]:(r=(0,Q.jsx)(`div`,{className:`flex flex-1 items-center justify-center px-5 text-center text-xs text-muted-foreground/70`,children:n}),t[0]=n,t[1]=r),r}function Pe(){let e=(0,$.c)(19),t;e[0]===Symbol.for(`react.memo_cache_sentinel`)?(t={strict:!1,select:Ie},e[0]=t):t=e[0];let n=a(t),r;e[1]===Symbol.for(`react.memo_cache_sentinel`)?(r={strict:!1,select:Fe},e[1]=r):r=e[1];let i=B(r),o=i.rightPanel===`diff`,s=n?.threadId??null,c,l;e[2]===n?l=e[3]:(l=C(n),e[2]=n,e[3]=l),c=l;let u=E(c),f=He(u),p=u?.worktreePath,m=f?.cwd,h;e[4]!==p||e[5]!==m?(h=I({threadWorktreePath:p,projectCwd:m}),e[4]=p,e[5]=m,e[6]=h):h=e[6];let g=h,_=u?.environmentId??null,v=g??null,y;e[7]!==_||e[8]!==v?(y={environmentId:_,cwd:v},e[7]=_,e[8]=v,e[9]=y):y=e[9];let b=d(y),x;e[10]===b.data?x=e[11]:(x=z(b.data),e[10]=b.data,e[11]=x);let S=x,w;return e[12]!==g||e[13]!==u||e[14]!==s||e[15]!==o||e[16]!==i||e[17]!==S?(w={activeThread:u,activeThreadId:s,activeCwd:g,isGitRepo:S,diffSearch:i,diffOpen:o},e[12]=g,e[13]=u,e[14]=s,e[15]=o,e[16]=i,e[17]=S,e[18]=w):w=e[18],w}function Fe(e){return G(e)}function Ie(e){return h(e)}function Le(e){let{activeThread:t,activeThreadId:n,activeCwd:r,isGitRepo:i,diffSearch:a,diffOpen:o}=Pe(),{turnDiffSummaries:s,inferredCheckpointTurnCountByTurnId:c}=H(t),u=a.diffTurnId??null,d=u===null?null:a.diffFilePath??null,{activeCheckpointRange:f,conversationCacheScope:p,orderedTurnDiffSummaries:m,selectedTurn:h}=(0,X.useMemo)(()=>te({summaries:s,inferredCheckpointTurnCountByTurnId:c,selectedTurnId:u}),[c,u,s]),g=l(xe(we({environmentId:t?.environmentId,threadId:n,range:f,selectedTurnId:h?.turnId,conversationCacheScope:p,enabled:i}))),_=g.isLoading,v=Ce(g.error),y=g.data?.diff,b=typeof y==`string`&&y.trim().length===0,{emptyDiffMessage:x}=(0,X.useMemo)(()=>ae(h),[h]),S=(0,X.useMemo)(()=>ce(y,`diff-panel:${e}`),[e,y]),C=(0,X.useMemo)(()=>Ue(S),[S]);return{activeCwd:r,activeThread:t,bodyState:ue({hasActiveThread:!!t,isGitRepo:i,turnSummaryCount:m.length,checkpointDiffError:v,hasRenderablePatch:!!S,isLoadingCheckpointDiff:_,hasNoNetChanges:b,emptyDiffMessage:x}),diffOpen:o,inferredCheckpointTurnCountByTurnId:c,orderedTurnDiffSummaries:m,renderableFiles:C,renderablePatch:S,selectedFilePath:d,selectedTurn:h,selectedTurnId:u}}function Re(e){let t=(0,$.c)(4),{bodyState:n}=e;if(n.kind===`loading`){let e;return t[0]===Symbol.for(`react.memo_cache_sentinel`)?(e=(0,Q.jsx)(D,{label:`Loading checkpoint diff...`}),t[0]=e):e=t[0],e}let r;t[1]===Symbol.for(`react.memo_cache_sentinel`)?(r=(0,Q.jsx)(L,{className:`size-7 text-muted-foreground/25`}),t[1]=r):r=t[1];let i=n.kind===`empty`?n.message:`No diff is available for this range.`,a;return t[2]===i?a=t[3]:(a=(0,Q.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center gap-2 px-5 py-2 text-center`,children:[r,(0,Q.jsx)(`p`,{className:`text-xs text-muted-foreground/70`,children:i})]}),t[2]=i,t[3]=a),a}var ze=180;function Be(e){let t=(0,$.c)(14),{direction:n,strip:r}=e,i=n===`left`,a=i?r.canScrollLeft:r.canScrollRight,o=i?U:u,s=i?`left-0`:`right-0`,c=a?`border-border/70 hover:border-border hover:text-foreground`:`cursor-not-allowed border-border/40 text-muted-foreground/40`,l;t[0]!==s||t[1]!==c?(l=P(`absolute top-1/2 z-20 inline-flex size-6 -translate-y-1/2 items-center justify-center rounded-md border bg-background/90 text-muted-foreground transition-colors`,s,c),t[0]=s,t[1]=c,t[2]=l):l=t[2];let d;t[3]!==i||t[4]!==r?(d=()=>r.scrollBy(i?-180:ze),t[3]=i,t[4]=r,t[5]=d):d=t[5];let f=!a,p=`Scroll turn list ${n}`,m;t[6]===o?m=t[7]:(m=(0,Q.jsx)(o,{className:`size-3.5`}),t[6]=o,t[7]=m);let h;return t[8]!==l||t[9]!==d||t[10]!==f||t[11]!==p||t[12]!==m?(h=(0,Q.jsx)(`button`,{type:`button`,className:l,onClick:d,disabled:f,"aria-label":p,children:m}),t[8]=l,t[9]=d,t[10]=f,t[11]=p,t[12]=m,t[13]=h):h=t[13],h}function Ve(e){let t=(0,$.c)(23),{summary:n,selected:r,turnCount:i,timestampFormat:a,onSelect:o}=e,s;t[0]!==o||t[1]!==n.turnId?(s=()=>o(n.turnId),t[0]=o,t[1]=n.turnId,t[2]=s):s=t[2];let c=n.turnId,l=r?`border-border bg-accent text-accent-foreground`:`border-border/70 bg-background/70 text-muted-foreground/80 hover:border-border hover:text-foreground/80`,u;t[3]===l?u=t[4]:(u=P(`rounded-md border px-2 py-1 text-left transition-colors`,l),t[3]=l,t[4]=u);let d=i??`?`,f;t[5]===d?f=t[6]:(f=(0,Q.jsxs)(`span`,{className:`text-[10px] leading-tight font-medium`,children:[`Turn `,d]}),t[5]=d,t[6]=f);let p;t[7]!==n.completedAt||t[8]!==a?(p=y(n.completedAt,a),t[7]=n.completedAt,t[8]=a,t[9]=p):p=t[9];let m;t[10]===p?m=t[11]:(m=(0,Q.jsx)(`span`,{className:`text-[9px] leading-tight opacity-70`,children:p}),t[10]=p,t[11]=m);let h;t[12]!==f||t[13]!==m?(h=(0,Q.jsxs)(`div`,{className:`flex items-center gap-1`,children:[f,m]}),t[12]=f,t[13]=m,t[14]=h):h=t[14];let g;t[15]!==u||t[16]!==h?(g=(0,Q.jsx)(`div`,{className:u,children:h}),t[15]=u,t[16]=h,t[17]=g):g=t[17];let _;return t[18]!==r||t[19]!==n.turnId||t[20]!==s||t[21]!==g?(_=(0,Q.jsx)(`button`,{type:`button`,className:`shrink-0 rounded-md`,onClick:s,title:c,"data-turn-chip-selected":r,children:g}),t[18]=r,t[19]=n.turnId,t[20]=s,t[21]=g,t[22]=_):_=t[22],_}function He(e){let t=(0,$.c)(3),n=e?.environmentId,r=e?.projectId,i;return t[0]!==n||t[1]!==r?(i=e=>n&&r?S(e,{environmentId:n,projectId:r}):void 0,t[0]=n,t[1]=r,t[2]=i):i=t[2],E(i)}function Ue(e){return!e||e.kind!==`files`?[]:e.files.toSorted((e,t)=>Y(e).localeCompare(Y(t),void 0,{numeric:!0,sensitivity:`base`}))}export{Oe as default};
64
- //# sourceMappingURL=DiffPanel-BEf3EXPK.js.map
64
+ //# sourceMappingURL=DiffPanel-Bn53zJRq.js.map