@cmmd-center/forge 0.13.96 → 0.13.98

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
@@ -66041,7 +66041,7 @@ function normalizeNumberish(value) {
66041
66041
  }
66042
66042
  //#endregion
66043
66043
  //#region package.json
66044
- var version$1 = "0.13.96";
66044
+ var version$1 = "0.13.98";
66045
66045
  //#endregion
66046
66046
  //#region src/sentry.ts
66047
66047
  const SERVER_APP_NAME = "forge-server";
@@ -98014,6 +98014,119 @@ function providerAuthFailureMessage(message, provider, env = process.env) {
98014
98014
  }).message;
98015
98015
  }
98016
98016
  //#endregion
98017
+ //#region ../../packages/shared/src/publicProviderCopy.ts
98018
+ const PUBLIC_PROVIDER_LEAK_PATTERNS = [
98019
+ /\bDeepSeek\b/i,
98020
+ /\bKimi\b/i,
98021
+ /\bMoonshot\b/i,
98022
+ /\bdeepseek[-._a-z0-9]*\b/i,
98023
+ /\bkimi[-._a-z0-9]*\b/i,
98024
+ /\bmoonshot[-._a-z0-9]*\b/i,
98025
+ /\bAPEX_API_KEY\b/,
98026
+ /\bDEEPSEEK_API_KEY\b/,
98027
+ /\bKIMI_API_KEY\b/,
98028
+ /\bOPENAI_API_KEY\b/,
98029
+ /\bANTHROPIC_API_KEY\b/,
98030
+ /\bCURSOR_API_KEY\b/,
98031
+ /\bOPENCODE_API_KEY\b/,
98032
+ /\bforge_proxy_[A-Za-z0-9._-]+\b/,
98033
+ /\bProviderValidationError\b/,
98034
+ /\/forge-server\/node_modules\//,
98035
+ /https?:\/\/[^\s'"<>)]*\/api\/provider-egress\/[^\s'"<>)]*/i,
98036
+ /https?:\/\/[^\s'"<>)]*(?:apex|deepseek|moonshot|kimi)[^\s'"<>)]*/i
98037
+ ];
98038
+ const DEFAULT_PUBLIC_PROVIDER_ERROR = "CMMD is temporarily unavailable. Check the workspace AI connection and retry.";
98039
+ function isProviderRateOrQuotaError(message) {
98040
+ if (!message) return false;
98041
+ const normalized = message.toLowerCase();
98042
+ return /\b(rate[\s-]?limit|too\s+many\s+requests|usage[ _-]limit|usage_limit_reached|quota|insufficient_quota)\b/.test(normalized) || /\b429\b/.test(normalized);
98043
+ }
98044
+ function providerLifecycleOrAccountCopy(message) {
98045
+ if (/\bbound to provider account\b/.test(message) && /\bcannot use provider account\b/.test(message)) return "Forge could not switch this conversation to the selected AI account. Retry the account switch.";
98046
+ if (/\bforge_runtime_repairing\b/.test(message) || /\bthis turn was interrupted because the environment is being repaired\b/.test(message)) return "This turn was interrupted because the environment is being repaired. Retry after the repair finishes.";
98047
+ if (/\bforge_runtime_stopped\b/.test(message) || /\bthis turn was interrupted because the environment was stopped\b/.test(message)) return "This turn was interrupted because the environment was stopped. Start the environment and retry.";
98048
+ return null;
98049
+ }
98050
+ /**
98051
+ * Infer a SAFE, clearer failure category from a (possibly leaky) provider error.
98052
+ *
98053
+ * Returns a canned, user-facing message — it never echoes the raw input, so it
98054
+ * is safe to use even when the source message contains provider internals.
98055
+ * Used to give actionable feedback ("model isn't available", "rate-limited",
98056
+ * "auth failed") instead of the blanket "CMMD is temporarily unavailable."
98057
+ * Returns null when no category can be confidently inferred.
98058
+ */
98059
+ function categorizePublicProviderError(message) {
98060
+ if (!message) return null;
98061
+ const m = message.toLowerCase();
98062
+ const lifecycleOrAccountCopy = providerLifecycleOrAccountCopy(m);
98063
+ if (lifecycleOrAccountCopy !== null) return lifecycleOrAccountCopy;
98064
+ if (/\bforge_provider_model_not_allowed\b/.test(m) || /\bnot\s+scoped\s+to\s+the\s+requested\s+model\b/.test(m)) return "The workspace AI credential does not cover the model this turn asked for. Retry, or pick that model for the thread.";
98065
+ if (/\bmodel\b[\s\S]*\b(not\s+(found|available|supported)|does\s+not\s+exist|unsupported|invalid|unknown)\b/.test(m) || /\b(unsupported|unknown|invalid)\b[\s\S]*\bmodel\b/.test(m) || /\b(model_not_found|invalid_model|model_not_supported)\b/.test(m)) return "The selected model isn't available right now. Pick a different model and retry.";
98066
+ if (isProviderRateOrQuotaError(m)) return "The AI service is rate-limited or out of quota. Wait a moment and retry.";
98067
+ if (/_credential_reconnect_required\b/.test(m)) return "The workspace AI credential needs to be reconnected. Reconnect it in Settings > Providers, then retry.";
98068
+ if (/\b(unauthorized|forbidden|authentication\s+(failed|error|required)|invalid\s+api\s+key|expired\s+(token|credential))\b/.test(m) || /\b40[13]\b/.test(m)) return "Workspace AI authentication failed. Reconnect the workspace and retry.";
98069
+ if (/\b(timed?\s*out|timeout|overloaded|service\s+unavailable)\b/.test(m) || /\b50[234]\b/.test(m)) return "The AI service is temporarily overloaded. Retry in a moment.";
98070
+ return null;
98071
+ }
98072
+ function containsPublicProviderLeak(message) {
98073
+ if (!message) return false;
98074
+ return PUBLIC_PROVIDER_LEAK_PATTERNS.some((pattern) => pattern.test(message));
98075
+ }
98076
+ function sanitizePublicProviderText(message, options = {}) {
98077
+ if (message === void 0 || message === null) return null;
98078
+ const trimmed = message.trim();
98079
+ if (trimmed.length === 0) return null;
98080
+ if (!containsPublicProviderLeak(trimmed)) return trimmed;
98081
+ return categorizePublicProviderError(trimmed) ?? options.fallback ?? "CMMD is temporarily unavailable. Check the workspace AI connection and retry.";
98082
+ }
98083
+ //#endregion
98084
+ //#region src/orchestration/providerRetryableFailure.ts
98085
+ /**
98086
+ * Classifies a provider turn-start failure as a retryable rate-limit or
98087
+ * transient-availability failure (429/503), a terminal failure that names why
98088
+ * it will never clear on its own, or unrecognized (null).
98089
+ *
98090
+ * CMMD-Center/forge#3558: a 429 from CMMD's provider egress used to leave no
98091
+ * trace at all, because nothing in the turn-start path recognized it as a
98092
+ * distinct, retryable failure. `ProviderCommandReactor` uses this to decide
98093
+ * whether to retry a turn start with backoff, and to name the provider,
98094
+ * status and Retry-After in the `provider.turn.start.failed` activity CMMD's
98095
+ * watchdog reads once retries are exhausted.
98096
+ *
98097
+ * Reuses `isProviderRateOrQuotaError` (the same predicate the public-copy
98098
+ * sanitizer uses to recognize a rate-limit message) rather than restating its
98099
+ * word list here.
98100
+ */
98101
+ const SERVICE_UNAVAILABLE_PATTERN = /\b(503|service\s+unavailable)\b/i;
98102
+ const RATE_LIMITED_PAST_TENSE_PATTERN = /\brate[\s-]?limit(?:ed|ing)?\b/i;
98103
+ const QUOTA_OR_USAGE_LIMIT_PATTERN = /\b(usage[ _-]limit|usage_limit_reached|quota|insufficient_quota)\b/i;
98104
+ const EXPLICIT_429_PATTERN = /\b429\b/;
98105
+ const RETRY_AFTER_SECONDS_PATTERN = /retry-after[^0-9]{0,10}(\d+)|(?:try again|retry)\s+in\s+(\d+)\s*(?:s\b|sec(?:onds?)?\b)?/i;
98106
+ function parseRetryAfterSeconds(detail) {
98107
+ const match = detail.match(RETRY_AFTER_SECONDS_PATTERN);
98108
+ if (!match) return null;
98109
+ const raw = match[1] ?? match[2];
98110
+ const seconds = raw ? Number(raw) : NaN;
98111
+ return Number.isFinite(seconds) ? seconds : null;
98112
+ }
98113
+ function classifyRetryableProviderFailure(detail) {
98114
+ if (!detail || detail.trim().length === 0) return null;
98115
+ if (QUOTA_OR_USAGE_LIMIT_PATTERN.test(detail) && !EXPLICIT_429_PATTERN.test(detail)) return {
98116
+ kind: "terminal",
98117
+ reason: "quota",
98118
+ message: detail
98119
+ };
98120
+ const isRateLimited = isProviderRateOrQuotaError(detail) || RATE_LIMITED_PAST_TENSE_PATTERN.test(detail);
98121
+ const isUnavailable = SERVICE_UNAVAILABLE_PATTERN.test(detail);
98122
+ if (!isRateLimited && !isUnavailable) return null;
98123
+ return {
98124
+ kind: "retryable",
98125
+ status: isRateLimited ? 429 : 503,
98126
+ retryAfterSeconds: parseRetryAfterSeconds(detail)
98127
+ };
98128
+ }
98129
+ //#endregion
98017
98130
  //#region src/orchestration/turnFailureReason.ts
98018
98131
  /**
98019
98132
  * Machine-readable reasons for a turn that failed before it produced any
@@ -98047,6 +98160,31 @@ function classifyProviderTurnStartFailureReason(detail) {
98047
98160
  message
98048
98161
  };
98049
98162
  }
98163
+ /**
98164
+ * Classifies a turn that ended mid-flight, after it had already started
98165
+ * (CMMD-Center/forge#3562 piece A): a `runtime.error` that reached CMMD as
98166
+ * `error_summary`, now also read into a `turn_status: failed` reason.
98167
+ *
98168
+ * `provider_turn_failed` is the code CMMD's own error_summary heuristic
98169
+ * already assigns this class of failure
98170
+ * (`shared/forge-work-session-failure-reasons.ts`), so a Forge-sent
98171
+ * `turn_status` carrying it lines up with what CMMD already infers instead
98172
+ * of teaching it a new code for the common case. `provider_usage_limit`
98173
+ * reuses the same wording `classifyRetryableProviderFailure` already treats
98174
+ * as a wall that will not clear by retrying (CMMD-Center/forge#3558): a
98175
+ * usage-limit message inside a turn that already ended is worth naming
98176
+ * specifically, even without the fuller upstream port (see the piece A PR's
98177
+ * follow-up issue) that would stop Codex from retrying against that wall in
98178
+ * the first place.
98179
+ */
98180
+ function classifyMidTurnFailureReason(detail) {
98181
+ const message = detail && detail.trim().length > 0 ? detail : "The runtime reported an error while this run was in progress.";
98182
+ const classified = classifyRetryableProviderFailure(detail);
98183
+ return {
98184
+ code: classified?.kind === "terminal" && classified.reason === "quota" ? "provider_usage_limit" : "provider_turn_failed",
98185
+ message
98186
+ };
98187
+ }
98050
98188
  function checkpointTimeoutReason(detail) {
98051
98189
  return {
98052
98190
  code: "checkpoint_timeout",
@@ -98181,6 +98319,108 @@ function serializeReplicaMessage(message) {
98181
98319
  };
98182
98320
  }
98183
98321
  //#endregion
98322
+ //#region src/orchestration/turnTerminalStatus.ts
98323
+ /**
98324
+ * Shared vocabulary between the reactor that records how a turn ended
98325
+ * (`Layers/CheckpointReactor.ts`, on the provider's own `turn.completed`
98326
+ * event) and the serializer that turns that record into CMMD's `turn_status`
98327
+ * terminal event (`runtimeReplication/turnTerminalStatusSerializer.ts`).
98328
+ * CMMD-Center/forge#3562 piece A, CMMD-Center/CMMD#5822.
98329
+ */
98330
+ /** The activity kind this durable record uses. Never sent to CMMD as-is: the
98331
+ * serializer reads it and emits the wire `turn_status` event instead. */
98332
+ const TURN_TERMINAL_STATUS_ACTIVITY_KIND = "turn.terminal-status";
98333
+ /**
98334
+ * CMMD's three-way outcome from the provider's own four-way `turn.completed`
98335
+ * state. `cancelled` and `interrupted` both read as `interrupted`: neither
98336
+ * the provider wording nor CMMD's Work Session UI distinguishes an
98337
+ * operator-cancelled turn from one the provider gave up on mid-flight.
98338
+ */
98339
+ function turnTerminalOutcomeFromRuntimeState(state) {
98340
+ if (state === "failed") return "failed";
98341
+ if (state === "completed") return "completed";
98342
+ return "interrupted";
98343
+ }
98344
+ /**
98345
+ * Deterministic activity id for a turn's terminal record: never
98346
+ * `crypto.randomUUID()`. The projector replaces an activity by id
98347
+ * (`thread.activity-appended`), so a redelivered `turn.completed` for the
98348
+ * same turn lands on the same row instead of adding a second one, and the
98349
+ * serializer's own `eventId` (`activity:<id>`) inherits the same guarantee.
98350
+ */
98351
+ function turnTerminalStatusActivityId(turnId) {
98352
+ return `turn-terminal:${turnId}`;
98353
+ }
98354
+ //#endregion
98355
+ //#region src/runtimeReplication/eventFormatting.ts
98356
+ /**
98357
+ * Small formatting helpers shared by every source `serializer.ts` folds into
98358
+ * a thread's replicated event list. Kept in their own module, with no
98359
+ * dependency on `serializer.ts` itself, so a narrower serializer (such as
98360
+ * `turnTerminalStatusSerializer.ts`) can reuse them without creating an
98361
+ * import cycle back into the file that assembles the full event list.
98362
+ */
98363
+ function text(value, max) {
98364
+ const normalized = value.trim();
98365
+ return normalized ? normalized.slice(0, max) : null;
98366
+ }
98367
+ function canonicalRuntimeEventTimestamp(value) {
98368
+ let timestamp = new Date(value);
98369
+ if (Number.isNaN(timestamp.getTime())) {
98370
+ const legacyBsdNanoseconds = value.match(/^(.*:\d{2})\.\d+NZ$/);
98371
+ timestamp = new Date(legacyBsdNanoseconds ? `${legacyBsdNanoseconds[1]}Z` : value);
98372
+ }
98373
+ if (Number.isNaN(timestamp.getTime())) throw new Error(`Invalid runtime event timestamp: ${value}`);
98374
+ return timestamp.toISOString();
98375
+ }
98376
+ //#endregion
98377
+ //#region src/runtimeReplication/turnTerminalStatusSerializer.ts
98378
+ function outcomeOf(payload) {
98379
+ if (!payload || typeof payload !== "object") return null;
98380
+ const outcome = payload.outcome;
98381
+ return outcome === "completed" || outcome === "interrupted" || outcome === "failed" ? outcome : null;
98382
+ }
98383
+ function errorMessageOf(payload) {
98384
+ if (!payload || typeof payload !== "object") return null;
98385
+ const message = payload.errorMessage;
98386
+ return typeof message === "string" && message.trim().length > 0 ? message : null;
98387
+ }
98388
+ /**
98389
+ * Turns the one durable activity `Layers/CheckpointReactor.ts` records when a
98390
+ * turn ends into CMMD's `turn_status` terminal event (CMMD-Center/forge#3562
98391
+ * piece A, CMMD-Center/CMMD#5822): `completed`, `interrupted`, or `failed`
98392
+ * with a structured `reason`. `error_summary` (`serializeFailureActivity` in
98393
+ * `serializer.ts`) keeps replicating separately for a mid-turn failure; this
98394
+ * is added next to it, never instead of it.
98395
+ *
98396
+ * The activity's own id is deterministic (`turn-terminal:<turnId>`,
98397
+ * `turnTerminalStatusActivityId`), so this event's `eventId` -- built from
98398
+ * that id the same way every other activity-sourced event on this thread is
98399
+ * (`activity:<id>`) -- can never collide with a second, different terminal
98400
+ * status for the same turn: there is exactly one activity row to read it
98401
+ * from, and the reactor that writes that row never overwrites it once set.
98402
+ */
98403
+ function serializeTurnTerminalStatusActivity(activity) {
98404
+ if (activity.kind !== "turn.terminal-status" || !activity.turnId) return null;
98405
+ const outcome = outcomeOf(activity.payload);
98406
+ if (outcome === null) return null;
98407
+ const reason = outcome === "failed" ? classifyMidTurnFailureReason(errorMessageOf(activity.payload)) : null;
98408
+ return {
98409
+ sourceSequence: null,
98410
+ event: {
98411
+ eventId: `activity:${activity.id}`,
98412
+ occurredAt: canonicalRuntimeEventTimestamp(activity.createdAt),
98413
+ turnId: activity.turnId,
98414
+ kind: "turn_status",
98415
+ status: outcome,
98416
+ ...reason ? { reason: {
98417
+ code: reason.code,
98418
+ message: text(reason.message, 2e3) ?? reason.message
98419
+ } } : {}
98420
+ }
98421
+ };
98422
+ }
98423
+ //#endregion
98184
98424
  //#region src/runtimeReplication/serializer.ts
98185
98425
  function threadStatus(thread) {
98186
98426
  if (thread.archivedAt) return "archived";
@@ -98247,19 +98487,6 @@ function serializeRuntimeInventory(snapshot, providerInventory) {
98247
98487
  ...providerInventory === void 0 ? {} : { providers: serializeProviderCatalog(providerInventory) }
98248
98488
  };
98249
98489
  }
98250
- function text(value, max) {
98251
- const normalized = value.trim();
98252
- return normalized ? normalized.slice(0, max) : null;
98253
- }
98254
- function canonicalRuntimeEventTimestamp(value) {
98255
- let timestamp = new Date(value);
98256
- if (Number.isNaN(timestamp.getTime())) {
98257
- const legacyBsdNanoseconds = value.match(/^(.*:\d{2})\.\d+NZ$/);
98258
- timestamp = new Date(legacyBsdNanoseconds ? `${legacyBsdNanoseconds[1]}Z` : value);
98259
- }
98260
- if (Number.isNaN(timestamp.getTime())) throw new Error(`Invalid runtime event timestamp: ${value}`);
98261
- return timestamp.toISOString();
98262
- }
98263
98490
  /** Spread onto an event: present only when the projection knows the turn. */
98264
98491
  function eventTurn(turnId) {
98265
98492
  return turnId ? { turnId } : {};
@@ -98564,10 +98791,13 @@ function foldReportedUsage(reported) {
98564
98791
  * model, so a mid-thread switch used to republish a finished turn as a second
98565
98792
  * row for spend that happened once (FOR-36388, fixed in FOR-36438).
98566
98793
  */
98567
- /** Turns named on this thread's own rows; hydrated replica rows carry no local turn. */
98794
+ /** Turns named on this thread's own rows; hydrated replica rows carry no local
98795
+ * turn, and the terminal-status activity (CMMD-Center/forge#3562 piece A) is
98796
+ * a wire-protocol source in its own right, not a Usage signal, so it is
98797
+ * excluded the same way a `replica.*` activity is. */
98568
98798
  function localTurnIds(thread) {
98569
98799
  const fromMessages = thread.messages.filter((message) => !message.streaming).map((message) => message.turnId);
98570
- const fromActivities = thread.activities.filter((activity) => !activity.kind.startsWith("replica.")).map((activity) => activity.turnId);
98800
+ const fromActivities = thread.activities.filter((activity) => !activity.kind.startsWith("replica.") && activity.kind !== "turn.terminal-status").map((activity) => activity.turnId);
98571
98801
  const turnIds = /* @__PURE__ */ new Set();
98572
98802
  for (const turnId of [...fromMessages, ...fromActivities]) if (turnId) turnIds.add(turnId);
98573
98803
  return turnIds;
@@ -98577,8 +98807,12 @@ function settledTurnIds(thread) {
98577
98807
  if (thread.latestTurn?.state === "running") turnIds.delete(thread.latestTurn.turnId);
98578
98808
  return turnIds;
98579
98809
  }
98810
+ /** A turn's own activities for Usage derivation, excluding the terminal-status
98811
+ * activity: that record's own `createdAt` (the turn's very end) must never
98812
+ * shift `turnLatestAt`, or an already-acknowledged usage row would rehash
98813
+ * the moment a turn that used to have no terminal activity gains one. */
98580
98814
  function turnActivities(thread, turnId) {
98581
- return thread.activities.filter((activity) => activity.turnId === turnId).toSorted((left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id));
98815
+ return thread.activities.filter((activity) => activity.turnId === turnId && activity.kind !== "turn.terminal-status").toSorted((left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id));
98582
98816
  }
98583
98817
  /** The last thing that happened in the turn: what the Recorded turn is stamped with. */
98584
98818
  function turnLatestAt(thread, turnId, activities) {
@@ -98787,6 +99021,10 @@ function serializeRuntimeThreadEvents(thread) {
98787
99021
  const event = serializePlanActivity(activity);
98788
99022
  return event === null ? [] : [event];
98789
99023
  });
99024
+ const turnTerminalStatuses = thread.activities.flatMap((activity) => {
99025
+ const event = serializeTurnTerminalStatusActivity(activity);
99026
+ return event === null ? [] : [event];
99027
+ });
98790
99028
  const recordedTurns = serializeRecordedTurns(thread);
98791
99029
  const textGenerations = serializeTextGenerations(thread);
98792
99030
  const priorEvents = [
@@ -98796,6 +99034,7 @@ function serializeRuntimeThreadEvents(thread) {
98796
99034
  ...worktreeLaunchActivities,
98797
99035
  ...planActivities,
98798
99036
  ...failureActivities,
99037
+ ...turnTerminalStatuses,
98799
99038
  ...recordedTurns,
98800
99039
  ...textGenerations
98801
99040
  ];
@@ -213749,73 +213988,6 @@ const makeCodexAdapter = fn$1("makeCodexAdapter")(function* (options) {
213749
213988
  function makeCodexAdapterLive(options) {
213750
213989
  return effect(CodexAdapter, makeCodexAdapter(options));
213751
213990
  }
213752
- //#endregion
213753
- //#region ../../packages/shared/src/publicProviderCopy.ts
213754
- const PUBLIC_PROVIDER_LEAK_PATTERNS = [
213755
- /\bDeepSeek\b/i,
213756
- /\bKimi\b/i,
213757
- /\bMoonshot\b/i,
213758
- /\bdeepseek[-._a-z0-9]*\b/i,
213759
- /\bkimi[-._a-z0-9]*\b/i,
213760
- /\bmoonshot[-._a-z0-9]*\b/i,
213761
- /\bAPEX_API_KEY\b/,
213762
- /\bDEEPSEEK_API_KEY\b/,
213763
- /\bKIMI_API_KEY\b/,
213764
- /\bOPENAI_API_KEY\b/,
213765
- /\bANTHROPIC_API_KEY\b/,
213766
- /\bCURSOR_API_KEY\b/,
213767
- /\bOPENCODE_API_KEY\b/,
213768
- /\bforge_proxy_[A-Za-z0-9._-]+\b/,
213769
- /\bProviderValidationError\b/,
213770
- /\/forge-server\/node_modules\//,
213771
- /https?:\/\/[^\s'"<>)]*\/api\/provider-egress\/[^\s'"<>)]*/i,
213772
- /https?:\/\/[^\s'"<>)]*(?:apex|deepseek|moonshot|kimi)[^\s'"<>)]*/i
213773
- ];
213774
- const DEFAULT_PUBLIC_PROVIDER_ERROR = "CMMD is temporarily unavailable. Check the workspace AI connection and retry.";
213775
- function isProviderRateOrQuotaError(message) {
213776
- if (!message) return false;
213777
- const normalized = message.toLowerCase();
213778
- return /\b(rate[\s-]?limit|too\s+many\s+requests|usage[ _-]limit|usage_limit_reached|quota|insufficient_quota)\b/.test(normalized) || /\b429\b/.test(normalized);
213779
- }
213780
- function providerLifecycleOrAccountCopy(message) {
213781
- if (/\bbound to provider account\b/.test(message) && /\bcannot use provider account\b/.test(message)) return "Forge could not switch this conversation to the selected AI account. Retry the account switch.";
213782
- if (/\bforge_runtime_repairing\b/.test(message) || /\bthis turn was interrupted because the environment is being repaired\b/.test(message)) return "This turn was interrupted because the environment is being repaired. Retry after the repair finishes.";
213783
- if (/\bforge_runtime_stopped\b/.test(message) || /\bthis turn was interrupted because the environment was stopped\b/.test(message)) return "This turn was interrupted because the environment was stopped. Start the environment and retry.";
213784
- return null;
213785
- }
213786
- /**
213787
- * Infer a SAFE, clearer failure category from a (possibly leaky) provider error.
213788
- *
213789
- * Returns a canned, user-facing message — it never echoes the raw input, so it
213790
- * is safe to use even when the source message contains provider internals.
213791
- * Used to give actionable feedback ("model isn't available", "rate-limited",
213792
- * "auth failed") instead of the blanket "CMMD is temporarily unavailable."
213793
- * Returns null when no category can be confidently inferred.
213794
- */
213795
- function categorizePublicProviderError(message) {
213796
- if (!message) return null;
213797
- const m = message.toLowerCase();
213798
- const lifecycleOrAccountCopy = providerLifecycleOrAccountCopy(m);
213799
- if (lifecycleOrAccountCopy !== null) return lifecycleOrAccountCopy;
213800
- if (/\bforge_provider_model_not_allowed\b/.test(m) || /\bnot\s+scoped\s+to\s+the\s+requested\s+model\b/.test(m)) return "The workspace AI credential does not cover the model this turn asked for. Retry, or pick that model for the thread.";
213801
- if (/\bmodel\b[\s\S]*\b(not\s+(found|available|supported)|does\s+not\s+exist|unsupported|invalid|unknown)\b/.test(m) || /\b(unsupported|unknown|invalid)\b[\s\S]*\bmodel\b/.test(m) || /\b(model_not_found|invalid_model|model_not_supported)\b/.test(m)) return "The selected model isn't available right now. Pick a different model and retry.";
213802
- if (isProviderRateOrQuotaError(m)) return "The AI service is rate-limited or out of quota. Wait a moment and retry.";
213803
- if (/_credential_reconnect_required\b/.test(m)) return "The workspace AI credential needs to be reconnected. Reconnect it in Settings > Providers, then retry.";
213804
- if (/\b(unauthorized|forbidden|authentication\s+(failed|error|required)|invalid\s+api\s+key|expired\s+(token|credential))\b/.test(m) || /\b40[13]\b/.test(m)) return "Workspace AI authentication failed. Reconnect the workspace and retry.";
213805
- if (/\b(timed?\s*out|timeout|overloaded|service\s+unavailable)\b/.test(m) || /\b50[234]\b/.test(m)) return "The AI service is temporarily overloaded. Retry in a moment.";
213806
- return null;
213807
- }
213808
- function containsPublicProviderLeak(message) {
213809
- if (!message) return false;
213810
- return PUBLIC_PROVIDER_LEAK_PATTERNS.some((pattern) => pattern.test(message));
213811
- }
213812
- function sanitizePublicProviderText(message, options = {}) {
213813
- if (message === void 0 || message === null) return null;
213814
- const trimmed = message.trim();
213815
- if (trimmed.length === 0) return null;
213816
- if (!containsPublicProviderLeak(trimmed)) return trimmed;
213817
- return categorizePublicProviderError(trimmed) ?? options.fallback ?? "CMMD is temporarily unavailable. Check the workspace AI connection and retry.";
213818
- }
213819
213991
  function resolveApexBaseUrl(settings, config) {
213820
213992
  return config?.forgeApexBaseUrl || settings.baseUrl || "https://apex.cmmd.ai";
213821
213993
  }
@@ -292518,52 +292690,6 @@ function applyThreadGoalPreamble(goal, input) {
292518
292690
  return trimmedInput.length > 0 ? `${preamble}\n\n${trimmedInput}` : preamble;
292519
292691
  }
292520
292692
  //#endregion
292521
- //#region src/orchestration/providerRetryableFailure.ts
292522
- /**
292523
- * Classifies a provider turn-start failure as a retryable rate-limit or
292524
- * transient-availability failure (429/503), a terminal failure that names why
292525
- * it will never clear on its own, or unrecognized (null).
292526
- *
292527
- * CMMD-Center/forge#3558: a 429 from CMMD's provider egress used to leave no
292528
- * trace at all, because nothing in the turn-start path recognized it as a
292529
- * distinct, retryable failure. `ProviderCommandReactor` uses this to decide
292530
- * whether to retry a turn start with backoff, and to name the provider,
292531
- * status and Retry-After in the `provider.turn.start.failed` activity CMMD's
292532
- * watchdog reads once retries are exhausted.
292533
- *
292534
- * Reuses `isProviderRateOrQuotaError` (the same predicate the public-copy
292535
- * sanitizer uses to recognize a rate-limit message) rather than restating its
292536
- * word list here.
292537
- */
292538
- const SERVICE_UNAVAILABLE_PATTERN = /\b(503|service\s+unavailable)\b/i;
292539
- const RATE_LIMITED_PAST_TENSE_PATTERN = /\brate[\s-]?limit(?:ed|ing)?\b/i;
292540
- const QUOTA_OR_USAGE_LIMIT_PATTERN = /\b(usage[ _-]limit|usage_limit_reached|quota|insufficient_quota)\b/i;
292541
- const EXPLICIT_429_PATTERN = /\b429\b/;
292542
- const RETRY_AFTER_SECONDS_PATTERN = /retry-after[^0-9]{0,10}(\d+)|(?:try again|retry)\s+in\s+(\d+)\s*(?:s\b|sec(?:onds?)?\b)?/i;
292543
- function parseRetryAfterSeconds(detail) {
292544
- const match = detail.match(RETRY_AFTER_SECONDS_PATTERN);
292545
- if (!match) return null;
292546
- const raw = match[1] ?? match[2];
292547
- const seconds = raw ? Number(raw) : NaN;
292548
- return Number.isFinite(seconds) ? seconds : null;
292549
- }
292550
- function classifyRetryableProviderFailure(detail) {
292551
- if (!detail || detail.trim().length === 0) return null;
292552
- if (QUOTA_OR_USAGE_LIMIT_PATTERN.test(detail) && !EXPLICIT_429_PATTERN.test(detail)) return {
292553
- kind: "terminal",
292554
- reason: "quota",
292555
- message: detail
292556
- };
292557
- const isRateLimited = isProviderRateOrQuotaError(detail) || RATE_LIMITED_PAST_TENSE_PATTERN.test(detail);
292558
- const isUnavailable = SERVICE_UNAVAILABLE_PATTERN.test(detail);
292559
- if (!isRateLimited && !isUnavailable) return null;
292560
- return {
292561
- kind: "retryable",
292562
- status: isRateLimited ? 429 : 503,
292563
- retryAfterSeconds: parseRetryAfterSeconds(detail)
292564
- };
292565
- }
292566
- //#endregion
292567
292693
  //#region src/orchestration/Layers/ProviderCommandReactor.ts
292568
292694
  function toNonEmptyProviderInput(value) {
292569
292695
  const normalized = value?.trim();
@@ -294739,12 +294865,62 @@ const CheckpointReactorLive = effect(CheckpointReactor, gen(function* () {
294739
294865
  createdAt: input.createdAt
294740
294866
  });
294741
294867
  });
294868
+ /**
294869
+ * The one durable, deterministic-id activity that records how a turn ended
294870
+ * (CMMD-Center/forge#3562 piece A, CMMD-Center/CMMD#5822): `completed`,
294871
+ * `interrupted` (an abort or a provider cancellation), or `failed` with the
294872
+ * provider's own error message. Recorded here, ahead of every
294873
+ * checkpoint-specific early return below, so it fires for every turn
294874
+ * regardless of whether this workspace can capture a git checkpoint at
294875
+ * all -- unlike a checkpoint, this never depends on `resolveCheckpointCwd`.
294876
+ *
294877
+ * The activity id is derived from the turn id, never `crypto.randomUUID()`,
294878
+ * so a redelivered `turn.completed` for the same turn replaces the same
294879
+ * row rather than adding a second one. The guard below additionally
294880
+ * refuses to touch a turn that already has one: first write wins, so a
294881
+ * later, different signal for the same turn can never overwrite an
294882
+ * outcome CMMD may already have acknowledged.
294883
+ *
294884
+ * Deriving the wire `turn_status` event from a new activity recorded at
294885
+ * the moment the turn actually ends -- not from `thread.latestTurn` or
294886
+ * `thread.checkpoints`, both of which already hold outcomes for turns that
294887
+ * settled before this shipped -- is deliberate: those would insert a brand
294888
+ * new event into history CMMD already acknowledged for every existing
294889
+ * thread, which `RuntimeThreadHistoryConflict` exists specifically to
294890
+ * reject (CMMD-Center/forge#3497). A turn that settled before this shipped
294891
+ * gets no terminal event; only a turn that ends after it does.
294892
+ */
294893
+ const recordTurnTerminalStatus = fn$1("recordTurnTerminalStatus")(function* (event, thread, turnId) {
294894
+ const activityId = turnTerminalStatusActivityId(turnId);
294895
+ if (thread.activities.some((activity) => activity.id === activityId)) return;
294896
+ const outcome = turnTerminalOutcomeFromRuntimeState(event.payload.state);
294897
+ const recordedAt = (/* @__PURE__ */ new Date()).toISOString();
294898
+ yield* orchestrationEngine.dispatch({
294899
+ type: "thread.activity.append",
294900
+ commandId: serverCommandId$1("turn-terminal-status"),
294901
+ threadId: event.threadId,
294902
+ activity: {
294903
+ id: EventId.make(activityId),
294904
+ tone: outcome === "failed" ? "error" : "info",
294905
+ kind: TURN_TERMINAL_STATUS_ACTIVITY_KIND,
294906
+ summary: `Turn ${outcome}`,
294907
+ payload: {
294908
+ outcome,
294909
+ ...outcome === "failed" && event.payload.errorMessage ? { errorMessage: event.payload.errorMessage } : {}
294910
+ },
294911
+ turnId,
294912
+ createdAt: recordedAt
294913
+ },
294914
+ createdAt: recordedAt
294915
+ });
294916
+ });
294742
294917
  const captureCheckpointFromTurnCompletion = fn$1("captureCheckpointFromTurnCompletion")(function* (event) {
294743
294918
  const turnId = toTurnId(event.turnId);
294744
294919
  if (!turnId) return;
294745
294920
  const readModel = yield* orchestrationEngine.getReadModel();
294746
294921
  const thread = readModel.threads.find((entry) => entry.id === event.threadId);
294747
294922
  if (!thread) return;
294923
+ yield* recordTurnTerminalStatus(event, thread, turnId);
294748
294924
  if (thread.session?.activeTurnId && !sameId(thread.session.activeTurnId, turnId)) return;
294749
294925
  if (thread.checkpoints.some((checkpoint) => checkpoint.turnId === turnId && checkpoint.status !== "missing")) return;
294750
294926
  const checkpointCwd = yield* resolveCheckpointCwd({
@@ -299501,7 +299677,7 @@ function resolveBuildCommitFromEnv(env) {
299501
299677
  * environment descriptor down instead of reporting an honest "unknown".
299502
299678
  */
299503
299679
  function readBakedBuildCommit() {
299504
- return "96780e9bb987ecd23f530709589bda1b4b5791e5";
299680
+ return "af7d46dcc7bdd81e6994e3590d9fca779411f1c4";
299505
299681
  }
299506
299682
  async function resolveServerBuildCommit(input) {
299507
299683
  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{Fn as a,Gr as o,Hl as s,Jr as c,Or as l,Tn as u,Wr as d,al as f,c as p,d as m,fn as h,fr as g,gr as _,hr as v,ii as y,jn as b,js as x,m as S,ni as C,o as w,ol as T,qo as E,qt as D,rl as O,rs as k,s as A,t as j,tl as M,u as N}from"./WorkerPoolContext-VAp-zZQ5.js";import{hn as P}from"./CompositeItem-DNkNENOR.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-BtFYmUB0.js";import{Dn as q,at as J,it as ee}from"./src-DFTFXdyK.js";import"./cmmdAuthRedirect-DCgS12fq.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-ZO6qepWo.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,m=(0,X.useContext)(j),h=A(),g=(0,X.useRef)(null),_=p(n=>{if(n!=null){if(g.current!=null)throw Error(`useFileDiffInstance: An instance should not already exist when a node is created`);d==null?g.current=new re(Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),l?void 0:m,!0):g.current=new pe(Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),d,o,l?void 0:m,!0),g.current.hydrate({fileDiff:e,fileContainer:n,lineAnnotations:r,prerenderedHTML:a})}else{if(g.current==null)throw Error(`useFileDiffInstance: A FileDiff instance should exist when unmounting`);g.current.cleanUp(),g.current=null}});return me(()=>{let{current:n}=g;if(n==null)return;let a=Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),o=a!==void 0&&!D(n.options,a);n.setOptions(a),n.render({forceRender:o,fileDiff:e,lineAnnotations:r}),i!==void 0&&n.setSelectedLines(i)}),me(()=>{if(u&&g.current!=null){if(h===void 0)throw Error(`FileDiff: EditContext is not attached`);let e=h(n??{});if(e==null)throw Error(`FileDiff: EditProvider.createEditor must return an editor instance`);try{return e.edit(g.current)}catch(t){throw e.cleanUp(),t}}},[u]),{ref:_,getHoveredLine:(0,X.useCallback)(()=>g.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:g=!1,edit:_=!1}){let{ref:v,getHoveredLine:y}=he({fileDiff:e,options:t,editorOptions:n,metrics:r,lineAnnotations:i,selectedLines:a,prerenderedHTML:c,hasGutterRenderUtility:m!=null,hasCustomHeader:u!=null,disableWorkerPool:g,edit:_});return(0,Q.jsx)(h,{ref:v,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 f({queryKey:x.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{Fn as a,Gr as o,Hl as s,Jr as c,Or as l,Tn as u,Wr as d,al as f,c as p,d as m,fn as h,fr as g,gr as _,hr as v,ii as y,jn as b,js as x,m as S,ni as C,o as w,ol as T,qo as E,qt as D,rl as O,rs as k,s as A,t as j,tl as M,u as N}from"./WorkerPoolContext-G1u5WJw4.js";import{hn as P}from"./CompositeItem-DNkNENOR.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-DYODAvp9.js";import{Dn as q,at as J,it as ee}from"./src-DFTFXdyK.js";import"./cmmdAuthRedirect-DCgS12fq.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-DifBpfCt.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,m=(0,X.useContext)(j),h=A(),g=(0,X.useRef)(null),_=p(n=>{if(n!=null){if(g.current!=null)throw Error(`useFileDiffInstance: An instance should not already exist when a node is created`);d==null?g.current=new re(Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),l?void 0:m,!0):g.current=new pe(Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),d,o,l?void 0:m,!0),g.current.hydrate({fileDiff:e,fileContainer:n,lineAnnotations:r,prerenderedHTML:a})}else{if(g.current==null)throw Error(`useFileDiffInstance: A FileDiff instance should exist when unmounting`);g.current.cleanUp(),g.current=null}});return me(()=>{let{current:n}=g;if(n==null)return;let a=Z({controlledSelection:f,hasCustomHeader:c,hasGutterRenderUtility:s,options:t}),o=a!==void 0&&!D(n.options,a);n.setOptions(a),n.render({forceRender:o,fileDiff:e,lineAnnotations:r}),i!==void 0&&n.setSelectedLines(i)}),me(()=>{if(u&&g.current!=null){if(h===void 0)throw Error(`FileDiff: EditContext is not attached`);let e=h(n??{});if(e==null)throw Error(`FileDiff: EditProvider.createEditor must return an editor instance`);try{return e.edit(g.current)}catch(t){throw e.cleanUp(),t}}},[u]),{ref:_,getHoveredLine:(0,X.useCallback)(()=>g.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:g=!1,edit:_=!1}){let{ref:v,getHoveredLine:y}=he({fileDiff:e,options:t,editorOptions:n,metrics:r,lineAnnotations:i,selectedLines:a,prerenderedHTML:c,hasGutterRenderUtility:m!=null,hasCustomHeader:u!=null,disableWorkerPool:g,edit:_});return(0,Q.jsx)(h,{ref:v,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 f({queryKey:x.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}=v(),s=_(),[c,d]=(0,X.useState)(`stacked`),[f,p]=(0,X.useState)(s.diffWordWrap),h=(0,X.useRef)(null),g=(0,X.useRef)(!1),y=Te(),{activeCwd:b,activeThread:x,bodyState:S,diffOpen:C,inferredCheckpointTurnCountByTurnId:w,orderedTurnDiffSummaries:T,renderableFiles:E,renderablePatch:D,selectedFilePath:k,selectedTurn:A,selectedTurnId:j}=Le(i),N,P;t[0]!==C||t[1]!==s.diffWordWrap?(N=()=>{C&&!g.current&&p(s.diffWordWrap),g.current=C},P=[C,s.diffWordWrap],t[0]=C,t[1]=s.diffWordWrap,t[2]=N,t[3]=P):(N=t[2],P=t[3]),(0,X.useEffect)(N,P);let F;t[4]===k?F=t[5]:(F=()=>{!k||!h.current||Array.from(h.current.querySelectorAll(`[data-diff-file-path]`)).find(e=>e.dataset.diffFilePath===k)?.scrollIntoView({block:`nearest`})},t[4]=k,t[5]=F);let I;t[6]!==E||t[7]!==k?(I=[k,E],t[6]=E,t[7]=k,t[8]=I):I=t[8],(0,X.useEffect)(F,I);let L;t[9]===b?L=t[10]:(L=e=>{let t=l();if(!t)return;let n=b?u(e,b):e;o(t,n).catch(ke)},t[9]=b,t[10]=L);let R=L,z;t[11]===x?z=t[12]:(z=e=>{x&&a.getState().openDiff(O(M(x.environmentId,x.id)),e)},t[11]=x,t[12]=z);let B=z,V;t[13]===x?V=t[14]:(V=()=>{x&&a.getState().openDiff(O(M(x.environmentId,x.id)))},t[13]=x,t[14]=V);let H=V,U;t[15]===y.remeasure?U=t[16]:(U=()=>{let e=window.requestAnimationFrame(y.remeasure);return()=>window.cancelAnimationFrame(e)},t[15]=y.remeasure,t[16]=U);let W;t[17]!==T||t[18]!==j||t[19]!==y.remeasure?(W=[T,j,y.remeasure],t[17]=T,t[18]=j,t[19]=y.remeasure,t[20]=W):W=t[20],(0,X.useEffect)(U,W),Ee(y.ref,A?.turnId??j);let G;t[21]!==c||t[22]!==f||t[23]!==w||t[24]!==T||t[25]!==B||t[26]!==H||t[27]!==A||t[28]!==j||t[29]!==s||t[30]!==y?(G=(0,Q.jsx)(Ae,{diffRenderMode:c,diffWordWrap:f,inferredCheckpointTurnCountByTurnId:w,orderedTurnDiffSummaries:T,selectTurn:B,selectWholeConversation:H,selectedTurn:A,selectedTurnId:j,setDiffRenderMode:d,setDiffWordWrap:p,settings:s,turnStrip:y}),t[21]=c,t[22]=f,t[23]=w,t[24]=T,t[25]=B,t[26]=H,t[27]=A,t[28]=j,t[29]=s,t[30]=y,t[31]=G):G=t[31];let K=G,q;t[32]!==S||t[33]!==c||t[34]!==f||t[35]!==R||t[36]!==E||t[37]!==D||t[38]!==i?(q=(0,Q.jsx)(je,{bodyState:S,diffRenderMode:c,diffWordWrap:f,openDiffFileInEditor:R,patchViewportRef:h,renderableFiles:E,renderablePatch:D,resolvedTheme:i}),t[32]=S,t[33]=c,t[34]=f,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)(m,{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:S(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=s(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),a=i.rightPanel===`diff`,o=n?.threadId??null,c,l;e[2]===n?l=e[3]:(l=b(n),e[2]=n,e[3]=l),c=l;let u=k(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 x=d(y),S;e[10]===x.data?S=e[11]:(S=z(x.data),e[10]=x.data,e[11]=S);let C=S,w;return e[12]!==g||e[13]!==u||e[14]!==o||e[15]!==a||e[16]!==i||e[17]!==C?(w={activeThread:u,activeThreadId:o,activeCwd:g,isGitRepo:C,diffSearch:i,diffOpen:a},e[12]=g,e[13]=u,e[14]=o,e[15]=a,e[16]=i,e[17]=C,e[18]=w):w=e[18],w}function Fe(e){return G(e)}function Ie(e){return C(e)}function Le(e){let{activeThread:t,activeThreadId:n,activeCwd:r,isGitRepo:i,diffSearch:a,diffOpen:o}=Pe(),{turnDiffSummaries:s,inferredCheckpointTurnCountByTurnId:c}=H(t),l=a.diffTurnId??null,u=l===null?null:a.diffFilePath??null,{activeCheckpointRange:d,conversationCacheScope:f,orderedTurnDiffSummaries:p,selectedTurn:m}=(0,X.useMemo)(()=>te({summaries:s,inferredCheckpointTurnCountByTurnId:c,selectedTurnId:l}),[c,l,s]),h=T(xe(we({environmentId:t?.environmentId,threadId:n,range:d,selectedTurnId:m?.turnId,conversationCacheScope:f,enabled:i}))),g=h.isLoading,_=Ce(h.error),v=h.data?.diff,y=typeof v==`string`&&v.trim().length===0,{emptyDiffMessage:b}=(0,X.useMemo)(()=>ae(m),[m]),x=(0,X.useMemo)(()=>ce(v,`diff-panel:${e}`),[e,v]),S=(0,X.useMemo)(()=>Ue(x),[x]);return{activeCwd:r,activeThread:t,bodyState:ue({hasActiveThread:!!t,isGitRepo:i,turnSummaryCount:p.length,checkpointDiffError:_,hasRenderablePatch:!!x,isLoadingCheckpointDiff:g,hasNoNetChanges:y,emptyDiffMessage:b}),diffOpen:o,inferredCheckpointTurnCountByTurnId:c,orderedTurnDiffSummaries:p,renderableFiles:S,renderablePatch:x,selectedFilePath:u,selectedTurn:m,selectedTurnId:l}}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)(N,{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:y,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 u;t[3]!==i||t[4]!==r?(u=()=>r.scrollBy(i?-180:ze),t[3]=i,t[4]=r,t[5]=u):u=t[5];let d=!a,f=`Scroll turn list ${n}`,p;t[6]===o?p=t[7]:(p=(0,Q.jsx)(o,{className:`size-3.5`}),t[6]=o,t[7]=p);let m;return t[8]!==l||t[9]!==u||t[10]!==d||t[11]!==f||t[12]!==p?(m=(0,Q.jsx)(`button`,{type:`button`,className:l,onClick:u,disabled:d,"aria-label":f,children:p}),t[8]=l,t[9]=u,t[10]=d,t[11]=f,t[12]=p,t[13]=m):m=t[13],m}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=g(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 _;t[15]!==u||t[16]!==h?(_=(0,Q.jsx)(`div`,{className:u,children:h}),t[15]=u,t[16]=h,t[17]=_):_=t[17];let v;return t[18]!==r||t[19]!==n.turnId||t[20]!==s||t[21]!==_?(v=(0,Q.jsx)(`button`,{type:`button`,className:`shrink-0 rounded-md`,onClick:s,title:c,"data-turn-chip-selected":r,children:_}),t[18]=r,t[19]=n.turnId,t[20]=s,t[21]=_,t[22]=v):v=t[22],v}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?E(e,{environmentId:n,projectId:r}):void 0,t[0]=n,t[1]=r,t[2]=i):i=t[2],k(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-CQF1ISJz.js.map
64
+ //# sourceMappingURL=DiffPanel-BXrpBBfH.js.map