@cmmd-center/forge 0.13.69 → 0.13.71

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.69";
65982
+ var version$1 = "0.13.71";
65983
65983
  //#endregion
65984
65984
  //#region src/sentry.ts
65985
65985
  const SERVER_APP_NAME = "forge-server";
@@ -66939,6 +66939,7 @@ const runtimeReplicationPublicationAttemptsTotal = counter("t3_runtime_replicati
66939
66939
  const runtimeReplicationPublicationRetriesTotal = counter("t3_runtime_replication_publication_retries_total", { description: "Total runtime replication retries scheduled after recoverable failures." });
66940
66940
  const runtimeReplicationPublicationLatency = timer("t3_runtime_replication_publication_latency", { description: "Time from durable enqueue to canonical CMMD acknowledgement." });
66941
66941
  const cmmdCredentialRefreshTotal = counter("t3_cmmd_credential_refresh_total", { description: "CMMD JWT refresh attempts for a Forge session, by rung (self-refresh | grant-redemption) and outcome (attempted | succeeded)." });
66942
+ const cmmdTokenMintTotal = counter("t3_cmmd_token_mint_total", { description: "CMMD short-lived forge-token mints through the mint lane (forge#3518), by outcome (attempted | succeeded). The legacy rotation ladder keeps reporting t3_cmmd_credential_refresh_total, so the two lanes stay separable in every dashboard." });
66942
66943
  const cmmdRotationFenceAppliedTotal = counter("t3_cmmd_rotation_fence_applied_total", { description: "Sessions Forge refused to rotate CMMD credentials for, because the rotation fence applied." });
66943
66944
  const cmmdCredentialRowDeletedTotal = counter("t3_cmmd_credential_row_deleted_total", { description: "command_access_tokens rows actually deleted by clearUnrecoverableCmmdAuthForSession, by reason." });
66944
66945
  const metricAttributes = (attributes) => Object.entries(compactMetricAttributes(attributes));
@@ -70944,6 +70945,63 @@ function parseCmmdOAuthRefreshResponse(value) {
70944
70945
  };
70945
70946
  }
70946
70947
  /**
70948
+ * Read the one field the mint lane consumes from CMMD's mint response.
70949
+ * Returns null unless `access_token` is present and non-empty.
70950
+ */
70951
+ function parseCmmdTokenMintResponse(value) {
70952
+ if (!value || typeof value !== "object") return null;
70953
+ const accessToken = value["access_token"];
70954
+ if (typeof accessToken !== "string" || accessToken.trim().length === 0) return null;
70955
+ return { accessToken: accessToken.trim() };
70956
+ }
70957
+ /**
70958
+ * How long the mint may take before the lane gives up on it. Minting is one
70959
+ * grant lookup and one signature on CMMD's side; anything slower is treated
70960
+ * like a failure and the resolver falls through to the legacy ladder.
70961
+ */
70962
+ const MINT_TIMEOUT_MS = 1e4;
70963
+ /**
70964
+ * Mint a short-lived forge-scoped access token from a durable session grant
70965
+ * (forge#3518 expand phase).
70966
+ *
70967
+ * The grant is non-rotating and redeemable on demand, so this is the mint
70968
+ * lane's entire refresh story: call it again when the short-lived token
70969
+ * expires. CMMD answers with `access_token` only (no refresh token, no MCP
70970
+ * PAT, nothing durable), so a session that lives entirely on this lane never
70971
+ * accumulates long-lived credential state on Forge's side.
70972
+ *
70973
+ * Returns null for every failure because the resolver wants a value, not a
70974
+ * thrown error; the failure modes are logged by status and OAuth error code
70975
+ * the same way `refreshCmmdJwt` logs them. A rejection here is never fed to
70976
+ * the credential-rejection ledger: the ledger exists to prove a session's
70977
+ * *rotation* credential is dead, and the grant dying says nothing about the
70978
+ * refresh token the legacy fallback still owns.
70979
+ */
70980
+ function mintCmmdShortLivedToken(grantToken) {
70981
+ return fetch(new URL("/api/mcp-server/oauth/token", resolveCommandAppUrl()).toString(), {
70982
+ method: "POST",
70983
+ headers: { "Content-Type": "application/json" },
70984
+ body: JSON.stringify({
70985
+ grant_type: "forge_token_mint",
70986
+ grant_token: grantToken,
70987
+ client_id: "cmmd-forge-web"
70988
+ }),
70989
+ signal: AbortSignal.timeout(MINT_TIMEOUT_MS)
70990
+ }).then(async (response) => {
70991
+ if (!response.ok) {
70992
+ const errorCode = await readOAuthErrorCode(response);
70993
+ console.warn(`[cmmd-auth] CMMD refused a forge token mint with ${response.status}${errorCode === null ? "" : ` (${errorCode})`}`);
70994
+ return null;
70995
+ }
70996
+ const parsed = parseCmmdTokenMintResponse(await response.json());
70997
+ if (!parsed) console.warn("[cmmd-auth] CMMD accepted a forge token mint but returned no usable access token");
70998
+ return parsed;
70999
+ }).catch((cause) => {
71000
+ console.warn(`[cmmd-auth] CMMD forge token mint could not be completed: ${String(cause)}`);
71001
+ return null;
71002
+ });
71003
+ }
71004
+ /**
70947
71005
  * Redeem a durable CMMD session grant for a fresh credential set.
70948
71006
  *
70949
71007
  * The grant is CMMD's designed recovery path for exactly the case a rotating
@@ -71034,6 +71092,42 @@ async function readOAuthErrorCode(response) {
71034
71092
  }
71035
71093
  }
71036
71094
  //#endregion
71095
+ //#region src/command/cmmdTokenMintLane.ts
71096
+ /**
71097
+ * The CMMD token-mint lane (forge#3518, expand phase).
71098
+ *
71099
+ * A new FIRST rung beside the legacy credential ladder: instead of rotating
71100
+ * CMMD's single-use refresh tokens, the resolver mints a short-lived
71101
+ * forge-scoped access token from the session's durable, non-rotating session
71102
+ * grant (`grant_type: forge_token_mint` on CMMD's token endpoint). The mint
71103
+ * spends nothing that cannot be spent again, so it cannot race itself into
71104
+ * `invalid_grant` the way a rotation can.
71105
+ *
71106
+ * Behind a config flag that is OFF unless explicitly enabled: production
71107
+ * keeps the legacy ladder as the only lane until this is switched on
71108
+ * deliberately. When enabled, the lane is tried before the legacy ladder;
71109
+ * every legacy rung (rotation fence, self-refresh, grant redemption,
71110
+ * bootstrap promotion, subject fallback) still exists below it unchanged and
71111
+ * still guards itself with the rejection ledger.
71112
+ */
71113
+ /** Env var that enables the mint lane. Unset and anything but an affirmative value is off. */
71114
+ const CMMD_TOKEN_MINT_LANE_ENV = "FORGE_CMMD_TOKEN_MINT_LANE";
71115
+ const AFFIRMATIVE_VALUES = new Set([
71116
+ "1",
71117
+ "on",
71118
+ "true",
71119
+ "yes"
71120
+ ]);
71121
+ /**
71122
+ * Whether the mint lane may run. Default off everywhere: a missing env var is
71123
+ * the production posture, and an opt-in flag must not half-default to on in
71124
+ * any environment a misconfigured deploy might land in.
71125
+ */
71126
+ function isCmmdTokenMintLaneEnabled(env = process.env) {
71127
+ const raw = env[CMMD_TOKEN_MINT_LANE_ENV]?.trim().toLowerCase();
71128
+ return raw !== void 0 && AFFIRMATIVE_VALUES.has(raw);
71129
+ }
71130
+ //#endregion
71037
71131
  //#region src/command/cmmdRotationFence.ts
71038
71132
  /**
71039
71133
  * Log and count a fence application, without changing the verdict it reports.
@@ -71122,12 +71216,13 @@ function usableCmmdUserJwt(token) {
71122
71216
  function storeResolvedJwt(sessionId, accessToken, refreshToken) {
71123
71217
  return setCommandJwtForSession(sessionId, accessToken, refreshToken ? { refreshToken } : {}).pipe(ignore({ log: true }));
71124
71218
  }
71125
- function logCmmdJwtRung(context, rung, outcome, reason) {
71219
+ function logCmmdJwtRung(context, rung, outcome, reason, lane = "legacy") {
71126
71220
  return (outcome === "failed" ? logWarning$1 : logInfo)("CMMD JWT resolver rung.", {
71127
71221
  sessionId: context.sessionId,
71128
71222
  subject: context.subject,
71129
71223
  deviceType: context.deviceType,
71130
71224
  caller: context.caller,
71225
+ lane,
71131
71226
  rung,
71132
71227
  outcome,
71133
71228
  reason
@@ -71140,6 +71235,25 @@ function recordCmmdCredentialRefreshMetric(rung, outcome) {
71140
71235
  })), 1);
71141
71236
  }
71142
71237
  const inFlightRefreshes = /* @__PURE__ */ new Map();
71238
+ /** In-flight mints, keyed by session, same shape as `inFlightRefreshes`. */
71239
+ const inFlightMints = /* @__PURE__ */ new Map();
71240
+ /**
71241
+ * Collapse concurrent mints for one session into a single upstream call. A
71242
+ * mint cannot race itself into `invalid_grant` (the grant is non-rotating),
71243
+ * so this is call-rate hygiene, not correctness: two tabs observing the same
71244
+ * expiry must not both hit CMMD when one mint would do.
71245
+ */
71246
+ function mintOnceForSession(sessionId, grantToken) {
71247
+ return promise(() => {
71248
+ const existing = inFlightMints.get(sessionId);
71249
+ if (existing) return existing;
71250
+ const pending = mintCmmdShortLivedToken(grantToken).catch(() => null).finally(() => {
71251
+ inFlightMints.delete(sessionId);
71252
+ });
71253
+ inFlightMints.set(sessionId, pending);
71254
+ return pending;
71255
+ });
71256
+ }
71143
71257
  function refreshOnceForSession(sessionId, refreshToken) {
71144
71258
  return promise(() => {
71145
71259
  const existing = inFlightRefreshes.get(sessionId);
@@ -71179,6 +71293,39 @@ function trySelfRefresh(sessionId, context) {
71179
71293
  });
71180
71294
  }
71181
71295
  /**
71296
+ * The mint lane's rung (forge#3518, expand phase): mint a short-lived
71297
+ * forge-scoped access token from this session's durable session grant.
71298
+ *
71299
+ * Tried FIRST, before the rotation fence and the whole legacy ladder, when
71300
+ * `FORGE_CMMD_TOKEN_MINT_LANE` is on. Minting spends nothing that cannot be
71301
+ * spent again (the grant is non-rotating), so unlike the legacy rungs it is
71302
+ * safe for a session the rotation fence fences off, and it never feeds the
71303
+ * credential-rejection ledger: this rung failing says nothing about whether
71304
+ * the legacy rungs below it can still succeed.
71305
+ *
71306
+ * Only the JWT is persisted (`setCommandJwtForSession`, no refresh token):
71307
+ * the short lifetime is the expiry story, and re-minting is the refresh
71308
+ * story. A session that lives entirely on this lane accumulates no new
71309
+ * long-lived credential state beyond the grant it already had.
71310
+ */
71311
+ function tryMintShortLivedToken(sessionId, context) {
71312
+ const grantToken = readCommandSessionGrantForSession(sessionId);
71313
+ if (!grantToken) return logCmmdJwtRung(context, "mint", "skipped", "no session grant stored for this session", "mint").pipe(as$3(null));
71314
+ return gen(function* () {
71315
+ yield* logCmmdJwtRung(context, "mint", "attempted", "minting a short-lived forge-scoped token from this session's grant", "mint");
71316
+ yield* update$3(withAttributes(cmmdTokenMintTotal, metricAttributes({ outcome: "attempted" })), 1);
71317
+ const accessToken = usableCmmdUserJwt((yield* mintOnceForSession(sessionId, grantToken))?.accessToken);
71318
+ if (!accessToken) {
71319
+ yield* logCmmdJwtRung(context, "mint", "failed", "CMMD token mint did not return a usable user access JWT", "mint");
71320
+ return null;
71321
+ }
71322
+ yield* setCommandJwtForSession(sessionId, accessToken, {}).pipe(ignore({ log: true }));
71323
+ yield* update$3(withAttributes(cmmdTokenMintTotal, metricAttributes({ outcome: "succeeded" })), 1);
71324
+ yield* logCmmdJwtRung(context, "mint", "succeeded", "CMMD minted a short-lived forge-scoped token", "mint");
71325
+ return accessToken;
71326
+ });
71327
+ }
71328
+ /**
71182
71329
  * Last-resort recovery: redeem this session's durable CMMD session grant.
71183
71330
  *
71184
71331
  * A refresh token is single-use, so a session that lost a rotation — raced, or
@@ -71298,8 +71445,10 @@ function runRecoveryLadder(sessionId, normalizedSubject, forceRefresh, context)
71298
71445
  * Resolve the CMMD REST JWT for a Forge session.
71299
71446
  *
71300
71447
  * Forge session auth is long-lived compared with the short-lived CMMD JWT.
71301
- * When the session JWT expires, recover by promoting a valid subject-level JWT
71302
- * or rotating the stored CMMD refresh token.
71448
+ * When the session JWT expires, recover by minting a fresh short-lived token
71449
+ * from the session grant (the mint lane; default-off, forge#3518), or, on
71450
+ * the legacy lane, by promoting a valid subject-level JWT or rotating the
71451
+ * stored CMMD refresh token.
71303
71452
  *
71304
71453
  * Fail-closed: never returns a non-user / malformed Bearer. Callers must map
71305
71454
  * null to CMMD_AUTH_REQUIRED and must not call CMMD upstream with a bad token.
@@ -71319,7 +71468,8 @@ function resolveCmmdJwtForSession({ sessionId, subject, logPrefix = "cmmd-auth",
71319
71468
  })));
71320
71469
  }
71321
71470
  const normalizedSubject = subject?.trim() || null;
71322
- if (!normalizedSubject && !forceRefresh) return succeed(null);
71471
+ const mintLaneEnabled = isCmmdTokenMintLaneEnabled();
71472
+ if (!normalizedSubject && !forceRefresh && !mintLaneEnabled) return succeed(null);
71323
71473
  return gen(function* () {
71324
71474
  const context = {
71325
71475
  sessionId,
@@ -71327,6 +71477,14 @@ function resolveCmmdJwtForSession({ sessionId, subject, logPrefix = "cmmd-auth",
71327
71477
  deviceType: yield* readClientDeviceTypeForSession(sessionId),
71328
71478
  caller: logPrefix
71329
71479
  };
71480
+ if (mintLaneEnabled) {
71481
+ const minted = yield* tryMintShortLivedToken(sessionId, context);
71482
+ if (minted) return minted;
71483
+ if (!normalizedSubject && !forceRefresh) {
71484
+ yield* logCmmdJwtRung(context, "mint", "failed", "no subject to resolve and the mint lane produced nothing", "mint");
71485
+ return null;
71486
+ }
71487
+ }
71330
71488
  if (yield* isRotationFencedSession(sessionId)) {
71331
71489
  yield* logCmmdJwtRung(context, "rotation-fence", "failed", "session is fenced from rotating CMMD credentials");
71332
71490
  return null;
@@ -87512,6 +87670,38 @@ function readRuntimeBrokerAuthority(input) {
87512
87670
  if (authority.credentialEpoch !== input.credentialEpoch) return null;
87513
87671
  return authority.token;
87514
87672
  }
87673
+ /**
87674
+ * Why a scoped lookup would miss, without mutating the map.
87675
+ *
87676
+ * "no live broker authority for this session" used to be one flat reason
87677
+ * whether nothing had ever been recorded, an entry had just expired, or an
87678
+ * entry existed for the wrong runtime, machine, or epoch. This lets a caller
87679
+ * name the distinction to an operator reading a production refusal.
87680
+ *
87681
+ * Read-only by design: call this BEFORE readRuntimeBrokerAuthority for the
87682
+ * same input. That read evicts an expired entry as it scans, so calling this
87683
+ * afterward would find the entry already gone and report "absent" for what
87684
+ * was really "expired".
87685
+ */
87686
+ function describeRuntimeBrokerAuthorityMiss(input) {
87687
+ const nowSeconds = input.nowSeconds ?? Math.floor(Date.now() / 1e3);
87688
+ const scopedAuthorities = authorities.get(input.sessionId)?.get(input.requiredScope);
87689
+ if (!scopedAuthorities || scopedAuthorities.size === 0) return "absent";
87690
+ let selected = null;
87691
+ let sawExpired = false;
87692
+ for (const authority of scopedAuthorities.values()) {
87693
+ if (authority.expiresAtSeconds <= nowSeconds) {
87694
+ sawExpired = true;
87695
+ continue;
87696
+ }
87697
+ if (!selected || authority.expiresAtSeconds >= selected.expiresAtSeconds) selected = authority;
87698
+ }
87699
+ if (!selected) return sawExpired ? "expired" : "absent";
87700
+ if (selected.runtimeId !== input.runtimeId) return "runtime mismatch";
87701
+ if (selected.machineId !== input.machineId) return "machine mismatch";
87702
+ if (selected.credentialEpoch !== input.credentialEpoch) return "epoch mismatch";
87703
+ return "absent";
87704
+ }
87515
87705
  function readRuntimeBrokerAuthorityForRuntime(input) {
87516
87706
  for (const sessionId of authorities.keys()) {
87517
87707
  const token = readRuntimeBrokerAuthority({
@@ -151967,6 +152157,30 @@ function runtimeAuthoritySessionId(input) {
151967
152157
  if (input.authSessionId) return input.authSessionId;
151968
152158
  return input.threadId ? readThreadSessionId(input.threadId) : null;
151969
152159
  }
152160
+ const BROKER_AUTHORITY_MISS_PHRASE = {
152161
+ absent: "nothing has ever been recorded for this session and scope",
152162
+ expired: "the recorded authority already passed its expiry",
152163
+ "runtime mismatch": "the recorded authority names a different runtime",
152164
+ "machine mismatch": "the recorded authority names a different machine",
152165
+ "epoch mismatch": "the recorded authority names a different credential epoch"
152166
+ };
152167
+ /**
152168
+ * The base "no live broker authority" reason, enriched with what the lookup
152169
+ * compared and why it missed when that detail is available.
152170
+ *
152171
+ * A production refusal used to say only "no live broker authority for this
152172
+ * session", true whether nothing had ever been recorded, an entry had just
152173
+ * expired, or an entry existed for the wrong runtime, machine, or epoch. An
152174
+ * operator reading the log had no way to tell those apart (CMMD-Center/forge#3547).
152175
+ * `missDetail` is optional so a caller that has not resolved it (or a test
152176
+ * pinning the plain-outcome mapping) still gets the original, unqualified
152177
+ * sentence.
152178
+ */
152179
+ function describeNoLiveBrokerAuthorityReason(sessionId, missDetail) {
152180
+ const base = "no live broker authority for this session";
152181
+ if (!missDetail) return base;
152182
+ return `${base} (looked up session ${sessionId}, scope ${missDetail.requiredScope}, runtime ${missDetail.runtimeId}, machine ${missDetail.machineId}, epoch ${missDetail.credentialEpoch}: ${BROKER_AUTHORITY_MISS_PHRASE[missDetail.missReason]})`;
152183
+ }
151970
152184
  /**
151971
152185
  * Pure mapping from the three preconditions to an outcome.
151972
152186
  *
@@ -151992,7 +152206,7 @@ function resolveBrokerTicketOutcome(input) {
151992
152206
  token: input.brokerAuthority
151993
152207
  } : {
151994
152208
  kind: "unavailable",
151995
- reason: "no live broker authority for this session"
152209
+ reason: describeNoLiveBrokerAuthorityReason(input.sessionId, input.missDetail ?? null)
151996
152210
  };
151997
152211
  }
151998
152212
  /**
@@ -152024,17 +152238,43 @@ function runtimeProviderBrokerToken(input) {
152024
152238
  brokerAuthority: null
152025
152239
  });
152026
152240
  const sessionId = runtimeAuthoritySessionId(input);
152241
+ if (!sessionId) return resolveBrokerTicketOutcome({
152242
+ identityMode: "exact",
152243
+ legacyGrantToken: null,
152244
+ sessionId: null,
152245
+ brokerAuthority: null
152246
+ });
152247
+ const runtimeId = process.env.FORGE_CMMD_RUNTIME_ID;
152248
+ const requiredScope = "provider";
152249
+ const nowSeconds = Math.floor(Date.now() / 1e3);
152250
+ const missReason = describeRuntimeBrokerAuthorityMiss({
152251
+ sessionId,
152252
+ runtimeId,
152253
+ machineId: identity.machineId,
152254
+ credentialEpoch: identity.credentialEpoch,
152255
+ requiredScope,
152256
+ nowSeconds
152257
+ });
152258
+ const brokerAuthority = readRuntimeBrokerAuthority({
152259
+ sessionId,
152260
+ runtimeId,
152261
+ machineId: identity.machineId,
152262
+ credentialEpoch: identity.credentialEpoch,
152263
+ requiredScope,
152264
+ nowSeconds
152265
+ });
152027
152266
  return resolveBrokerTicketOutcome({
152028
152267
  identityMode: "exact",
152029
152268
  legacyGrantToken: null,
152030
152269
  sessionId,
152031
- brokerAuthority: sessionId ? readRuntimeBrokerAuthority({
152032
- sessionId,
152033
- runtimeId: process.env.FORGE_CMMD_RUNTIME_ID,
152270
+ brokerAuthority,
152271
+ missDetail: brokerAuthority ? null : {
152272
+ requiredScope,
152273
+ runtimeId,
152034
152274
  machineId: identity.machineId,
152035
152275
  credentialEpoch: identity.credentialEpoch,
152036
- requiredScope: "provider"
152037
- }) : null
152276
+ missReason
152277
+ }
152038
152278
  });
152039
152279
  }
152040
152280
  async function fetchRuntimeProviderGrant(input) {
@@ -297854,7 +298094,7 @@ function resolveBuildCommitFromEnv(env) {
297854
298094
  * environment descriptor down instead of reporting an honest "unknown".
297855
298095
  */
297856
298096
  function readBakedBuildCommit() {
297857
- return "ac91dc3fd479252ab728872fa5df9aaf5959eca7";
298097
+ return "8e9fcb0318612dd80655f7c9662dd9128b8f005c";
297858
298098
  }
297859
298099
  async function resolveServerBuildCommit(input) {
297860
298100
  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-DeM453UE.js";import{hn as P}from"./CompositeItem-BsSeqHOM.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-DRTMsi3V.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-Be6CFoCi.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-DrmtqFA3.js";import{hn as P}from"./CompositeItem-BsSeqHOM.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-BN2Oq2PR.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-QEKd4_Au.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-CVv1a4t6.js.map
64
+ //# sourceMappingURL=DiffPanel-7EXLivet.js.map