@x1a0f3n9/dsh-failover-queue 0.1.11 → 0.1.12

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/README.md CHANGED
@@ -10,7 +10,7 @@ A `P1` / `P-` chip sits on the composer. Click it to:
10
10
  - Drag to reorder priority (P1 primary, P2 / P3 backup)
11
11
  - Add routes from the live provider+model catalog
12
12
 
13
- On failure, same-route `llm-retry` runs first. `AUTH` / `RATE_LIMIT` / `NO_ADAPTER` skip that wait, open the circuit, and jump to the next P. After `cooldownMs`, P1 becomes HalfOpen and the next request probes it — failover is not sticky. While enabled, requests prefer the first healthy P, not the session picker.
13
+ On failure, same-route `llm-retry` runs first. `AUTH` / `RATE_LIMIT` / `NO_ADAPTER` / `SERVER` / `TIMEOUT` / `TRANSPORT` skip that wait, open the circuit, and jump to the next P. A 503 does not wait out twenty same-route retries. After `cooldownMs`, P1 becomes HalfOpen and the next request probes it — failover is not sticky. While enabled, requests prefer the first healthy P, not the session picker.
14
14
 
15
15
  ## Install
16
16
 
@@ -53,7 +53,7 @@ Reload the Web GUI. The composer shows `P-`. Settings left nav has a **Failover*
53
53
  cooldownMs: 60000
54
54
  failureThreshold: 2
55
55
  successThreshold: 2
56
- immediateCodes: [AUTH, RATE_LIMIT, NO_ADAPTER]
56
+ immediateCodes: [AUTH, RATE_LIMIT, NO_ADAPTER, SERVER, TIMEOUT, TRANSPORT]
57
57
  ```
58
58
 
59
59
  ## Limits
package/README.zh.md CHANGED
@@ -8,7 +8,7 @@ CC Switch 风格的 **P1 / P2 / P3** 故障转移插件,给 DeepSeek Harness /
8
8
  - 拖动手柄改优先级(P1 主,P2 / P3 备用)
9
9
  - 从当前已配置的供应商+模型里加路由
10
10
 
11
- 失败时:同一条路由先走 `llm-retry`;`AUTH` / `RATE_LIMIT` / `NO_ADAPTER` 立刻熔断并切下一条。`cooldownMs` 之后 P1 进入半开探活,下一次请求会切回 P1,不会粘在 P2。开启后请求优先打健康的最高优先级档,不看会话里随手选的模型。
11
+ 失败时:同一条路由先走 `llm-retry`;`AUTH` / `RATE_LIMIT` / `NO_ADAPTER` / `SERVER` / `TIMEOUT` / `TRANSPORT` 立刻熔断并切下一条。503 不会在同一条路由上重试 20 次。`cooldownMs` 之后 P1 进入半开探活,下一次请求会切回 P1,不会粘在 P2。开启后请求优先打健康的最高优先级档,不看会话里随手选的模型。
12
12
 
13
13
  ## 安装
14
14
 
@@ -51,7 +51,7 @@ dsh plugin --profile web add /path/to/dsh-failover-queue
51
51
  cooldownMs: 60000
52
52
  failureThreshold: 2
53
53
  successThreshold: 2
54
- immediateCodes: [AUTH, RATE_LIMIT, NO_ADAPTER]
54
+ immediateCodes: [AUTH, RATE_LIMIT, NO_ADAPTER, SERVER, TIMEOUT, TRANSPORT]
55
55
  ```
56
56
 
57
57
  ## 限制
package/lib/client.js CHANGED
@@ -2037,16 +2037,24 @@ var src_default = Schema;
2037
2037
 
2038
2038
  //#endregion
2039
2039
  //#region src/config.ts
2040
+ /**
2041
+ * Codes that mean this route cannot serve the request now.
2042
+ * `EMPTY_RESPONSE` stays on same-route `llm-retry`.
2043
+ */
2044
+ const DEFAULT_IMMEDIATE_CODES = [
2045
+ "AUTH",
2046
+ "RATE_LIMIT",
2047
+ "NO_ADAPTER",
2048
+ "SERVER",
2049
+ "TIMEOUT",
2050
+ "TRANSPORT"
2051
+ ];
2040
2052
  /** Runtime schema. */
2041
2053
  const Config = src_default.object({
2042
2054
  cooldownMs: src_default.number().min(0).default(6e4),
2043
2055
  failureThreshold: src_default.number().min(1).default(2),
2044
2056
  successThreshold: src_default.number().min(1).default(2),
2045
- immediateCodes: src_default.array(src_default.string()).default([
2046
- "AUTH",
2047
- "RATE_LIMIT",
2048
- "NO_ADAPTER"
2049
- ])
2057
+ immediateCodes: src_default.array(src_default.string()).default([...DEFAULT_IMMEDIATE_CODES])
2050
2058
  });
2051
2059
  const QueueRouteSchema = src_default.object({
2052
2060
  provider: src_default.string(),
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["parsed: unknown","groups: ProviderGroup[]","next: QueueRoute[]","top: number","route: QueueRoute","snapshot","zh: Record<FailoverKey, string>","en: Record<FailoverKey, string>","value","buffer: number[]","result: any[]","result","a","b","template","options: Schemastery.Options","options","valueMap","result: Dict<string>","pattern","result: Dict","result: any[]","value","resolvers: Dict<Schemastery.Resolve>","date","e: any","keys: string[]","result: any","rKey: string","messages: any[]","value: any","formatters: Dict<Formatter>","key","Config: z<Config>","z","QueueRouteSchema: z<QueueRoute>","CircuitHealthSchema: z<CircuitHealth>","FailoverSettingsSchema: z<FailoverSettings>","DEFAULT_SETTINGS: FailoverSettings","snapshot: FailoverSnapshot"],"sources":["../src/types.ts","../src/candidates.ts","../src/queue.ts","../src/client/place.ts","../src/circuit.ts","../src/client/styles.ts","../src/client/QueuePanel.tsx","../src/client/FailoverChip.tsx","../src/client/locales.ts","../../deepseek-harness/vendor/cosmokit/src/misc.ts","../../deepseek-harness/vendor/cosmokit/src/types.ts","../../deepseek-harness/vendor/cosmokit/src/time.ts","../../deepseek-harness/vendor/schemastery/src/index.ts","../src/config.ts","../src/client/state.ts","../src/client/index.ts"],"sourcesContent":["/** One provider+model slot in the failover queue. P1 is index 0. */\nexport interface QueueRoute {\n /** Adapter route key (`GenerateOptions.provider`). */\n readonly provider: string\n /** Model id for that route. */\n readonly model: string\n /** Optional display label; the chip falls back to `provider/model`. */\n readonly label?: string\n}\n\n/** Closed = healthy, Open = skipped, HalfOpen = one probe. */\nexport type CircuitState = 'closed' | 'open' | 'half_open'\n\n/** Host-projected breaker badge for one queue route. Memory-only on the host. */\nexport interface CircuitHealth {\n readonly provider: string\n readonly model: string\n readonly state: CircuitState\n readonly failures: number\n}\n\n/** Persisted failover document (settings namespace `dsh-failover-queue`). */\nexport interface FailoverSettings {\n /** When false, the plugin never overlays or retries across routes. */\n enabled: boolean\n /** Last picked queue index (P1 = 0). Clamped on read. Not a sticky pointer. */\n currentIndex: number\n /** Ordered routes. Index 0 is P1. */\n queue: QueueRoute[]\n /** Live circuit badges. Host memory is the source of truth. */\n circuits?: CircuitHealth[]\n}\n\n/** One advertised catalog row the panel can add. */\nexport interface FailoverCandidate {\n readonly provider: string\n readonly providerName: string\n readonly model: string\n readonly name: string\n}\n\n/** Marker the `/failover __candidates` handler prefixes onto JSON. */\nexport const CANDIDATES_MARKER = 'FAILOVER_CANDIDATES_V1'\n","import { CANDIDATES_MARKER, type FailoverCandidate } from './types.ts'\n\n/**\n * Parse `/failover __candidates` command text into catalog rows.\n * @param text - command success text, possibly including the marker prefix.\n * @returns recognized provider+model rows; unknown text is empty.\n */\nexport function candidatesFromText(text: string): FailoverCandidate[] {\n const marker = text.indexOf(CANDIDATES_MARKER)\n if (marker < 0) return []\n const json = text.slice(marker + CANDIDATES_MARKER.length).trim()\n try {\n const parsed: unknown = JSON.parse(json)\n if (!Array.isArray(parsed)) return []\n return parsed.flatMap((row) => {\n if (typeof row !== 'object' || row === null) return []\n const item = row as Record<string, unknown>\n if (typeof item.provider !== 'string' || typeof item.model !== 'string') return []\n return [{\n provider: item.provider,\n providerName: typeof item.providerName === 'string' ? item.providerName : item.provider,\n model: item.model,\n name: typeof item.name === 'string' ? item.name : item.model,\n }]\n })\n } catch {\n return []\n }\n}\n\n/**\n * Flatten `session/modelCatalog` into the same provider+model rows.\n * @param value - RPC value, or undefined when the call failed.\n * @returns one row per model in successful groups.\n */\nexport function candidatesFromCatalog(value: unknown): FailoverCandidate[] {\n if (typeof value !== 'object' || value === null) return []\n const groups = (value as { groups?: unknown }).groups\n if (!Array.isArray(groups)) return []\n return groups.flatMap((group) => {\n if (typeof group !== 'object' || group === null) return []\n const row = group as { id?: unknown; name?: unknown; models?: unknown }\n if (typeof row.id !== 'string' || !Array.isArray(row.models)) return []\n const providerName = typeof row.name === 'string' ? row.name : row.id\n return row.models.flatMap((model) => {\n if (typeof model !== 'object' || model === null) return []\n const item = model as { id?: unknown; name?: unknown }\n if (typeof item.id !== 'string') return []\n return [{\n provider: row.id,\n providerName,\n model: item.id,\n name: typeof item.name === 'string' ? item.name : item.id,\n }]\n })\n })\n}\n\n/** One provider plus the models still available to add. */\nexport interface ProviderGroup {\n readonly provider: string\n readonly providerName: string\n readonly models: readonly FailoverCandidate[]\n}\n\n/**\n * Group flattened catalog rows by provider, keeping first-seen order.\n * @param rows - available provider+model rows.\n * @returns one group per provider.\n */\nexport function groupCandidatesByProvider(rows: readonly FailoverCandidate[]): ProviderGroup[] {\n const groups: ProviderGroup[] = []\n const index = new Map<string, number>()\n for (const row of rows) {\n const at = index.get(row.provider)\n if (at === undefined) {\n index.set(row.provider, groups.length)\n groups.push({\n provider: row.provider,\n providerName: row.providerName,\n models: [row],\n })\n continue\n }\n const current = groups[at]\n if (current === undefined) continue\n groups[at] = { ...current, models: [...current.models, row] }\n }\n return groups\n}\n","import type { FailoverCandidate, QueueRoute } from './types.ts'\n\n/** Stable identity for cooldown and de-dupe. */\nexport function routeKey(route: QueueRoute): string {\n return `${route.provider}\\0${route.model}`\n}\n\n/**\n * Clamp a queue index into `[0, length)` (or `0` when empty).\n * @param index - requested index.\n * @param length - queue length.\n * @returns a usable index.\n */\nexport function clampIndex(index: number, length: number): number {\n if (length <= 0) return 0\n if (!Number.isFinite(index)) return 0\n const whole = Math.trunc(index)\n if (whole < 0) return 0\n if (whole >= length) return length - 1\n return whole\n}\n\n/**\n * Move one queue item from `from` to `to`.\n * @param queue - current ordered routes.\n * @param from - source index.\n * @param to - destination index.\n * @returns a new array.\n */\nexport function reorderQueue(\n queue: readonly QueueRoute[],\n from: number,\n to: number,\n): QueueRoute[] {\n if (from === to) return [...queue]\n if (from < 0 || from >= queue.length) return [...queue]\n if (to < 0 || to >= queue.length) return [...queue]\n const next = [...queue]\n const [item] = next.splice(from, 1)\n if (item === undefined) return next\n next.splice(to, 0, item)\n return next\n}\n\n/**\n * Follow the same route after a drag, not the same slot.\n * @param currentIndex - active index before the move.\n * @param from - dragged index.\n * @param to - drop index.\n * @returns the index of the previously active route.\n */\nexport function indexAfterReorder(currentIndex: number, from: number, to: number): number {\n if (currentIndex === from) return to\n if (from < currentIndex && to >= currentIndex) return currentIndex - 1\n if (from > currentIndex && to <= currentIndex) return currentIndex + 1\n return currentIndex\n}\n\n/**\n * Next uncooled route after `currentIndex`, wrapping once.\n * @param queue - ordered routes.\n * @param currentIndex - failed slot.\n * @param isCooled - true when this route should be skipped.\n * @returns the next index, or `undefined` when nothing remains.\n */\nexport function advanceIndex(\n queue: readonly QueueRoute[],\n currentIndex: number,\n isCooled: (route: QueueRoute) => boolean,\n): number | undefined {\n if (queue.length < 2) return undefined\n const start = clampIndex(currentIndex, queue.length)\n for (let step = 1; step < queue.length; step += 1) {\n const index = (start + step) % queue.length\n const route = queue[index]\n if (route !== undefined && !isCooled(route)) return index\n }\n return undefined\n}\n\n/**\n * True when this failure should skip remaining same-route retries.\n * @param code - provider-neutral `LlmFailure.code`.\n * @param immediateCodes - configured trip codes.\n */\nexport function shouldFailoverImmediately(\n code: string,\n immediateCodes: readonly string[],\n): boolean {\n return immediateCodes.includes(code)\n}\n\n/**\n * Drop duplicate provider+model pairs, keeping the first occurrence.\n * @param queue - possibly messy user input.\n */\nexport function dedupeQueue(queue: readonly QueueRoute[]): QueueRoute[] {\n const seen = new Set<string>()\n const next: QueueRoute[] = []\n for (const route of queue) {\n const provider = route.provider.trim()\n const model = route.model.trim()\n if (provider === '' || model === '') continue\n const key = routeKey({ provider, model })\n if (seen.has(key)) continue\n seen.add(key)\n next.push({\n provider,\n model,\n ...route.label === undefined || route.label.trim() === ''\n ? {}\n : { label: route.label.trim() },\n })\n }\n return next\n}\n\n/**\n * Names the chip and queue rows show for one route.\n * Prefers the live catalog's provider/model titles, then the stored label.\n * @param route - queue slot.\n * @param candidates - advertised catalog, possibly empty.\n */\nexport function routeDisplay(\n route: QueueRoute,\n candidates: readonly FailoverCandidate[] = [],\n): { provider: string; model: string } {\n const hit = candidates.find(row => row.provider === route.provider && row.model === route.model)\n const provider = hit?.providerName.trim() || route.provider\n const model = route.label?.trim() || hit?.name.trim() || route.model\n return { provider, model }\n}\n","export const COMPOSER_PANEL_MARGIN = 8\nexport const COMPOSER_PANEL_GAP = 8\nexport const COMPOSER_PANEL_MAX_HEIGHT = 420\n\nexport interface BoxEdge {\n top: number\n right: number\n bottom: number\n}\n\nexport interface ComposerPanelPlacement {\n left: number\n top: number\n maxHeight: number\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\n/**\n * Cap the composer popover so it can sit inside the viewport with 8px gutters.\n * @param viewportHeight - `window.innerHeight`.\n * @returns CSS max-height in pixels.\n */\nexport function composerPanelMaxHeight(viewportHeight: number): number {\n return Math.min(\n COMPOSER_PANEL_MAX_HEIGHT,\n Math.max(0, viewportHeight - COMPOSER_PANEL_MARGIN * 2),\n )\n}\n\n/**\n * Prefer above the chip; go below only when the full panel fits; otherwise clamp.\n * @param input - trigger box, measured size, and viewport.\n * @returns fixed `left`/`top` plus the height cap to apply.\n */\nexport function placeComposerPanel(input: {\n trigger: BoxEdge\n width: number\n height: number\n viewportWidth: number\n viewportHeight: number\n}): ComposerPanelPlacement {\n const maxHeight = composerPanelMaxHeight(input.viewportHeight)\n const height = Math.min(Math.max(0, input.height), maxHeight)\n const maxWidth = Math.max(0, input.viewportWidth - COMPOSER_PANEL_MARGIN * 2)\n const width = Math.min(Math.max(0, input.width), maxWidth)\n const left = clamp(\n input.trigger.right - width,\n COMPOSER_PANEL_MARGIN,\n Math.max(COMPOSER_PANEL_MARGIN, input.viewportWidth - width - COMPOSER_PANEL_MARGIN),\n )\n const minTop = COMPOSER_PANEL_MARGIN\n const maxTop = Math.max(minTop, input.viewportHeight - height - COMPOSER_PANEL_MARGIN)\n const above = input.trigger.top - COMPOSER_PANEL_GAP - height\n const below = input.trigger.bottom + COMPOSER_PANEL_GAP\n let top: number\n if (above >= minTop) {\n top = above\n } else if (below + height <= input.viewportHeight - COMPOSER_PANEL_MARGIN) {\n top = below\n } else {\n top = clamp(above, minTop, maxTop)\n }\n return { left, top, maxHeight }\n}\n","import { routeKey } from './queue.ts'\nimport type { CircuitHealth, CircuitState, QueueRoute } from './types.ts'\n\n/** Closed / Open / HalfOpen knobs. Chat-friendly defaults, CC Switch-shaped. */\nexport interface CircuitConfig {\n /** Consecutive failures that open a Closed breaker. */\n readonly failureThreshold: number\n /** Consecutive HalfOpen successes that close the breaker. */\n readonly successThreshold: number\n /** Milliseconds an Open breaker waits before becoming HalfOpen. */\n readonly timeoutMs: number\n}\n\n/** Default: 2 failures, 2 probe successes, 60s Open. */\nexport const DEFAULT_CIRCUIT: CircuitConfig = {\n failureThreshold: 2,\n successThreshold: 2,\n timeoutMs: 60_000,\n}\n\n/** Result of taking a HalfOpen probe permit. */\nexport interface ProbeDecision {\n readonly allowed: boolean\n readonly halfOpen: boolean\n}\n\n/** One queue pick: first Closed, else first HalfOpen. */\nexport interface CircuitPick {\n readonly index: number\n readonly route: QueueRoute\n readonly halfOpen: boolean\n}\n\n/**\n * One route's Closed / Open / HalfOpen breaker.\n *\n * HalfOpen allows a single in-flight probe. Open becomes HalfOpen after\n * `timeoutMs`. Immediate failures (AUTH / RATE_LIMIT / NO_ADAPTER) open on\n * the first hit. Memory-only: a process restart starts Closed.\n */\nexport class CircuitBreaker {\n private state: CircuitState = 'closed'\n private failures = 0\n private successes = 0\n private openedAt: number | null = null\n private halfOpenPermit = 0\n\n /**\n * @param config - thresholds and Open timeout.\n */\n constructor(private readonly config: CircuitConfig) {}\n\n /** Copy of counters for badges and tests. */\n snapshot(): {\n readonly state: CircuitState\n readonly failures: number\n readonly successes: number\n readonly openedAt: number | null\n } {\n return {\n state: this.state,\n failures: this.failures,\n successes: this.successes,\n openedAt: this.openedAt,\n }\n }\n\n /**\n * Whether this route may be selected. Open → HalfOpen when the wait elapses.\n * Does not consume the probe permit.\n * @param now - epoch ms.\n */\n isAvailable(now: number): boolean {\n this.maybeHalfOpen(now)\n return this.state === 'closed' || this.state === 'half_open'\n }\n\n /**\n * Reserve this route for one request. HalfOpen consumes the single permit.\n * @param now - epoch ms.\n */\n allowProbe(now: number): ProbeDecision {\n this.maybeHalfOpen(now)\n if (this.state === 'closed') return { allowed: true, halfOpen: false }\n if (this.state === 'half_open') {\n if (this.halfOpenPermit >= 1) return { allowed: false, halfOpen: true }\n this.halfOpenPermit = 1\n return { allowed: true, halfOpen: true }\n }\n return { allowed: false, halfOpen: false }\n }\n\n /** Probe succeeded. Two successes close a HalfOpen breaker. */\n recordSuccess(): void {\n this.releaseProbe()\n this.failures = 0\n if (this.state !== 'half_open') return\n this.successes += 1\n if (this.successes >= this.config.successThreshold) this.transitionClosed()\n }\n\n /**\n * Probe or Closed request failed.\n * @param now - epoch ms used as Open timestamp.\n * @param immediate - open on this hit regardless of `failureThreshold`.\n */\n recordFailure(now: number, immediate = false): void {\n this.releaseProbe()\n this.failures += 1\n this.successes = 0\n if (this.state === 'half_open' || immediate || this.failures >= this.config.failureThreshold) {\n this.transitionOpen(now)\n }\n }\n\n /** Drop the HalfOpen permit without changing health (cancel / abandon). */\n releaseProbe(): void {\n this.halfOpenPermit = 0\n }\n\n private maybeHalfOpen(now: number): void {\n if (this.state !== 'open' || this.openedAt === null) return\n if (now - this.openedAt < this.config.timeoutMs) return\n this.state = 'half_open'\n this.successes = 0\n this.halfOpenPermit = 0\n }\n\n private transitionOpen(now: number): void {\n this.state = 'open'\n this.openedAt = now\n this.successes = 0\n this.halfOpenPermit = 0\n }\n\n private transitionClosed(): void {\n this.state = 'closed'\n this.failures = 0\n this.successes = 0\n this.openedAt = null\n this.halfOpenPermit = 0\n }\n}\n\n/** Per-route breaker map. Missing keys start Closed. */\nexport class CircuitBank {\n private readonly breakers = new Map<string, CircuitBreaker>()\n\n /**\n * @param config - shared knobs for every route.\n */\n constructor(private readonly config: CircuitConfig) {}\n\n /**\n * Breaker for one provider+model pair.\n * @param key - {@link routeKey}.\n */\n get(key: string): CircuitBreaker {\n const existing = this.breakers.get(key)\n if (existing !== undefined) return existing\n const created = new CircuitBreaker(this.config)\n this.breakers.set(key, created)\n return created\n }\n\n /**\n * Badge rows for the live queue. Touches `isAvailable` so Open can show\n * HalfOpen after the wait without consuming a permit.\n * @param queue - ordered routes.\n * @param now - epoch ms.\n */\n health(queue: readonly QueueRoute[], now: number): CircuitHealth[] {\n return queue.map((route) => {\n const breaker = this.get(routeKey(route))\n breaker.isAvailable(now)\n const snap = breaker.snapshot()\n return {\n provider: route.provider,\n model: route.model,\n state: snap.state,\n failures: snap.failures,\n }\n })\n }\n}\n\n/**\n * First Closed route, else first HalfOpen with a free permit. Never sticky.\n * @param queue - P1…Pn.\n * @param bank - per-route breakers.\n * @param now - epoch ms.\n * @param skip - route key to ignore (the attempt that just failed).\n */\nexport function pickFirstAvailable(\n queue: readonly QueueRoute[],\n bank: CircuitBank,\n now: number,\n skip?: string,\n): CircuitPick | undefined {\n for (let index = 0; index < queue.length; index += 1) {\n const route = queue[index]\n if (route === undefined) continue\n const key = routeKey(route)\n if (skip !== undefined && key === skip) continue\n const breaker = bank.get(key)\n if (!breaker.isAvailable(now)) continue\n const probe = breaker.allowProbe(now)\n if (!probe.allowed) continue\n return { index, route, halfOpen: probe.halfOpen }\n }\n return undefined\n}\n\n/**\n * Queue index of the first available route, without consuming a probe permit.\n * @param queue - P1…Pn.\n * @param bank - per-route breakers.\n * @param now - epoch ms.\n * @param skip - route key to ignore.\n */\nexport function firstAvailableIndex(\n queue: readonly QueueRoute[],\n bank: CircuitBank,\n now: number,\n skip?: string,\n): number | undefined {\n for (let index = 0; index < queue.length; index += 1) {\n const route = queue[index]\n if (route === undefined) continue\n const key = routeKey(route)\n if (skip !== undefined && key === skip) continue\n if (bank.get(key).isAvailable(now)) return index\n }\n return undefined\n}\n\n/**\n * Badge tone for one queue row.\n * @param health - host snapshot for this route, if any.\n */\nexport function circuitTone(health: CircuitHealth | undefined): 'ok' | 'probe' | 'open' {\n if (health === undefined) return 'ok'\n if (health.state === 'open') return 'open'\n if (health.state === 'half_open') return 'probe'\n return health.failures > 0 ? 'probe' : 'ok'\n}\n\n/**\n * Match a queue route to a health row.\n * @param route - queue slot.\n * @param circuits - host snapshot.\n */\nexport function healthFor(\n route: QueueRoute,\n circuits: readonly CircuitHealth[],\n): CircuitHealth | undefined {\n return circuits.find(row => row.provider === route.provider && row.model === route.model)\n}\n","/** Class names shared between the injected DOM and the stylesheet. */\nexport const CLASS = {\n chip: 'dsh-fq-chip',\n chipOn: 'dsh-fq-chip-on',\n chipKicker: 'dsh-fq-chip-kicker',\n chipPriority: 'dsh-fq-chip-priority',\n chipRoute: 'dsh-fq-chip-route',\n page: 'dsh-fq-page',\n pageIntro: 'dsh-fq-page-intro',\n panel: 'dsh-fq-panel',\n panelPage: 'dsh-fq-panel-page',\n head: 'dsh-fq-head',\n title: 'dsh-fq-title',\n switchRow: 'dsh-fq-switch-row',\n switchCopy: 'dsh-fq-switch-copy',\n hint: 'dsh-fq-hint',\n list: 'dsh-fq-list',\n row: 'dsh-fq-row',\n rowActive: 'dsh-fq-row-active',\n handle: 'dsh-fq-handle',\n health: 'dsh-fq-health',\n healthOk: 'dsh-fq-health-ok',\n healthProbe: 'dsh-fq-health-probe',\n healthOpen: 'dsh-fq-health-open',\n badge: 'dsh-fq-badge',\n meta: 'dsh-fq-meta',\n name: 'dsh-fq-name',\n sub: 'dsh-fq-sub',\n remove: 'dsh-fq-remove',\n picker: 'dsh-fq-picker',\n pickerBtn: 'dsh-fq-picker-btn',\n menu: 'dsh-fq-menu',\n search: 'dsh-fq-search',\n catalog: 'dsh-fq-catalog',\n catalogItem: 'dsh-fq-catalog-item',\n catalogProvider: 'dsh-fq-catalog-provider',\n chevron: 'dsh-fq-chevron',\n back: 'dsh-fq-back',\n empty: 'dsh-fq-empty',\n toggle: 'dsh-fq-toggle',\n toggleOn: 'dsh-fq-toggle-on',\n toggleThumb: 'dsh-fq-toggle-thumb',\n} as const\n\n/** One injected stylesheet scoped under `.dsh-fq-*`. */\nexport const STYLE = `\n.dsh-fq-chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n max-width: min(280px, 42vw);\n height: 22px;\n padding: 0 8px;\n border: 0;\n border-radius: 6px;\n background: var(--dsw-alias-fill-tsp-secondary, rgba(255,255,255,0.06));\n color: var(--dsw-alias-label-secondary, inherit);\n font-size: 12px;\n line-height: 22px;\n font-weight: 500;\n letter-spacing: 0.01em;\n cursor: pointer;\n overflow: hidden;\n white-space: nowrap;\n}\n.dsh-fq-chip:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.10));\n}\n.dsh-fq-chip-on {\n background: color-mix(in srgb, var(--dsw-alias-label-accent, #34d399) 16%, transparent);\n color: var(--dsw-alias-label-accent, #34d399);\n}\n.dsh-fq-chip-kicker {\n flex-shrink: 0;\n font-weight: 600;\n}\n.dsh-fq-chip-priority {\n flex-shrink: 0;\n font-weight: 700;\n}\n.dsh-fq-chip-route {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-fq-panel {\n position: relative;\n z-index: auto;\n width: 320px;\n max-height: min(420px, calc(100vh - 16px));\n overflow: auto;\n padding: 12px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12));\n border-radius: 12px;\n background: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3, #1c1c1e));\n box-shadow: var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.35));\n color: var(--dsw-alias-label-primary, inherit);\n font-size: 13px;\n line-height: 18px;\n}\n.dsh-fq-page {\n max-width: 560px;\n padding: 4px 0 24px;\n}\n.dsh-fq-page-intro {\n margin: 0 0 12px;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 13px;\n line-height: 18px;\n}\n.dsh-fq-page .dsh-fq-panel,\n.dsh-fq-panel.dsh-fq-panel-page {\n position: static;\n z-index: auto;\n width: auto;\n max-height: none;\n overflow: visible;\n box-shadow: none;\n}\n.dsh-fq-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin-bottom: 8px;\n}\n.dsh-fq-title {\n font-size: 14px;\n font-weight: 600;\n}\n.dsh-fq-switch-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 8px;\n}\n.dsh-fq-switch-copy {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n.dsh-fq-switch-copy small {\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 11px;\n}\n.dsh-fq-hint, .dsh-fq-empty {\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 12px;\n margin: 0 0 8px;\n}\n.dsh-fq-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0 0 8px;\n padding: 0;\n list-style: none;\n}\n.dsh-fq-row {\n display: grid;\n grid-template-columns: 16px 8px 32px minmax(0, 1fr) 28px;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n border-radius: 8px;\n background: var(--dsw-alias-fill-tsp-secondary, rgba(255,255,255,0.04));\n cursor: pointer;\n}\n.dsh-fq-row:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.08));\n}\n.dsh-fq-row-active {\n outline: 1px solid color-mix(in srgb, var(--dsw-alias-label-accent, #34d399) 50%, transparent);\n}\n.dsh-fq-handle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n cursor: grab;\n}\n.dsh-fq-handle:active { cursor: grabbing; }\n.dsh-fq-health {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n justify-self: center;\n}\n.dsh-fq-health-ok { background: #34d399; }\n.dsh-fq-health-probe { background: #fbbf24; }\n.dsh-fq-health-open { background: #f87171; }\n.dsh-fq-badge {\n font-size: 11px;\n font-weight: 700;\n color: var(--dsw-alias-label-accent, #34d399);\n}\n.dsh-fq-meta {\n min-width: 0;\n display: flex;\n flex-direction: column;\n}\n.dsh-fq-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n.dsh-fq-sub {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 11px;\n}\n.dsh-fq-remove {\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n cursor: pointer;\n border-radius: 6px;\n height: 24px;\n padding: 0 6px;\n}\n.dsh-fq-remove:hover {\n color: var(--dsw-alias-label-primary, inherit);\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.08));\n}\n.dsh-fq-picker {\n position: relative;\n margin-top: 8px;\n}\n.dsh-fq-picker-btn {\n width: 100%;\n height: 28px;\n padding: 0 8px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12));\n background: var(--dsw-alias-bg-layer-2, #141416);\n color: var(--dsw-alias-label-primary, #f5f5f7);\n font-size: 12px;\n text-align: left;\n cursor: pointer;\n}\n.dsh-fq-picker-btn:disabled {\n cursor: default;\n opacity: 0.65;\n}\n.dsh-fq-menu {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px;\n overflow: hidden;\n border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12));\n border-radius: 8px;\n background: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3, #1c1c1e));\n box-shadow: var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.45));\n color: var(--dsw-alias-label-primary, #f5f5f7);\n box-sizing: border-box;\n}\n.dsh-fq-search {\n width: 100%;\n box-sizing: border-box;\n flex-shrink: 0;\n height: 28px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12));\n background: var(--dsw-alias-bg-layer-2, #141416);\n color: var(--dsw-alias-label-primary, #f5f5f7);\n font-size: 12px;\n padding: 0 8px;\n}\n.dsh-fq-search::placeholder {\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n}\n.dsh-fq-catalog {\n display: flex;\n flex-direction: column;\n flex: 1;\n margin: 0;\n padding: 0;\n list-style: none;\n min-height: 0;\n overflow: auto;\n}\n.dsh-fq-catalog-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n width: 100%;\n margin: 0;\n padding: 5px 10px;\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-primary, #f5f5f7);\n text-align: left;\n cursor: pointer;\n}\n.dsh-fq-catalog-item:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.08));\n}\n.dsh-fq-catalog-item:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.dsh-fq-catalog-provider {\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.dsh-fq-chevron {\n flex-shrink: 0;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 16px;\n line-height: 1;\n}\n.dsh-fq-back {\n flex-shrink: 0;\n align-self: flex-start;\n height: 24px;\n padding: 0 6px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #d1d1d6);\n font-size: 12px;\n cursor: pointer;\n}\n.dsh-fq-back:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.08));\n color: var(--dsw-alias-label-primary, #f5f5f7);\n}\n.dsh-fq-toggle {\n position: relative;\n width: 36px;\n height: 20px;\n flex-shrink: 0;\n border: 0;\n border-radius: 10px;\n background: var(--dsw-alias-fill-tsp-secondary, rgba(255,255,255,0.18));\n cursor: pointer;\n padding: 0;\n}\n.dsh-fq-toggle-on {\n background: var(--dsw-alias-label-accent, #34d399);\n}\n.dsh-fq-toggle-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: #fff;\n transition: transform 120ms ease;\n}\n.dsh-fq-toggle-on .dsh-fq-toggle-thumb {\n transform: translateX(16px);\n}\n`\n","import { useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type DragEvent, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\nimport { groupCandidatesByProvider } from '../candidates.ts'\nimport { circuitTone, healthFor } from '../circuit.ts'\nimport { clampIndex, indexAfterReorder, reorderQueue, routeDisplay, routeKey } from '../queue.ts'\nimport type { FailoverCandidate } from '../types.ts'\nimport type { FailoverKey } from './locales.ts'\nimport { CLASS } from './styles.ts'\nimport type { FailoverSnapshot, QueueRoute } from './state.ts'\n\n/** Writes the panel issues against the host settings document. */\nexport interface QueuePanelApi {\n setEnabled(enabled: boolean): Promise<void>\n setQueue(queue: readonly QueueRoute[], currentIndex: number): Promise<void>\n}\n\nexport interface QueuePanelProps {\n readonly state: FailoverSnapshot\n readonly api: QueuePanelApi\n readonly t: (key: FailoverKey, params?: Record<string, string | number>) => string\n readonly onClose?: () => void\n /** In-flow settings page; skip the composer popover's fixed positioning. */\n readonly embedded?: boolean\n}\n\nfunction candidateMatches(row: FailoverCandidate, query: string): boolean {\n const needle = query.trim().toLowerCase()\n if (needle === '') return true\n return [row.provider, row.providerName, row.model, row.name].some(part => part.toLowerCase().includes(needle))\n}\n\n/**\n * Drag-reorder P1/P2/P3 list plus the auto-failover switch.\n * @param props - live snapshot, settings writes, locale.\n */\nexport function QueuePanel({ state, api, t, onClose, embedded = false }: QueuePanelProps): ReactNode {\n const [pending, setPending] = useState(false)\n const [query, setQuery] = useState('')\n const [menuOpen, setMenuOpen] = useState(false)\n const [selectedProvider, setSelectedProvider] = useState<string | null>(null)\n const pickerRef = useRef<HTMLDivElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const [menuPos, setMenuPos] = useState<CSSProperties | null>(null)\n const available = useMemo(() => {\n const taken = new Set(state.queue.map(routeKey))\n return state.candidates.filter(row => !taken.has(routeKey({\n provider: row.provider,\n model: row.model,\n })))\n }, [state.candidates, state.queue])\n const groups = useMemo(() => groupCandidatesByProvider(available), [available])\n const needle = query.trim().toLowerCase()\n const visibleGroups = useMemo(() => {\n if (needle === '') return groups\n return groups.filter(group => (\n group.provider.toLowerCase().includes(needle)\n || group.providerName.toLowerCase().includes(needle)\n || group.models.some(row => candidateMatches(row, query))\n ))\n }, [groups, needle, query])\n const selectedGroup = selectedProvider === null\n ? undefined\n : groups.find(group => group.provider === selectedProvider)\n const visibleModels = useMemo(() => {\n if (selectedGroup === undefined) return []\n if (needle === '') return [...selectedGroup.models]\n return selectedGroup.models.filter(row => candidateMatches(row, query))\n }, [selectedGroup, needle, query])\n\n const closeMenu = (): void => {\n setMenuOpen(false)\n setSelectedProvider(null)\n setQuery('')\n }\n\n useEffect(() => {\n if (!menuOpen) return\n const onDoc = (event: MouseEvent): void => {\n const target = event.target as Node\n if (pickerRef.current?.contains(target) === true) return\n if (menuRef.current?.contains(target) === true) return\n closeMenu()\n }\n const onKey = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return\n if (selectedProvider !== null) {\n setSelectedProvider(null)\n return\n }\n closeMenu()\n }\n document.addEventListener('mousedown', onDoc)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', onDoc)\n document.removeEventListener('keydown', onKey)\n }\n }, [menuOpen, selectedProvider])\n\n useLayoutEffect(() => {\n if (!menuOpen) {\n setMenuPos(null)\n return\n }\n const place = (): void => {\n const trigger = pickerRef.current\n if (trigger === null) return\n const rect = trigger.getBoundingClientRect()\n const width = Math.max(rect.width, 280)\n const maxHeight = Math.min(320, Math.floor(window.innerHeight * 0.5))\n const roomAbove = rect.top - 8\n const roomBelow = window.innerHeight - rect.bottom - 8\n const openUp = roomAbove >= 160 || roomAbove >= roomBelow\n const top = openUp\n ? Math.max(8, rect.top - 6 - maxHeight)\n : Math.min(rect.bottom + 6, window.innerHeight - maxHeight - 8)\n setMenuPos({\n position: 'fixed',\n left: Math.min(rect.left, window.innerWidth - width - 8),\n width,\n top,\n maxHeight,\n zIndex: 2100,\n })\n }\n place()\n window.addEventListener('resize', place)\n window.addEventListener('scroll', place, true)\n return () => {\n window.removeEventListener('resize', place)\n window.removeEventListener('scroll', place, true)\n }\n }, [menuOpen, selectedProvider, visibleGroups.length, visibleModels.length, query])\n\n const run = (work: () => Promise<void>): void => {\n if (pending) return\n setPending(true)\n void work().finally(() => { setPending(false) })\n }\n\n const onDrop = (to: number, event: DragEvent<HTMLLIElement>): void => {\n event.preventDefault()\n const from = Number(event.dataTransfer.getData('text/plain'))\n if (!Number.isInteger(from) || from === to) return\n const queue = reorderQueue(state.queue, from, to)\n const currentIndex = indexAfterReorder(state.currentIndex, from, to)\n run(() => api.setQueue(queue, currentIndex))\n }\n\n const addCandidate = (row: FailoverCandidate): void => {\n const route: QueueRoute = {\n provider: row.provider,\n model: row.model,\n label: row.name,\n }\n closeMenu()\n run(() => api.setQueue([...state.queue, route], state.currentIndex))\n }\n\n const pickerLabel = !state.candidatesLoaded\n ? t('panel.add.loading')\n : groups.length === 0\n ? t('panel.add.none')\n : t('panel.add.placeholderCount', { count: groups.length })\n\n const emptyMenu = selectedProvider === null\n ? visibleGroups.length === 0\n : visibleModels.length === 0\n\n return (\n <div\n className={embedded ? `${CLASS.panel} ${CLASS.panelPage}` : CLASS.panel}\n role={embedded ? 'region' : 'dialog'}\n aria-label={t('panel.title')}\n >\n <div className={CLASS.head}>\n <div className={CLASS.title}>{t('panel.title')}</div>\n {onClose === undefined ? null : (\n <button type=\"button\" className={CLASS.remove} onClick={onClose}>{t('panel.close')}</button>\n )}\n </div>\n <div className={CLASS.switchRow}>\n <div className={CLASS.switchCopy}>\n <span>{t('panel.switch')}</span>\n <small>{state.enabled ? t('panel.switch.on') : t('panel.switch.off')}</small>\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n className={`${CLASS.toggle}${state.enabled ? ` ${CLASS.toggleOn}` : ''}`}\n aria-checked={state.enabled}\n aria-label={t('panel.switch')}\n disabled={pending}\n onClick={() => { run(() => api.setEnabled(!state.enabled)) }}\n >\n <span className={CLASS.toggleThumb} />\n </button>\n </div>\n <p className={CLASS.hint}>{t('panel.hint')}</p>\n {state.queue.length === 0 ? (\n <p className={CLASS.empty}>{t('panel.empty')}</p>\n ) : (\n <ul className={CLASS.list}>\n {state.queue.map((route, index) => {\n const active = index === clampIndex(state.currentIndex, state.queue.length)\n const display = routeDisplay(route, state.candidates)\n const title = `${display.provider}/${display.model}`\n const tone = circuitTone(healthFor(route, state.circuits ?? []))\n const healthKey = tone === 'ok'\n ? 'panel.health.ok'\n : tone === 'probe' ? 'panel.health.probe' : 'panel.health.open'\n const healthLabel = t(healthKey)\n const healthClass = tone === 'ok'\n ? CLASS.healthOk\n : tone === 'probe' ? CLASS.healthProbe : CLASS.healthOpen\n return (\n <li\n key={routeKey(route)}\n className={`${CLASS.row}${active ? ` ${CLASS.rowActive}` : ''}`}\n onDragOver={(event) => { event.preventDefault() }}\n onDrop={(event) => { onDrop(index, event) }}\n onClick={() => {\n if (index === state.currentIndex) return\n run(() => api.setQueue(state.queue, index))\n }}\n >\n <span\n className={CLASS.handle}\n draggable\n title={t('panel.drag')}\n aria-label={t('panel.drag')}\n onDragStart={(event) => {\n event.dataTransfer.setData('text/plain', String(index))\n event.dataTransfer.effectAllowed = 'move'\n }}\n onClick={(event) => { event.stopPropagation() }}\n >\n ⋮⋮\n </span>\n <span className={`${CLASS.health} ${healthClass}`} title={healthLabel} aria-label={healthLabel} />\n <span className={CLASS.badge}>P{index + 1}</span>\n <span className={CLASS.meta}>\n <span className={CLASS.name}>\n {title}\n {active ? ` · ${t('panel.current')}` : ''}\n </span>\n <span className={CLASS.sub}>{route.provider} / {route.model}</span>\n </span>\n <button\n type=\"button\"\n className={CLASS.remove}\n aria-label={t('panel.remove')}\n onClick={(event) => {\n event.stopPropagation()\n const queue = state.queue.filter((_, item) => item !== index)\n const currentIndex = index < state.currentIndex\n ? state.currentIndex - 1\n : index === state.currentIndex\n ? clampIndex(state.currentIndex, queue.length)\n : state.currentIndex\n run(() => api.setQueue(queue, currentIndex))\n }}\n >\n ×\n </button>\n </li>\n )\n })}\n </ul>\n )}\n <div className={CLASS.picker} ref={pickerRef}>\n <button\n type=\"button\"\n className={CLASS.pickerBtn}\n disabled={pending || !state.candidatesLoaded || groups.length === 0}\n aria-expanded={menuOpen}\n aria-haspopup=\"listbox\"\n aria-label={t('panel.add')}\n onClick={() => {\n if (menuOpen) {\n closeMenu()\n return\n }\n setMenuOpen(true)\n }}\n >\n {pickerLabel}\n </button>\n {menuOpen && state.candidatesLoaded && groups.length > 0 && menuPos !== null\n ? createPortal(\n <div className={CLASS.menu} ref={menuRef} style={menuPos}>\n {selectedProvider === null ? null : (\n <button\n type=\"button\"\n className={CLASS.back}\n onClick={() => { setSelectedProvider(null) }}\n >\n ← {t('panel.add.back')}\n </button>\n )}\n <input\n className={CLASS.search}\n value={query}\n autoFocus\n disabled={pending}\n placeholder={selectedProvider === null ? t('panel.add.searchProvider') : t('panel.add.searchModel')}\n aria-label={selectedProvider === null ? t('panel.add.searchProvider') : t('panel.add.searchModel')}\n onChange={(event) => { setQuery(event.target.value) }}\n />\n {emptyMenu ? (\n <p className={CLASS.empty}>{t('panel.add.nomatch')}</p>\n ) : selectedProvider === null ? (\n <ul className={CLASS.catalog} role=\"listbox\" aria-label={t('panel.add')}>\n {visibleGroups.map((group) => (\n <li key={group.provider}>\n <button\n type=\"button\"\n className={`${CLASS.catalogItem} ${CLASS.catalogProvider}`}\n disabled={pending}\n aria-label={`${group.providerName}, ${t('panel.add.modelCount', { count: group.models.length })}`}\n onClick={() => { setSelectedProvider(group.provider) }}\n >\n <span className={CLASS.meta}>\n <span className={CLASS.name}>{group.providerName}</span>\n <span className={CLASS.sub}>{group.provider} · {t('panel.add.modelCount', { count: group.models.length })}</span>\n </span>\n <span className={CLASS.chevron} aria-hidden=\"true\">›</span>\n </button>\n </li>\n ))}\n </ul>\n ) : (\n <ul className={CLASS.catalog} role=\"listbox\" aria-label={selectedGroup?.providerName ?? t('panel.add')}>\n {visibleModels.map((row) => (\n <li key={routeKey({ provider: row.provider, model: row.model })}>\n <button\n type=\"button\"\n className={CLASS.catalogItem}\n role=\"option\"\n disabled={pending}\n aria-label={`${t('panel.add')}: ${row.name}`}\n onClick={() => { addCandidate(row) }}\n >\n <span className={CLASS.name}>{row.name}</span>\n <span className={CLASS.sub}>{row.model}</span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>,\n document.body,\n )\n : null}\n </div>\n </div>\n )\n}\n","import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\nimport { clampIndex, routeDisplay } from '../queue.ts'\nimport type { FailoverKey } from './locales.ts'\nimport { placeComposerPanel } from './place.ts'\nimport { QueuePanel, type QueuePanelApi } from './QueuePanel.tsx'\nimport { CLASS } from './styles.ts'\nimport type { FailoverSnapshot } from './state.ts'\n\ntype Translate = (key: FailoverKey, params?: Record<string, string | number>) => string\n\n/** Registration-side face plus the renderer-bound snapshot hook. */\nexport interface FailoverChipInjected {\n /** Slot renderer binds `hooks.failover` as a selector hook, not a zero-arg reader. */\n useFailover: <S>(selector: (snapshot: FailoverSnapshot) => S) => S\n api: QueuePanelApi\n loadCandidates: (sessionId: string) => Promise<void>\n getSessionId?: () => string\n}\n\nexport interface FailoverChipProps extends FailoverChipInjected {\n sessionId?: string\n t: Translate\n}\n\nfunction sessionOf(props: FailoverChipProps): string {\n return props.sessionId ?? props.getSessionId?.() ?? ''\n}\n\nfunction chipCopy(state: FailoverSnapshot, t: Translate): {\n title: string\n aria: string\n slot: number | undefined\n route: string | undefined\n} {\n if (!state.enabled) {\n return { title: t('chip.title.off'), aria: t('chip.aria.off'), slot: undefined, route: undefined }\n }\n if (state.queue.length === 0) {\n return {\n title: t('chip.empty'),\n aria: t('chip.empty'),\n slot: undefined,\n route: t('chip.empty'),\n }\n }\n const slot = clampIndex(state.currentIndex, state.queue.length) + 1\n const current = state.queue[slot - 1]\n if (current === undefined) {\n return {\n title: t('chip.empty'),\n aria: t('chip.empty'),\n slot: undefined,\n route: t('chip.empty'),\n }\n }\n const display = routeDisplay(current, state.candidates)\n const params = { slot, provider: display.provider, model: display.model }\n return {\n title: t('chip.on', params),\n aria: t('chip.aria.on', params),\n slot,\n route: `${display.provider}/${display.model}`,\n }\n}\n\n/**\n * Composer chip: shows failover status and opens the drag panel.\n * @param props - composed slot props.\n */\nexport function FailoverChip(props: FailoverChipProps): ReactNode {\n const { useFailover, api, loadCandidates, t } = props\n const state = useFailover(snapshot => snapshot)\n const sessionId = sessionOf(props)\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const panelRef = useRef<HTMLDivElement | null>(null)\n const [pos, setPos] = useState<CSSProperties | null>(null)\n const copy = chipCopy(state, t)\n\n useEffect(() => {\n void loadCandidates(sessionId)\n }, [loadCandidates, sessionId])\n\n useLayoutEffect(() => {\n if (!open) return\n const place = (): void => {\n const trigger = rootRef.current\n const panel = panelRef.current\n if (trigger === null || panel === null) return\n const rect = trigger.getBoundingClientRect()\n const placed = placeComposerPanel({\n trigger: rect,\n width: panel.offsetWidth,\n height: panel.offsetHeight,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n })\n setPos({\n left: placed.left,\n top: placed.top,\n maxHeight: placed.maxHeight,\n })\n }\n place()\n const observer = new ResizeObserver(place)\n if (panelRef.current !== null) observer.observe(panelRef.current)\n window.addEventListener('resize', place)\n window.addEventListener('scroll', place, true)\n return () => {\n observer.disconnect()\n window.removeEventListener('resize', place)\n window.removeEventListener('scroll', place, true)\n }\n }, [open, state.queue.length, state.enabled, copy.route])\n\n useEffect(() => {\n if (!open) return\n const close = (event: MouseEvent): void => {\n const target = event.target\n if (!(target instanceof Node)) return\n if (rootRef.current?.contains(target) === true) return\n if (panelRef.current?.contains(target) === true) return\n if (target instanceof Element && target.closest('.dsh-fq-menu') !== null) return\n setOpen(false)\n }\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') setOpen(false)\n }\n document.addEventListener('mousedown', close)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', close)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n return (\n <div ref={rootRef}>\n <button\n type=\"button\"\n className={`${CLASS.chip}${state.enabled ? ` ${CLASS.chipOn}` : ''}`}\n aria-pressed={state.enabled}\n aria-expanded={open}\n aria-label={copy.aria}\n title={copy.title}\n onMouseDown={(event) => { event.preventDefault() }}\n onClick={() => { setOpen(value => !value) }}\n >\n <span className={CLASS.chipKicker}>{t('chip.kicker')}</span>\n {copy.slot === undefined\n ? <span className={CLASS.chipRoute}>{copy.route ?? t('chip.off')}</span>\n : (\n <>\n <span className={CLASS.chipPriority}>P{copy.slot}</span>\n <span className={CLASS.chipRoute}>{copy.route}</span>\n </>\n )}\n </button>\n {open && createPortal(\n <div ref={panelRef} style={{ ...pos, position: 'fixed', zIndex: 2000, overflow: 'auto' }}>\n <QueuePanel state={state} api={api} t={t} onClose={() => { setOpen(false) }} />\n </div>,\n document.body,\n )}\n </div>\n )\n}\n\n/**\n * Settings left-nav page: the same queue editor, in document flow.\n * @param props - composed slot props.\n */\nexport function FailoverSettingsCard(props: FailoverChipProps): ReactNode {\n const { useFailover, api, loadCandidates, t } = props\n const state = useFailover(snapshot => snapshot)\n const sessionId = sessionOf(props)\n useEffect(() => {\n void loadCandidates(sessionId)\n }, [loadCandidates, sessionId])\n return (\n <div className={CLASS.page}>\n <p className={CLASS.pageIntro}>{t('settings.intro')}</p>\n <QueuePanel state={state} api={api} t={t} embedded />\n </div>\n )\n}\n","/** Locale bundles for the failover chip and drag panel. */\nexport const NS = 'failover' as const\n\n/** Keys owned by this dictionary. */\nexport type FailoverKey =\n | 'chip.kicker'\n | 'chip.off'\n | 'chip.empty'\n | 'chip.on'\n | 'chip.aria.on'\n | 'chip.aria.off'\n | 'chip.title.off'\n | 'panel.title'\n | 'panel.switch'\n | 'panel.switch.on'\n | 'panel.switch.off'\n | 'panel.empty'\n | 'panel.add'\n | 'panel.add.placeholderCount'\n | 'panel.add.searchProvider'\n | 'panel.add.searchModel'\n | 'panel.add.back'\n | 'panel.add.modelCount'\n | 'panel.add.loading'\n | 'panel.add.none'\n | 'panel.add.nomatch'\n | 'panel.remove'\n | 'panel.drag'\n | 'panel.current'\n | 'panel.close'\n | 'panel.hint'\n | 'panel.health.ok'\n | 'panel.health.probe'\n | 'panel.health.open'\n | 'settings.tab'\n | 'settings.intro'\n\nexport const zh: Record<FailoverKey, string> = {\n 'chip.kicker': '故障转移:',\n 'chip.off': '关',\n 'chip.empty': '无队列',\n 'chip.on': '故障转移:P{slot} {provider}/{model}',\n 'chip.aria.on': '故障转移已开启,当前 P{slot} {provider}/{model},点击打开队列',\n 'chip.aria.off': '故障转移已关闭,点击打开队列',\n 'chip.title.off': '自动故障转移关闭。点进去开启并编排队列。',\n 'panel.title': '故障转移队列',\n 'panel.switch': '自动故障转移',\n 'panel.switch.on': '失败按 P1 → P2 → P3 切换;P1 恢复后探活切回',\n 'panel.switch.off': '只用当前会话模型,不跨路由',\n 'panel.empty': '队列是空的。从下面点一条路由,P1 就是主供应商。',\n 'panel.add': '加入队列',\n 'panel.add.placeholderCount': '选择供应商({count})',\n 'panel.add.searchProvider': '搜索供应商…',\n 'panel.add.searchModel': '搜索模型…',\n 'panel.add.back': '返回供应商',\n 'panel.add.modelCount': '{count} 个模型',\n 'panel.add.loading': '正在读取已配置的模型…',\n 'panel.add.none': '没有可加的路由。先在「模型」里配供应商。',\n 'panel.add.nomatch': '没有匹配的路由。',\n 'panel.remove': '移除',\n 'panel.drag': '拖动改优先级',\n 'panel.current': '当前',\n 'panel.close': '关闭',\n 'panel.hint': '拖动左侧手柄调整 P1/P2/P3。失败切下一档;P1 恢复后会探活切回,不会粘在 P2。',\n 'panel.health.ok': '健康',\n 'panel.health.probe': '探活中',\n 'panel.health.open': '已熔断',\n 'settings.tab': '故障转移',\n 'settings.intro': '编排 P1 / P2 / P3。开启后请求优先 P1;失败熔断后切备用档,P1 恢复后探活切回。',\n}\n\nexport const en: Record<FailoverKey, string> = {\n 'chip.kicker': 'Failover: ',\n 'chip.off': 'Off',\n 'chip.empty': 'empty',\n 'chip.on': 'Failover: P{slot} {provider}/{model}',\n 'chip.aria.on': 'Failover on, current P{slot} {provider}/{model}, click to open the queue',\n 'chip.aria.off': 'Failover off, click to open the queue',\n 'chip.title.off': 'Auto failover is off. Click to enable and edit the queue.',\n 'panel.title': 'Failover queue',\n 'panel.switch': 'Auto failover',\n 'panel.switch.on': 'On failure, switch P1 → P2 → P3; recovered P1 is probed again',\n 'panel.switch.off': 'Use the session model only',\n 'panel.empty': 'Queue is empty. Click a route below. P1 is the primary.',\n 'panel.add': 'Add to queue',\n 'panel.add.placeholderCount': 'Pick a provider ({count})',\n 'panel.add.searchProvider': 'Search providers…',\n 'panel.add.searchModel': 'Search models…',\n 'panel.add.back': 'Back to providers',\n 'panel.add.modelCount': '{count} models',\n 'panel.add.loading': 'Loading configured models…',\n 'panel.add.none': 'No routes to add. Configure a provider under Models first.',\n 'panel.add.nomatch': 'No matching routes.',\n 'panel.remove': 'Remove',\n 'panel.drag': 'Drag to reorder',\n 'panel.current': 'current',\n 'panel.close': 'Close',\n 'panel.hint': 'Drag the handle to change P1/P2/P3. Failover is not sticky: P1 is probed again after it recovers.',\n 'panel.health.ok': 'healthy',\n 'panel.health.probe': 'probing',\n 'panel.health.open': 'open',\n 'settings.tab': 'Failover',\n 'settings.intro': 'Arrange P1 / P2 / P3. While on, requests prefer P1. A recovered P1 is probed and selected again.',\n}\n","/** String/symbol keyed dictionary type. */\nexport type Dict<T = any, K extends string | symbol = string> = { [key in K]: T }\n/** Safely read `T[K]`, returning `never` when `K` is not a key of `T`. */\nexport type Get<T extends {}, K> = K extends keyof T ? T[K] : never\n/** Conditional extraction helper with a configurable return type. */\nexport type Extract<S, T, U = S> = S extends T ? U : never\n/** Accept a value or an array, unless the value is already an array type. */\nexport type MaybeArray<T> = [T] extends [unknown[]] ? T : T | T[]\n/** Wrap a value in `Promise`, preserving the resolved type of existing promises. */\nexport type Promisify<T> = Promise<T extends Promise<infer S> ? S : T>\n/** Accept a value or promise unless the value type is already promise-like. */\nexport type Awaitable<T> = [T] extends [Promise<unknown>] ? T : T | Promise<T>\n/** Convert a union type to an intersection type. */\nexport type Intersect<U> = (U extends any ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I : never\n\n/** No-op callback returning `undefined` at runtime and `any` at type level. */\nexport function noop(): any {}\n\n/** Return true when a value is `null` or `undefined`. */\nexport function isNullable(value: any): value is null | undefined | void {\n return value === null || value === undefined\n}\n\n/** Return true when a value is neither `null` nor `undefined`. */\nexport function isNonNullable<T>(value: T): value is NonNullable<T> {\n return !isNullable(value)\n}\n\n/** Return true for non-array object values. */\nexport function isPlainObject(data: any) {\n return data && typeof data === 'object' && !Array.isArray(data)\n}\n\n/** Filter object entries with a key type guard. */\nexport function filterKeys<T, K extends string, U extends K>(object: Dict<T, K>, filter: (key: K, value: T) => key is U): Dict<T, U>\n/** Filter object entries with a boolean predicate. */\nexport function filterKeys<T, K extends string>(object: Dict<T, K>, filter: (key: K, value: T) => boolean): Dict<T, K>\n/** Filter object entries and return a new object. */\nexport function filterKeys(object: {}, filter: (key: string, value: any) => boolean) {\n return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value)))\n}\n\n/** Map object values while preserving the original key set. */\nexport function mapValues<U, T, K extends string>(object: Dict<T, K>, transform: (value: T, key: K) => U) {\n return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, (transform as any)(value, key)])) as Dict<U, K>\n}\n\n/** Alias for `mapValues`. */\nexport { mapValues as valueMap }\n\n/** Pick selected keys from an object, optionally including `undefined` values. */\nexport function pick<T extends object, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean) {\n if (!keys) return { ...source }\n const result = {} as Pick<T, K>\n for (const key of keys) {\n if (forced || source[key] !== undefined) result[key] = source[key]\n }\n return result\n}\n\n/** Omit selected keys from a shallow object copy. */\nexport function omit<T, K extends keyof T>(source: T, keys?: Iterable<K>) {\n if (!keys) return { ...source }\n const result = { ...source } as Omit<T, K>\n for (const key of keys) {\n Reflect.deleteProperty(result, key)\n }\n return result\n}\n\n/** Define a non-enumerable writable property with a typed key. */\nexport function defineProperty<T, K extends keyof T>(object: T, key: K, value: T[K]): T\n/** Define a non-enumerable writable property with an arbitrary key. */\nexport function defineProperty<T, K extends keyof any>(object: T, key: K, value: any): T\n/** Define a non-enumerable writable property and return the object. */\nexport function defineProperty<T, K extends keyof any>(object: T, key: K, value: any) {\n return Object.defineProperty(object, key, { writable: true, value, enumerable: false })\n}\n","import { isNullable } from './misc.ts'\n\ntype GlobalConstructorNames = keyof {\n [K in keyof typeof globalThis as typeof globalThis[K] extends abstract new (...args: any) => any ? K : never]: K\n}\n\n/** Create a predicate for a global constructor name. */\nexport function is<K extends GlobalConstructorNames>(type: K): (value: any) => value is InstanceType<typeof globalThis[K]>\n/** Test whether a value matches a global constructor name. */\nexport function is<K extends GlobalConstructorNames>(type: K, value: any): value is InstanceType<typeof globalThis[K]>\n/** Test values using `instanceof` with a `toStringTag` fallback. */\nexport function is<K extends GlobalConstructorNames>(type: K, value?: any): any {\n if (arguments.length === 1) return (value: any) => is(type, value)\n return type in globalThis && value instanceof (globalThis[type] as any)\n || Object.prototype.toString.call(value).slice(8, -1) === type\n}\n\nfunction isArrayBufferLike(value: any): value is ArrayBufferLike {\n return is('ArrayBuffer', value) || is('SharedArrayBuffer', value)\n}\n\nfunction isArrayBufferSource(value: any): value is Binary.Source {\n return isArrayBufferLike(value) || ArrayBuffer.isView(value)\n}\n\n/** Binary source detection and base64/hex conversion helpers. */\nexport namespace Binary {\n export type Source<T extends ArrayBufferLike = ArrayBufferLike> = T | ArrayBufferView<T>\n\n export const is = isArrayBufferLike\n export const isSource = isArrayBufferSource\n\n export function fromSource<T extends ArrayBufferLike>(source: Source<T>): T {\n if (ArrayBuffer.isView(source)) {\n // https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer#answer-31394257\n return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength) as T\n } else {\n return source\n }\n }\n\n export function toBase64(source: Source) {\n source = fromSource(source)\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(source).toString('base64')\n }\n let binary = ''\n const bytes = new Uint8Array(source)\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i])\n }\n return btoa(binary)\n }\n\n export function fromBase64(source: string) {\n if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'base64'))\n return Uint8Array.from(atob(source), c => c.charCodeAt(0))\n }\n\n export function toHex(source: Source) {\n source = fromSource(source)\n if (typeof Buffer !== 'undefined') return Buffer.from(source).toString('hex')\n return Array.from(new Uint8Array(source), byte => byte.toString(16).padStart(2, '0')).join('')\n }\n\n export function fromHex(source: string) {\n if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'hex'))\n const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1)\n const buffer: number[] = []\n for (let i = 0; i < hex.length; i += 2) {\n buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16))\n }\n return Uint8Array.from(buffer).buffer\n }\n}\n\n/** Decode a base64 string into binary data. */\nexport const base64ToArrayBuffer = Binary.fromBase64\n/** Encode binary data as base64. */\nexport const arrayBufferToBase64 = Binary.toBase64\n/** Decode a hex string into binary data. */\nexport const hexToArrayBuffer = Binary.fromHex\n/** Encode binary data as hex. */\nexport const arrayBufferToHex = Binary.toHex\n\n/** Deep-clone common JavaScript values while preserving prototypes. */\nexport function clone<T>(source: T): T\n/** Deep-clone common JavaScript values while preserving prototypes and cycles. */\nexport function clone(source: any, refs = new Map<any, any>()) {\n if (!source || typeof source !== 'object') return source\n if (is('Date', source)) return new Date(source.valueOf())\n if (is('RegExp', source)) return new RegExp(source.source, source.flags)\n if (isArrayBufferLike(source)) return source.slice(0)\n if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength)\n const cached = refs.get(source)\n if (cached) return cached\n if (Array.isArray(source)) {\n const result: any[] = []\n refs.set(source, result)\n source.forEach((value, index) => {\n result[index] = Reflect.apply(clone, null, [value, refs])\n })\n return result\n }\n const result = Object.create(Object.getPrototypeOf(source))\n refs.set(source, result)\n for (const key of Reflect.ownKeys(source)) {\n const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) }\n if ('value' in descriptor) {\n descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs])\n }\n Reflect.defineProperty(result, key, descriptor)\n }\n return result\n}\n\n/** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */\nexport function deepEqual(a: any, b: any, strict?: boolean): boolean {\n if (a === b) return true\n if (!strict && isNullable(a) && isNullable(b)) return true\n if (typeof a !== typeof b) return false\n if (typeof a !== 'object') return false\n if (!a || !b) return false\n\n function check<T>(test: (x: any) => x is T, then: (a: T, b: T) => boolean) {\n return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : undefined\n }\n\n return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index])))\n ?? check(is('Date'), (a, b) => a.valueOf() === b.valueOf())\n ?? check(is('RegExp'), (a, b) => a.source === b.source && a.flags === b.flags)\n ?? check(isArrayBufferLike, (a, b) => {\n if (a.byteLength !== b.byteLength) return false\n const viewA = new Uint8Array(a)\n const viewB = new Uint8Array(b)\n for (let i = 0; i < viewA.length; i++) {\n if (viewA[i] !== viewB[i]) return false\n }\n return true\n })\n ?? Object.keys({ ...a, ...b }).every(key => deepEqual(a[key], b[key], strict))\n}\n","/** Time constants plus parsing and formatting helpers. */\nexport namespace Time {\n export const millisecond = 1\n export const second = 1000\n export const minute = second * 60\n export const hour = minute * 60\n export const day = hour * 24\n export const week = day * 7\n\n let timezoneOffset = new Date().getTimezoneOffset()\n\n export function setTimezoneOffset(offset: number) {\n timezoneOffset = offset\n }\n\n export function getTimezoneOffset() {\n return timezoneOffset\n }\n\n export function getDateNumber(date: number | Date = new Date(), offset?: number) {\n if (typeof date === 'number') date = new Date(date)\n if (offset === undefined) offset = timezoneOffset\n return Math.floor((date.valueOf() / minute - offset) / 1440)\n }\n\n export function fromDateNumber(value: number, offset?: number) {\n const date = new Date(value * day)\n if (offset === undefined) offset = timezoneOffset\n return new Date(+date + offset * minute)\n }\n\n const numeric = /\\d+(?:\\.\\d+)?/.source\n const timeRegExp = new RegExp(`^${[\n 'w(?:eek(?:s)?)?',\n 'd(?:ay(?:s)?)?',\n 'h(?:our(?:s)?)?',\n 'm(?:in(?:ute)?(?:s)?)?',\n 's(?:ec(?:ond)?(?:s)?)?',\n ].map(unit => `(${numeric}${unit})?`).join('')}$`)\n\n export function parseTime(source: string) {\n const capture = timeRegExp.exec(source)\n if (!capture) return 0\n return (parseFloat(capture[1]) * week || 0)\n + (parseFloat(capture[2]) * day || 0)\n + (parseFloat(capture[3]) * hour || 0)\n + (parseFloat(capture[4]) * minute || 0)\n + (parseFloat(capture[5]) * second || 0)\n }\n\n export function parseDate(date: string) {\n const parsed = parseTime(date)\n if (parsed) {\n date = Date.now() + parsed as any\n } else if (/^\\d{1,2}(:\\d{1,2}){1,2}$/.test(date)) {\n date = `${new Date().toLocaleDateString()}-${date}`\n } else if (/^\\d{1,2}-\\d{1,2}-\\d{1,2}(:\\d{1,2}){1,2}$/.test(date)) {\n date = `${new Date().getFullYear()}-${date}`\n }\n return date ? new Date(date) : new Date()\n }\n\n export function format(ms: number) {\n const abs = Math.abs(ms)\n if (abs >= day - hour / 2) {\n return Math.round(ms / day) + 'd'\n } else if (abs >= hour - minute / 2) {\n return Math.round(ms / hour) + 'h'\n } else if (abs >= minute - second / 2) {\n return Math.round(ms / minute) + 'm'\n } else if (abs >= second) {\n return Math.round(ms / second) + 's'\n }\n return ms + 'ms'\n }\n\n export function toDigits(source: number, length = 2) {\n return source.toString().padStart(length, '0')\n }\n\n export function template(template: string, time = new Date()) {\n return template\n .replace('yyyy', time.getFullYear().toString())\n .replace('yy', time.getFullYear().toString().slice(2))\n .replace('MM', toDigits(time.getMonth() + 1))\n .replace('dd', toDigits(time.getDate()))\n .replace('hh', toDigits(time.getHours()))\n .replace('mm', toDigits(time.getMinutes()))\n .replace('ss', toDigits(time.getSeconds()))\n .replace('SSS', toDigits(time.getMilliseconds(), 3))\n }\n}\n","import { Binary, clone, deepEqual, filterKeys, isNullable, isPlainObject, pick, valueMap, type Dict } from '@deepseek-ai/cosmokit'\nimport type { StandardSchemaV1 } from '@standard-schema/spec'\n\nconst kSchema = Symbol.for('schemastery')\nconst kValidationError = Symbol.for('ValidationError')\n\ndeclare global {\n namespace Schemastery {\n /** Convert primitive constructors, constants, and existing schemas into a schema type. */\n export type From<X> =\n | X extends string | number | boolean ? Schema<X>\n : X extends Schema ? X\n : X extends typeof String ? Schema<string>\n : X extends typeof Number ? Schema<number>\n : X extends typeof Boolean ? Schema<boolean>\n : X extends typeof Function ? Schema<Function, (...args: any[]) => any>\n : X extends Constructor<infer S> ? Schema<S>\n : never\n\n type TypeS1<X> = X extends Schema<infer S, unknown> ? S : never\n type Inverse<X> = X extends Schema<any, infer Y> ? (arg: Y) => void : never\n\n /** Input type accepted by a schema-like value. */\n export type TypeS<X> = TypeS1<From<X>>\n /** Output type returned by a schema-like value after validation. */\n export type TypeT<X> = ReturnType<From<X>>\n /** Resolver callback used by custom schema types registered with `Schema.extend()`. */\n export type Resolve = (data: any, schema: Schema, options: Options, strict?: boolean) => [any, any?]\n\n /** Input type accepted by one schema in an intersection. */\n export type IntersectS<X> = From<X> extends Schema<infer S, unknown> ? S : never\n /** Output type returned by one schema in an intersection. */\n export type IntersectT<X> = Inverse<From<X>> extends ((arg: infer T) => void) ? T : never\n\n type TupleS<X extends readonly any[]> = X extends readonly [infer L, ...infer R] ? [TypeS<L>?, ...TupleS<R>] : any[]\n type TupleT<X extends readonly any[]> = X extends readonly [infer L, ...infer R] ? [TypeT<L>?, ...TupleT<R>] : any[]\n type ObjectS<X extends Dict> = { [K in keyof X]?: TypeS<X[K]> | null } & Dict\n type ObjectT<X extends Dict> = { [K in keyof X]: TypeT<X[K]> } & Dict\n type Constructor<T = any> = new (...args: any[]) => T\n\n /** Static constructor and factory methods exposed by the default `Schema` export. */\n export interface Static {\n <T = any>(options: Partial<Schema<T>>): Schema<T>\n new <T = any>(options: Partial<Schema<T>>): Schema<T>\n prototype: Schema\n /** Validate a value against a schema node and return `[output, adaptedInput?]`. */\n resolve: Resolve\n /** Infer a schema from a primitive value, constructor, or existing schema. */\n from<X = any>(source?: X): From<X>\n /** Register a resolver for a custom schema `type`. */\n extend(type: string, resolve: Resolve): void\n /** Accept any value without validation. */\n any<T = any>(): Schema<T>\n /** Accept only nullable input. */\n never(): Schema<never>\n /** Accept exactly one constant value. */\n const<const T>(value: T): Schema<T>\n /** Accept strings, with optional metadata constraints added by instance methods. */\n string(): Schema<string>\n /** Accept numbers, with optional range and step constraints. */\n number(): Schema<number>\n /** Accept non-negative integer numbers. */\n natural(): Schema<number>\n /** Accept a number between 0 and 1 and mark it as a slider. */\n percent(): Schema<number>\n /** Accept booleans. */\n boolean(): Schema<boolean>\n /** Accept `Date` instances or parse datetime strings into `Date` objects. */\n date(): Schema<string | Date, Date>\n /** Accept `RegExp` instances or parse strings into regular expressions. */\n regExp(flag?: string): Schema<string | RegExp, RegExp>\n /** Accept binary sources and normalize them to `ArrayBufferLike`. */\n arrayBuffer(): Schema<Binary.Source, ArrayBufferLike>\n arrayBuffer(encoding: 'hex' | 'base64'): Schema<Binary.Source | string, ArrayBufferLike>\n /** Accept a numeric bitset or string keys and normalize to a number. */\n bitset<K extends string>(bits: Partial<Record<K, number>>): Schema<number | readonly K[], number>\n /** Accept functions. */\n function(): Schema<Function, (...args: any[]) => any>\n /** Accept instances of a constructor or objects whose constructor name matches. */\n is(constructor: string): Schema\n is<T>(constructor: Constructor<T>): Schema<T>\n /** Accept arrays whose elements match `inner`. */\n array<X>(inner: X): Schema<TypeS<X>[], TypeT<X>[]>\n /** Accept plain objects with values matching `inner` and optional key schema. */\n dict<X, Y extends Schema<any, string> = Schema<string>>(inner: X, sKey?: Y): Schema<Dict<TypeS<X>, TypeS<Y>>, Dict<TypeT<X>, TypeT<Y>>>\n /** Accept tuple arrays where each index matches the corresponding schema. */\n tuple<const X extends readonly any[]>(list: X): Schema<TupleS<X>, TupleT<X>>\n /** Accept plain objects whose declared properties match the schema dictionary. */\n object<X extends Dict>(dict: X): Schema<ObjectS<X>, ObjectT<X>>\n /** Accept values matching at least one schema in `list`. */\n union<const X>(list: readonly X[]): Schema<TypeS<X>, TypeT<X>>\n /** Accept values matching every schema in `list`, merging object outputs. */\n intersect<const X>(list: readonly X[]): Schema<IntersectS<X>, IntersectT<X>>\n /** Validate with `inner`, then convert the result with `callback`. */\n transform<X, T>(inner: X, callback: (value: TypeS<X>, options: Schemastery.Options) => T, preserve?: boolean): Schema<TypeS<X>, T>\n /** Defer construction of a recursive schema until validation or serialization. */\n lazy<X extends Schema>(callback: () => X): X\n ValidationError: typeof ValidationError\n }\n\n /** Runtime validation options shared by all schema calls. */\n interface Options {\n /** Remove invalid object properties instead of throwing when possible. */\n autofix?: boolean\n /** Skip validation for selected values and schema nodes. */\n ignore?(data: any, schema: Schema): boolean\n /** Path used to format nested validation errors. */\n path?: (keyof any)[]\n }\n\n /** UI and validation metadata attached by schema builder methods. */\n export interface Meta<T = any> {\n default?: T extends {} ? Partial<T> : T\n required?: boolean\n disabled?: boolean\n collapse?: boolean\n badges?: { text: string; type: string }[]\n hidden?: boolean\n loose?: boolean\n role?: string\n extra?: any\n link?: string\n description?: string | Dict<string>\n comment?: string\n pattern?: { source: string; flags?: string }\n max?: number\n min?: number\n step?: number\n }\n }\n\n /** Callable schema instance that validates input and returns normalized output. */\n interface Schemastery<S = any, T = S> {\n (data?: S | null, options?: Schemastery.Options): T\n new (data?: S | null, options?: Schemastery.Options): T\n [kSchema]: true\n uid: number\n meta: Schemastery.Meta<T>\n type: string\n sKey?: Schema\n inner?: Schema\n list?: Schema[]\n dict?: Dict<Schema>\n bits?: Dict<number>\n callback?: Function\n constructor?: string | Function\n builder?: Function\n value?: T\n refs?: Dict<Schema>\n preserve?: boolean\n '~standard': StandardSchemaV1.Props // <S, T>\n /** Format this schema as a compact TypeScript-like type string. */\n toString(inline?: boolean): string\n /** Serialize this schema, preserving shared and recursive references. */\n toJSON(): Schema<S, T>\n /** Mark nullable input as invalid unless a default supplies a fallback. */\n required(value?: boolean): Schema<S, T>\n /** Hide this schema node from UI renderers. */\n hidden(value?: boolean): Schema<S, T>\n /** Return the default value instead of throwing when validation fails. */\n loose(value?: boolean): Schema<S, T>\n /** Attach a renderer role and optional role-specific metadata. */\n role(text: string, extra?: any): Schema<S, T>\n /** Attach an external documentation link. */\n link(link: string): Schema<S, T>\n /** Set the fallback value used for nullable input. */\n default(value: T): Schema<S, T>\n /** Attach an auxiliary comment for documentation or form UIs. */\n comment(text: string): Schema<S, T>\n /** Attach a localized or plain description for documentation or form UIs. */\n description(text: string): Schema<S, T>\n /** Mark this schema node as disabled for form UIs. */\n disabled(value?: boolean): Schema<S, T>\n /** Request collapsed rendering for nested form UIs. */\n collapse(value?: boolean): Schema<S, T>\n /** Add a deprecated badge to this schema node. */\n deprecated(): Schema<S, T>\n /** Add an experimental badge to this schema node. */\n experimental(): Schema<S, T>\n /** Require strings to match a regular expression. */\n pattern(regexp: RegExp): Schema<S, T>\n /** Set an inclusive maximum for numbers or collection lengths. */\n max(value: number): Schema<S, T>\n /** Set an inclusive minimum for numbers or collection lengths. */\n min(value: number): Schema<S, T>\n /** Set the numeric increment constraint. */\n step(value: number): Schema<S, T>\n /** Add or replace an object property schema. */\n set(key: string, value: Schema): Schema<S, T>\n /** Append a tuple, union, or intersection member schema. */\n push(value: Schema): Schema<S, T>\n /** Remove values equal to schema defaults from normalized output. */\n simplify(value?: any): any\n /** Return a schema clone with descriptions merged from locale messages. */\n i18n(messages: Dict): Schema<S, T>\n /** Attach arbitrary metadata consumed by form renderers and downstream tools. */\n extra<K extends keyof Schemastery.Meta>(key: K, value: Schemastery.Meta[K]): Schema<S, T>\n }\n}\n\ndeclare namespace globalThis {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n export let __schemastery_index__: number\n export let __schemastery_refs__: Record<number, Schema> | undefined\n}\n\nglobalThis.__schemastery_index__ ??= 0\nglobalThis.__schemastery_refs__ = undefined\n\nclass ValidationError extends TypeError {\n name = 'ValidationError'\n\n constructor(message: string, public options: Schemastery.Options) {\n let prefix = '$'\n for (const segment of options.path || []) {\n if (typeof segment === 'string') {\n prefix += '.' + segment\n } else if (typeof segment === 'number') {\n prefix += '[' + segment + ']'\n } else if (typeof segment === 'symbol') {\n prefix += `[Symbol(${segment.toString()})]`\n }\n }\n if (prefix.startsWith('.')) prefix = prefix.slice(1)\n super((prefix === '$' ? '' : `${prefix} `) + message)\n }\n\n static is(error: any): error is ValidationError {\n return !!error?.[kValidationError]\n }\n}\n\nObject.defineProperty(ValidationError.prototype, kValidationError, {\n value: true,\n})\n\ntype Schema<S = any, T = S> = Schemastery<S, T>\n\nconst Schema = function (options: Schema) {\n const schema = function (data: any, options: Schemastery.Options = {}) {\n return Schema.resolve(data, schema, options)[0]\n } as Schema\n\n if (options.refs) {\n const refs = valueMap(options.refs, options => new Schema(options))\n const getRef = (uid: any) => refs[uid]!\n for (const key in refs) {\n const options = refs[key]!\n options.sKey = getRef(options.sKey)\n options.inner = getRef(options.inner)\n options.list = options.list && options.list.map(getRef)\n options.dict = options.dict && valueMap(options.dict, getRef)\n }\n return refs[options.uid!]\n }\n\n Object.assign(schema, options)\n if (typeof schema.callback === 'string') {\n try {\n // eslint-disable-next-line no-new-func\n schema.callback = new Function('return ' + schema.callback)()\n } catch {}\n }\n Object.defineProperty(schema, 'uid', { value: globalThis.__schemastery_index__++ })\n Object.setPrototypeOf(schema, Schema.prototype)\n schema.meta ||= {}\n schema.toString = schema.toString.bind(schema)\n return schema\n} as Schemastery.Static\n\nSchema.prototype = Object.create(Function.prototype)\n\nSchema.prototype[kSchema] = true\n\nObject.defineProperty(Schema.prototype, '~standard', {\n get(this: Schema) {\n return {\n version: 1,\n vendor: 'schemastery',\n validate: (value: unknown) => {\n try {\n return { value: Schema.resolve(value, this, {})[0] }\n } catch (error) {\n if (ValidationError.is(error)) {\n return { issues: [{ message: error.message, path: error.options.path }] }\n }\n throw error\n }\n },\n }\n },\n})\n\nSchema.ValidationError = ValidationError\n\nSchema.prototype.toJSON = function toJSON() {\n if (globalThis.__schemastery_refs__) {\n globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this }))\n return this.uid as any\n }\n\n globalThis.__schemastery_refs__ = { [this.uid]: { ...this } as Schema }\n globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this }))\n const result = { uid: this.uid, refs: globalThis.__schemastery_refs__ }\n globalThis.__schemastery_refs__ = undefined\n return result\n}\n\nSchema.prototype.set = function set(key, value) {\n this.dict![key] = value\n return this\n}\n\nSchema.prototype.push = function push(value) {\n this.list!.push(value)\n return this\n}\n\nfunction mergeDesc(original: undefined | string | Dict<string>, messages: Dict) {\n const result: Dict<string> = typeof original === 'string' ? { '': original } : { ...original }\n for (const locale in messages) {\n const value = messages[locale]\n if (value?.$description || value?.$desc) {\n result[locale] = value.$description || value.$desc\n } else if (typeof value === 'string') {\n result[locale] = value\n }\n }\n return result\n}\n\nfunction getInner(value: any) {\n return value?.$value ?? value?.$inner\n}\n\nfunction extractKeys(data: any) {\n return filterKeys(data ?? {}, key => !key.startsWith('$'))\n}\n\nSchema.prototype.i18n = function i18n(messages) {\n const schema = Schema(this)\n const desc = mergeDesc(schema.meta.description, messages)\n if (Object.keys(desc).length) schema.meta.description = desc\n if (schema.dict) {\n schema.dict = valueMap(schema.dict, (inner, key) => {\n return inner.i18n(valueMap(messages, (data) => getInner(data)?.[key] ?? data?.[key]))\n })\n }\n if (schema.list) {\n schema.list = schema.list!.map((inner, index) => {\n return inner.i18n(valueMap(messages, (data = {}) => {\n if (Array.isArray(getInner(data))) return getInner(data)[index]\n if (Array.isArray(data)) return data[index]\n return extractKeys(data)\n }))\n })\n }\n if (schema.inner) {\n schema.inner = schema.inner.i18n(valueMap(messages, (data) => {\n if (getInner(data)) return getInner(data)\n return extractKeys(data)\n }))\n }\n if (schema.sKey) {\n schema.sKey = schema.sKey.i18n(valueMap(messages, (data) => data?.$key))\n }\n return schema\n}\n\nSchema.prototype.extra = function extra(key, value) {\n const schema = Schema(this)\n schema.meta = { ...schema.meta, [key]: value }\n return schema\n}\n\nfor (const key of ['required', 'disabled', 'collapse', 'hidden', 'loose']) {\n Object.assign(Schema.prototype, {\n [key](this: Schema, value = true) {\n const schema = Schema(this)\n schema.meta = { ...schema.meta, [key]: value }\n return schema\n },\n })\n}\n\nSchema.prototype.deprecated = function deprecated() {\n const schema = Schema(this)\n schema.meta.badges ||= []\n schema.meta.badges.push({ text: 'deprecated', type: 'danger' })\n return schema\n}\n\nSchema.prototype.experimental = function experimental() {\n const schema = Schema(this)\n schema.meta.badges ||= []\n schema.meta.badges.push({ text: 'experimental', type: 'warning' })\n return schema\n}\n\nSchema.prototype.pattern = function pattern(regexp) {\n const schema = Schema(this)\n const pattern = pick(regexp, ['source', 'flags'])\n schema.meta = { ...schema.meta, pattern }\n return schema\n}\n\nSchema.prototype.simplify = function simplify(this: Schema, value) {\n if (deepEqual(value, this.meta.default, this.type === 'dict')) return null\n if (isNullable(value)) return value\n if (this.type === 'object' || this.type === 'dict') {\n const result: Dict = {}\n for (const key in value) {\n const schema = this.type === 'object' ? this.dict![key] : this.inner\n const item = schema?.simplify(value[key])\n if (this.type === 'dict' || !isNullable(item)) result[key] = item\n }\n if (deepEqual(result, this.meta.default, this.type === 'dict')) return null\n return result\n } else if (this.type === 'array' || this.type === 'tuple') {\n const result: any[] = []\n ;(value as any[]).forEach((value, index) => {\n const schema = this.type === 'array' ? this.inner : this.list![index]\n const item = schema ? schema.simplify(value) : value\n result.push(item)\n })\n return result\n } else if (this.type === 'intersect') {\n const result: Dict = {}\n for (const item of this.list!) {\n Object.assign(result, item.simplify(value))\n }\n return result\n } else if (this.type === 'union') {\n for (const schema of this.list!) {\n try {\n Schema.resolve(value, schema, {})\n return schema.simplify(value)\n } catch {}\n }\n }\n return value\n}\n\nSchema.prototype.toString = function toString(inline?: boolean) {\n return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`\n}\n\nSchema.prototype.role = function role(role, extra) {\n const schema = Schema(this)\n schema.meta = { ...schema.meta, role, extra }\n return schema\n}\n\nfor (const key of ['default', 'link', 'comment', 'description', 'max', 'min', 'step']) {\n Object.assign(Schema.prototype, {\n [key](this: Schema, value: any) {\n const schema = Schema(this)\n schema.meta = { ...schema.meta, [key]: value }\n return schema\n },\n })\n}\n\nconst resolvers: Dict<Schemastery.Resolve> = {}\n\nSchema.extend = function extend(type, resolve) {\n resolvers[type] = resolve\n}\n\nSchema.resolve = function resolve(data, schema, options = {}, strict = false) {\n if (!schema) return [data]\n if (options.ignore?.(data, schema)) return [data]\n\n if (isNullable(data) && schema.type !== 'lazy') {\n if (schema.meta.required) throw new ValidationError(`missing required value`, options)\n let current = schema\n let fallback = schema.meta.default\n while (current?.type === 'intersect' && isNullable(fallback)) {\n current = current.list![0]\n fallback = current?.meta.default\n }\n if (isNullable(fallback)) return [data]\n data = clone(fallback)\n }\n\n const callback = resolvers[schema.type]\n if (!callback) throw new ValidationError(`unsupported type \"${schema.type}\"`, options)\n\n try {\n return callback(data, schema, options, strict)\n } catch (error) {\n if (!schema.meta.loose) throw error\n return [schema.meta.default]\n }\n}\n\nSchema.from = function from(source: any) {\n if (isNullable(source)) {\n return Schema.any()\n } else if (['string', 'number', 'boolean'].includes(typeof source)) {\n return Schema.const(source).required()\n } else if (source[kSchema]) {\n return source\n } else if (typeof source === 'function') {\n switch (source) {\n case String: return Schema.string().required()\n case Number: return Schema.number().required()\n case Boolean: return Schema.boolean().required()\n case Function: return Schema.function().required()\n default: return Schema.is(source).required()\n }\n } else {\n throw new TypeError(`cannot infer schema from ${source}`)\n }\n}\n\nSchema.lazy = function lazy(builder) {\n const toJSON = () => {\n if (!schema.inner![kSchema]) {\n schema.inner = schema.builder!()\n schema.inner!.meta = { ...schema.meta, ...schema.inner!.meta }\n }\n return schema.inner!.toJSON()\n }\n const schema = new Schema({ type: 'lazy', builder, inner: { toJSON } as any })\n return schema as any\n}\n\nSchema.natural = function natural() {\n return Schema.number().step(1).min(0)\n}\n\nSchema.percent = function percent() {\n return Schema.number().step(0.01).min(0).max(1).role('slider')\n}\n\nSchema.date = function date() {\n return Schema.union([\n Schema.is(Date),\n Schema.transform(Schema.string().role('datetime'), (value, options) => {\n const date = new Date(value)\n if (isNaN(+date)) throw new ValidationError(`invalid date \"${value}\"`, options)\n return date\n }, true),\n ])\n}\n\nSchema.regExp = function regExp(flag = '') {\n return Schema.union([\n Schema.is(RegExp),\n Schema.transform(Schema.string().role('regexp', { flag }), (value, options) => {\n try {\n return new RegExp(value, flag)\n } catch (e: any) {\n throw new ValidationError(e.message, options)\n }\n }, true),\n ])\n}\n\nSchema.arrayBuffer = function arrayBuffer(encoding?: 'hex' | 'base64'): any {\n return Schema.union([\n Schema.is(ArrayBuffer),\n Schema.is(SharedArrayBuffer),\n Schema.transform(Schema.any<ArrayBufferView>(), (value, options) => {\n if (Binary.isSource(value)) return Binary.fromSource(value)\n throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options)\n }, true),\n ...encoding ? [Schema.transform(Schema.string(), (value, options) => {\n try {\n return encoding === 'base64'\n ? Binary.fromBase64(value)\n : Binary.fromHex(value)\n } catch (e: any) {\n throw new ValidationError(e.message, options)\n }\n }, true)] as const : [],\n ])\n}\n\nSchema.extend('lazy', (data, schema, options, strict) => {\n if (!schema.inner![kSchema]) {\n schema.inner = schema.builder!()\n schema.inner!.meta = { ...schema.meta, ...schema.inner!.meta }\n }\n return Schema.resolve(data, schema.inner!, options, strict)\n})\n\nSchema.extend('any', (data) => {\n return [data]\n})\n\nSchema.extend('never', (data, _, options) => {\n throw new ValidationError(`expected nullable but got ${data}`, options)\n})\n\nSchema.extend('const', (data, { value }, options) => {\n if (deepEqual(data, value)) return [value]\n throw new ValidationError(`expected ${value} but got ${data}`, options)\n})\n\nfunction checkWithinRange(data: number, meta: Schemastery.Meta<any>, description: string, options: Schemastery.Options, skipMin = false) {\n const { max = Infinity, min = -Infinity } = meta\n if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options)\n if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options)\n}\n\nSchema.extend('string', (data, { meta }, options) => {\n if (typeof data !== 'string') throw new ValidationError(`expected string but got ${data}`, options)\n if (meta.pattern) {\n const regexp = new RegExp(meta.pattern.source, meta.pattern.flags)\n if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options)\n }\n checkWithinRange(data.length, meta, 'string length', options)\n return [data]\n})\n\nfunction decimalShift(data: number, digits: number) {\n const str = data.toString()\n if (str.includes('e')) return data * Math.pow(10, digits)\n const index = str.indexOf('.')\n if (index === -1) return data * Math.pow(10, digits)\n const frac = str.slice(index + 1)\n const integer = str.slice(0, index)\n if (frac.length <= digits) return +(integer + frac.padEnd(digits, '0'))\n return +(integer + frac.slice(0, digits) + '.' + frac.slice(digits))\n}\n\nfunction isMultipleOf(data: number, min: number, step: number) {\n step = Math.abs(step)\n if (!/^\\d+\\.\\d+$/.test(step.toString())) {\n return (data - min) % step === 0\n }\n const index = step.toString().indexOf('.')\n const digits = step.toString().slice(index + 1).length\n return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0\n}\n\nSchema.extend('number', (data, { meta }, options) => {\n if (typeof data !== 'number') throw new ValidationError(`expected number but got ${data}`, options)\n checkWithinRange(data, meta, 'number', options)\n const { step } = meta\n if (step && !isMultipleOf(data, meta.min ?? 0, step)) {\n throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options)\n }\n return [data]\n})\n\nSchema.extend('boolean', (data, _, options) => {\n if (typeof data === 'boolean') return [data]\n throw new ValidationError(`expected boolean but got ${data}`, options)\n})\n\nSchema.extend('bitset', (data, { bits, meta }, options) => {\n let value = 0, keys: string[] = []\n if (typeof data === 'number') {\n value = data\n for (const key in bits!) {\n if (data & bits![key]!) {\n keys.push(key)\n }\n }\n } else if (Array.isArray(data)) {\n keys = data\n for (const key of keys) {\n if (typeof key !== 'string') throw new ValidationError(`expected string but got ${key}`, options)\n if (key in bits!) value |= bits![key]!\n }\n } else {\n throw new ValidationError(`expected number or array but got ${data}`, options)\n }\n if (value === meta.default) return [value]\n return [value, keys]\n})\n\nSchema.extend('function', (data, _, options) => {\n if (typeof data === 'function') return [data]\n throw new ValidationError(`expected function but got ${data}`, options)\n})\n\nSchema.extend('is', (data, { constructor }, options) => {\n if (typeof constructor === 'function') {\n if (data instanceof constructor) return [data]\n throw new ValidationError(`expected ${constructor.name} but got ${data}`, options)\n } else {\n if (isNullable(data)) {\n throw new ValidationError(`expected ${constructor} but got ${data}`, options)\n }\n let prototype = Object.getPrototypeOf(data)\n while (prototype) {\n if (prototype.constructor?.name === constructor) return [data]\n prototype = Object.getPrototypeOf(prototype)\n }\n throw new ValidationError(`expected ${constructor} but got ${data}`, options)\n }\n})\n\nfunction property(data: any, key: keyof any, schema: Schema, options: Schemastery.Options) {\n try {\n const [value, adapted] = Schema.resolve(data[key], schema, {\n ...options,\n path: [...options.path || [], key],\n })\n if (adapted !== undefined) data[key] = adapted\n return value\n } catch (e) {\n if (!options?.autofix) throw e\n delete data[key]\n return schema.meta.default\n }\n}\n\nSchema.extend('array', (data, { inner, meta }, options) => {\n if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options)\n checkWithinRange(data.length, meta, 'array length', options, !isNullable(inner!.meta.default))\n return [data.map((_, index) => property(data, index, inner!, options))]\n})\n\nSchema.extend('dict', (data, { inner, sKey }, options, strict) => {\n if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options)\n const result: any = {}\n for (const key in data) {\n let rKey: string\n try {\n rKey = Schema.resolve(key, sKey!, options)[0]\n } catch (error) {\n if (strict) continue\n throw error\n }\n result[rKey] = property(data, key, inner!, options)\n data[rKey] = data[key]\n if (key !== rKey) delete data[key]\n }\n return [result]\n})\n\nSchema.extend('tuple', (data, { list }, options, strict) => {\n if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options)\n const result = list!.map((inner, index) => property(data, index, inner, options))\n if (strict) return [result]\n result.push(...data.slice(list!.length))\n return [result]\n})\n\nfunction merge(result: any, data: any) {\n for (const key in data) {\n if (key in result) continue\n result[key] = data[key]\n }\n}\n\nSchema.extend('object', (data, { dict }, options, strict) => {\n if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options)\n const result: any = {}\n for (const key in dict) {\n const value = property(data, key, dict![key]!, options)\n if (!isNullable(value) || key in data) {\n result[key] = value\n }\n }\n if (!strict) merge(result, data)\n return [result]\n})\n\nSchema.extend('union', (data, { list, toString }, options, strict) => {\n const messages: any[] = []\n for (const inner of list!) {\n try {\n return Schema.resolve(data, inner, options, strict)\n } catch (error) {\n messages.push(error)\n }\n }\n throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)\n})\n\nSchema.extend('intersect', (data, { list, toString }, options, strict) => {\n if (!list!.length) return [data]\n let result\n for (const inner of list!) {\n const value: any = Schema.resolve(data, inner, options, true)[0]\n if (isNullable(value)) continue\n if (isNullable(result)) {\n result = value\n } else if (typeof result !== typeof value) {\n throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)\n } else if (typeof value === 'object') {\n merge(result ??= {}, value)\n } else if (result !== value) {\n throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)\n }\n }\n if (!strict && isPlainObject(data)) merge(result, data)\n return [result]\n})\n\nSchema.extend('transform', (data, { inner, callback, preserve }, options) => {\n const [result, adapted = data] = Schema.resolve(data, inner!, options, true)\n if (preserve) {\n return [callback!(result)]\n // } else if (isPlainObject(data)) {\n // const temp: any = {}\n // for (const key in result) {\n // if (!(key in data)) continue\n // temp[key] = data[key]\n // delete data[key]\n // }\n // Object.assign(data, callback!(temp))\n // return [callback!(result)]\n } else {\n return [callback!(result), callback!(adapted)]\n }\n})\n\ntype Formatter = (schema: Schema, inline?: boolean) => string\nconst formatters: Dict<Formatter> = {}\n\nfunction defineMethod(name: string, keys: (keyof Schema)[], format: Formatter) {\n formatters[name] = format\n Object.assign(Schema, {\n [name](...args: any[]) {\n const schema = new Schema({ type: name } as Schema)\n keys.forEach((key, index) => {\n switch (key) {\n case 'sKey': schema.sKey = args[index] ?? Schema.string(); break\n case 'inner': schema.inner = Schema.from(args[index]); break\n case 'list': schema.list = args[index].map(Schema.from); break\n case 'dict': schema.dict = valueMap(args[index], Schema.from); break\n case 'bits': {\n schema.bits = {}\n for (const key in args[index]) {\n if (typeof args[index][key] !== 'number') continue\n schema.bits[key] = args[index][key]\n }\n break\n }\n case 'callback': {\n const callback = schema.callback = args[index]\n ;callback['toJSON'] ||= () => callback.toString()\n break\n }\n case 'constructor': {\n const constructor = schema.constructor = args[index]\n if (typeof constructor === 'function') {\n ;constructor['toJSON'] ||= () => constructor['name']\n }\n break\n }\n default: schema[key] = args[index] as never\n }\n })\n if (name === 'object' || name === 'dict') {\n schema.meta.default = {}\n } else if (name === 'array' || name === 'tuple') {\n schema.meta.default = []\n } else if (name === 'bitset') {\n schema.meta.default = 0\n }\n return schema\n },\n })\n}\n\ndefineMethod('is', ['constructor'], ({ constructor }) => {\n if (typeof constructor === 'function') {\n return constructor.name\n } else {\n return constructor!\n }\n})\n\ndefineMethod('any', [], () => 'any')\ndefineMethod('never', [], () => 'never')\ndefineMethod('const', ['value'], ({ value }) => typeof value === 'string' ? JSON.stringify(value) : value)\ndefineMethod('string', [], () => 'string')\ndefineMethod('number', [], () => 'number')\ndefineMethod('boolean', [], () => 'boolean')\ndefineMethod('bitset', ['bits'], () => 'bitset')\ndefineMethod('function', [], () => 'function')\ndefineMethod('array', ['inner'], ({ inner }) => `${inner!.toString(true)}[]`)\ndefineMethod('dict', ['inner', 'sKey'], ({ inner, sKey }) => `{ [key: ${sKey!.toString()}]: ${inner!.toString()} }`)\ndefineMethod('tuple', ['list'], ({ list }) => `[${list!.map((inner) => inner.toString()).join(', ')}]`)\n\ndefineMethod('object', ['dict'], ({ dict }) => {\n if (Object.keys(dict!).length === 0) return '{}'\n return `{ ${Object.entries(dict!).map(([key, inner]) => {\n return `${key}${inner!.meta.required ? '' : '?'}: ${inner!.toString()}`\n }).join(', ')} }`\n})\n\ndefineMethod('union', ['list'], ({ list }, inline) => {\n const result = list!.map(({ toString: format }) => format()).join(' | ')\n return inline ? `(${result})` : result\n})\n\ndefineMethod('intersect', ['list'], ({ list }) => {\n return `${list!.map((inner) => inner.toString(true)).join(' & ')}`\n})\n\ndefineMethod('transform', ['inner', 'callback', 'preserve'], ({ inner }, isInner) => inner!.toString(isInner))\n\nexport default Schema\n","import z from '@deepseek-ai/schemastery'\nimport type { CircuitHealth, FailoverSettings, QueueRoute } from './types.ts'\n\n/** Plugin config accepted from cordis.yml / the bundle patch. */\nexport interface Config {\n /** Milliseconds an Open circuit waits before a HalfOpen probe. Default 60000. */\n cooldownMs?: number\n /** Consecutive failures that open a Closed breaker. Default 2. */\n failureThreshold?: number\n /** Consecutive HalfOpen successes that close the breaker. Default 2. */\n successThreshold?: number\n /**\n * Failure codes that skip remaining same-route retries, open the circuit\n * immediately, and jump to the next P. Default `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`.\n */\n immediateCodes?: string[]\n}\n\n/** Config after schema defaults. */\nexport interface ResolvedConfig {\n cooldownMs: number\n failureThreshold: number\n successThreshold: number\n immediateCodes: readonly string[]\n}\n\n/** Runtime schema. */\nexport const Config: z<Config> = z.object({\n cooldownMs: z.number().min(0).default(60_000),\n failureThreshold: z.number().min(1).default(2),\n successThreshold: z.number().min(1).default(2),\n immediateCodes: z.array(z.string()).default(['AUTH', 'RATE_LIMIT', 'NO_ADAPTER']),\n})\n\n/**\n * Apply schema defaults.\n * @param config - raw plugin config, possibly partial.\n */\nexport function resolveConfig(config: Config = {}): ResolvedConfig {\n return Config(config) as ResolvedConfig\n}\n\n/** Settings namespace (hyphenated; settings forbids dots). */\nexport const SETTINGS_NAMESPACE = 'dsh-failover-queue'\n\nconst QueueRouteSchema: z<QueueRoute> = z.object({\n provider: z.string(),\n model: z.string(),\n label: z.string().default(''),\n})\n\nconst CircuitHealthSchema: z<CircuitHealth> = z.object({\n provider: z.string(),\n model: z.string(),\n state: z.string().default('closed'),\n failures: z.number().min(0).default(0),\n})\n\n/** Persisted user document. */\nexport const FailoverSettingsSchema: z<FailoverSettings> = z.object({\n enabled: z.boolean().default(false),\n currentIndex: z.number().step(1).min(0).default(0),\n queue: z.array(QueueRouteSchema).default([]),\n circuits: z.array(CircuitHealthSchema).default([]),\n})\n\n/** Empty queue, failover off. */\nexport const DEFAULT_SETTINGS: FailoverSettings = {\n enabled: false,\n currentIndex: 0,\n queue: [],\n circuits: [],\n}\n","import type { FailoverCandidate, FailoverSettings, QueueRoute } from '../types.ts'\nimport { DEFAULT_SETTINGS } from '../config.ts'\nimport { clampIndex, dedupeQueue } from '../queue.ts'\n\n/** Live snapshot published to the chip via the inject hooks seat. */\nexport interface FailoverSnapshot extends FailoverSettings {\n /** Catalog rows the add list can pick. */\n readonly candidates: readonly FailoverCandidate[]\n /** False until the first catalog/slash-command fetch finishes. */\n readonly candidatesLoaded: boolean\n}\n\nconst listeners = new Set<() => void>()\nlet snapshot: FailoverSnapshot = {\n ...DEFAULT_SETTINGS,\n circuits: [],\n candidates: [],\n candidatesLoaded: false,\n}\n\nfunction publish(next: FailoverSnapshot): void {\n snapshot = next\n for (const listener of [...listeners]) listener()\n}\n\n/** Bare observable the slot renderer binds to `useFailover`. */\nexport const failoverSource = {\n subscribe(listener: () => void): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n getSnapshot(): FailoverSnapshot {\n return snapshot\n },\n}\n\n/**\n * Replace settings fields, keep candidates.\n * @param settings - persisted document.\n */\nexport function replaceSettings(settings: FailoverSettings): void {\n const queue = dedupeQueue(settings.queue)\n publish({\n enabled: settings.enabled,\n queue,\n currentIndex: clampIndex(settings.currentIndex, queue.length),\n circuits: settings.circuits ?? [],\n candidates: snapshot.candidates,\n candidatesLoaded: snapshot.candidatesLoaded,\n })\n}\n\n/**\n * Replace the add-list catalog.\n * @param candidates - advertised provider+model rows.\n */\nexport function replaceCandidates(candidates: readonly FailoverCandidate[]): void {\n publish({ ...snapshot, candidates, candidatesLoaded: true })\n}\n\n/** Read the current snapshot (event-handler path). */\nexport function peek(): FailoverSnapshot {\n return snapshot\n}\n\nexport type { FailoverCandidate, FailoverSettings, QueueRoute }\n","/**\n * Browser half of dsh-failover-queue: a P1/P- chip on the composer tool row\n * and a Settings left-nav page. The chip still opens the drag-reorder popover.\n */\nimport type { Context } from '@deepseek-ai/cordis'\nimport { candidatesFromCatalog, candidatesFromText } from '../candidates.ts'\nimport type { FailoverSettings } from '../types.ts'\nimport { FailoverChip, FailoverSettingsCard } from './FailoverChip.tsx'\nimport { en, NS, zh, type FailoverKey } from './locales.ts'\nimport { failoverSource, replaceCandidates, replaceSettings } from './state.ts'\nimport { STYLE } from './styles.ts'\n\n/** Browser plugin context used here. Extra services are ignored. */\ninterface FailoverClientContext {\n effect(fn: () => (() => void) | void, name?: string): () => void\n locale: {\n register: (ns: string, packs: { zh: typeof zh; en: typeof en }) => () => void\n bind: (ns: string) => (key: FailoverKey, params?: Record<string, string | number>) => string\n }\n slots: {\n inject: (name: string, factory: () => () => void) => void\n register: (options: Record<string, unknown>, component: unknown) => () => void\n }\n settingsScope: {\n bind: (spec: { namespace: string }) => {\n getSnapshot: () => { value?: FailoverSettings; writable: boolean }\n set: (field: string, value: unknown) => Promise<void>\n subscribe: (cb: () => void) => () => void\n }\n }\n remote: {\n commands: {\n execute: (sessionId: string, line: string, attachments: unknown[]) => Promise<{\n ok: boolean\n value?: { text?: string } | string\n error?: { message: string; code: string }\n }>\n }\n session?: {\n modelCatalog: () => Promise<{\n ok: boolean\n value?: unknown\n error?: { message: string }\n }>\n }\n }\n}\n\n/** Required services for the composer chip and settings page. */\nexport const inject = ['slots', 'locale', 'settingsScope', 'remote', 'remote.commands', 'remote.session']\n\n\ninterface SessionList {\n list?: { getSnapshot: () => { current?: string } }\n}\n\nfunction currentSessionId(ctx: Context, sessionId?: string): string {\n if (typeof sessionId === 'string' && sessionId !== '') return sessionId\n // Property access throws without inject; get() is the optional read.\n const sessions = ctx.get('sessions') as SessionList | undefined\n const current = sessions?.list?.getSnapshot?.().current\n return typeof current === 'string' ? current : ''\n}\n\nfunction circuitState(value: unknown): 'closed' | 'open' | 'half_open' {\n if (value === 'open' || value === 'half_open' || value === 'closed') return value\n return 'closed'\n}\n\nfunction settingsFromUnknown(value: unknown): FailoverSettings | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const record = value as { enabled?: unknown; currentIndex?: unknown; queue?: unknown; circuits?: unknown }\n if (typeof record.enabled !== 'boolean') return undefined\n if (typeof record.currentIndex !== 'number') return undefined\n if (!Array.isArray(record.queue)) return undefined\n const queue = record.queue.flatMap((row) => {\n if (typeof row !== 'object' || row === null) return []\n const item = row as { provider?: unknown; model?: unknown; label?: unknown }\n if (typeof item.provider !== 'string' || typeof item.model !== 'string') return []\n return [{\n provider: item.provider,\n model: item.model,\n ...typeof item.label === 'string' ? { label: item.label } : {},\n }]\n })\n const circuits = Array.isArray(record.circuits)\n ? record.circuits.flatMap((row) => {\n if (typeof row !== 'object' || row === null) return []\n const item = row as { provider?: unknown; model?: unknown; state?: unknown; failures?: unknown }\n if (typeof item.provider !== 'string' || typeof item.model !== 'string') return []\n return [{\n provider: item.provider,\n model: item.model,\n state: circuitState(item.state),\n failures: typeof item.failures === 'number' && item.failures > 0 ? item.failures : 0,\n }]\n })\n : []\n return { enabled: record.enabled, currentIndex: record.currentIndex, queue, circuits }\n}\n\n/**\n * Register dictionaries, the composer chip, and the Settings left-nav page.\n * @param ctx - browser plugin context.\n */\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as FailoverClientContext\n const scope = client.settingsScope.bind({ namespace: 'dsh-failover-queue' })\n\n const pull = (): void => {\n const value = settingsFromUnknown(scope.getSnapshot().value)\n if (value !== undefined) replaceSettings(value)\n }\n pull()\n\n const api = {\n setEnabled: async (enabled: boolean) => {\n await scope.set('enabled', enabled)\n },\n setQueue: async (queue: FailoverSettings['queue'], currentIndex: number) => {\n await scope.set('queue', queue)\n await scope.set('currentIndex', currentIndex)\n },\n }\n\n const loadCandidates = async (sessionId: string): Promise<void> => {\n const catalog = await client.remote.session?.modelCatalog()\n if (catalog?.ok) {\n const rows = candidatesFromCatalog(catalog.value)\n if (rows.length > 0) {\n replaceCandidates(rows)\n return\n }\n }\n if (sessionId === '') return\n const result = await client.remote.commands.execute(sessionId, '/failover __candidates', [])\n if (!result.ok) return\n const text = typeof result.value === 'string'\n ? result.value\n : typeof result.value?.text === 'string' ? result.value.text : ''\n if (text === '') return\n replaceCandidates(candidatesFromText(text))\n }\n\n const injected = (sessionId?: string) => ({\n hooks: { failover: failoverSource },\n api,\n loadCandidates,\n getSessionId: () => currentSessionId(ctx, sessionId),\n })\n\n client.effect(() => {\n const style = document.createElement('style')\n style.dataset.plugin = 'dsh-failover-queue'\n style.textContent = STYLE\n document.head.appendChild(style)\n return () => { style.remove() }\n }, 'dsh-failover-queue: styles')\n\n client.effect(() => client.locale.register(NS, { zh, en }), 'dsh-failover-queue: dictionaries')\n client.effect(() => scope.subscribe(pull), 'dsh-failover-queue: settings')\n\n client.slots.inject('conversation.input.right', () => client.slots.register({\n name: 'conversation.input.right',\n id: 'dsh-failover-queue',\n order: 40,\n locale: NS,\n inject: injected,\n }, FailoverChip))\n\n client.slots.inject('settings.section', () => client.slots.register({\n name: 'settings.section',\n id: 'failover',\n order: 17,\n locale: NS,\n label: () => client.locale.bind(NS)('settings.tab'),\n inject: injected,\n }, FailoverSettingsCard))\n}\n"],"mappings":";;;;;;;;AA0CA,MAAa,oBAAoB;;;;;;;;;ACnCjC,SAAgB,mBAAmB,MAAmC;CACpE,MAAM,SAAS,KAAK,QAAQ,kBAAkB;AAC9C,KAAI,SAAS,EAAG,QAAO,EAAE;CACzB,MAAM,OAAO,KAAK,MAAM,SAAS,kBAAkB,OAAO,CAAC,MAAM;AACjE,KAAI;EACF,MAAMA,SAAkB,KAAK,MAAM,KAAK;AACxC,MAAI,CAAC,MAAM,QAAQ,OAAO,CAAE,QAAO,EAAE;AACrC,SAAO,OAAO,SAAS,QAAQ;AAC7B,OAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO,EAAE;GACtD,MAAM,OAAO;AACb,OAAI,OAAO,KAAK,aAAa,YAAY,OAAO,KAAK,UAAU,SAAU,QAAO,EAAE;AAClF,UAAO,CAAC;IACN,UAAU,KAAK;IACf,cAAc,OAAO,KAAK,iBAAiB,WAAW,KAAK,eAAe,KAAK;IAC/E,OAAO,KAAK;IACZ,MAAM,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAK;IACxD,CAAC;IACF;SACI;AACN,SAAO,EAAE;;;;;;;;AASb,SAAgB,sBAAsB,OAAqC;AACzE,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO,EAAE;CAC1D,MAAM,SAAU,MAA+B;AAC/C,KAAI,CAAC,MAAM,QAAQ,OAAO,CAAE,QAAO,EAAE;AACrC,QAAO,OAAO,SAAS,UAAU;AAC/B,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO,EAAE;EAC1D,MAAM,MAAM;AACZ,MAAI,OAAO,IAAI,OAAO,YAAY,CAAC,MAAM,QAAQ,IAAI,OAAO,CAAE,QAAO,EAAE;EACvE,MAAM,eAAe,OAAO,IAAI,SAAS,WAAW,IAAI,OAAO,IAAI;AACnE,SAAO,IAAI,OAAO,SAAS,UAAU;AACnC,OAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO,EAAE;GAC1D,MAAM,OAAO;AACb,OAAI,OAAO,KAAK,OAAO,SAAU,QAAO,EAAE;AAC1C,UAAO,CAAC;IACN,UAAU,IAAI;IACd;IACA,OAAO,KAAK;IACZ,MAAM,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAK;IACxD,CAAC;IACF;GACF;;;;;;;AAeJ,SAAgB,0BAA0B,MAAqD;CAC7F,MAAMC,SAA0B,EAAE;CAClC,MAAM,wBAAQ,IAAI,KAAqB;AACvC,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,KAAK,MAAM,IAAI,IAAI,SAAS;AAClC,MAAI,OAAO,QAAW;AACpB,SAAM,IAAI,IAAI,UAAU,OAAO,OAAO;AACtC,UAAO,KAAK;IACV,UAAU,IAAI;IACd,cAAc,IAAI;IAClB,QAAQ,CAAC,IAAI;IACd,CAAC;AACF;;EAEF,MAAM,UAAU,OAAO;AACvB,MAAI,YAAY,OAAW;AAC3B,SAAO,MAAM;GAAE,GAAG;GAAS,QAAQ,CAAC,GAAG,QAAQ,QAAQ,IAAI;GAAE;;AAE/D,QAAO;;;;;;ACrFT,SAAgB,SAAS,OAA2B;AAClD,QAAO,GAAG,MAAM,SAAS,IAAI,MAAM;;;;;;;;AASrC,SAAgB,WAAW,OAAe,QAAwB;AAChE,KAAI,UAAU,EAAG,QAAO;AACxB,KAAI,CAAC,OAAO,SAAS,MAAM,CAAE,QAAO;CACpC,MAAM,QAAQ,KAAK,MAAM,MAAM;AAC/B,KAAI,QAAQ,EAAG,QAAO;AACtB,KAAI,SAAS,OAAQ,QAAO,SAAS;AACrC,QAAO;;;;;;;;;AAUT,SAAgB,aACd,OACA,MACA,IACc;AACd,KAAI,SAAS,GAAI,QAAO,CAAC,GAAG,MAAM;AAClC,KAAI,OAAO,KAAK,QAAQ,MAAM,OAAQ,QAAO,CAAC,GAAG,MAAM;AACvD,KAAI,KAAK,KAAK,MAAM,MAAM,OAAQ,QAAO,CAAC,GAAG,MAAM;CACnD,MAAM,OAAO,CAAC,GAAG,MAAM;CACvB,MAAM,CAAC,QAAQ,KAAK,OAAO,MAAM,EAAE;AACnC,KAAI,SAAS,OAAW,QAAO;AAC/B,MAAK,OAAO,IAAI,GAAG,KAAK;AACxB,QAAO;;;;;;;;;AAUT,SAAgB,kBAAkB,cAAsB,MAAc,IAAoB;AACxF,KAAI,iBAAiB,KAAM,QAAO;AAClC,KAAI,OAAO,gBAAgB,MAAM,aAAc,QAAO,eAAe;AACrE,KAAI,OAAO,gBAAgB,MAAM,aAAc,QAAO,eAAe;AACrE,QAAO;;;;;;AAyCT,SAAgB,YAAY,OAA4C;CACtE,MAAM,uBAAO,IAAI,KAAa;CAC9B,MAAMC,OAAqB,EAAE;AAC7B,MAAK,MAAM,SAAS,OAAO;EACzB,MAAM,WAAW,MAAM,SAAS,MAAM;EACtC,MAAM,QAAQ,MAAM,MAAM,MAAM;AAChC,MAAI,aAAa,MAAM,UAAU,GAAI;EACrC,MAAM,MAAM,SAAS;GAAE;GAAU;GAAO,CAAC;AACzC,MAAI,KAAK,IAAI,IAAI,CAAE;AACnB,OAAK,IAAI,IAAI;AACb,OAAK,KAAK;GACR;GACA;GACA,GAAG,MAAM,UAAU,UAAa,MAAM,MAAM,MAAM,KAAK,KACnD,EAAE,GACF,EAAE,OAAO,MAAM,MAAM,MAAM,EAAE;GAClC,CAAC;;AAEJ,QAAO;;;;;;;;AAST,SAAgB,aACd,OACA,aAA2C,EAAE,EACR;CACrC,MAAM,MAAM,WAAW,MAAK,QAAO,IAAI,aAAa,MAAM,YAAY,IAAI,UAAU,MAAM,MAAM;AAGhG,QAAO;EAAE,UAFQ,KAAK,aAAa,MAAM,IAAI,MAAM;EAEhC,OADL,MAAM,OAAO,MAAM,IAAI,KAAK,KAAK,MAAM,IAAI,MAAM;EACrC;;;;;AClI5B,MAAa,wBAAwB;AACrC,MAAa,qBAAqB;AAClC,MAAa,4BAA4B;AAczC,SAAS,MAAM,OAAe,KAAa,KAAqB;AAC9D,QAAO,KAAK,IAAI,KAAK,IAAI,OAAO,IAAI,EAAE,IAAI;;;;;;;AAQ5C,SAAgB,uBAAuB,gBAAgC;AACrE,QAAO,KAAK,IACV,2BACA,KAAK,IAAI,GAAG,iBAAiB,wBAAwB,EAAE,CACxD;;;;;;;AAQH,SAAgB,mBAAmB,OAMR;CACzB,MAAM,YAAY,uBAAuB,MAAM,eAAe;CAC9D,MAAM,SAAS,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,OAAO,EAAE,UAAU;CAC7D,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM,gBAAgB,wBAAwB,EAAE;CAC7E,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,MAAM,EAAE,SAAS;CAC1D,MAAM,OAAO,MACX,MAAM,QAAQ,QAAQ,OACtB,uBACA,KAAK,IAAI,uBAAuB,MAAM,gBAAgB,QAAQ,sBAAsB,CACrF;CACD,MAAM,SAAS;CACf,MAAM,SAAS,KAAK,IAAI,QAAQ,MAAM,iBAAiB,SAAS,sBAAsB;CACtF,MAAM,QAAQ,MAAM,QAAQ,MAAM,qBAAqB;CACvD,MAAM,QAAQ,MAAM,QAAQ,SAAS;CACrC,IAAIC;AACJ,KAAI,SAAS,OACX,OAAM;UACG,QAAQ,UAAU,MAAM,iBAAiB,sBAClD,OAAM;KAEN,OAAM,MAAM,OAAO,QAAQ,OAAO;AAEpC,QAAO;EAAE;EAAM;EAAK;EAAW;;;;;;;;;AC+KjC,SAAgB,YAAY,QAA4D;AACtF,KAAI,WAAW,OAAW,QAAO;AACjC,KAAI,OAAO,UAAU,OAAQ,QAAO;AACpC,KAAI,OAAO,UAAU,YAAa,QAAO;AACzC,QAAO,OAAO,WAAW,IAAI,UAAU;;;;;;;AAQzC,SAAgB,UACd,OACA,UAC2B;AAC3B,QAAO,SAAS,MAAK,QAAO,IAAI,aAAa,MAAM,YAAY,IAAI,UAAU,MAAM,MAAM;;;;;;AC/P3F,MAAa,QAAQ;CACnB,MAAM;CACN,QAAQ;CACR,YAAY;CACZ,cAAc;CACd,WAAW;CACX,MAAM;CACN,WAAW;CACX,OAAO;CACP,WAAW;CACX,MAAM;CACN,OAAO;CACP,WAAW;CACX,YAAY;CACZ,MAAM;CACN,MAAM;CACN,KAAK;CACL,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,aAAa;CACb,YAAY;CACZ,OAAO;CACP,MAAM;CACN,MAAM;CACN,KAAK;CACL,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,MAAM;CACN,QAAQ;CACR,SAAS;CACT,aAAa;CACb,iBAAiB;CACjB,SAAS;CACT,MAAM;CACN,OAAO;CACP,QAAQ;CACR,UAAU;CACV,aAAa;CACd;;AAGD,MAAa,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpBrB,SAAS,iBAAiB,KAAwB,OAAwB;CACxE,MAAM,SAAS,MAAM,MAAM,CAAC,aAAa;AACzC,KAAI,WAAW,GAAI,QAAO;AAC1B,QAAO;EAAC,IAAI;EAAU,IAAI;EAAc,IAAI;EAAO,IAAI;EAAK,CAAC,MAAK,SAAQ,KAAK,aAAa,CAAC,SAAS,OAAO,CAAC;;;;;;AAOhH,SAAgB,WAAW,EAAE,OAAO,KAAK,GAAG,SAAS,WAAW,SAAqC;CACnG,MAAM,CAAC,SAAS,kCAAuB,MAAM;CAC7C,MAAM,CAAC,OAAO,gCAAqB,GAAG;CACtC,MAAM,CAAC,UAAU,mCAAwB,MAAM;CAC/C,MAAM,CAAC,kBAAkB,2CAA+C,KAAK;CAC7E,MAAM,8BAA0C,KAAK;CACrD,MAAM,4BAAwC,KAAK;CACnD,MAAM,CAAC,SAAS,kCAA6C,KAAK;CAClE,MAAM,qCAA0B;EAC9B,MAAM,QAAQ,IAAI,IAAI,MAAM,MAAM,IAAI,SAAS,CAAC;AAChD,SAAO,MAAM,WAAW,QAAO,QAAO,CAAC,MAAM,IAAI,SAAS;GACxD,UAAU,IAAI;GACd,OAAO,IAAI;GACZ,CAAC,CAAC,CAAC;IACH,CAAC,MAAM,YAAY,MAAM,MAAM,CAAC;CACnC,MAAM,kCAAuB,0BAA0B,UAAU,EAAE,CAAC,UAAU,CAAC;CAC/E,MAAM,SAAS,MAAM,MAAM,CAAC,aAAa;CACzC,MAAM,yCAA8B;AAClC,MAAI,WAAW,GAAI,QAAO;AAC1B,SAAO,OAAO,QAAO,UACnB,MAAM,SAAS,aAAa,CAAC,SAAS,OAAO,IAC1C,MAAM,aAAa,aAAa,CAAC,SAAS,OAAO,IACjD,MAAM,OAAO,MAAK,QAAO,iBAAiB,KAAK,MAAM,CAAC,CACzD;IACD;EAAC;EAAQ;EAAQ;EAAM,CAAC;CAC3B,MAAM,gBAAgB,qBAAqB,OACvC,SACA,OAAO,MAAK,UAAS,MAAM,aAAa,iBAAiB;CAC7D,MAAM,yCAA8B;AAClC,MAAI,kBAAkB,OAAW,QAAO,EAAE;AAC1C,MAAI,WAAW,GAAI,QAAO,CAAC,GAAG,cAAc,OAAO;AACnD,SAAO,cAAc,OAAO,QAAO,QAAO,iBAAiB,KAAK,MAAM,CAAC;IACtE;EAAC;EAAe;EAAQ;EAAM,CAAC;CAElC,MAAM,kBAAwB;AAC5B,cAAY,MAAM;AAClB,sBAAoB,KAAK;AACzB,WAAS,GAAG;;AAGd,4BAAgB;AACd,MAAI,CAAC,SAAU;EACf,MAAM,SAAS,UAA4B;GACzC,MAAM,SAAS,MAAM;AACrB,OAAI,UAAU,SAAS,SAAS,OAAO,KAAK,KAAM;AAClD,OAAI,QAAQ,SAAS,SAAS,OAAO,KAAK,KAAM;AAChD,cAAW;;EAEb,MAAM,SAAS,UAA+B;AAC5C,OAAI,MAAM,QAAQ,SAAU;AAC5B,OAAI,qBAAqB,MAAM;AAC7B,wBAAoB,KAAK;AACzB;;AAEF,cAAW;;AAEb,WAAS,iBAAiB,aAAa,MAAM;AAC7C,WAAS,iBAAiB,WAAW,MAAM;AAC3C,eAAa;AACX,YAAS,oBAAoB,aAAa,MAAM;AAChD,YAAS,oBAAoB,WAAW,MAAM;;IAE/C,CAAC,UAAU,iBAAiB,CAAC;AAEhC,kCAAsB;AACpB,MAAI,CAAC,UAAU;AACb,cAAW,KAAK;AAChB;;EAEF,MAAM,cAAoB;GACxB,MAAM,UAAU,UAAU;AAC1B,OAAI,YAAY,KAAM;GACtB,MAAM,OAAO,QAAQ,uBAAuB;GAC5C,MAAM,QAAQ,KAAK,IAAI,KAAK,OAAO,IAAI;GACvC,MAAM,YAAY,KAAK,IAAI,KAAK,KAAK,MAAM,OAAO,cAAc,GAAI,CAAC;GACrE,MAAM,YAAY,KAAK,MAAM;GAC7B,MAAM,YAAY,OAAO,cAAc,KAAK,SAAS;GAErD,MAAM,MADS,aAAa,OAAO,aAAa,YAE5C,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,UAAU,GACrC,KAAK,IAAI,KAAK,SAAS,GAAG,OAAO,cAAc,YAAY,EAAE;AACjE,cAAW;IACT,UAAU;IACV,MAAM,KAAK,IAAI,KAAK,MAAM,OAAO,aAAa,QAAQ,EAAE;IACxD;IACA;IACA;IACA,QAAQ;IACT,CAAC;;AAEJ,SAAO;AACP,SAAO,iBAAiB,UAAU,MAAM;AACxC,SAAO,iBAAiB,UAAU,OAAO,KAAK;AAC9C,eAAa;AACX,UAAO,oBAAoB,UAAU,MAAM;AAC3C,UAAO,oBAAoB,UAAU,OAAO,KAAK;;IAElD;EAAC;EAAU;EAAkB,cAAc;EAAQ,cAAc;EAAQ;EAAM,CAAC;CAEnF,MAAM,OAAO,SAAoC;AAC/C,MAAI,QAAS;AACb,aAAW,KAAK;AAChB,EAAK,MAAM,CAAC,cAAc;AAAE,cAAW,MAAM;IAAG;;CAGlD,MAAM,UAAU,IAAY,UAA0C;AACpE,QAAM,gBAAgB;EACtB,MAAM,OAAO,OAAO,MAAM,aAAa,QAAQ,aAAa,CAAC;AAC7D,MAAI,CAAC,OAAO,UAAU,KAAK,IAAI,SAAS,GAAI;EAC5C,MAAM,QAAQ,aAAa,MAAM,OAAO,MAAM,GAAG;EACjD,MAAM,eAAe,kBAAkB,MAAM,cAAc,MAAM,GAAG;AACpE,YAAU,IAAI,SAAS,OAAO,aAAa,CAAC;;CAG9C,MAAM,gBAAgB,QAAiC;EACrD,MAAMC,QAAoB;GACxB,UAAU,IAAI;GACd,OAAO,IAAI;GACX,OAAO,IAAI;GACZ;AACD,aAAW;AACX,YAAU,IAAI,SAAS,CAAC,GAAG,MAAM,OAAO,MAAM,EAAE,MAAM,aAAa,CAAC;;CAGtE,MAAM,cAAc,CAAC,MAAM,mBACvB,EAAE,oBAAoB,GACtB,OAAO,WAAW,IAChB,EAAE,iBAAiB,GACnB,EAAE,8BAA8B,EAAE,OAAO,OAAO,QAAQ,CAAC;CAE/D,MAAM,YAAY,qBAAqB,OACnC,cAAc,WAAW,IACzB,cAAc,WAAW;AAE7B,QACE,4CAAC;EACC,WAAW,WAAW,GAAG,MAAM,MAAM,GAAG,MAAM,cAAc,MAAM;EAClE,MAAM,WAAW,WAAW;EAC5B,cAAY,EAAE,cAAc;;GAE5B,4CAAC;IAAI,WAAW,MAAM;eACpB,2CAAC;KAAI,WAAW,MAAM;eAAQ,EAAE,cAAc;MAAO,EACpD,YAAY,SAAY,OACvB,2CAAC;KAAO,MAAK;KAAS,WAAW,MAAM;KAAQ,SAAS;eAAU,EAAE,cAAc;MAAU;KAE1F;GACN,4CAAC;IAAI,WAAW,MAAM;eACpB,4CAAC;KAAI,WAAW,MAAM;gBACpB,2CAAC,oBAAM,EAAE,eAAe,GAAQ,EAChC,2CAAC,qBAAO,MAAM,UAAU,EAAE,kBAAkB,GAAG,EAAE,mBAAmB,GAAS;MACzE,EACN,2CAAC;KACC,MAAK;KACL,MAAK;KACL,WAAW,GAAG,MAAM,SAAS,MAAM,UAAU,IAAI,MAAM,aAAa;KACpE,gBAAc,MAAM;KACpB,cAAY,EAAE,eAAe;KAC7B,UAAU;KACV,eAAe;AAAE,gBAAU,IAAI,WAAW,CAAC,MAAM,QAAQ,CAAC;;eAE1D,2CAAC,UAAK,WAAW,MAAM,cAAe;MAC/B;KACL;GACN,2CAAC;IAAE,WAAW,MAAM;cAAO,EAAE,aAAa;KAAK;GAC9C,MAAM,MAAM,WAAW,IACtB,2CAAC;IAAE,WAAW,MAAM;cAAQ,EAAE,cAAc;KAAK,GAEjD,2CAAC;IAAG,WAAW,MAAM;cAClB,MAAM,MAAM,KAAK,OAAO,UAAU;KACjC,MAAM,SAAS,UAAU,WAAW,MAAM,cAAc,MAAM,MAAM,OAAO;KAC3E,MAAM,UAAU,aAAa,OAAO,MAAM,WAAW;KACrD,MAAM,QAAQ,GAAG,QAAQ,SAAS,GAAG,QAAQ;KAC7C,MAAM,OAAO,YAAY,UAAU,OAAO,MAAM,YAAY,EAAE,CAAC,CAAC;KAIhE,MAAM,cAAc,EAHF,SAAS,OACvB,oBACA,SAAS,UAAU,uBAAuB,oBACd;KAChC,MAAM,cAAc,SAAS,OACzB,MAAM,WACN,SAAS,UAAU,MAAM,cAAc,MAAM;AACjD,YACE,4CAAC;MAEC,WAAW,GAAG,MAAM,MAAM,SAAS,IAAI,MAAM,cAAc;MAC3D,aAAa,UAAU;AAAE,aAAM,gBAAgB;;MAC/C,SAAS,UAAU;AAAE,cAAO,OAAO,MAAM;;MACzC,eAAe;AACb,WAAI,UAAU,MAAM,aAAc;AAClC,iBAAU,IAAI,SAAS,MAAM,OAAO,MAAM,CAAC;;;OAG7C,2CAAC;QACC,WAAW,MAAM;QACjB;QACA,OAAO,EAAE,aAAa;QACtB,cAAY,EAAE,aAAa;QAC3B,cAAc,UAAU;AACtB,eAAM,aAAa,QAAQ,cAAc,OAAO,MAAM,CAAC;AACvD,eAAM,aAAa,gBAAgB;;QAErC,UAAU,UAAU;AAAE,eAAM,iBAAiB;;kBAC9C;SAEM;OACP,2CAAC;QAAK,WAAW,GAAG,MAAM,OAAO,GAAG;QAAe,OAAO;QAAa,cAAY;SAAe;OAClG,4CAAC;QAAK,WAAW,MAAM;mBAAO,KAAE,QAAQ;SAAS;OACjD,4CAAC;QAAK,WAAW,MAAM;mBACrB,4CAAC;SAAK,WAAW,MAAM;oBACpB,OACA,SAAS,MAAM,EAAE,gBAAgB,KAAK;UAClC,EACP,4CAAC;SAAK,WAAW,MAAM;;UAAM,MAAM;UAAS;UAAI,MAAM;;UAAa;SAC9D;OACP,2CAAC;QACC,MAAK;QACL,WAAW,MAAM;QACjB,cAAY,EAAE,eAAe;QAC7B,UAAU,UAAU;AAClB,eAAM,iBAAiB;SACvB,MAAM,QAAQ,MAAM,MAAM,QAAQ,GAAG,SAAS,SAAS,MAAM;SAC7D,MAAM,eAAe,QAAQ,MAAM,eAC/B,MAAM,eAAe,IACrB,UAAU,MAAM,eACd,WAAW,MAAM,cAAc,MAAM,OAAO,GAC5C,MAAM;AACZ,mBAAU,IAAI,SAAS,OAAO,aAAa,CAAC;;kBAE/C;SAEQ;;QA/CJ,SAAS,MAAM,CAgDjB;MAEP;KACC;GAEP,4CAAC;IAAI,WAAW,MAAM;IAAQ,KAAK;eACjC,2CAAC;KACC,MAAK;KACL,WAAW,MAAM;KACjB,UAAU,WAAW,CAAC,MAAM,oBAAoB,OAAO,WAAW;KAClE,iBAAe;KACf,iBAAc;KACd,cAAY,EAAE,YAAY;KAC1B,eAAe;AACb,UAAI,UAAU;AACZ,kBAAW;AACX;;AAEF,kBAAY,KAAK;;eAGlB;MACM,EACR,YAAY,MAAM,oBAAoB,OAAO,SAAS,KAAK,YAAY,mCAEpE,4CAAC;KAAI,WAAW,MAAM;KAAM,KAAK;KAAS,OAAO;;MAC9C,qBAAqB,OAAO,OAC3B,4CAAC;OACC,MAAK;OACL,WAAW,MAAM;OACjB,eAAe;AAAE,4BAAoB,KAAK;;kBAC3C,MACI,EAAE,iBAAiB;QACf;MAEX,2CAAC;OACC,WAAW,MAAM;OACjB,OAAO;OACP;OACA,UAAU;OACV,aAAa,qBAAqB,OAAO,EAAE,2BAA2B,GAAG,EAAE,wBAAwB;OACnG,cAAY,qBAAqB,OAAO,EAAE,2BAA2B,GAAG,EAAE,wBAAwB;OAClG,WAAW,UAAU;AAAE,iBAAS,MAAM,OAAO,MAAM;;QACnD;MACD,YACC,2CAAC;OAAE,WAAW,MAAM;iBAAQ,EAAE,oBAAoB;QAAK,GACrD,qBAAqB,OACvB,2CAAC;OAAG,WAAW,MAAM;OAAS,MAAK;OAAU,cAAY,EAAE,YAAY;iBACpE,cAAc,KAAK,UAClB,2CAAC,kBACC,4CAAC;QACC,MAAK;QACL,WAAW,GAAG,MAAM,YAAY,GAAG,MAAM;QACzC,UAAU;QACV,cAAY,GAAG,MAAM,aAAa,IAAI,EAAE,wBAAwB,EAAE,OAAO,MAAM,OAAO,QAAQ,CAAC;QAC/F,eAAe;AAAE,6BAAoB,MAAM,SAAS;;mBAEpD,4CAAC;SAAK,WAAW,MAAM;oBACrB,2CAAC;UAAK,WAAW,MAAM;oBAAO,MAAM;WAAoB,EACxD,4CAAC;UAAK,WAAW,MAAM;;WAAM,MAAM;WAAS;WAAI,EAAE,wBAAwB,EAAE,OAAO,MAAM,OAAO,QAAQ,CAAC;;WAAQ;UAC5G,EACP,2CAAC;SAAK,WAAW,MAAM;SAAS,eAAY;mBAAO;UAAQ;SACpD,IAbF,MAAM,SAcV,CACL;QACC,GAEL,2CAAC;OAAG,WAAW,MAAM;OAAS,MAAK;OAAU,cAAY,eAAe,gBAAgB,EAAE,YAAY;iBACnG,cAAc,KAAK,QAClB,2CAAC,kBACC,4CAAC;QACC,MAAK;QACL,WAAW,MAAM;QACjB,MAAK;QACL,UAAU;QACV,cAAY,GAAG,EAAE,YAAY,CAAC,IAAI,IAAI;QACtC,eAAe;AAAE,sBAAa,IAAI;;mBAElC,2CAAC;SAAK,WAAW,MAAM;mBAAO,IAAI;UAAY,EAC9C,2CAAC;SAAK,WAAW,MAAM;mBAAM,IAAI;UAAa;SACvC,IAXF,SAAS;QAAE,UAAU,IAAI;QAAU,OAAO,IAAI;QAAO,CAAC,CAY1D,CACL;QACC;;MAEH,EACN,SAAS,KACV,GACC;KACA;;GACF;;;;;AC1UV,SAAS,UAAU,OAAkC;AACnD,QAAO,MAAM,aAAa,MAAM,gBAAgB,IAAI;;AAGtD,SAAS,SAAS,OAAyB,GAKzC;AACA,KAAI,CAAC,MAAM,QACT,QAAO;EAAE,OAAO,EAAE,iBAAiB;EAAE,MAAM,EAAE,gBAAgB;EAAE,MAAM;EAAW,OAAO;EAAW;AAEpG,KAAI,MAAM,MAAM,WAAW,EACzB,QAAO;EACL,OAAO,EAAE,aAAa;EACtB,MAAM,EAAE,aAAa;EACrB,MAAM;EACN,OAAO,EAAE,aAAa;EACvB;CAEH,MAAM,OAAO,WAAW,MAAM,cAAc,MAAM,MAAM,OAAO,GAAG;CAClE,MAAM,UAAU,MAAM,MAAM,OAAO;AACnC,KAAI,YAAY,OACd,QAAO;EACL,OAAO,EAAE,aAAa;EACtB,MAAM,EAAE,aAAa;EACrB,MAAM;EACN,OAAO,EAAE,aAAa;EACvB;CAEH,MAAM,UAAU,aAAa,SAAS,MAAM,WAAW;CACvD,MAAM,SAAS;EAAE;EAAM,UAAU,QAAQ;EAAU,OAAO,QAAQ;EAAO;AACzE,QAAO;EACL,OAAO,EAAE,WAAW,OAAO;EAC3B,MAAM,EAAE,gBAAgB,OAAO;EAC/B;EACA,OAAO,GAAG,QAAQ,SAAS,GAAG,QAAQ;EACvC;;;;;;AAOH,SAAgB,aAAa,OAAqC;CAChE,MAAM,EAAE,aAAa,KAAK,gBAAgB,MAAM;CAChD,MAAM,QAAQ,aAAY,eAAYC,WAAS;CAC/C,MAAM,YAAY,UAAU,MAAM;CAClC,MAAM,CAAC,MAAM,+BAAoB,MAAM;CACvC,MAAM,4BAAwC,KAAK;CACnD,MAAM,6BAAyC,KAAK;CACpD,MAAM,CAAC,KAAK,8BAAyC,KAAK;CAC1D,MAAM,OAAO,SAAS,OAAO,EAAE;AAE/B,4BAAgB;AACd,EAAK,eAAe,UAAU;IAC7B,CAAC,gBAAgB,UAAU,CAAC;AAE/B,kCAAsB;AACpB,MAAI,CAAC,KAAM;EACX,MAAM,cAAoB;GACxB,MAAM,UAAU,QAAQ;GACxB,MAAM,QAAQ,SAAS;AACvB,OAAI,YAAY,QAAQ,UAAU,KAAM;GAExC,MAAM,SAAS,mBAAmB;IAChC,SAFW,QAAQ,uBAAuB;IAG1C,OAAO,MAAM;IACb,QAAQ,MAAM;IACd,eAAe,OAAO;IACtB,gBAAgB,OAAO;IACxB,CAAC;AACF,UAAO;IACL,MAAM,OAAO;IACb,KAAK,OAAO;IACZ,WAAW,OAAO;IACnB,CAAC;;AAEJ,SAAO;EACP,MAAM,WAAW,IAAI,eAAe,MAAM;AAC1C,MAAI,SAAS,YAAY,KAAM,UAAS,QAAQ,SAAS,QAAQ;AACjE,SAAO,iBAAiB,UAAU,MAAM;AACxC,SAAO,iBAAiB,UAAU,OAAO,KAAK;AAC9C,eAAa;AACX,YAAS,YAAY;AACrB,UAAO,oBAAoB,UAAU,MAAM;AAC3C,UAAO,oBAAoB,UAAU,OAAO,KAAK;;IAElD;EAAC;EAAM,MAAM,MAAM;EAAQ,MAAM;EAAS,KAAK;EAAM,CAAC;AAEzD,4BAAgB;AACd,MAAI,CAAC,KAAM;EACX,MAAM,SAAS,UAA4B;GACzC,MAAM,SAAS,MAAM;AACrB,OAAI,EAAE,kBAAkB,MAAO;AAC/B,OAAI,QAAQ,SAAS,SAAS,OAAO,KAAK,KAAM;AAChD,OAAI,SAAS,SAAS,SAAS,OAAO,KAAK,KAAM;AACjD,OAAI,kBAAkB,WAAW,OAAO,QAAQ,eAAe,KAAK,KAAM;AAC1E,WAAQ,MAAM;;EAEhB,MAAM,SAAS,UAA+B;AAC5C,OAAI,MAAM,QAAQ,SAAU,SAAQ,MAAM;;AAE5C,WAAS,iBAAiB,aAAa,MAAM;AAC7C,WAAS,iBAAiB,WAAW,MAAM;AAC3C,eAAa;AACX,YAAS,oBAAoB,aAAa,MAAM;AAChD,YAAS,oBAAoB,WAAW,MAAM;;IAE/C,CAAC,KAAK,CAAC;AAEV,QACE,4CAAC;EAAI,KAAK;aACR,4CAAC;GACC,MAAK;GACL,WAAW,GAAG,MAAM,OAAO,MAAM,UAAU,IAAI,MAAM,WAAW;GAChE,gBAAc,MAAM;GACpB,iBAAe;GACf,cAAY,KAAK;GACjB,OAAO,KAAK;GACZ,cAAc,UAAU;AAAE,UAAM,gBAAgB;;GAChD,eAAe;AAAE,aAAQ,UAAS,CAAC,MAAM;;cAEzC,2CAAC;IAAK,WAAW,MAAM;cAAa,EAAE,cAAc;KAAQ,EAC3D,KAAK,SAAS,SACX,2CAAC;IAAK,WAAW,MAAM;cAAY,KAAK,SAAS,EAAE,WAAW;KAAQ,GAEtE,qFACE,4CAAC;IAAK,WAAW,MAAM;eAAc,KAAE,KAAK;KAAY,EACxD,2CAAC;IAAK,WAAW,MAAM;cAAY,KAAK;KAAa,IACpD;IAEA,EACR,oCACC,2CAAC;GAAI,KAAK;GAAU,OAAO;IAAE,GAAG;IAAK,UAAU;IAAS,QAAQ;IAAM,UAAU;IAAQ;aACtF,2CAAC;IAAkB;IAAY;IAAQ;IAAG,eAAe;AAAE,aAAQ,MAAM;;KAAM;IAC3E,EACN,SAAS,KACV;GACG;;;;;;AAQV,SAAgB,qBAAqB,OAAqC;CACxE,MAAM,EAAE,aAAa,KAAK,gBAAgB,MAAM;CAChD,MAAM,QAAQ,aAAY,eAAYA,WAAS;CAC/C,MAAM,YAAY,UAAU,MAAM;AAClC,4BAAgB;AACd,EAAK,eAAe,UAAU;IAC7B,CAAC,gBAAgB,UAAU,CAAC;AAC/B,QACE,4CAAC;EAAI,WAAW,MAAM;aACpB,2CAAC;GAAE,WAAW,MAAM;aAAY,EAAE,iBAAiB;IAAK,EACxD,2CAAC;GAAkB;GAAY;GAAQ;GAAG;IAAW;GACjD;;;;;;ACvLV,MAAa,KAAK;AAoClB,MAAaC,KAAkC;CAC7C,eAAe;CACf,YAAY;CACZ,cAAc;CACd,WAAW;CACX,gBAAgB;CAChB,iBAAiB;CACjB,kBAAkB;CAClB,eAAe;CACf,gBAAgB;CAChB,mBAAmB;CACnB,oBAAoB;CACpB,eAAe;CACf,aAAa;CACb,8BAA8B;CAC9B,4BAA4B;CAC5B,yBAAyB;CACzB,kBAAkB;CAClB,wBAAwB;CACxB,qBAAqB;CACrB,kBAAkB;CAClB,qBAAqB;CACrB,gBAAgB;CAChB,cAAc;CACd,iBAAiB;CACjB,eAAe;CACf,cAAc;CACd,mBAAmB;CACnB,sBAAsB;CACtB,qBAAqB;CACrB,gBAAgB;CAChB,kBAAkB;CACnB;AAED,MAAaC,KAAkC;CAC7C,eAAe;CACf,YAAY;CACZ,cAAc;CACd,WAAW;CACX,gBAAgB;CAChB,iBAAiB;CACjB,kBAAkB;CAClB,eAAe;CACf,gBAAgB;CAChB,mBAAmB;CACnB,oBAAoB;CACpB,eAAe;CACf,aAAa;CACb,8BAA8B;CAC9B,4BAA4B;CAC5B,yBAAyB;CACzB,kBAAkB;CAClB,wBAAwB;CACxB,qBAAqB;CACrB,kBAAkB;CAClB,qBAAqB;CACrB,gBAAgB;CAChB,cAAc;CACd,iBAAiB;CACjB,eAAe;CACf,cAAc;CACd,mBAAmB;CACnB,sBAAsB;CACtB,qBAAqB;CACrB,gBAAgB;CAChB,kBAAkB;CACnB;;;;;ACpFD,SAAgB,WAAW,OAA8C;AACvE,QAAO,UAAU,QAAQ,UAAU;;;AASrC,SAAgB,cAAc,MAAW;AACvC,QAAO,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,KAAK;;;AAQjE,SAAgB,WAAW,QAAY,QAA8C;AACnF,QAAO,OAAO,YAAY,OAAO,QAAQ,OAAO,CAAC,QAAQ,CAAC,KAAK,WAAW,OAAO,KAAK,MAAM,CAAC,CAAC;;;AAIhG,SAAgB,UAAkC,QAAoB,WAAoC;AACxG,QAAO,OAAO,YAAY,OAAO,QAAQ,OAAO,CAAC,KAAK,CAAC,KAAK,WAAW,CAAC,KAAM,UAAkB,OAAO,IAAI,CAAC,CAAC,CAAC;;;AAOhH,SAAgB,KAA0C,QAAW,MAAoB,QAAkB;AACzG,KAAI,CAAC,KAAM,QAAO,EAAE,GAAG,QAAQ;CAC/B,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,OAAO,KAChB,KAAI,UAAU,OAAO,SAAS,OAAW,QAAO,OAAO,OAAO;AAEhE,QAAO;;;;;;AC9CT,SAAgB,GAAqC,MAAS,OAAkB;AAC9E,KAAI,UAAU,WAAW,EAAG,SAAQ,YAAe,GAAG,MAAMC,QAAM;AAClE,QAAO,QAAQ,cAAc,iBAAkB,WAAW,SACrD,OAAO,UAAU,SAAS,KAAK,MAAM,CAAC,MAAM,GAAG,GAAG,KAAK;;AAG9D,SAAS,kBAAkB,OAAsC;AAC/D,QAAO,GAAG,eAAe,MAAM,IAAI,GAAG,qBAAqB,MAAM;;AAGnE,SAAS,oBAAoB,OAAoC;AAC/D,QAAO,kBAAkB,MAAM,IAAI,YAAY,OAAO,MAAM;;;;cAO1C;oBACM;CAEjB,SAAS,WAAsC,QAAsB;AAC1E,MAAI,YAAY,OAAO,OAAO,CAE5B,QAAO,OAAO,OAAO,MAAM,OAAO,YAAY,OAAO,aAAa,OAAO,WAAW;MAEpF,QAAO;;;CAIJ,SAAS,SAAS,QAAgB;AACvC,WAAS,WAAW,OAAO;AAC3B,MAAI,OAAO,WAAW,YACpB,QAAO,OAAO,KAAK,OAAO,CAAC,SAAS,SAAS;EAE/C,IAAI,SAAS;EACb,MAAM,QAAQ,IAAI,WAAW,OAAO;AACpC,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,YAAY,IACpC,WAAU,OAAO,aAAa,MAAM,GAAG;AAEzC,SAAO,KAAK,OAAO;;;CAGd,SAAS,WAAW,QAAgB;AACzC,MAAI,OAAO,WAAW,YAAa,QAAO,WAAW,OAAO,KAAK,QAAQ,SAAS,CAAC;AACnF,SAAO,WAAW,KAAK,KAAK,OAAO,GAAE,MAAK,EAAE,WAAW,EAAE,CAAC;;;CAGrD,SAAS,MAAM,QAAgB;AACpC,WAAS,WAAW,OAAO;AAC3B,MAAI,OAAO,WAAW,YAAa,QAAO,OAAO,KAAK,OAAO,CAAC,SAAS,MAAM;AAC7E,SAAO,MAAM,KAAK,IAAI,WAAW,OAAO,GAAE,SAAQ,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG;;;CAGzF,SAAS,QAAQ,QAAgB;AACtC,MAAI,OAAO,WAAW,YAAa,QAAO,WAAW,OAAO,KAAK,QAAQ,MAAM,CAAC;EAChF,MAAM,MAAM,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO,MAAM,GAAG,OAAO,SAAS,EAAE;EACjF,MAAMC,SAAmB,EAAE;AAC3B,OAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,EACnC,QAAO,KAAK,SAAS,GAAG,IAAI,KAAK,IAAI,IAAI,MAAM,GAAG,CAAC;AAErD,SAAO,WAAW,KAAK,OAAO,CAAC;;;;;AAKnC,MAAa,sBAAsB,OAAO;;AAE1C,MAAa,sBAAsB,OAAO;;AAE1C,MAAa,mBAAmB,OAAO;;AAEvC,MAAa,mBAAmB,OAAO;;AAKvC,SAAgB,MAAM,QAAa,uBAAO,IAAI,KAAe,EAAE;AAC7D,KAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAClD,KAAI,GAAG,QAAQ,OAAO,CAAE,QAAO,IAAI,KAAK,OAAO,SAAS,CAAC;AACzD,KAAI,GAAG,UAAU,OAAO,CAAE,QAAO,IAAI,OAAO,OAAO,QAAQ,OAAO,MAAM;AACxE,KAAI,kBAAkB,OAAO,CAAE,QAAO,OAAO,MAAM,EAAE;AACrD,KAAI,YAAY,OAAO,OAAO,CAAE,QAAO,OAAO,OAAO,MAAM,OAAO,YAAY,OAAO,aAAa,OAAO,WAAW;CACpH,MAAM,SAAS,KAAK,IAAI,OAAO;AAC/B,KAAI,OAAQ,QAAO;AACnB,KAAI,MAAM,QAAQ,OAAO,EAAE;EACzB,MAAMC,WAAgB,EAAE;AACxB,OAAK,IAAI,QAAQC,SAAO;AACxB,SAAO,SAAS,OAAO,UAAU;AAC/B,YAAO,SAAS,QAAQ,MAAM,OAAO,MAAM,CAAC,OAAO,KAAK,CAAC;IACzD;AACF,SAAOA;;CAET,MAAM,SAAS,OAAO,OAAO,OAAO,eAAe,OAAO,CAAC;AAC3D,MAAK,IAAI,QAAQ,OAAO;AACxB,MAAK,MAAM,OAAO,QAAQ,QAAQ,OAAO,EAAE;EACzC,MAAM,aAAa,EAAE,GAAG,QAAQ,yBAAyB,QAAQ,IAAI,EAAE;AACvE,MAAI,WAAW,WACb,YAAW,QAAQ,QAAQ,MAAM,OAAO,MAAM,CAAC,WAAW,OAAO,KAAK,CAAC;AAEzE,UAAQ,eAAe,QAAQ,KAAK,WAAW;;AAEjD,QAAO;;;AAIT,SAAgB,UAAU,GAAQ,GAAQ,QAA2B;AACnE,KAAI,MAAM,EAAG,QAAO;AACpB,KAAI,CAAC,UAAU,WAAW,EAAE,IAAI,WAAW,EAAE,CAAE,QAAO;AACtD,KAAI,OAAO,MAAM,OAAO,EAAG,QAAO;AAClC,KAAI,OAAO,MAAM,SAAU,QAAO;AAClC,KAAI,CAAC,KAAK,CAAC,EAAG,QAAO;CAErB,SAAS,MAAS,MAA0B,MAA+B;AACzE,SAAO,KAAK,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,GAAG,EAAE,GAAG,QAAQ,KAAK,EAAE,GAAG,QAAQ;;AAGpE,QAAO,MAAM,MAAM,UAAU,KAAG,QAAMC,IAAE,WAAWC,IAAE,UAAUD,IAAE,OAAO,MAAM,UAAU,UAAU,MAAMC,IAAE,OAAO,CAAC,CAAC,IAC9G,MAAM,GAAG,OAAO,GAAG,KAAG,QAAMD,IAAE,SAAS,KAAKC,IAAE,SAAS,CAAC,IACxD,MAAM,GAAG,SAAS,GAAG,KAAG,QAAMD,IAAE,WAAWC,IAAE,UAAUD,IAAE,UAAUC,IAAE,MAAM,IAC3E,MAAM,oBAAoB,KAAG,QAAM;AACpC,MAAID,IAAE,eAAeC,IAAE,WAAY,QAAO;EAC1C,MAAM,QAAQ,IAAI,WAAWD,IAAE;EAC/B,MAAM,QAAQ,IAAI,WAAWC,IAAE;AAC/B,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAChC,KAAI,MAAM,OAAO,MAAM,GAAI,QAAO;AAEpC,SAAO;GACP,IACC,OAAO,KAAK;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC,CAAC,OAAM,QAAO,UAAU,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;;;;;;;qBC1IrD;CACpB,MAAM,wBAAS;CACf,MAAM,wBAAS,SAAS;CACxB,MAAM,oBAAO,SAAS;CACtB,MAAM,kBAAM,OAAO;CACnB,MAAM,oBAAO,MAAM;CAE1B,IAAI,kCAAiB,IAAI,MAAM,EAAC,mBAAmB;CAE5C,SAAS,kBAAkB,QAAgB;AAChD,mBAAiB;;;CAGZ,SAAS,oBAAoB;AAClC,SAAO;;;CAGF,SAAS,cAAc,uBAAsB,IAAI,MAAM,EAAE,QAAiB;AAC/E,MAAI,OAAO,SAAS,SAAU,QAAO,IAAI,KAAK,KAAK;AACnD,MAAI,WAAW,OAAW,UAAS;AACnC,SAAO,KAAK,OAAO,KAAK,SAAS,GAAG,SAAS,UAAU,KAAK;;;CAGvD,SAAS,eAAe,OAAe,QAAiB;EAC7D,MAAM,OAAO,IAAI,KAAK,QAAQ,IAAI;AAClC,MAAI,WAAW,OAAW,UAAS;AACnC,SAAO,IAAI,KAAK,CAAC,OAAO,SAAS,OAAO;;;CAG1C,MAAM,UAAU,gBAAgB;CAChC,MAAM,6BAAa,IAAI,OAAO,IAAI;EAChC;EACA;EACA;EACA;EACA;EACD,CAAC,KAAI,SAAQ,IAAI,UAAU,KAAK,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG;CAE3C,SAAS,UAAU,QAAgB;EACxC,MAAM,UAAU,WAAW,KAAK,OAAO;AACvC,MAAI,CAAC,QAAS,QAAO;AACrB,UAAQ,WAAW,QAAQ,GAAG,GAAG,QAAQ,MACpC,WAAW,QAAQ,GAAG,GAAG,OAAO,MAChC,WAAW,QAAQ,GAAG,GAAG,QAAQ,MACjC,WAAW,QAAQ,GAAG,GAAG,UAAU,MACnC,WAAW,QAAQ,GAAG,GAAG,UAAU;;;CAGnC,SAAS,UAAU,MAAc;EACtC,MAAM,SAAS,UAAU,KAAK;AAC9B,MAAI,OACF,QAAO,KAAK,KAAK,GAAG;WACX,2BAA2B,KAAK,KAAK,CAC9C,QAAO,oBAAG,IAAI,MAAM,EAAC,oBAAoB,CAAC,GAAG;WACpC,2CAA2C,KAAK,KAAK,CAC9D,QAAO,oBAAG,IAAI,MAAM,EAAC,aAAa,CAAC,GAAG;AAExC,SAAO,OAAO,IAAI,KAAK,KAAK,mBAAG,IAAI,MAAM;;;CAGpC,SAAS,OAAO,IAAY;EACjC,MAAM,MAAM,KAAK,IAAI,GAAG;AACxB,MAAI,OAAO,MAAM,OAAO,EACtB,QAAO,KAAK,MAAM,KAAK,IAAI,GAAG;WACrB,OAAO,OAAO,SAAS,EAChC,QAAO,KAAK,MAAM,KAAK,KAAK,GAAG;WACtB,OAAO,SAAS,SAAS,EAClC,QAAO,KAAK,MAAM,KAAK,OAAO,GAAG;WACxB,OAAO,OAChB,QAAO,KAAK,MAAM,KAAK,OAAO,GAAG;AAEnC,SAAO,KAAK;;;CAGP,SAAS,SAAS,QAAgB,SAAS,GAAG;AACnD,SAAO,OAAO,UAAU,CAAC,SAAS,QAAQ,IAAI;;;CAGzC,SAAS,SAAS,YAAkB,uBAAO,IAAI,MAAM,EAAE;AAC5D,SAAOC,WACJ,QAAQ,QAAQ,KAAK,aAAa,CAAC,UAAU,CAAC,CAC9C,QAAQ,MAAM,KAAK,aAAa,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CACrD,QAAQ,MAAM,SAAS,KAAK,UAAU,GAAG,EAAE,CAAC,CAC5C,QAAQ,MAAM,SAAS,KAAK,SAAS,CAAC,CAAC,CACvC,QAAQ,MAAM,SAAS,KAAK,UAAU,CAAC,CAAC,CACxC,QAAQ,MAAM,SAAS,KAAK,YAAY,CAAC,CAAC,CAC1C,QAAQ,MAAM,SAAS,KAAK,YAAY,CAAC,CAAC,CAC1C,QAAQ,OAAO,SAAS,KAAK,iBAAiB,EAAE,EAAE,CAAC;;;;;;;ACtF1D,MAAM,UAAU,OAAO,IAAI,cAAc;AACzC,MAAM,mBAAmB,OAAO,IAAI,kBAAkB;AA0MtD,WAAW,0BAA0B;AACrC,WAAW,uBAAuB;AAElC,IAAM,kBAAN,cAA8B,UAAU;CACtC,OAAO;CAEP,YAAY,SAAiB,AAAOC,SAA8B;EAChE,IAAI,SAAS;AACb,OAAK,MAAM,WAAW,QAAQ,QAAQ,EAAE,CACtC,KAAI,OAAO,YAAY,SACrB,WAAU,MAAM;WACP,OAAO,YAAY,SAC5B,WAAU,MAAM,UAAU;WACjB,OAAO,YAAY,SAC5B,WAAU,WAAW,QAAQ,UAAU,CAAC;AAG5C,MAAI,OAAO,WAAW,IAAI,CAAE,UAAS,OAAO,MAAM,EAAE;AACpD,SAAO,WAAW,MAAM,KAAK,GAAG,OAAO,MAAM,QAAQ;EAZnB;;CAepC,OAAO,GAAG,OAAsC;AAC9C,SAAO,CAAC,CAAC,QAAQ;;;AAIrB,OAAO,eAAe,gBAAgB,WAAW,kBAAkB,EACjE,OAAO,MACR,CAAC;AAIF,MAAM,SAAS,SAAU,SAAiB;CACxC,MAAM,SAAS,SAAU,MAAW,YAA+B,EAAE,EAAE;AACrE,SAAO,OAAO,QAAQ,MAAM,QAAQC,UAAQ,CAAC;;AAG/C,KAAI,QAAQ,MAAM;EAChB,MAAM,OAAOC,UAAS,QAAQ,OAAM,cAAW,IAAI,OAAOD,UAAQ,CAAC;EACnE,MAAM,UAAU,QAAa,KAAK;AAClC,OAAK,MAAM,OAAO,MAAM;GACtB,MAAMA,YAAU,KAAK;AACrB,aAAQ,OAAO,OAAOA,UAAQ,KAAK;AACnC,aAAQ,QAAQ,OAAOA,UAAQ,MAAM;AACrC,aAAQ,OAAOA,UAAQ,QAAQA,UAAQ,KAAK,IAAI,OAAO;AACvD,aAAQ,OAAOA,UAAQ,QAAQC,UAASD,UAAQ,MAAM,OAAO;;AAE/D,SAAO,KAAK,QAAQ;;AAGtB,QAAO,OAAO,QAAQ,QAAQ;AAC9B,KAAI,OAAO,OAAO,aAAa,SAC7B,KAAI;AAEF,SAAO,WAAW,IAAI,SAAS,YAAY,OAAO,SAAS,EAAE;SACvD;AAEV,QAAO,eAAe,QAAQ,OAAO,EAAE,OAAO,WAAW,yBAAyB,CAAC;AACnF,QAAO,eAAe,QAAQ,OAAO,UAAU;AAC/C,QAAO,SAAS,EAAE;AAClB,QAAO,WAAW,OAAO,SAAS,KAAK,OAAO;AAC9C,QAAO;;AAGT,OAAO,YAAY,OAAO,OAAO,SAAS,UAAU;AAEpD,OAAO,UAAU,WAAW;AAE5B,OAAO,eAAe,OAAO,WAAW,aAAa,EACnD,MAAkB;AAChB,QAAO;EACL,SAAS;EACT,QAAQ;EACR,WAAW,UAAmB;AAC5B,OAAI;AACF,WAAO,EAAE,OAAO,OAAO,QAAQ,OAAO,MAAM,EAAE,CAAC,CAAC,IAAI;YAC7C,OAAO;AACd,QAAI,gBAAgB,GAAG,MAAM,CAC3B,QAAO,EAAE,QAAQ,CAAC;KAAE,SAAS,MAAM;KAAS,MAAM,MAAM,QAAQ;KAAM,CAAC,EAAE;AAE3E,UAAM;;;EAGX;GAEJ,CAAC;AAEF,OAAO,kBAAkB;AAEzB,OAAO,UAAU,SAAS,SAAS,SAAS;AAC1C,KAAI,WAAW,sBAAsB;AACnC,aAAW,qBAAqB,KAAK,SAAS,KAAK,MAAM,KAAK,UAAU,EAAE,GAAG,MAAM,CAAC,CAAC;AACrF,SAAO,KAAK;;AAGd,YAAW,uBAAuB,GAAG,KAAK,MAAM,EAAE,GAAG,MAAM,EAAY;AACvE,YAAW,qBAAqB,KAAK,OAAO,KAAK,MAAM,KAAK,UAAU,EAAE,GAAG,MAAM,CAAC,CAAC;CACnF,MAAM,SAAS;EAAE,KAAK,KAAK;EAAK,MAAM,WAAW;EAAsB;AACvE,YAAW,uBAAuB;AAClC,QAAO;;AAGT,OAAO,UAAU,MAAM,SAAS,IAAI,KAAK,OAAO;AAC9C,MAAK,KAAM,OAAO;AAClB,QAAO;;AAGT,OAAO,UAAU,OAAO,SAAS,KAAK,OAAO;AAC3C,MAAK,KAAM,KAAK,MAAM;AACtB,QAAO;;AAGT,SAAS,UAAU,UAA6C,UAAgB;CAC9E,MAAME,SAAuB,OAAO,aAAa,WAAW,EAAE,IAAI,UAAU,GAAG,EAAE,GAAG,UAAU;AAC9F,MAAK,MAAM,UAAU,UAAU;EAC7B,MAAM,QAAQ,SAAS;AACvB,MAAI,OAAO,gBAAgB,OAAO,MAChC,QAAO,UAAU,MAAM,gBAAgB,MAAM;WACpC,OAAO,UAAU,SAC1B,QAAO,UAAU;;AAGrB,QAAO;;AAGT,SAAS,SAAS,OAAY;AAC5B,QAAO,OAAO,UAAU,OAAO;;AAGjC,SAAS,YAAY,MAAW;AAC9B,QAAO,WAAW,QAAQ,EAAE,GAAE,QAAO,CAAC,IAAI,WAAW,IAAI,CAAC;;AAG5D,OAAO,UAAU,OAAO,SAAS,KAAK,UAAU;CAC9C,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAM,OAAO,UAAU,OAAO,KAAK,aAAa,SAAS;AACzD,KAAI,OAAO,KAAK,KAAK,CAAC,OAAQ,QAAO,KAAK,cAAc;AACxD,KAAI,OAAO,KACT,QAAO,OAAOD,UAAS,OAAO,OAAO,OAAO,QAAQ;AAClD,SAAO,MAAM,KAAKA,UAAS,WAAW,SAAS,SAAS,KAAK,GAAG,QAAQ,OAAO,KAAK,CAAC;GACrF;AAEJ,KAAI,OAAO,KACT,QAAO,OAAO,OAAO,KAAM,KAAK,OAAO,UAAU;AAC/C,SAAO,MAAM,KAAKA,UAAS,WAAW,OAAO,EAAE,KAAK;AAClD,OAAI,MAAM,QAAQ,SAAS,KAAK,CAAC,CAAE,QAAO,SAAS,KAAK,CAAC;AACzD,OAAI,MAAM,QAAQ,KAAK,CAAE,QAAO,KAAK;AACrC,UAAO,YAAY,KAAK;IACxB,CAAC;GACH;AAEJ,KAAI,OAAO,MACT,QAAO,QAAQ,OAAO,MAAM,KAAKA,UAAS,WAAW,SAAS;AAC5D,MAAI,SAAS,KAAK,CAAE,QAAO,SAAS,KAAK;AACzC,SAAO,YAAY,KAAK;GACxB,CAAC;AAEL,KAAI,OAAO,KACT,QAAO,OAAO,OAAO,KAAK,KAAKA,UAAS,WAAW,SAAS,MAAM,KAAK,CAAC;AAE1E,QAAO;;AAGT,OAAO,UAAU,QAAQ,SAAS,MAAM,KAAK,OAAO;CAClD,MAAM,SAAS,OAAO,KAAK;AAC3B,QAAO,OAAO;EAAE,GAAG,OAAO;GAAO,MAAM;EAAO;AAC9C,QAAO;;AAGT,KAAK,MAAM,OAAO;CAAC;CAAY;CAAY;CAAY;CAAU;CAAQ,CACvE,QAAO,OAAO,OAAO,WAAW,EAC9B,CAAC,KAAmB,QAAQ,MAAM;CAChC,MAAM,SAAS,OAAO,KAAK;AAC3B,QAAO,OAAO;EAAE,GAAG,OAAO;GAAO,MAAM;EAAO;AAC9C,QAAO;GAEV,CAAC;AAGJ,OAAO,UAAU,aAAa,SAAS,aAAa;CAClD,MAAM,SAAS,OAAO,KAAK;AAC3B,QAAO,KAAK,WAAW,EAAE;AACzB,QAAO,KAAK,OAAO,KAAK;EAAE,MAAM;EAAc,MAAM;EAAU,CAAC;AAC/D,QAAO;;AAGT,OAAO,UAAU,eAAe,SAAS,eAAe;CACtD,MAAM,SAAS,OAAO,KAAK;AAC3B,QAAO,KAAK,WAAW,EAAE;AACzB,QAAO,KAAK,OAAO,KAAK;EAAE,MAAM;EAAgB,MAAM;EAAW,CAAC;AAClE,QAAO;;AAGT,OAAO,UAAU,UAAU,SAAS,QAAQ,QAAQ;CAClD,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAME,YAAU,KAAK,QAAQ,CAAC,UAAU,QAAQ,CAAC;AACjD,QAAO,OAAO;EAAE,GAAG,OAAO;EAAM;EAAS;AACzC,QAAO;;AAGT,OAAO,UAAU,WAAW,SAAS,SAAuB,OAAO;AACjE,KAAI,UAAU,OAAO,KAAK,KAAK,SAAS,KAAK,SAAS,OAAO,CAAE,QAAO;AACtE,KAAI,WAAW,MAAM,CAAE,QAAO;AAC9B,KAAI,KAAK,SAAS,YAAY,KAAK,SAAS,QAAQ;EAClD,MAAMC,SAAe,EAAE;AACvB,OAAK,MAAM,OAAO,OAAO;GAEvB,MAAM,QADS,KAAK,SAAS,WAAW,KAAK,KAAM,OAAO,KAAK,QAC1C,SAAS,MAAM,KAAK;AACzC,OAAI,KAAK,SAAS,UAAU,CAAC,WAAW,KAAK,CAAE,QAAO,OAAO;;AAE/D,MAAI,UAAU,QAAQ,KAAK,KAAK,SAAS,KAAK,SAAS,OAAO,CAAE,QAAO;AACvE,SAAO;YACE,KAAK,SAAS,WAAW,KAAK,SAAS,SAAS;EACzD,MAAMC,SAAgB,EAAE;AACvB,EAAC,MAAgB,SAAS,SAAO,UAAU;GAC1C,MAAM,SAAS,KAAK,SAAS,UAAU,KAAK,QAAQ,KAAK,KAAM;GAC/D,MAAM,OAAO,SAAS,OAAO,SAASC,QAAM,GAAGA;AAC/C,UAAO,KAAK,KAAK;IACjB;AACF,SAAO;YACE,KAAK,SAAS,aAAa;EACpC,MAAMF,SAAe,EAAE;AACvB,OAAK,MAAM,QAAQ,KAAK,KACtB,QAAO,OAAO,QAAQ,KAAK,SAAS,MAAM,CAAC;AAE7C,SAAO;YACE,KAAK,SAAS,QACvB,MAAK,MAAM,UAAU,KAAK,KACxB,KAAI;AACF,SAAO,QAAQ,OAAO,QAAQ,EAAE,CAAC;AACjC,SAAO,OAAO,SAAS,MAAM;SACvB;AAGZ,QAAO;;AAGT,OAAO,UAAU,WAAW,SAAS,SAAS,QAAkB;AAC9D,QAAO,WAAW,KAAK,QAAQ,MAAM,OAAO,IAAI,UAAU,KAAK,KAAK;;AAGtE,OAAO,UAAU,OAAO,SAAS,KAAK,QAAM,OAAO;CACjD,MAAM,SAAS,OAAO,KAAK;AAC3B,QAAO,OAAO;EAAE,GAAG,OAAO;EAAM;EAAM;EAAO;AAC7C,QAAO;;AAGT,KAAK,MAAM,OAAO;CAAC;CAAW;CAAQ;CAAW;CAAe;CAAO;CAAO;CAAO,CACnF,QAAO,OAAO,OAAO,WAAW,EAC9B,CAAC,KAAmB,OAAY;CAC9B,MAAM,SAAS,OAAO,KAAK;AAC3B,QAAO,OAAO;EAAE,GAAG,OAAO;GAAO,MAAM;EAAO;AAC9C,QAAO;GAEV,CAAC;AAGJ,MAAMG,YAAuC,EAAE;AAE/C,OAAO,SAAS,SAAS,OAAO,MAAM,SAAS;AAC7C,WAAU,QAAQ;;AAGpB,OAAO,UAAU,SAAS,QAAQ,MAAM,QAAQ,UAAU,EAAE,EAAE,SAAS,OAAO;AAC5E,KAAI,CAAC,OAAQ,QAAO,CAAC,KAAK;AAC1B,KAAI,QAAQ,SAAS,MAAM,OAAO,CAAE,QAAO,CAAC,KAAK;AAEjD,KAAI,WAAW,KAAK,IAAI,OAAO,SAAS,QAAQ;AAC9C,MAAI,OAAO,KAAK,SAAU,OAAM,IAAI,gBAAgB,0BAA0B,QAAQ;EACtF,IAAI,UAAU;EACd,IAAI,WAAW,OAAO,KAAK;AAC3B,SAAO,SAAS,SAAS,eAAe,WAAW,SAAS,EAAE;AAC5D,aAAU,QAAQ,KAAM;AACxB,cAAW,SAAS,KAAK;;AAE3B,MAAI,WAAW,SAAS,CAAE,QAAO,CAAC,KAAK;AACvC,SAAO,MAAM,SAAS;;CAGxB,MAAM,WAAW,UAAU,OAAO;AAClC,KAAI,CAAC,SAAU,OAAM,IAAI,gBAAgB,qBAAqB,OAAO,KAAK,IAAI,QAAQ;AAEtF,KAAI;AACF,SAAO,SAAS,MAAM,QAAQ,SAAS,OAAO;UACvC,OAAO;AACd,MAAI,CAAC,OAAO,KAAK,MAAO,OAAM;AAC9B,SAAO,CAAC,OAAO,KAAK,QAAQ;;;AAIhC,OAAO,OAAO,SAAS,KAAK,QAAa;AACvC,KAAI,WAAW,OAAO,CACpB,QAAO,OAAO,KAAK;UACV;EAAC;EAAU;EAAU;EAAU,CAAC,SAAS,OAAO,OAAO,CAChE,QAAO,OAAO,MAAM,OAAO,CAAC,UAAU;UAC7B,OAAO,SAChB,QAAO;UACE,OAAO,WAAW,WAC3B,SAAQ,QAAR;EACE,KAAK,OAAQ,QAAO,OAAO,QAAQ,CAAC,UAAU;EAC9C,KAAK,OAAQ,QAAO,OAAO,QAAQ,CAAC,UAAU;EAC9C,KAAK,QAAS,QAAO,OAAO,SAAS,CAAC,UAAU;EAChD,KAAK,SAAU,QAAO,OAAO,UAAU,CAAC,UAAU;EAClD,QAAS,QAAO,OAAO,GAAG,OAAO,CAAC,UAAU;;KAG9C,OAAM,IAAI,UAAU,4BAA4B,SAAS;;AAI7D,OAAO,OAAO,SAAS,KAAK,SAAS;CACnC,MAAM,eAAe;AACnB,MAAI,CAAC,OAAO,MAAO,UAAU;AAC3B,UAAO,QAAQ,OAAO,SAAU;AAChC,UAAO,MAAO,OAAO;IAAE,GAAG,OAAO;IAAM,GAAG,OAAO,MAAO;IAAM;;AAEhE,SAAO,OAAO,MAAO,QAAQ;;CAE/B,MAAM,SAAS,IAAI,OAAO;EAAE,MAAM;EAAQ;EAAS,OAAO,EAAE,QAAQ;EAAS,CAAC;AAC9E,QAAO;;AAGT,OAAO,UAAU,SAAS,UAAU;AAClC,QAAO,OAAO,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE;;AAGvC,OAAO,UAAU,SAAS,UAAU;AAClC,QAAO,OAAO,QAAQ,CAAC,KAAK,IAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS;;AAGhE,OAAO,OAAO,SAAS,OAAO;AAC5B,QAAO,OAAO,MAAM,CAClB,OAAO,GAAG,KAAK,EACf,OAAO,UAAU,OAAO,QAAQ,CAAC,KAAK,WAAW,GAAG,OAAO,YAAY;EACrE,MAAMC,SAAO,IAAI,KAAK,MAAM;AAC5B,MAAI,MAAM,CAACA,OAAK,CAAE,OAAM,IAAI,gBAAgB,iBAAiB,MAAM,IAAI,QAAQ;AAC/E,SAAOA;IACN,KAAK,CACT,CAAC;;AAGJ,OAAO,SAAS,SAAS,OAAO,OAAO,IAAI;AACzC,QAAO,OAAO,MAAM,CAClB,OAAO,GAAG,OAAO,EACjB,OAAO,UAAU,OAAO,QAAQ,CAAC,KAAK,UAAU,EAAE,MAAM,CAAC,GAAG,OAAO,YAAY;AAC7E,MAAI;AACF,UAAO,IAAI,OAAO,OAAO,KAAK;WACvBC,GAAQ;AACf,SAAM,IAAI,gBAAgB,EAAE,SAAS,QAAQ;;IAE9C,KAAK,CACT,CAAC;;AAGJ,OAAO,cAAc,SAAS,YAAY,UAAkC;AAC1E,QAAO,OAAO,MAAM;EAClB,OAAO,GAAG,YAAY;EACtB,OAAO,GAAG,kBAAkB;EAC5B,OAAO,UAAU,OAAO,KAAsB,GAAG,OAAO,YAAY;AAClE,OAAI,OAAO,SAAS,MAAM,CAAE,QAAO,OAAO,WAAW,MAAM;AAC3D,SAAM,IAAI,gBAAgB,sCAAsC,SAAS,QAAQ;KAChF,KAAK;EACR,GAAG,WAAW,CAAC,OAAO,UAAU,OAAO,QAAQ,GAAG,OAAO,YAAY;AACnE,OAAI;AACF,WAAO,aAAa,WAChB,OAAO,WAAW,MAAM,GACxB,OAAO,QAAQ,MAAM;YAClBA,GAAQ;AACf,UAAM,IAAI,gBAAgB,EAAE,SAAS,QAAQ;;KAE9C,KAAK,CAAC,GAAY,EAAE;EACxB,CAAC;;AAGJ,OAAO,OAAO,SAAS,MAAM,QAAQ,SAAS,WAAW;AACvD,KAAI,CAAC,OAAO,MAAO,UAAU;AAC3B,SAAO,QAAQ,OAAO,SAAU;AAChC,SAAO,MAAO,OAAO;GAAE,GAAG,OAAO;GAAM,GAAG,OAAO,MAAO;GAAM;;AAEhE,QAAO,OAAO,QAAQ,MAAM,OAAO,OAAQ,SAAS,OAAO;EAC3D;AAEF,OAAO,OAAO,QAAQ,SAAS;AAC7B,QAAO,CAAC,KAAK;EACb;AAEF,OAAO,OAAO,UAAU,MAAM,GAAG,YAAY;AAC3C,OAAM,IAAI,gBAAgB,6BAA6B,QAAQ,QAAQ;EACvE;AAEF,OAAO,OAAO,UAAU,MAAM,EAAE,SAAS,YAAY;AACnD,KAAI,UAAU,MAAM,MAAM,CAAE,QAAO,CAAC,MAAM;AAC1C,OAAM,IAAI,gBAAgB,YAAY,MAAM,WAAW,QAAQ,QAAQ;EACvE;AAEF,SAAS,iBAAiB,MAAc,MAA6B,aAAqB,SAA8B,UAAU,OAAO;CACvI,MAAM,EAAE,MAAM,UAAU,MAAM,cAAc;AAC5C,KAAI,OAAO,IAAK,OAAM,IAAI,gBAAgB,YAAY,YAAY,MAAM,IAAI,WAAW,QAAQ,QAAQ;AACvG,KAAI,OAAO,OAAO,CAAC,QAAS,OAAM,IAAI,gBAAgB,YAAY,YAAY,MAAM,IAAI,WAAW,QAAQ,QAAQ;;AAGrH,OAAO,OAAO,WAAW,MAAM,EAAE,QAAQ,YAAY;AACnD,KAAI,OAAO,SAAS,SAAU,OAAM,IAAI,gBAAgB,2BAA2B,QAAQ,QAAQ;AACnG,KAAI,KAAK,SAAS;EAChB,MAAM,SAAS,IAAI,OAAO,KAAK,QAAQ,QAAQ,KAAK,QAAQ,MAAM;AAClE,MAAI,CAAC,OAAO,KAAK,KAAK,CAAE,OAAM,IAAI,gBAAgB,iCAAiC,UAAU,QAAQ;;AAEvG,kBAAiB,KAAK,QAAQ,MAAM,iBAAiB,QAAQ;AAC7D,QAAO,CAAC,KAAK;EACb;AAEF,SAAS,aAAa,MAAc,QAAgB;CAClD,MAAM,MAAM,KAAK,UAAU;AAC3B,KAAI,IAAI,SAAS,IAAI,CAAE,QAAO,OAAO,KAAK,IAAI,IAAI,OAAO;CACzD,MAAM,QAAQ,IAAI,QAAQ,IAAI;AAC9B,KAAI,UAAU,GAAI,QAAO,OAAO,KAAK,IAAI,IAAI,OAAO;CACpD,MAAM,OAAO,IAAI,MAAM,QAAQ,EAAE;CACjC,MAAM,UAAU,IAAI,MAAM,GAAG,MAAM;AACnC,KAAI,KAAK,UAAU,OAAQ,QAAO,EAAE,UAAU,KAAK,OAAO,QAAQ,IAAI;AACtE,QAAO,EAAE,UAAU,KAAK,MAAM,GAAG,OAAO,GAAG,MAAM,KAAK,MAAM,OAAO;;AAGrE,SAAS,aAAa,MAAc,KAAa,MAAc;AAC7D,QAAO,KAAK,IAAI,KAAK;AACrB,KAAI,CAAC,aAAa,KAAK,KAAK,UAAU,CAAC,CACrC,SAAQ,OAAO,OAAO,SAAS;CAEjC,MAAM,QAAQ,KAAK,UAAU,CAAC,QAAQ,IAAI;CAC1C,MAAM,SAAS,KAAK,UAAU,CAAC,MAAM,QAAQ,EAAE,CAAC;AAChD,QAAO,KAAK,IAAI,aAAa,MAAM,OAAO,GAAG,aAAa,KAAK,OAAO,CAAC,GAAG,aAAa,MAAM,OAAO,KAAK;;AAG3G,OAAO,OAAO,WAAW,MAAM,EAAE,QAAQ,YAAY;AACnD,KAAI,OAAO,SAAS,SAAU,OAAM,IAAI,gBAAgB,2BAA2B,QAAQ,QAAQ;AACnG,kBAAiB,MAAM,MAAM,UAAU,QAAQ;CAC/C,MAAM,EAAE,SAAS;AACjB,KAAI,QAAQ,CAAC,aAAa,MAAM,KAAK,OAAO,GAAG,KAAK,CAClD,OAAM,IAAI,gBAAgB,+BAA+B,KAAK,WAAW,QAAQ,QAAQ;AAE3F,QAAO,CAAC,KAAK;EACb;AAEF,OAAO,OAAO,YAAY,MAAM,GAAG,YAAY;AAC7C,KAAI,OAAO,SAAS,UAAW,QAAO,CAAC,KAAK;AAC5C,OAAM,IAAI,gBAAgB,4BAA4B,QAAQ,QAAQ;EACtE;AAEF,OAAO,OAAO,WAAW,MAAM,EAAE,MAAM,QAAQ,YAAY;CACzD,IAAI,QAAQ,GAAGC,OAAiB,EAAE;AAClC,KAAI,OAAO,SAAS,UAAU;AAC5B,UAAQ;AACR,OAAK,MAAM,OAAO,KAChB,KAAI,OAAO,KAAM,KACf,MAAK,KAAK,IAAI;YAGT,MAAM,QAAQ,KAAK,EAAE;AAC9B,SAAO;AACP,OAAK,MAAM,OAAO,MAAM;AACtB,OAAI,OAAO,QAAQ,SAAU,OAAM,IAAI,gBAAgB,2BAA2B,OAAO,QAAQ;AACjG,OAAI,OAAO,KAAO,UAAS,KAAM;;OAGnC,OAAM,IAAI,gBAAgB,oCAAoC,QAAQ,QAAQ;AAEhF,KAAI,UAAU,KAAK,QAAS,QAAO,CAAC,MAAM;AAC1C,QAAO,CAAC,OAAO,KAAK;EACpB;AAEF,OAAO,OAAO,aAAa,MAAM,GAAG,YAAY;AAC9C,KAAI,OAAO,SAAS,WAAY,QAAO,CAAC,KAAK;AAC7C,OAAM,IAAI,gBAAgB,6BAA6B,QAAQ,QAAQ;EACvE;AAEF,OAAO,OAAO,OAAO,MAAM,EAAE,eAAe,YAAY;AACtD,KAAI,OAAO,gBAAgB,YAAY;AACrC,MAAI,gBAAgB,YAAa,QAAO,CAAC,KAAK;AAC9C,QAAM,IAAI,gBAAgB,YAAY,YAAY,KAAK,WAAW,QAAQ,QAAQ;QAC7E;AACL,MAAI,WAAW,KAAK,CAClB,OAAM,IAAI,gBAAgB,YAAY,YAAY,WAAW,QAAQ,QAAQ;EAE/E,IAAI,YAAY,OAAO,eAAe,KAAK;AAC3C,SAAO,WAAW;AAChB,OAAI,UAAU,aAAa,SAAS,YAAa,QAAO,CAAC,KAAK;AAC9D,eAAY,OAAO,eAAe,UAAU;;AAE9C,QAAM,IAAI,gBAAgB,YAAY,YAAY,WAAW,QAAQ,QAAQ;;EAE/E;AAEF,SAAS,SAAS,MAAW,KAAgB,QAAgB,SAA8B;AACzF,KAAI;EACF,MAAM,CAAC,OAAO,WAAW,OAAO,QAAQ,KAAK,MAAM,QAAQ;GACzD,GAAG;GACH,MAAM,CAAC,GAAG,QAAQ,QAAQ,EAAE,EAAE,IAAI;GACnC,CAAC;AACF,MAAI,YAAY,OAAW,MAAK,OAAO;AACvC,SAAO;UACA,GAAG;AACV,MAAI,CAAC,SAAS,QAAS,OAAM;AAC7B,SAAO,KAAK;AACZ,SAAO,OAAO,KAAK;;;AAIvB,OAAO,OAAO,UAAU,MAAM,EAAE,OAAO,QAAQ,YAAY;AACzD,KAAI,CAAC,MAAM,QAAQ,KAAK,CAAE,OAAM,IAAI,gBAAgB,0BAA0B,QAAQ,QAAQ;AAC9F,kBAAiB,KAAK,QAAQ,MAAM,gBAAgB,SAAS,CAAC,WAAW,MAAO,KAAK,QAAQ,CAAC;AAC9F,QAAO,CAAC,KAAK,KAAK,GAAG,UAAU,SAAS,MAAM,OAAO,OAAQ,QAAQ,CAAC,CAAC;EACvE;AAEF,OAAO,OAAO,SAAS,MAAM,EAAE,OAAO,QAAQ,SAAS,WAAW;AAChE,KAAI,CAAC,cAAc,KAAK,CAAE,OAAM,IAAI,gBAAgB,2BAA2B,QAAQ,QAAQ;CAC/F,MAAMC,SAAc,EAAE;AACtB,MAAK,MAAM,OAAO,MAAM;EACtB,IAAIC;AACJ,MAAI;AACF,UAAO,OAAO,QAAQ,KAAK,MAAO,QAAQ,CAAC;WACpC,OAAO;AACd,OAAI,OAAQ;AACZ,SAAM;;AAER,SAAO,QAAQ,SAAS,MAAM,KAAK,OAAQ,QAAQ;AACnD,OAAK,QAAQ,KAAK;AAClB,MAAI,QAAQ,KAAM,QAAO,KAAK;;AAEhC,QAAO,CAAC,OAAO;EACf;AAEF,OAAO,OAAO,UAAU,MAAM,EAAE,QAAQ,SAAS,WAAW;AAC1D,KAAI,CAAC,MAAM,QAAQ,KAAK,CAAE,OAAM,IAAI,gBAAgB,0BAA0B,QAAQ,QAAQ;CAC9F,MAAM,SAAS,KAAM,KAAK,OAAO,UAAU,SAAS,MAAM,OAAO,OAAO,QAAQ,CAAC;AACjF,KAAI,OAAQ,QAAO,CAAC,OAAO;AAC3B,QAAO,KAAK,GAAG,KAAK,MAAM,KAAM,OAAO,CAAC;AACxC,QAAO,CAAC,OAAO;EACf;AAEF,SAAS,MAAM,QAAa,MAAW;AACrC,MAAK,MAAM,OAAO,MAAM;AACtB,MAAI,OAAO,OAAQ;AACnB,SAAO,OAAO,KAAK;;;AAIvB,OAAO,OAAO,WAAW,MAAM,EAAE,QAAQ,SAAS,WAAW;AAC3D,KAAI,CAAC,cAAc,KAAK,CAAE,OAAM,IAAI,gBAAgB,2BAA2B,QAAQ,QAAQ;CAC/F,MAAMD,SAAc,EAAE;AACtB,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,SAAS,MAAM,KAAK,KAAM,MAAO,QAAQ;AACvD,MAAI,CAAC,WAAW,MAAM,IAAI,OAAO,KAC/B,QAAO,OAAO;;AAGlB,KAAI,CAAC,OAAQ,OAAM,QAAQ,KAAK;AAChC,QAAO,CAAC,OAAO;EACf;AAEF,OAAO,OAAO,UAAU,MAAM,EAAE,MAAM,YAAY,SAAS,WAAW;CACpE,MAAME,WAAkB,EAAE;AAC1B,MAAK,MAAM,SAAS,KAClB,KAAI;AACF,SAAO,OAAO,QAAQ,MAAM,OAAO,SAAS,OAAO;UAC5C,OAAO;AACd,WAAS,KAAK,MAAM;;AAGxB,OAAM,IAAI,gBAAgB,YAAY,UAAU,CAAC,WAAW,KAAK,UAAU,KAAK,IAAI,QAAQ;EAC5F;AAEF,OAAO,OAAO,cAAc,MAAM,EAAE,MAAM,YAAY,SAAS,WAAW;AACxE,KAAI,CAAC,KAAM,OAAQ,QAAO,CAAC,KAAK;CAChC,IAAI;AACJ,MAAK,MAAM,SAAS,MAAO;EACzB,MAAMC,QAAa,OAAO,QAAQ,MAAM,OAAO,SAAS,KAAK,CAAC;AAC9D,MAAI,WAAW,MAAM,CAAE;AACvB,MAAI,WAAW,OAAO,CACpB,UAAS;WACA,OAAO,WAAW,OAAO,MAClC,OAAM,IAAI,gBAAgB,YAAY,UAAU,CAAC,WAAW,KAAK,UAAU,KAAK,IAAI,QAAQ;WACnF,OAAO,UAAU,SAC1B,OAAM,WAAW,EAAE,EAAE,MAAM;WAClB,WAAW,MACpB,OAAM,IAAI,gBAAgB,YAAY,UAAU,CAAC,WAAW,KAAK,UAAU,KAAK,IAAI,QAAQ;;AAGhG,KAAI,CAAC,UAAU,cAAc,KAAK,CAAE,OAAM,QAAQ,KAAK;AACvD,QAAO,CAAC,OAAO;EACf;AAEF,OAAO,OAAO,cAAc,MAAM,EAAE,OAAO,UAAU,YAAY,YAAY;CAC3E,MAAM,CAAC,QAAQ,UAAU,QAAQ,OAAO,QAAQ,MAAM,OAAQ,SAAS,KAAK;AAC5E,KAAI,SACF,QAAO,CAAC,SAAU,OAAO,CAAC;KAW1B,QAAO,CAAC,SAAU,OAAO,EAAE,SAAU,QAAQ,CAAC;EAEhD;AAGF,MAAMC,aAA8B,EAAE;AAEtC,SAAS,aAAa,MAAc,MAAwB,QAAmB;AAC7E,YAAW,QAAQ;AACnB,QAAO,OAAO,QAAQ,EACpB,CAAC,MAAM,GAAG,MAAa;EACrB,MAAM,SAAS,IAAI,OAAO,EAAE,MAAM,MAAM,CAAW;AACnD,OAAK,SAAS,KAAK,UAAU;AAC3B,WAAQ,KAAR;IACE,KAAK;AAAQ,YAAO,OAAO,KAAK,UAAU,OAAO,QAAQ;AAAE;IAC3D,KAAK;AAAS,YAAO,QAAQ,OAAO,KAAK,KAAK,OAAO;AAAE;IACvD,KAAK;AAAQ,YAAO,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK;AAAE;IACzD,KAAK;AAAQ,YAAO,OAAOd,UAAS,KAAK,QAAQ,OAAO,KAAK;AAAE;IAC/D,KAAK;AACH,YAAO,OAAO,EAAE;AAChB,UAAK,MAAMe,SAAO,KAAK,QAAQ;AAC7B,UAAI,OAAO,KAAK,OAAOA,WAAS,SAAU;AAC1C,aAAO,KAAKA,SAAO,KAAK,OAAOA;;AAEjC;IAEF,KAAK,YAAY;KACf,MAAM,WAAW,OAAO,WAAW,KAAK;AACvC,cAAS,oBAAoB,SAAS,UAAU;AACjD;;IAEF,KAAK,eAAe;KAClB,MAAM,cAAc,OAAO,cAAc,KAAK;AAC9C,SAAI,OAAO,gBAAgB,WACxB,aAAY,oBAAoB,YAAY;AAE/C;;IAEF,QAAS,QAAO,OAAO,KAAK;;IAE9B;AACF,MAAI,SAAS,YAAY,SAAS,OAChC,QAAO,KAAK,UAAU,EAAE;WACf,SAAS,WAAW,SAAS,QACtC,QAAO,KAAK,UAAU,EAAE;WACf,SAAS,SAClB,QAAO,KAAK,UAAU;AAExB,SAAO;IAEV,CAAC;;AAGJ,aAAa,MAAM,CAAC,cAAc,GAAG,EAAE,kBAAkB;AACvD,KAAI,OAAO,gBAAgB,WACzB,QAAO,YAAY;KAEnB,QAAO;EAET;AAEF,aAAa,OAAO,EAAE,QAAQ,MAAM;AACpC,aAAa,SAAS,EAAE,QAAQ,QAAQ;AACxC,aAAa,SAAS,CAAC,QAAQ,GAAG,EAAE,YAAY,OAAO,UAAU,WAAW,KAAK,UAAU,MAAM,GAAG,MAAM;AAC1G,aAAa,UAAU,EAAE,QAAQ,SAAS;AAC1C,aAAa,UAAU,EAAE,QAAQ,SAAS;AAC1C,aAAa,WAAW,EAAE,QAAQ,UAAU;AAC5C,aAAa,UAAU,CAAC,OAAO,QAAQ,SAAS;AAChD,aAAa,YAAY,EAAE,QAAQ,WAAW;AAC9C,aAAa,SAAS,CAAC,QAAQ,GAAG,EAAE,YAAY,GAAG,MAAO,SAAS,KAAK,CAAC,IAAI;AAC7E,aAAa,QAAQ,CAAC,SAAS,OAAO,GAAG,EAAE,OAAO,WAAW,WAAW,KAAM,UAAU,CAAC,KAAK,MAAO,UAAU,CAAC,IAAI;AACpH,aAAa,SAAS,CAAC,OAAO,GAAG,EAAE,WAAW,IAAI,KAAM,KAAK,UAAU,MAAM,UAAU,CAAC,CAAC,KAAK,KAAK,CAAC,GAAG;AAEvG,aAAa,UAAU,CAAC,OAAO,GAAG,EAAE,WAAW;AAC7C,KAAI,OAAO,KAAK,KAAM,CAAC,WAAW,EAAG,QAAO;AAC5C,QAAO,KAAK,OAAO,QAAQ,KAAM,CAAC,KAAK,CAAC,KAAK,WAAW;AACtD,SAAO,GAAG,MAAM,MAAO,KAAK,WAAW,KAAK,IAAI,IAAI,MAAO,UAAU;GACrE,CAAC,KAAK,KAAK,CAAC;EACd;AAEF,aAAa,SAAS,CAAC,OAAO,GAAG,EAAE,QAAQ,WAAW;CACpD,MAAM,SAAS,KAAM,KAAK,EAAE,UAAU,aAAa,QAAQ,CAAC,CAAC,KAAK,MAAM;AACxE,QAAO,SAAS,IAAI,OAAO,KAAK;EAChC;AAEF,aAAa,aAAa,CAAC,OAAO,GAAG,EAAE,WAAW;AAChD,QAAO,GAAG,KAAM,KAAK,UAAU,MAAM,SAAS,KAAK,CAAC,CAAC,KAAK,MAAM;EAChE;AAEF,aAAa,aAAa;CAAC;CAAS;CAAY;CAAW,GAAG,EAAE,SAAS,YAAY,MAAO,SAAS,QAAQ,CAAC;AAE9G,kBAAe;;;;;AC12Bf,MAAaC,SAAoBC,YAAE,OAAO;CACxC,YAAYA,YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,IAAO;CAC7C,kBAAkBA,YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CAC9C,kBAAkBA,YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CAC9C,gBAAgBA,YAAE,MAAMA,YAAE,QAAQ,CAAC,CAAC,QAAQ;EAAC;EAAQ;EAAc;EAAa,CAAC;CAClF,CAAC;AAaF,MAAMC,mBAAkCD,YAAE,OAAO;CAC/C,UAAUA,YAAE,QAAQ;CACpB,OAAOA,YAAE,QAAQ;CACjB,OAAOA,YAAE,QAAQ,CAAC,QAAQ,GAAG;CAC9B,CAAC;AAEF,MAAME,sBAAwCF,YAAE,OAAO;CACrD,UAAUA,YAAE,QAAQ;CACpB,OAAOA,YAAE,QAAQ;CACjB,OAAOA,YAAE,QAAQ,CAAC,QAAQ,SAAS;CACnC,UAAUA,YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CACvC,CAAC;;AAGF,MAAaG,yBAA8CH,YAAE,OAAO;CAClE,SAASA,YAAE,SAAS,CAAC,QAAQ,MAAM;CACnC,cAAcA,YAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CAClD,OAAOA,YAAE,MAAM,iBAAiB,CAAC,QAAQ,EAAE,CAAC;CAC5C,UAAUA,YAAE,MAAM,oBAAoB,CAAC,QAAQ,EAAE,CAAC;CACnD,CAAC;;AAGF,MAAaI,mBAAqC;CAChD,SAAS;CACT,cAAc;CACd,OAAO,EAAE;CACT,UAAU,EAAE;CACb;;;;AC5DD,MAAM,4BAAY,IAAI,KAAiB;AACvC,IAAIC,WAA6B;CAC/B,GAAG;CACH,UAAU,EAAE;CACZ,YAAY,EAAE;CACd,kBAAkB;CACnB;AAED,SAAS,QAAQ,MAA8B;AAC7C,YAAW;AACX,MAAK,MAAM,YAAY,CAAC,GAAG,UAAU,CAAE,WAAU;;;AAInD,MAAa,iBAAiB;CAC5B,UAAU,UAAkC;AAC1C,YAAU,IAAI,SAAS;AACvB,eAAa;AACX,aAAU,OAAO,SAAS;;;CAG9B,cAAgC;AAC9B,SAAO;;CAEV;;;;;AAMD,SAAgB,gBAAgB,UAAkC;CAChE,MAAM,QAAQ,YAAY,SAAS,MAAM;AACzC,SAAQ;EACN,SAAS,SAAS;EAClB;EACA,cAAc,WAAW,SAAS,cAAc,MAAM,OAAO;EAC7D,UAAU,SAAS,YAAY,EAAE;EACjC,YAAY,SAAS;EACrB,kBAAkB,SAAS;EAC5B,CAAC;;;;;;AAOJ,SAAgB,kBAAkB,YAAgD;AAChF,SAAQ;EAAE,GAAG;EAAU;EAAY,kBAAkB;EAAM,CAAC;;;;;;ACV9D,MAAa,SAAS;CAAC;CAAS;CAAU;CAAiB;CAAU;CAAmB;CAAiB;AAOzG,SAAS,iBAAiB,KAAc,WAA4B;AAClE,KAAI,OAAO,cAAc,YAAY,cAAc,GAAI,QAAO;CAG9D,MAAM,UADW,IAAI,IAAI,WAAW,EACV,MAAM,eAAe,CAAC;AAChD,QAAO,OAAO,YAAY,WAAW,UAAU;;AAGjD,SAAS,aAAa,OAAiD;AACrE,KAAI,UAAU,UAAU,UAAU,eAAe,UAAU,SAAU,QAAO;AAC5E,QAAO;;AAGT,SAAS,oBAAoB,OAA8C;AACzE,KAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;CACxD,MAAM,SAAS;AACf,KAAI,OAAO,OAAO,YAAY,UAAW,QAAO;AAChD,KAAI,OAAO,OAAO,iBAAiB,SAAU,QAAO;AACpD,KAAI,CAAC,MAAM,QAAQ,OAAO,MAAM,CAAE,QAAO;CACzC,MAAM,QAAQ,OAAO,MAAM,SAAS,QAAQ;AAC1C,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO,EAAE;EACtD,MAAM,OAAO;AACb,MAAI,OAAO,KAAK,aAAa,YAAY,OAAO,KAAK,UAAU,SAAU,QAAO,EAAE;AAClF,SAAO,CAAC;GACN,UAAU,KAAK;GACf,OAAO,KAAK;GACZ,GAAG,OAAO,KAAK,UAAU,WAAW,EAAE,OAAO,KAAK,OAAO,GAAG,EAAE;GAC/D,CAAC;GACF;CACF,MAAM,WAAW,MAAM,QAAQ,OAAO,SAAS,GAC3C,OAAO,SAAS,SAAS,QAAQ;AACjC,MAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM,QAAO,EAAE;EACtD,MAAM,OAAO;AACb,MAAI,OAAO,KAAK,aAAa,YAAY,OAAO,KAAK,UAAU,SAAU,QAAO,EAAE;AAClF,SAAO,CAAC;GACN,UAAU,KAAK;GACf,OAAO,KAAK;GACZ,OAAO,aAAa,KAAK,MAAM;GAC/B,UAAU,OAAO,KAAK,aAAa,YAAY,KAAK,WAAW,IAAI,KAAK,WAAW;GACpF,CAAC;GACF,GACA,EAAE;AACN,QAAO;EAAE,SAAS,OAAO;EAAS,cAAc,OAAO;EAAc;EAAO;EAAU;;;;;;AAOxF,SAAgB,MAAM,KAAoB;CACxC,MAAM,SAAS;CACf,MAAM,QAAQ,OAAO,cAAc,KAAK,EAAE,WAAW,sBAAsB,CAAC;CAE5E,MAAM,aAAmB;EACvB,MAAM,QAAQ,oBAAoB,MAAM,aAAa,CAAC,MAAM;AAC5D,MAAI,UAAU,OAAW,iBAAgB,MAAM;;AAEjD,OAAM;CAEN,MAAM,MAAM;EACV,YAAY,OAAO,YAAqB;AACtC,SAAM,MAAM,IAAI,WAAW,QAAQ;;EAErC,UAAU,OAAO,OAAkC,iBAAyB;AAC1E,SAAM,MAAM,IAAI,SAAS,MAAM;AAC/B,SAAM,MAAM,IAAI,gBAAgB,aAAa;;EAEhD;CAED,MAAM,iBAAiB,OAAO,cAAqC;EACjE,MAAM,UAAU,MAAM,OAAO,OAAO,SAAS,cAAc;AAC3D,MAAI,SAAS,IAAI;GACf,MAAM,OAAO,sBAAsB,QAAQ,MAAM;AACjD,OAAI,KAAK,SAAS,GAAG;AACnB,sBAAkB,KAAK;AACvB;;;AAGJ,MAAI,cAAc,GAAI;EACtB,MAAM,SAAS,MAAM,OAAO,OAAO,SAAS,QAAQ,WAAW,0BAA0B,EAAE,CAAC;AAC5F,MAAI,CAAC,OAAO,GAAI;EAChB,MAAM,OAAO,OAAO,OAAO,UAAU,WACjC,OAAO,QACP,OAAO,OAAO,OAAO,SAAS,WAAW,OAAO,MAAM,OAAO;AACjE,MAAI,SAAS,GAAI;AACjB,oBAAkB,mBAAmB,KAAK,CAAC;;CAG7C,MAAM,YAAY,eAAwB;EACxC,OAAO,EAAE,UAAU,gBAAgB;EACnC;EACA;EACA,oBAAoB,iBAAiB,KAAK,UAAU;EACrD;AAED,QAAO,aAAa;EAClB,MAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,QAAM,QAAQ,SAAS;AACvB,QAAM,cAAc;AACpB,WAAS,KAAK,YAAY,MAAM;AAChC,eAAa;AAAE,SAAM,QAAQ;;IAC5B,6BAA6B;AAEhC,QAAO,aAAa,OAAO,OAAO,SAAS,IAAI;EAAE;EAAI;EAAI,CAAC,EAAE,mCAAmC;AAC/F,QAAO,aAAa,MAAM,UAAU,KAAK,EAAE,+BAA+B;AAE1E,QAAO,MAAM,OAAO,kCAAkC,OAAO,MAAM,SAAS;EAC1E,MAAM;EACN,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,QAAQ;EACT,EAAE,aAAa,CAAC;AAEjB,QAAO,MAAM,OAAO,0BAA0B,OAAO,MAAM,SAAS;EAClE,MAAM;EACN,IAAI;EACJ,OAAO;EACP,QAAQ;EACR,aAAa,OAAO,OAAO,KAAK,GAAG,CAAC,eAAe;EACnD,QAAQ;EACT,EAAE,qBAAqB,CAAC"}
1
+ {"version":3,"file":"client.js","names":["parsed: unknown","groups: ProviderGroup[]","next: QueueRoute[]","top: number","route: QueueRoute","snapshot","zh: Record<FailoverKey, string>","en: Record<FailoverKey, string>","value","buffer: number[]","result: any[]","result","a","b","template","options: Schemastery.Options","options","valueMap","result: Dict<string>","pattern","result: Dict","result: any[]","value","resolvers: Dict<Schemastery.Resolve>","date","e: any","keys: string[]","result: any","rKey: string","messages: any[]","value: any","formatters: Dict<Formatter>","key","Config: z<Config>","z","QueueRouteSchema: z<QueueRoute>","CircuitHealthSchema: z<CircuitHealth>","FailoverSettingsSchema: z<FailoverSettings>","DEFAULT_SETTINGS: FailoverSettings","snapshot: FailoverSnapshot"],"sources":["../src/types.ts","../src/candidates.ts","../src/queue.ts","../src/client/place.ts","../src/circuit.ts","../src/client/styles.ts","../src/client/QueuePanel.tsx","../src/client/FailoverChip.tsx","../src/client/locales.ts","../../deepseek-harness/vendor/cosmokit/src/misc.ts","../../deepseek-harness/vendor/cosmokit/src/types.ts","../../deepseek-harness/vendor/cosmokit/src/time.ts","../../deepseek-harness/vendor/schemastery/src/index.ts","../src/config.ts","../src/client/state.ts","../src/client/index.ts"],"sourcesContent":["/** One provider+model slot in the failover queue. P1 is index 0. */\nexport interface QueueRoute {\n /** Adapter route key (`GenerateOptions.provider`). */\n readonly provider: string\n /** Model id for that route. */\n readonly model: string\n /** Optional display label; the chip falls back to `provider/model`. */\n readonly label?: string\n}\n\n/** Closed = healthy, Open = skipped, HalfOpen = one probe. */\nexport type CircuitState = 'closed' | 'open' | 'half_open'\n\n/** Host-projected breaker badge for one queue route. Memory-only on the host. */\nexport interface CircuitHealth {\n readonly provider: string\n readonly model: string\n readonly state: CircuitState\n readonly failures: number\n}\n\n/** Persisted failover document (settings namespace `dsh-failover-queue`). */\nexport interface FailoverSettings {\n /** When false, the plugin never overlays or retries across routes. */\n enabled: boolean\n /** Last picked queue index (P1 = 0). Clamped on read. Not a sticky pointer. */\n currentIndex: number\n /** Ordered routes. Index 0 is P1. */\n queue: QueueRoute[]\n /** Live circuit badges. Host memory is the source of truth. */\n circuits?: CircuitHealth[]\n}\n\n/** One advertised catalog row the panel can add. */\nexport interface FailoverCandidate {\n readonly provider: string\n readonly providerName: string\n readonly model: string\n readonly name: string\n}\n\n/** Marker the `/failover __candidates` handler prefixes onto JSON. */\nexport const CANDIDATES_MARKER = 'FAILOVER_CANDIDATES_V1'\n","import { CANDIDATES_MARKER, type FailoverCandidate } from './types.ts'\n\n/**\n * Parse `/failover __candidates` command text into catalog rows.\n * @param text - command success text, possibly including the marker prefix.\n * @returns recognized provider+model rows; unknown text is empty.\n */\nexport function candidatesFromText(text: string): FailoverCandidate[] {\n const marker = text.indexOf(CANDIDATES_MARKER)\n if (marker < 0) return []\n const json = text.slice(marker + CANDIDATES_MARKER.length).trim()\n try {\n const parsed: unknown = JSON.parse(json)\n if (!Array.isArray(parsed)) return []\n return parsed.flatMap((row) => {\n if (typeof row !== 'object' || row === null) return []\n const item = row as Record<string, unknown>\n if (typeof item.provider !== 'string' || typeof item.model !== 'string') return []\n return [{\n provider: item.provider,\n providerName: typeof item.providerName === 'string' ? item.providerName : item.provider,\n model: item.model,\n name: typeof item.name === 'string' ? item.name : item.model,\n }]\n })\n } catch {\n return []\n }\n}\n\n/**\n * Flatten `session/modelCatalog` into the same provider+model rows.\n * @param value - RPC value, or undefined when the call failed.\n * @returns one row per model in successful groups.\n */\nexport function candidatesFromCatalog(value: unknown): FailoverCandidate[] {\n if (typeof value !== 'object' || value === null) return []\n const groups = (value as { groups?: unknown }).groups\n if (!Array.isArray(groups)) return []\n return groups.flatMap((group) => {\n if (typeof group !== 'object' || group === null) return []\n const row = group as { id?: unknown; name?: unknown; models?: unknown }\n if (typeof row.id !== 'string' || !Array.isArray(row.models)) return []\n const providerName = typeof row.name === 'string' ? row.name : row.id\n return row.models.flatMap((model) => {\n if (typeof model !== 'object' || model === null) return []\n const item = model as { id?: unknown; name?: unknown }\n if (typeof item.id !== 'string') return []\n return [{\n provider: row.id,\n providerName,\n model: item.id,\n name: typeof item.name === 'string' ? item.name : item.id,\n }]\n })\n })\n}\n\n/** One provider plus the models still available to add. */\nexport interface ProviderGroup {\n readonly provider: string\n readonly providerName: string\n readonly models: readonly FailoverCandidate[]\n}\n\n/**\n * Group flattened catalog rows by provider, keeping first-seen order.\n * @param rows - available provider+model rows.\n * @returns one group per provider.\n */\nexport function groupCandidatesByProvider(rows: readonly FailoverCandidate[]): ProviderGroup[] {\n const groups: ProviderGroup[] = []\n const index = new Map<string, number>()\n for (const row of rows) {\n const at = index.get(row.provider)\n if (at === undefined) {\n index.set(row.provider, groups.length)\n groups.push({\n provider: row.provider,\n providerName: row.providerName,\n models: [row],\n })\n continue\n }\n const current = groups[at]\n if (current === undefined) continue\n groups[at] = { ...current, models: [...current.models, row] }\n }\n return groups\n}\n","import type { FailoverCandidate, QueueRoute } from './types.ts'\n\n/** Stable identity for cooldown and de-dupe. */\nexport function routeKey(route: QueueRoute): string {\n return `${route.provider}\\0${route.model}`\n}\n\n/**\n * Clamp a queue index into `[0, length)` (or `0` when empty).\n * @param index - requested index.\n * @param length - queue length.\n * @returns a usable index.\n */\nexport function clampIndex(index: number, length: number): number {\n if (length <= 0) return 0\n if (!Number.isFinite(index)) return 0\n const whole = Math.trunc(index)\n if (whole < 0) return 0\n if (whole >= length) return length - 1\n return whole\n}\n\n/**\n * Move one queue item from `from` to `to`.\n * @param queue - current ordered routes.\n * @param from - source index.\n * @param to - destination index.\n * @returns a new array.\n */\nexport function reorderQueue(\n queue: readonly QueueRoute[],\n from: number,\n to: number,\n): QueueRoute[] {\n if (from === to) return [...queue]\n if (from < 0 || from >= queue.length) return [...queue]\n if (to < 0 || to >= queue.length) return [...queue]\n const next = [...queue]\n const [item] = next.splice(from, 1)\n if (item === undefined) return next\n next.splice(to, 0, item)\n return next\n}\n\n/**\n * Follow the same route after a drag, not the same slot.\n * @param currentIndex - active index before the move.\n * @param from - dragged index.\n * @param to - drop index.\n * @returns the index of the previously active route.\n */\nexport function indexAfterReorder(currentIndex: number, from: number, to: number): number {\n if (currentIndex === from) return to\n if (from < currentIndex && to >= currentIndex) return currentIndex - 1\n if (from > currentIndex && to <= currentIndex) return currentIndex + 1\n return currentIndex\n}\n\n/**\n * Next uncooled route after `currentIndex`, wrapping once.\n * @param queue - ordered routes.\n * @param currentIndex - failed slot.\n * @param isCooled - true when this route should be skipped.\n * @returns the next index, or `undefined` when nothing remains.\n */\nexport function advanceIndex(\n queue: readonly QueueRoute[],\n currentIndex: number,\n isCooled: (route: QueueRoute) => boolean,\n): number | undefined {\n if (queue.length < 2) return undefined\n const start = clampIndex(currentIndex, queue.length)\n for (let step = 1; step < queue.length; step += 1) {\n const index = (start + step) % queue.length\n const route = queue[index]\n if (route !== undefined && !isCooled(route)) return index\n }\n return undefined\n}\n\n/**\n * True when this failure should skip remaining same-route retries.\n * @param code - provider-neutral `LlmFailure.code`.\n * @param immediateCodes - configured trip codes.\n */\nexport function shouldFailoverImmediately(\n code: string,\n immediateCodes: readonly string[],\n): boolean {\n return immediateCodes.includes(code)\n}\n\n/**\n * Drop duplicate provider+model pairs, keeping the first occurrence.\n * @param queue - possibly messy user input.\n */\nexport function dedupeQueue(queue: readonly QueueRoute[]): QueueRoute[] {\n const seen = new Set<string>()\n const next: QueueRoute[] = []\n for (const route of queue) {\n const provider = route.provider.trim()\n const model = route.model.trim()\n if (provider === '' || model === '') continue\n const key = routeKey({ provider, model })\n if (seen.has(key)) continue\n seen.add(key)\n next.push({\n provider,\n model,\n ...route.label === undefined || route.label.trim() === ''\n ? {}\n : { label: route.label.trim() },\n })\n }\n return next\n}\n\n/**\n * Names the chip and queue rows show for one route.\n * Prefers the live catalog's provider/model titles, then the stored label.\n * @param route - queue slot.\n * @param candidates - advertised catalog, possibly empty.\n */\nexport function routeDisplay(\n route: QueueRoute,\n candidates: readonly FailoverCandidate[] = [],\n): { provider: string; model: string } {\n const hit = candidates.find(row => row.provider === route.provider && row.model === route.model)\n const provider = hit?.providerName.trim() || route.provider\n const model = route.label?.trim() || hit?.name.trim() || route.model\n return { provider, model }\n}\n","export const COMPOSER_PANEL_MARGIN = 8\nexport const COMPOSER_PANEL_GAP = 8\nexport const COMPOSER_PANEL_MAX_HEIGHT = 420\n\nexport interface BoxEdge {\n top: number\n right: number\n bottom: number\n}\n\nexport interface ComposerPanelPlacement {\n left: number\n top: number\n maxHeight: number\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\n/**\n * Cap the composer popover so it can sit inside the viewport with 8px gutters.\n * @param viewportHeight - `window.innerHeight`.\n * @returns CSS max-height in pixels.\n */\nexport function composerPanelMaxHeight(viewportHeight: number): number {\n return Math.min(\n COMPOSER_PANEL_MAX_HEIGHT,\n Math.max(0, viewportHeight - COMPOSER_PANEL_MARGIN * 2),\n )\n}\n\n/**\n * Prefer above the chip; go below only when the full panel fits; otherwise clamp.\n * @param input - trigger box, measured size, and viewport.\n * @returns fixed `left`/`top` plus the height cap to apply.\n */\nexport function placeComposerPanel(input: {\n trigger: BoxEdge\n width: number\n height: number\n viewportWidth: number\n viewportHeight: number\n}): ComposerPanelPlacement {\n const maxHeight = composerPanelMaxHeight(input.viewportHeight)\n const height = Math.min(Math.max(0, input.height), maxHeight)\n const maxWidth = Math.max(0, input.viewportWidth - COMPOSER_PANEL_MARGIN * 2)\n const width = Math.min(Math.max(0, input.width), maxWidth)\n const left = clamp(\n input.trigger.right - width,\n COMPOSER_PANEL_MARGIN,\n Math.max(COMPOSER_PANEL_MARGIN, input.viewportWidth - width - COMPOSER_PANEL_MARGIN),\n )\n const minTop = COMPOSER_PANEL_MARGIN\n const maxTop = Math.max(minTop, input.viewportHeight - height - COMPOSER_PANEL_MARGIN)\n const above = input.trigger.top - COMPOSER_PANEL_GAP - height\n const below = input.trigger.bottom + COMPOSER_PANEL_GAP\n let top: number\n if (above >= minTop) {\n top = above\n } else if (below + height <= input.viewportHeight - COMPOSER_PANEL_MARGIN) {\n top = below\n } else {\n top = clamp(above, minTop, maxTop)\n }\n return { left, top, maxHeight }\n}\n","import { routeKey } from './queue.ts'\nimport type { CircuitHealth, CircuitState, QueueRoute } from './types.ts'\n\n/** Closed / Open / HalfOpen knobs. Chat-friendly defaults, CC Switch-shaped. */\nexport interface CircuitConfig {\n /** Consecutive failures that open a Closed breaker. */\n readonly failureThreshold: number\n /** Consecutive HalfOpen successes that close the breaker. */\n readonly successThreshold: number\n /** Milliseconds an Open breaker waits before becoming HalfOpen. */\n readonly timeoutMs: number\n}\n\n/** Default: 2 failures, 2 probe successes, 60s Open. */\nexport const DEFAULT_CIRCUIT: CircuitConfig = {\n failureThreshold: 2,\n successThreshold: 2,\n timeoutMs: 60_000,\n}\n\n/** Result of taking a HalfOpen probe permit. */\nexport interface ProbeDecision {\n readonly allowed: boolean\n readonly halfOpen: boolean\n}\n\n/** One queue pick: first Closed, else first HalfOpen. */\nexport interface CircuitPick {\n readonly index: number\n readonly route: QueueRoute\n readonly halfOpen: boolean\n}\n\n/**\n * One route's Closed / Open / HalfOpen breaker.\n *\n * HalfOpen allows a single in-flight probe. Open becomes HalfOpen after\n * `timeoutMs`. Immediate failures (AUTH / RATE_LIMIT / NO_ADAPTER / SERVER /\n * TIMEOUT / TRANSPORT) open on the first hit. Memory-only: a process restart\n * starts Closed.\n */\nexport class CircuitBreaker {\n private state: CircuitState = 'closed'\n private failures = 0\n private successes = 0\n private openedAt: number | null = null\n private halfOpenPermit = 0\n\n /**\n * @param config - thresholds and Open timeout.\n */\n constructor(private readonly config: CircuitConfig) {}\n\n /** Copy of counters for badges and tests. */\n snapshot(): {\n readonly state: CircuitState\n readonly failures: number\n readonly successes: number\n readonly openedAt: number | null\n } {\n return {\n state: this.state,\n failures: this.failures,\n successes: this.successes,\n openedAt: this.openedAt,\n }\n }\n\n /**\n * Whether this route may be selected. Open → HalfOpen when the wait elapses.\n * Does not consume the probe permit.\n * @param now - epoch ms.\n */\n isAvailable(now: number): boolean {\n this.maybeHalfOpen(now)\n return this.state === 'closed' || this.state === 'half_open'\n }\n\n /**\n * Reserve this route for one request. HalfOpen consumes the single permit.\n * @param now - epoch ms.\n */\n allowProbe(now: number): ProbeDecision {\n this.maybeHalfOpen(now)\n if (this.state === 'closed') return { allowed: true, halfOpen: false }\n if (this.state === 'half_open') {\n if (this.halfOpenPermit >= 1) return { allowed: false, halfOpen: true }\n this.halfOpenPermit = 1\n return { allowed: true, halfOpen: true }\n }\n return { allowed: false, halfOpen: false }\n }\n\n /** Probe succeeded. Two successes close a HalfOpen breaker. */\n recordSuccess(): void {\n this.releaseProbe()\n this.failures = 0\n if (this.state !== 'half_open') return\n this.successes += 1\n if (this.successes >= this.config.successThreshold) this.transitionClosed()\n }\n\n /**\n * Probe or Closed request failed.\n * @param now - epoch ms used as Open timestamp.\n * @param immediate - open on this hit regardless of `failureThreshold`.\n */\n recordFailure(now: number, immediate = false): void {\n this.releaseProbe()\n this.failures += 1\n this.successes = 0\n if (this.state === 'half_open' || immediate || this.failures >= this.config.failureThreshold) {\n this.transitionOpen(now)\n }\n }\n\n /** Drop the HalfOpen permit without changing health (cancel / abandon). */\n releaseProbe(): void {\n this.halfOpenPermit = 0\n }\n\n private maybeHalfOpen(now: number): void {\n if (this.state !== 'open' || this.openedAt === null) return\n if (now - this.openedAt < this.config.timeoutMs) return\n this.state = 'half_open'\n this.successes = 0\n this.halfOpenPermit = 0\n }\n\n private transitionOpen(now: number): void {\n this.state = 'open'\n this.openedAt = now\n this.successes = 0\n this.halfOpenPermit = 0\n }\n\n private transitionClosed(): void {\n this.state = 'closed'\n this.failures = 0\n this.successes = 0\n this.openedAt = null\n this.halfOpenPermit = 0\n }\n}\n\n/** Per-route breaker map. Missing keys start Closed. */\nexport class CircuitBank {\n private readonly breakers = new Map<string, CircuitBreaker>()\n\n /**\n * @param config - shared knobs for every route.\n */\n constructor(private readonly config: CircuitConfig) {}\n\n /**\n * Breaker for one provider+model pair.\n * @param key - {@link routeKey}.\n */\n get(key: string): CircuitBreaker {\n const existing = this.breakers.get(key)\n if (existing !== undefined) return existing\n const created = new CircuitBreaker(this.config)\n this.breakers.set(key, created)\n return created\n }\n\n /**\n * Badge rows for the live queue. Touches `isAvailable` so Open can show\n * HalfOpen after the wait without consuming a permit.\n * @param queue - ordered routes.\n * @param now - epoch ms.\n */\n health(queue: readonly QueueRoute[], now: number): CircuitHealth[] {\n return queue.map((route) => {\n const breaker = this.get(routeKey(route))\n breaker.isAvailable(now)\n const snap = breaker.snapshot()\n return {\n provider: route.provider,\n model: route.model,\n state: snap.state,\n failures: snap.failures,\n }\n })\n }\n}\n\n/**\n * First Closed route, else first HalfOpen with a free permit. Never sticky.\n * @param queue - P1…Pn.\n * @param bank - per-route breakers.\n * @param now - epoch ms.\n * @param skip - route key to ignore (the attempt that just failed).\n */\nexport function pickFirstAvailable(\n queue: readonly QueueRoute[],\n bank: CircuitBank,\n now: number,\n skip?: string,\n): CircuitPick | undefined {\n for (let index = 0; index < queue.length; index += 1) {\n const route = queue[index]\n if (route === undefined) continue\n const key = routeKey(route)\n if (skip !== undefined && key === skip) continue\n const breaker = bank.get(key)\n if (!breaker.isAvailable(now)) continue\n const probe = breaker.allowProbe(now)\n if (!probe.allowed) continue\n return { index, route, halfOpen: probe.halfOpen }\n }\n return undefined\n}\n\n/**\n * Queue index of the first available route, without consuming a probe permit.\n * @param queue - P1…Pn.\n * @param bank - per-route breakers.\n * @param now - epoch ms.\n * @param skip - route key to ignore.\n */\nexport function firstAvailableIndex(\n queue: readonly QueueRoute[],\n bank: CircuitBank,\n now: number,\n skip?: string,\n): number | undefined {\n for (let index = 0; index < queue.length; index += 1) {\n const route = queue[index]\n if (route === undefined) continue\n const key = routeKey(route)\n if (skip !== undefined && key === skip) continue\n if (bank.get(key).isAvailable(now)) return index\n }\n return undefined\n}\n\n/**\n * Badge tone for one queue row.\n * @param health - host snapshot for this route, if any.\n */\nexport function circuitTone(health: CircuitHealth | undefined): 'ok' | 'probe' | 'open' {\n if (health === undefined) return 'ok'\n if (health.state === 'open') return 'open'\n if (health.state === 'half_open') return 'probe'\n return health.failures > 0 ? 'probe' : 'ok'\n}\n\n/**\n * Match a queue route to a health row.\n * @param route - queue slot.\n * @param circuits - host snapshot.\n */\nexport function healthFor(\n route: QueueRoute,\n circuits: readonly CircuitHealth[],\n): CircuitHealth | undefined {\n return circuits.find(row => row.provider === route.provider && row.model === route.model)\n}\n","/** Class names shared between the injected DOM and the stylesheet. */\nexport const CLASS = {\n chip: 'dsh-fq-chip',\n chipOn: 'dsh-fq-chip-on',\n chipKicker: 'dsh-fq-chip-kicker',\n chipPriority: 'dsh-fq-chip-priority',\n chipRoute: 'dsh-fq-chip-route',\n page: 'dsh-fq-page',\n pageIntro: 'dsh-fq-page-intro',\n panel: 'dsh-fq-panel',\n panelPage: 'dsh-fq-panel-page',\n head: 'dsh-fq-head',\n title: 'dsh-fq-title',\n switchRow: 'dsh-fq-switch-row',\n switchCopy: 'dsh-fq-switch-copy',\n hint: 'dsh-fq-hint',\n list: 'dsh-fq-list',\n row: 'dsh-fq-row',\n rowActive: 'dsh-fq-row-active',\n handle: 'dsh-fq-handle',\n health: 'dsh-fq-health',\n healthOk: 'dsh-fq-health-ok',\n healthProbe: 'dsh-fq-health-probe',\n healthOpen: 'dsh-fq-health-open',\n badge: 'dsh-fq-badge',\n meta: 'dsh-fq-meta',\n name: 'dsh-fq-name',\n sub: 'dsh-fq-sub',\n remove: 'dsh-fq-remove',\n picker: 'dsh-fq-picker',\n pickerBtn: 'dsh-fq-picker-btn',\n menu: 'dsh-fq-menu',\n search: 'dsh-fq-search',\n catalog: 'dsh-fq-catalog',\n catalogItem: 'dsh-fq-catalog-item',\n catalogProvider: 'dsh-fq-catalog-provider',\n chevron: 'dsh-fq-chevron',\n back: 'dsh-fq-back',\n empty: 'dsh-fq-empty',\n toggle: 'dsh-fq-toggle',\n toggleOn: 'dsh-fq-toggle-on',\n toggleThumb: 'dsh-fq-toggle-thumb',\n} as const\n\n/** One injected stylesheet scoped under `.dsh-fq-*`. */\nexport const STYLE = `\n.dsh-fq-chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n max-width: min(280px, 42vw);\n height: 22px;\n padding: 0 8px;\n border: 0;\n border-radius: 6px;\n background: var(--dsw-alias-fill-tsp-secondary, rgba(255,255,255,0.06));\n color: var(--dsw-alias-label-secondary, inherit);\n font-size: 12px;\n line-height: 22px;\n font-weight: 500;\n letter-spacing: 0.01em;\n cursor: pointer;\n overflow: hidden;\n white-space: nowrap;\n}\n.dsh-fq-chip:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.10));\n}\n.dsh-fq-chip-on {\n background: color-mix(in srgb, var(--dsw-alias-label-accent, #34d399) 16%, transparent);\n color: var(--dsw-alias-label-accent, #34d399);\n}\n.dsh-fq-chip-kicker {\n flex-shrink: 0;\n font-weight: 600;\n}\n.dsh-fq-chip-priority {\n flex-shrink: 0;\n font-weight: 700;\n}\n.dsh-fq-chip-route {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-fq-panel {\n position: relative;\n z-index: auto;\n width: 320px;\n max-height: min(420px, calc(100vh - 16px));\n overflow: auto;\n padding: 12px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12));\n border-radius: 12px;\n background: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3, #1c1c1e));\n box-shadow: var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.35));\n color: var(--dsw-alias-label-primary, inherit);\n font-size: 13px;\n line-height: 18px;\n}\n.dsh-fq-page {\n max-width: 560px;\n padding: 4px 0 24px;\n}\n.dsh-fq-page-intro {\n margin: 0 0 12px;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 13px;\n line-height: 18px;\n}\n.dsh-fq-page .dsh-fq-panel,\n.dsh-fq-panel.dsh-fq-panel-page {\n position: static;\n z-index: auto;\n width: auto;\n max-height: none;\n overflow: visible;\n box-shadow: none;\n}\n.dsh-fq-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin-bottom: 8px;\n}\n.dsh-fq-title {\n font-size: 14px;\n font-weight: 600;\n}\n.dsh-fq-switch-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 8px;\n}\n.dsh-fq-switch-copy {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n.dsh-fq-switch-copy small {\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 11px;\n}\n.dsh-fq-hint, .dsh-fq-empty {\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 12px;\n margin: 0 0 8px;\n}\n.dsh-fq-list {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0 0 8px;\n padding: 0;\n list-style: none;\n}\n.dsh-fq-row {\n display: grid;\n grid-template-columns: 16px 8px 32px minmax(0, 1fr) 28px;\n align-items: center;\n gap: 6px;\n padding: 6px 8px;\n border-radius: 8px;\n background: var(--dsw-alias-fill-tsp-secondary, rgba(255,255,255,0.04));\n cursor: pointer;\n}\n.dsh-fq-row:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.08));\n}\n.dsh-fq-row-active {\n outline: 1px solid color-mix(in srgb, var(--dsw-alias-label-accent, #34d399) 50%, transparent);\n}\n.dsh-fq-handle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n cursor: grab;\n}\n.dsh-fq-handle:active { cursor: grabbing; }\n.dsh-fq-health {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n justify-self: center;\n}\n.dsh-fq-health-ok { background: #34d399; }\n.dsh-fq-health-probe { background: #fbbf24; }\n.dsh-fq-health-open { background: #f87171; }\n.dsh-fq-badge {\n font-size: 11px;\n font-weight: 700;\n color: var(--dsw-alias-label-accent, #34d399);\n}\n.dsh-fq-meta {\n min-width: 0;\n display: flex;\n flex-direction: column;\n}\n.dsh-fq-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 500;\n}\n.dsh-fq-sub {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 11px;\n}\n.dsh-fq-remove {\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n cursor: pointer;\n border-radius: 6px;\n height: 24px;\n padding: 0 6px;\n}\n.dsh-fq-remove:hover {\n color: var(--dsw-alias-label-primary, inherit);\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.08));\n}\n.dsh-fq-picker {\n position: relative;\n margin-top: 8px;\n}\n.dsh-fq-picker-btn {\n width: 100%;\n height: 28px;\n padding: 0 8px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12));\n background: var(--dsw-alias-bg-layer-2, #141416);\n color: var(--dsw-alias-label-primary, #f5f5f7);\n font-size: 12px;\n text-align: left;\n cursor: pointer;\n}\n.dsh-fq-picker-btn:disabled {\n cursor: default;\n opacity: 0.65;\n}\n.dsh-fq-menu {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px;\n overflow: hidden;\n border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12));\n border-radius: 8px;\n background: var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3, #1c1c1e));\n box-shadow: var(--dsw-shadow-lv3, 0 12px 40px rgba(0,0,0,0.45));\n color: var(--dsw-alias-label-primary, #f5f5f7);\n box-sizing: border-box;\n}\n.dsh-fq-search {\n width: 100%;\n box-sizing: border-box;\n flex-shrink: 0;\n height: 28px;\n border-radius: 6px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(255,255,255,0.12));\n background: var(--dsw-alias-bg-layer-2, #141416);\n color: var(--dsw-alias-label-primary, #f5f5f7);\n font-size: 12px;\n padding: 0 8px;\n}\n.dsh-fq-search::placeholder {\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n}\n.dsh-fq-catalog {\n display: flex;\n flex-direction: column;\n flex: 1;\n margin: 0;\n padding: 0;\n list-style: none;\n min-height: 0;\n overflow: auto;\n}\n.dsh-fq-catalog-item {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 1px;\n width: 100%;\n margin: 0;\n padding: 5px 10px;\n border: 0;\n background: transparent;\n color: var(--dsw-alias-label-primary, #f5f5f7);\n text-align: left;\n cursor: pointer;\n}\n.dsh-fq-catalog-item:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.08));\n}\n.dsh-fq-catalog-item:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.dsh-fq-catalog-provider {\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n}\n.dsh-fq-chevron {\n flex-shrink: 0;\n color: var(--dsw-alias-label-tertiary, #8e8e93);\n font-size: 16px;\n line-height: 1;\n}\n.dsh-fq-back {\n flex-shrink: 0;\n align-self: flex-start;\n height: 24px;\n padding: 0 6px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary, #d1d1d6);\n font-size: 12px;\n cursor: pointer;\n}\n.dsh-fq-back:hover {\n background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,0.08));\n color: var(--dsw-alias-label-primary, #f5f5f7);\n}\n.dsh-fq-toggle {\n position: relative;\n width: 36px;\n height: 20px;\n flex-shrink: 0;\n border: 0;\n border-radius: 10px;\n background: var(--dsw-alias-fill-tsp-secondary, rgba(255,255,255,0.18));\n cursor: pointer;\n padding: 0;\n}\n.dsh-fq-toggle-on {\n background: var(--dsw-alias-label-accent, #34d399);\n}\n.dsh-fq-toggle-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: #fff;\n transition: transform 120ms ease;\n}\n.dsh-fq-toggle-on .dsh-fq-toggle-thumb {\n transform: translateX(16px);\n}\n`\n","import { useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type DragEvent, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\nimport { groupCandidatesByProvider } from '../candidates.ts'\nimport { circuitTone, healthFor } from '../circuit.ts'\nimport { clampIndex, indexAfterReorder, reorderQueue, routeDisplay, routeKey } from '../queue.ts'\nimport type { FailoverCandidate } from '../types.ts'\nimport type { FailoverKey } from './locales.ts'\nimport { CLASS } from './styles.ts'\nimport type { FailoverSnapshot, QueueRoute } from './state.ts'\n\n/** Writes the panel issues against the host settings document. */\nexport interface QueuePanelApi {\n setEnabled(enabled: boolean): Promise<void>\n setQueue(queue: readonly QueueRoute[], currentIndex: number): Promise<void>\n}\n\nexport interface QueuePanelProps {\n readonly state: FailoverSnapshot\n readonly api: QueuePanelApi\n readonly t: (key: FailoverKey, params?: Record<string, string | number>) => string\n readonly onClose?: () => void\n /** In-flow settings page; skip the composer popover's fixed positioning. */\n readonly embedded?: boolean\n}\n\nfunction candidateMatches(row: FailoverCandidate, query: string): boolean {\n const needle = query.trim().toLowerCase()\n if (needle === '') return true\n return [row.provider, row.providerName, row.model, row.name].some(part => part.toLowerCase().includes(needle))\n}\n\n/**\n * Drag-reorder P1/P2/P3 list plus the auto-failover switch.\n * @param props - live snapshot, settings writes, locale.\n */\nexport function QueuePanel({ state, api, t, onClose, embedded = false }: QueuePanelProps): ReactNode {\n const [pending, setPending] = useState(false)\n const [query, setQuery] = useState('')\n const [menuOpen, setMenuOpen] = useState(false)\n const [selectedProvider, setSelectedProvider] = useState<string | null>(null)\n const pickerRef = useRef<HTMLDivElement | null>(null)\n const menuRef = useRef<HTMLDivElement | null>(null)\n const [menuPos, setMenuPos] = useState<CSSProperties | null>(null)\n const available = useMemo(() => {\n const taken = new Set(state.queue.map(routeKey))\n return state.candidates.filter(row => !taken.has(routeKey({\n provider: row.provider,\n model: row.model,\n })))\n }, [state.candidates, state.queue])\n const groups = useMemo(() => groupCandidatesByProvider(available), [available])\n const needle = query.trim().toLowerCase()\n const visibleGroups = useMemo(() => {\n if (needle === '') return groups\n return groups.filter(group => (\n group.provider.toLowerCase().includes(needle)\n || group.providerName.toLowerCase().includes(needle)\n || group.models.some(row => candidateMatches(row, query))\n ))\n }, [groups, needle, query])\n const selectedGroup = selectedProvider === null\n ? undefined\n : groups.find(group => group.provider === selectedProvider)\n const visibleModels = useMemo(() => {\n if (selectedGroup === undefined) return []\n if (needle === '') return [...selectedGroup.models]\n return selectedGroup.models.filter(row => candidateMatches(row, query))\n }, [selectedGroup, needle, query])\n\n const closeMenu = (): void => {\n setMenuOpen(false)\n setSelectedProvider(null)\n setQuery('')\n }\n\n useEffect(() => {\n if (!menuOpen) return\n const onDoc = (event: MouseEvent): void => {\n const target = event.target as Node\n if (pickerRef.current?.contains(target) === true) return\n if (menuRef.current?.contains(target) === true) return\n closeMenu()\n }\n const onKey = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return\n if (selectedProvider !== null) {\n setSelectedProvider(null)\n return\n }\n closeMenu()\n }\n document.addEventListener('mousedown', onDoc)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', onDoc)\n document.removeEventListener('keydown', onKey)\n }\n }, [menuOpen, selectedProvider])\n\n useLayoutEffect(() => {\n if (!menuOpen) {\n setMenuPos(null)\n return\n }\n const place = (): void => {\n const trigger = pickerRef.current\n if (trigger === null) return\n const rect = trigger.getBoundingClientRect()\n const width = Math.max(rect.width, 280)\n const maxHeight = Math.min(320, Math.floor(window.innerHeight * 0.5))\n const roomAbove = rect.top - 8\n const roomBelow = window.innerHeight - rect.bottom - 8\n const openUp = roomAbove >= 160 || roomAbove >= roomBelow\n const top = openUp\n ? Math.max(8, rect.top - 6 - maxHeight)\n : Math.min(rect.bottom + 6, window.innerHeight - maxHeight - 8)\n setMenuPos({\n position: 'fixed',\n left: Math.min(rect.left, window.innerWidth - width - 8),\n width,\n top,\n maxHeight,\n zIndex: 2100,\n })\n }\n place()\n window.addEventListener('resize', place)\n window.addEventListener('scroll', place, true)\n return () => {\n window.removeEventListener('resize', place)\n window.removeEventListener('scroll', place, true)\n }\n }, [menuOpen, selectedProvider, visibleGroups.length, visibleModels.length, query])\n\n const run = (work: () => Promise<void>): void => {\n if (pending) return\n setPending(true)\n void work().finally(() => { setPending(false) })\n }\n\n const onDrop = (to: number, event: DragEvent<HTMLLIElement>): void => {\n event.preventDefault()\n const from = Number(event.dataTransfer.getData('text/plain'))\n if (!Number.isInteger(from) || from === to) return\n const queue = reorderQueue(state.queue, from, to)\n const currentIndex = indexAfterReorder(state.currentIndex, from, to)\n run(() => api.setQueue(queue, currentIndex))\n }\n\n const addCandidate = (row: FailoverCandidate): void => {\n const route: QueueRoute = {\n provider: row.provider,\n model: row.model,\n label: row.name,\n }\n closeMenu()\n run(() => api.setQueue([...state.queue, route], state.currentIndex))\n }\n\n const pickerLabel = !state.candidatesLoaded\n ? t('panel.add.loading')\n : groups.length === 0\n ? t('panel.add.none')\n : t('panel.add.placeholderCount', { count: groups.length })\n\n const emptyMenu = selectedProvider === null\n ? visibleGroups.length === 0\n : visibleModels.length === 0\n\n return (\n <div\n className={embedded ? `${CLASS.panel} ${CLASS.panelPage}` : CLASS.panel}\n role={embedded ? 'region' : 'dialog'}\n aria-label={t('panel.title')}\n >\n <div className={CLASS.head}>\n <div className={CLASS.title}>{t('panel.title')}</div>\n {onClose === undefined ? null : (\n <button type=\"button\" className={CLASS.remove} onClick={onClose}>{t('panel.close')}</button>\n )}\n </div>\n <div className={CLASS.switchRow}>\n <div className={CLASS.switchCopy}>\n <span>{t('panel.switch')}</span>\n <small>{state.enabled ? t('panel.switch.on') : t('panel.switch.off')}</small>\n </div>\n <button\n type=\"button\"\n role=\"switch\"\n className={`${CLASS.toggle}${state.enabled ? ` ${CLASS.toggleOn}` : ''}`}\n aria-checked={state.enabled}\n aria-label={t('panel.switch')}\n disabled={pending}\n onClick={() => { run(() => api.setEnabled(!state.enabled)) }}\n >\n <span className={CLASS.toggleThumb} />\n </button>\n </div>\n <p className={CLASS.hint}>{t('panel.hint')}</p>\n {state.queue.length === 0 ? (\n <p className={CLASS.empty}>{t('panel.empty')}</p>\n ) : (\n <ul className={CLASS.list}>\n {state.queue.map((route, index) => {\n const active = index === clampIndex(state.currentIndex, state.queue.length)\n const display = routeDisplay(route, state.candidates)\n const title = `${display.provider}/${display.model}`\n const tone = circuitTone(healthFor(route, state.circuits ?? []))\n const healthKey = tone === 'ok'\n ? 'panel.health.ok'\n : tone === 'probe' ? 'panel.health.probe' : 'panel.health.open'\n const healthLabel = t(healthKey)\n const healthClass = tone === 'ok'\n ? CLASS.healthOk\n : tone === 'probe' ? CLASS.healthProbe : CLASS.healthOpen\n return (\n <li\n key={routeKey(route)}\n className={`${CLASS.row}${active ? ` ${CLASS.rowActive}` : ''}`}\n onDragOver={(event) => { event.preventDefault() }}\n onDrop={(event) => { onDrop(index, event) }}\n onClick={() => {\n if (index === state.currentIndex) return\n run(() => api.setQueue(state.queue, index))\n }}\n >\n <span\n className={CLASS.handle}\n draggable\n title={t('panel.drag')}\n aria-label={t('panel.drag')}\n onDragStart={(event) => {\n event.dataTransfer.setData('text/plain', String(index))\n event.dataTransfer.effectAllowed = 'move'\n }}\n onClick={(event) => { event.stopPropagation() }}\n >\n ⋮⋮\n </span>\n <span className={`${CLASS.health} ${healthClass}`} title={healthLabel} aria-label={healthLabel} />\n <span className={CLASS.badge}>P{index + 1}</span>\n <span className={CLASS.meta}>\n <span className={CLASS.name}>\n {title}\n {active ? ` · ${t('panel.current')}` : ''}\n </span>\n <span className={CLASS.sub}>{route.provider} / {route.model}</span>\n </span>\n <button\n type=\"button\"\n className={CLASS.remove}\n aria-label={t('panel.remove')}\n onClick={(event) => {\n event.stopPropagation()\n const queue = state.queue.filter((_, item) => item !== index)\n const currentIndex = index < state.currentIndex\n ? state.currentIndex - 1\n : index === state.currentIndex\n ? clampIndex(state.currentIndex, queue.length)\n : state.currentIndex\n run(() => api.setQueue(queue, currentIndex))\n }}\n >\n ×\n </button>\n </li>\n )\n })}\n </ul>\n )}\n <div className={CLASS.picker} ref={pickerRef}>\n <button\n type=\"button\"\n className={CLASS.pickerBtn}\n disabled={pending || !state.candidatesLoaded || groups.length === 0}\n aria-expanded={menuOpen}\n aria-haspopup=\"listbox\"\n aria-label={t('panel.add')}\n onClick={() => {\n if (menuOpen) {\n closeMenu()\n return\n }\n setMenuOpen(true)\n }}\n >\n {pickerLabel}\n </button>\n {menuOpen && state.candidatesLoaded && groups.length > 0 && menuPos !== null\n ? createPortal(\n <div className={CLASS.menu} ref={menuRef} style={menuPos}>\n {selectedProvider === null ? null : (\n <button\n type=\"button\"\n className={CLASS.back}\n onClick={() => { setSelectedProvider(null) }}\n >\n ← {t('panel.add.back')}\n </button>\n )}\n <input\n className={CLASS.search}\n value={query}\n autoFocus\n disabled={pending}\n placeholder={selectedProvider === null ? t('panel.add.searchProvider') : t('panel.add.searchModel')}\n aria-label={selectedProvider === null ? t('panel.add.searchProvider') : t('panel.add.searchModel')}\n onChange={(event) => { setQuery(event.target.value) }}\n />\n {emptyMenu ? (\n <p className={CLASS.empty}>{t('panel.add.nomatch')}</p>\n ) : selectedProvider === null ? (\n <ul className={CLASS.catalog} role=\"listbox\" aria-label={t('panel.add')}>\n {visibleGroups.map((group) => (\n <li key={group.provider}>\n <button\n type=\"button\"\n className={`${CLASS.catalogItem} ${CLASS.catalogProvider}`}\n disabled={pending}\n aria-label={`${group.providerName}, ${t('panel.add.modelCount', { count: group.models.length })}`}\n onClick={() => { setSelectedProvider(group.provider) }}\n >\n <span className={CLASS.meta}>\n <span className={CLASS.name}>{group.providerName}</span>\n <span className={CLASS.sub}>{group.provider} · {t('panel.add.modelCount', { count: group.models.length })}</span>\n </span>\n <span className={CLASS.chevron} aria-hidden=\"true\">›</span>\n </button>\n </li>\n ))}\n </ul>\n ) : (\n <ul className={CLASS.catalog} role=\"listbox\" aria-label={selectedGroup?.providerName ?? t('panel.add')}>\n {visibleModels.map((row) => (\n <li key={routeKey({ provider: row.provider, model: row.model })}>\n <button\n type=\"button\"\n className={CLASS.catalogItem}\n role=\"option\"\n disabled={pending}\n aria-label={`${t('panel.add')}: ${row.name}`}\n onClick={() => { addCandidate(row) }}\n >\n <span className={CLASS.name}>{row.name}</span>\n <span className={CLASS.sub}>{row.model}</span>\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>,\n document.body,\n )\n : null}\n </div>\n </div>\n )\n}\n","import { useEffect, useLayoutEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport { createPortal } from 'react-dom'\nimport { clampIndex, routeDisplay } from '../queue.ts'\nimport type { FailoverKey } from './locales.ts'\nimport { placeComposerPanel } from './place.ts'\nimport { QueuePanel, type QueuePanelApi } from './QueuePanel.tsx'\nimport { CLASS } from './styles.ts'\nimport type { FailoverSnapshot } from './state.ts'\n\ntype Translate = (key: FailoverKey, params?: Record<string, string | number>) => string\n\n/** Registration-side face plus the renderer-bound snapshot hook. */\nexport interface FailoverChipInjected {\n /** Slot renderer binds `hooks.failover` as a selector hook, not a zero-arg reader. */\n useFailover: <S>(selector: (snapshot: FailoverSnapshot) => S) => S\n api: QueuePanelApi\n loadCandidates: (sessionId: string) => Promise<void>\n getSessionId?: () => string\n}\n\nexport interface FailoverChipProps extends FailoverChipInjected {\n sessionId?: string\n t: Translate\n}\n\nfunction sessionOf(props: FailoverChipProps): string {\n return props.sessionId ?? props.getSessionId?.() ?? ''\n}\n\nfunction chipCopy(state: FailoverSnapshot, t: Translate): {\n title: string\n aria: string\n slot: number | undefined\n route: string | undefined\n} {\n if (!state.enabled) {\n return { title: t('chip.title.off'), aria: t('chip.aria.off'), slot: undefined, route: undefined }\n }\n if (state.queue.length === 0) {\n return {\n title: t('chip.empty'),\n aria: t('chip.empty'),\n slot: undefined,\n route: t('chip.empty'),\n }\n }\n const slot = clampIndex(state.currentIndex, state.queue.length) + 1\n const current = state.queue[slot - 1]\n if (current === undefined) {\n return {\n title: t('chip.empty'),\n aria: t('chip.empty'),\n slot: undefined,\n route: t('chip.empty'),\n }\n }\n const display = routeDisplay(current, state.candidates)\n const params = { slot, provider: display.provider, model: display.model }\n return {\n title: t('chip.on', params),\n aria: t('chip.aria.on', params),\n slot,\n route: `${display.provider}/${display.model}`,\n }\n}\n\n/**\n * Composer chip: shows failover status and opens the drag panel.\n * @param props - composed slot props.\n */\nexport function FailoverChip(props: FailoverChipProps): ReactNode {\n const { useFailover, api, loadCandidates, t } = props\n const state = useFailover(snapshot => snapshot)\n const sessionId = sessionOf(props)\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const panelRef = useRef<HTMLDivElement | null>(null)\n const [pos, setPos] = useState<CSSProperties | null>(null)\n const copy = chipCopy(state, t)\n\n useEffect(() => {\n void loadCandidates(sessionId)\n }, [loadCandidates, sessionId])\n\n useLayoutEffect(() => {\n if (!open) return\n const place = (): void => {\n const trigger = rootRef.current\n const panel = panelRef.current\n if (trigger === null || panel === null) return\n const rect = trigger.getBoundingClientRect()\n const placed = placeComposerPanel({\n trigger: rect,\n width: panel.offsetWidth,\n height: panel.offsetHeight,\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n })\n setPos({\n left: placed.left,\n top: placed.top,\n maxHeight: placed.maxHeight,\n })\n }\n place()\n const observer = new ResizeObserver(place)\n if (panelRef.current !== null) observer.observe(panelRef.current)\n window.addEventListener('resize', place)\n window.addEventListener('scroll', place, true)\n return () => {\n observer.disconnect()\n window.removeEventListener('resize', place)\n window.removeEventListener('scroll', place, true)\n }\n }, [open, state.queue.length, state.enabled, copy.route])\n\n useEffect(() => {\n if (!open) return\n const close = (event: MouseEvent): void => {\n const target = event.target\n if (!(target instanceof Node)) return\n if (rootRef.current?.contains(target) === true) return\n if (panelRef.current?.contains(target) === true) return\n if (target instanceof Element && target.closest('.dsh-fq-menu') !== null) return\n setOpen(false)\n }\n const onKey = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') setOpen(false)\n }\n document.addEventListener('mousedown', close)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', close)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n return (\n <div ref={rootRef}>\n <button\n type=\"button\"\n className={`${CLASS.chip}${state.enabled ? ` ${CLASS.chipOn}` : ''}`}\n aria-pressed={state.enabled}\n aria-expanded={open}\n aria-label={copy.aria}\n title={copy.title}\n onMouseDown={(event) => { event.preventDefault() }}\n onClick={() => { setOpen(value => !value) }}\n >\n <span className={CLASS.chipKicker}>{t('chip.kicker')}</span>\n {copy.slot === undefined\n ? <span className={CLASS.chipRoute}>{copy.route ?? t('chip.off')}</span>\n : (\n <>\n <span className={CLASS.chipPriority}>P{copy.slot}</span>\n <span className={CLASS.chipRoute}>{copy.route}</span>\n </>\n )}\n </button>\n {open && createPortal(\n <div ref={panelRef} style={{ ...pos, position: 'fixed', zIndex: 2000, overflow: 'auto' }}>\n <QueuePanel state={state} api={api} t={t} onClose={() => { setOpen(false) }} />\n </div>,\n document.body,\n )}\n </div>\n )\n}\n\n/**\n * Settings left-nav page: the same queue editor, in document flow.\n * @param props - composed slot props.\n */\nexport function FailoverSettingsCard(props: FailoverChipProps): ReactNode {\n const { useFailover, api, loadCandidates, t } = props\n const state = useFailover(snapshot => snapshot)\n const sessionId = sessionOf(props)\n useEffect(() => {\n void loadCandidates(sessionId)\n }, [loadCandidates, sessionId])\n return (\n <div className={CLASS.page}>\n <p className={CLASS.pageIntro}>{t('settings.intro')}</p>\n <QueuePanel state={state} api={api} t={t} embedded />\n </div>\n )\n}\n","/** Locale bundles for the failover chip and drag panel. */\nexport const NS = 'failover' as const\n\n/** Keys owned by this dictionary. */\nexport type FailoverKey =\n | 'chip.kicker'\n | 'chip.off'\n | 'chip.empty'\n | 'chip.on'\n | 'chip.aria.on'\n | 'chip.aria.off'\n | 'chip.title.off'\n | 'panel.title'\n | 'panel.switch'\n | 'panel.switch.on'\n | 'panel.switch.off'\n | 'panel.empty'\n | 'panel.add'\n | 'panel.add.placeholderCount'\n | 'panel.add.searchProvider'\n | 'panel.add.searchModel'\n | 'panel.add.back'\n | 'panel.add.modelCount'\n | 'panel.add.loading'\n | 'panel.add.none'\n | 'panel.add.nomatch'\n | 'panel.remove'\n | 'panel.drag'\n | 'panel.current'\n | 'panel.close'\n | 'panel.hint'\n | 'panel.health.ok'\n | 'panel.health.probe'\n | 'panel.health.open'\n | 'settings.tab'\n | 'settings.intro'\n\nexport const zh: Record<FailoverKey, string> = {\n 'chip.kicker': '故障转移:',\n 'chip.off': '关',\n 'chip.empty': '无队列',\n 'chip.on': '故障转移:P{slot} {provider}/{model}',\n 'chip.aria.on': '故障转移已开启,当前 P{slot} {provider}/{model},点击打开队列',\n 'chip.aria.off': '故障转移已关闭,点击打开队列',\n 'chip.title.off': '自动故障转移关闭。点进去开启并编排队列。',\n 'panel.title': '故障转移队列',\n 'panel.switch': '自动故障转移',\n 'panel.switch.on': '失败按 P1 → P2 → P3 切换;P1 恢复后探活切回',\n 'panel.switch.off': '只用当前会话模型,不跨路由',\n 'panel.empty': '队列是空的。从下面点一条路由,P1 就是主供应商。',\n 'panel.add': '加入队列',\n 'panel.add.placeholderCount': '选择供应商({count})',\n 'panel.add.searchProvider': '搜索供应商…',\n 'panel.add.searchModel': '搜索模型…',\n 'panel.add.back': '返回供应商',\n 'panel.add.modelCount': '{count} 个模型',\n 'panel.add.loading': '正在读取已配置的模型…',\n 'panel.add.none': '没有可加的路由。先在「模型」里配供应商。',\n 'panel.add.nomatch': '没有匹配的路由。',\n 'panel.remove': '移除',\n 'panel.drag': '拖动改优先级',\n 'panel.current': '当前',\n 'panel.close': '关闭',\n 'panel.hint': '拖动左侧手柄调整 P1/P2/P3。失败切下一档;P1 恢复后会探活切回,不会粘在 P2。',\n 'panel.health.ok': '健康',\n 'panel.health.probe': '探活中',\n 'panel.health.open': '已熔断',\n 'settings.tab': '故障转移',\n 'settings.intro': '编排 P1 / P2 / P3。开启后请求优先 P1;失败熔断后切备用档,P1 恢复后探活切回。',\n}\n\nexport const en: Record<FailoverKey, string> = {\n 'chip.kicker': 'Failover: ',\n 'chip.off': 'Off',\n 'chip.empty': 'empty',\n 'chip.on': 'Failover: P{slot} {provider}/{model}',\n 'chip.aria.on': 'Failover on, current P{slot} {provider}/{model}, click to open the queue',\n 'chip.aria.off': 'Failover off, click to open the queue',\n 'chip.title.off': 'Auto failover is off. Click to enable and edit the queue.',\n 'panel.title': 'Failover queue',\n 'panel.switch': 'Auto failover',\n 'panel.switch.on': 'On failure, switch P1 → P2 → P3; recovered P1 is probed again',\n 'panel.switch.off': 'Use the session model only',\n 'panel.empty': 'Queue is empty. Click a route below. P1 is the primary.',\n 'panel.add': 'Add to queue',\n 'panel.add.placeholderCount': 'Pick a provider ({count})',\n 'panel.add.searchProvider': 'Search providers…',\n 'panel.add.searchModel': 'Search models…',\n 'panel.add.back': 'Back to providers',\n 'panel.add.modelCount': '{count} models',\n 'panel.add.loading': 'Loading configured models…',\n 'panel.add.none': 'No routes to add. Configure a provider under Models first.',\n 'panel.add.nomatch': 'No matching routes.',\n 'panel.remove': 'Remove',\n 'panel.drag': 'Drag to reorder',\n 'panel.current': 'current',\n 'panel.close': 'Close',\n 'panel.hint': 'Drag the handle to change P1/P2/P3. Failover is not sticky: P1 is probed again after it recovers.',\n 'panel.health.ok': 'healthy',\n 'panel.health.probe': 'probing',\n 'panel.health.open': 'open',\n 'settings.tab': 'Failover',\n 'settings.intro': 'Arrange P1 / P2 / P3. While on, requests prefer P1. A recovered P1 is probed and selected again.',\n}\n","/** String/symbol keyed dictionary type. */\nexport type Dict<T = any, K extends string | symbol = string> = { [key in K]: T }\n/** Safely read `T[K]`, returning `never` when `K` is not a key of `T`. */\nexport type Get<T extends {}, K> = K extends keyof T ? T[K] : never\n/** Conditional extraction helper with a configurable return type. */\nexport type Extract<S, T, U = S> = S extends T ? U : never\n/** Accept a value or an array, unless the value is already an array type. */\nexport type MaybeArray<T> = [T] extends [unknown[]] ? T : T | T[]\n/** Wrap a value in `Promise`, preserving the resolved type of existing promises. */\nexport type Promisify<T> = Promise<T extends Promise<infer S> ? S : T>\n/** Accept a value or promise unless the value type is already promise-like. */\nexport type Awaitable<T> = [T] extends [Promise<unknown>] ? T : T | Promise<T>\n/** Convert a union type to an intersection type. */\nexport type Intersect<U> = (U extends any ? (arg: U) => void : never) extends ((arg: infer I) => void) ? I : never\n\n/** No-op callback returning `undefined` at runtime and `any` at type level. */\nexport function noop(): any {}\n\n/** Return true when a value is `null` or `undefined`. */\nexport function isNullable(value: any): value is null | undefined | void {\n return value === null || value === undefined\n}\n\n/** Return true when a value is neither `null` nor `undefined`. */\nexport function isNonNullable<T>(value: T): value is NonNullable<T> {\n return !isNullable(value)\n}\n\n/** Return true for non-array object values. */\nexport function isPlainObject(data: any) {\n return data && typeof data === 'object' && !Array.isArray(data)\n}\n\n/** Filter object entries with a key type guard. */\nexport function filterKeys<T, K extends string, U extends K>(object: Dict<T, K>, filter: (key: K, value: T) => key is U): Dict<T, U>\n/** Filter object entries with a boolean predicate. */\nexport function filterKeys<T, K extends string>(object: Dict<T, K>, filter: (key: K, value: T) => boolean): Dict<T, K>\n/** Filter object entries and return a new object. */\nexport function filterKeys(object: {}, filter: (key: string, value: any) => boolean) {\n return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value)))\n}\n\n/** Map object values while preserving the original key set. */\nexport function mapValues<U, T, K extends string>(object: Dict<T, K>, transform: (value: T, key: K) => U) {\n return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, (transform as any)(value, key)])) as Dict<U, K>\n}\n\n/** Alias for `mapValues`. */\nexport { mapValues as valueMap }\n\n/** Pick selected keys from an object, optionally including `undefined` values. */\nexport function pick<T extends object, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean) {\n if (!keys) return { ...source }\n const result = {} as Pick<T, K>\n for (const key of keys) {\n if (forced || source[key] !== undefined) result[key] = source[key]\n }\n return result\n}\n\n/** Omit selected keys from a shallow object copy. */\nexport function omit<T, K extends keyof T>(source: T, keys?: Iterable<K>) {\n if (!keys) return { ...source }\n const result = { ...source } as Omit<T, K>\n for (const key of keys) {\n Reflect.deleteProperty(result, key)\n }\n return result\n}\n\n/** Define a non-enumerable writable property with a typed key. */\nexport function defineProperty<T, K extends keyof T>(object: T, key: K, value: T[K]): T\n/** Define a non-enumerable writable property with an arbitrary key. */\nexport function defineProperty<T, K extends keyof any>(object: T, key: K, value: any): T\n/** Define a non-enumerable writable property and return the object. */\nexport function defineProperty<T, K extends keyof any>(object: T, key: K, value: any) {\n return Object.defineProperty(object, key, { writable: true, value, enumerable: false })\n}\n","import { isNullable } from './misc.ts'\n\ntype GlobalConstructorNames = keyof {\n [K in keyof typeof globalThis as typeof globalThis[K] extends abstract new (...args: any) => any ? K : never]: K\n}\n\n/** Create a predicate for a global constructor name. */\nexport function is<K extends GlobalConstructorNames>(type: K): (value: any) => value is InstanceType<typeof globalThis[K]>\n/** Test whether a value matches a global constructor name. */\nexport function is<K extends GlobalConstructorNames>(type: K, value: any): value is InstanceType<typeof globalThis[K]>\n/** Test values using `instanceof` with a `toStringTag` fallback. */\nexport function is<K extends GlobalConstructorNames>(type: K, value?: any): any {\n if (arguments.length === 1) return (value: any) => is(type, value)\n return type in globalThis && value instanceof (globalThis[type] as any)\n || Object.prototype.toString.call(value).slice(8, -1) === type\n}\n\nfunction isArrayBufferLike(value: any): value is ArrayBufferLike {\n return is('ArrayBuffer', value) || is('SharedArrayBuffer', value)\n}\n\nfunction isArrayBufferSource(value: any): value is Binary.Source {\n return isArrayBufferLike(value) || ArrayBuffer.isView(value)\n}\n\n/** Binary source detection and base64/hex conversion helpers. */\nexport namespace Binary {\n export type Source<T extends ArrayBufferLike = ArrayBufferLike> = T | ArrayBufferView<T>\n\n export const is = isArrayBufferLike\n export const isSource = isArrayBufferSource\n\n export function fromSource<T extends ArrayBufferLike>(source: Source<T>): T {\n if (ArrayBuffer.isView(source)) {\n // https://stackoverflow.com/questions/8609289/convert-a-binary-nodejs-buffer-to-javascript-arraybuffer#answer-31394257\n return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength) as T\n } else {\n return source\n }\n }\n\n export function toBase64(source: Source) {\n source = fromSource(source)\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(source).toString('base64')\n }\n let binary = ''\n const bytes = new Uint8Array(source)\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i])\n }\n return btoa(binary)\n }\n\n export function fromBase64(source: string) {\n if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'base64'))\n return Uint8Array.from(atob(source), c => c.charCodeAt(0))\n }\n\n export function toHex(source: Source) {\n source = fromSource(source)\n if (typeof Buffer !== 'undefined') return Buffer.from(source).toString('hex')\n return Array.from(new Uint8Array(source), byte => byte.toString(16).padStart(2, '0')).join('')\n }\n\n export function fromHex(source: string) {\n if (typeof Buffer !== 'undefined') return fromSource(Buffer.from(source, 'hex'))\n const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1)\n const buffer: number[] = []\n for (let i = 0; i < hex.length; i += 2) {\n buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16))\n }\n return Uint8Array.from(buffer).buffer\n }\n}\n\n/** Decode a base64 string into binary data. */\nexport const base64ToArrayBuffer = Binary.fromBase64\n/** Encode binary data as base64. */\nexport const arrayBufferToBase64 = Binary.toBase64\n/** Decode a hex string into binary data. */\nexport const hexToArrayBuffer = Binary.fromHex\n/** Encode binary data as hex. */\nexport const arrayBufferToHex = Binary.toHex\n\n/** Deep-clone common JavaScript values while preserving prototypes. */\nexport function clone<T>(source: T): T\n/** Deep-clone common JavaScript values while preserving prototypes and cycles. */\nexport function clone(source: any, refs = new Map<any, any>()) {\n if (!source || typeof source !== 'object') return source\n if (is('Date', source)) return new Date(source.valueOf())\n if (is('RegExp', source)) return new RegExp(source.source, source.flags)\n if (isArrayBufferLike(source)) return source.slice(0)\n if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength)\n const cached = refs.get(source)\n if (cached) return cached\n if (Array.isArray(source)) {\n const result: any[] = []\n refs.set(source, result)\n source.forEach((value, index) => {\n result[index] = Reflect.apply(clone, null, [value, refs])\n })\n return result\n }\n const result = Object.create(Object.getPrototypeOf(source))\n refs.set(source, result)\n for (const key of Reflect.ownKeys(source)) {\n const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) }\n if ('value' in descriptor) {\n descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs])\n }\n Reflect.defineProperty(result, key, descriptor)\n }\n return result\n}\n\n/** Deeply compare arrays, dates, regexps, buffers, and plain object fields. */\nexport function deepEqual(a: any, b: any, strict?: boolean): boolean {\n if (a === b) return true\n if (!strict && isNullable(a) && isNullable(b)) return true\n if (typeof a !== typeof b) return false\n if (typeof a !== 'object') return false\n if (!a || !b) return false\n\n function check<T>(test: (x: any) => x is T, then: (a: T, b: T) => boolean) {\n return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : undefined\n }\n\n return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index])))\n ?? check(is('Date'), (a, b) => a.valueOf() === b.valueOf())\n ?? check(is('RegExp'), (a, b) => a.source === b.source && a.flags === b.flags)\n ?? check(isArrayBufferLike, (a, b) => {\n if (a.byteLength !== b.byteLength) return false\n const viewA = new Uint8Array(a)\n const viewB = new Uint8Array(b)\n for (let i = 0; i < viewA.length; i++) {\n if (viewA[i] !== viewB[i]) return false\n }\n return true\n })\n ?? Object.keys({ ...a, ...b }).every(key => deepEqual(a[key], b[key], strict))\n}\n","/** Time constants plus parsing and formatting helpers. */\nexport namespace Time {\n export const millisecond = 1\n export const second = 1000\n export const minute = second * 60\n export const hour = minute * 60\n export const day = hour * 24\n export const week = day * 7\n\n let timezoneOffset = new Date().getTimezoneOffset()\n\n export function setTimezoneOffset(offset: number) {\n timezoneOffset = offset\n }\n\n export function getTimezoneOffset() {\n return timezoneOffset\n }\n\n export function getDateNumber(date: number | Date = new Date(), offset?: number) {\n if (typeof date === 'number') date = new Date(date)\n if (offset === undefined) offset = timezoneOffset\n return Math.floor((date.valueOf() / minute - offset) / 1440)\n }\n\n export function fromDateNumber(value: number, offset?: number) {\n const date = new Date(value * day)\n if (offset === undefined) offset = timezoneOffset\n return new Date(+date + offset * minute)\n }\n\n const numeric = /\\d+(?:\\.\\d+)?/.source\n const timeRegExp = new RegExp(`^${[\n 'w(?:eek(?:s)?)?',\n 'd(?:ay(?:s)?)?',\n 'h(?:our(?:s)?)?',\n 'm(?:in(?:ute)?(?:s)?)?',\n 's(?:ec(?:ond)?(?:s)?)?',\n ].map(unit => `(${numeric}${unit})?`).join('')}$`)\n\n export function parseTime(source: string) {\n const capture = timeRegExp.exec(source)\n if (!capture) return 0\n return (parseFloat(capture[1]) * week || 0)\n + (parseFloat(capture[2]) * day || 0)\n + (parseFloat(capture[3]) * hour || 0)\n + (parseFloat(capture[4]) * minute || 0)\n + (parseFloat(capture[5]) * second || 0)\n }\n\n export function parseDate(date: string) {\n const parsed = parseTime(date)\n if (parsed) {\n date = Date.now() + parsed as any\n } else if (/^\\d{1,2}(:\\d{1,2}){1,2}$/.test(date)) {\n date = `${new Date().toLocaleDateString()}-${date}`\n } else if (/^\\d{1,2}-\\d{1,2}-\\d{1,2}(:\\d{1,2}){1,2}$/.test(date)) {\n date = `${new Date().getFullYear()}-${date}`\n }\n return date ? new Date(date) : new Date()\n }\n\n export function format(ms: number) {\n const abs = Math.abs(ms)\n if (abs >= day - hour / 2) {\n return Math.round(ms / day) + 'd'\n } else if (abs >= hour - minute / 2) {\n return Math.round(ms / hour) + 'h'\n } else if (abs >= minute - second / 2) {\n return Math.round(ms / minute) + 'm'\n } else if (abs >= second) {\n return Math.round(ms / second) + 's'\n }\n return ms + 'ms'\n }\n\n export function toDigits(source: number, length = 2) {\n return source.toString().padStart(length, '0')\n }\n\n export function template(template: string, time = new Date()) {\n return template\n .replace('yyyy', time.getFullYear().toString())\n .replace('yy', time.getFullYear().toString().slice(2))\n .replace('MM', toDigits(time.getMonth() + 1))\n .replace('dd', toDigits(time.getDate()))\n .replace('hh', toDigits(time.getHours()))\n .replace('mm', toDigits(time.getMinutes()))\n .replace('ss', toDigits(time.getSeconds()))\n .replace('SSS', toDigits(time.getMilliseconds(), 3))\n }\n}\n","import { Binary, clone, deepEqual, filterKeys, isNullable, isPlainObject, pick, valueMap, type Dict } from '@deepseek-ai/cosmokit'\nimport type { StandardSchemaV1 } from '@standard-schema/spec'\n\nconst kSchema = Symbol.for('schemastery')\nconst kValidationError = Symbol.for('ValidationError')\n\ndeclare global {\n namespace Schemastery {\n /** Convert primitive constructors, constants, and existing schemas into a schema type. */\n export type From<X> =\n | X extends string | number | boolean ? Schema<X>\n : X extends Schema ? X\n : X extends typeof String ? Schema<string>\n : X extends typeof Number ? Schema<number>\n : X extends typeof Boolean ? Schema<boolean>\n : X extends typeof Function ? Schema<Function, (...args: any[]) => any>\n : X extends Constructor<infer S> ? Schema<S>\n : never\n\n type TypeS1<X> = X extends Schema<infer S, unknown> ? S : never\n type Inverse<X> = X extends Schema<any, infer Y> ? (arg: Y) => void : never\n\n /** Input type accepted by a schema-like value. */\n export type TypeS<X> = TypeS1<From<X>>\n /** Output type returned by a schema-like value after validation. */\n export type TypeT<X> = ReturnType<From<X>>\n /** Resolver callback used by custom schema types registered with `Schema.extend()`. */\n export type Resolve = (data: any, schema: Schema, options: Options, strict?: boolean) => [any, any?]\n\n /** Input type accepted by one schema in an intersection. */\n export type IntersectS<X> = From<X> extends Schema<infer S, unknown> ? S : never\n /** Output type returned by one schema in an intersection. */\n export type IntersectT<X> = Inverse<From<X>> extends ((arg: infer T) => void) ? T : never\n\n type TupleS<X extends readonly any[]> = X extends readonly [infer L, ...infer R] ? [TypeS<L>?, ...TupleS<R>] : any[]\n type TupleT<X extends readonly any[]> = X extends readonly [infer L, ...infer R] ? [TypeT<L>?, ...TupleT<R>] : any[]\n type ObjectS<X extends Dict> = { [K in keyof X]?: TypeS<X[K]> | null } & Dict\n type ObjectT<X extends Dict> = { [K in keyof X]: TypeT<X[K]> } & Dict\n type Constructor<T = any> = new (...args: any[]) => T\n\n /** Static constructor and factory methods exposed by the default `Schema` export. */\n export interface Static {\n <T = any>(options: Partial<Schema<T>>): Schema<T>\n new <T = any>(options: Partial<Schema<T>>): Schema<T>\n prototype: Schema\n /** Validate a value against a schema node and return `[output, adaptedInput?]`. */\n resolve: Resolve\n /** Infer a schema from a primitive value, constructor, or existing schema. */\n from<X = any>(source?: X): From<X>\n /** Register a resolver for a custom schema `type`. */\n extend(type: string, resolve: Resolve): void\n /** Accept any value without validation. */\n any<T = any>(): Schema<T>\n /** Accept only nullable input. */\n never(): Schema<never>\n /** Accept exactly one constant value. */\n const<const T>(value: T): Schema<T>\n /** Accept strings, with optional metadata constraints added by instance methods. */\n string(): Schema<string>\n /** Accept numbers, with optional range and step constraints. */\n number(): Schema<number>\n /** Accept non-negative integer numbers. */\n natural(): Schema<number>\n /** Accept a number between 0 and 1 and mark it as a slider. */\n percent(): Schema<number>\n /** Accept booleans. */\n boolean(): Schema<boolean>\n /** Accept `Date` instances or parse datetime strings into `Date` objects. */\n date(): Schema<string | Date, Date>\n /** Accept `RegExp` instances or parse strings into regular expressions. */\n regExp(flag?: string): Schema<string | RegExp, RegExp>\n /** Accept binary sources and normalize them to `ArrayBufferLike`. */\n arrayBuffer(): Schema<Binary.Source, ArrayBufferLike>\n arrayBuffer(encoding: 'hex' | 'base64'): Schema<Binary.Source | string, ArrayBufferLike>\n /** Accept a numeric bitset or string keys and normalize to a number. */\n bitset<K extends string>(bits: Partial<Record<K, number>>): Schema<number | readonly K[], number>\n /** Accept functions. */\n function(): Schema<Function, (...args: any[]) => any>\n /** Accept instances of a constructor or objects whose constructor name matches. */\n is(constructor: string): Schema\n is<T>(constructor: Constructor<T>): Schema<T>\n /** Accept arrays whose elements match `inner`. */\n array<X>(inner: X): Schema<TypeS<X>[], TypeT<X>[]>\n /** Accept plain objects with values matching `inner` and optional key schema. */\n dict<X, Y extends Schema<any, string> = Schema<string>>(inner: X, sKey?: Y): Schema<Dict<TypeS<X>, TypeS<Y>>, Dict<TypeT<X>, TypeT<Y>>>\n /** Accept tuple arrays where each index matches the corresponding schema. */\n tuple<const X extends readonly any[]>(list: X): Schema<TupleS<X>, TupleT<X>>\n /** Accept plain objects whose declared properties match the schema dictionary. */\n object<X extends Dict>(dict: X): Schema<ObjectS<X>, ObjectT<X>>\n /** Accept values matching at least one schema in `list`. */\n union<const X>(list: readonly X[]): Schema<TypeS<X>, TypeT<X>>\n /** Accept values matching every schema in `list`, merging object outputs. */\n intersect<const X>(list: readonly X[]): Schema<IntersectS<X>, IntersectT<X>>\n /** Validate with `inner`, then convert the result with `callback`. */\n transform<X, T>(inner: X, callback: (value: TypeS<X>, options: Schemastery.Options) => T, preserve?: boolean): Schema<TypeS<X>, T>\n /** Defer construction of a recursive schema until validation or serialization. */\n lazy<X extends Schema>(callback: () => X): X\n ValidationError: typeof ValidationError\n }\n\n /** Runtime validation options shared by all schema calls. */\n interface Options {\n /** Remove invalid object properties instead of throwing when possible. */\n autofix?: boolean\n /** Skip validation for selected values and schema nodes. */\n ignore?(data: any, schema: Schema): boolean\n /** Path used to format nested validation errors. */\n path?: (keyof any)[]\n }\n\n /** UI and validation metadata attached by schema builder methods. */\n export interface Meta<T = any> {\n default?: T extends {} ? Partial<T> : T\n required?: boolean\n disabled?: boolean\n collapse?: boolean\n badges?: { text: string; type: string }[]\n hidden?: boolean\n loose?: boolean\n role?: string\n extra?: any\n link?: string\n description?: string | Dict<string>\n comment?: string\n pattern?: { source: string; flags?: string }\n max?: number\n min?: number\n step?: number\n }\n }\n\n /** Callable schema instance that validates input and returns normalized output. */\n interface Schemastery<S = any, T = S> {\n (data?: S | null, options?: Schemastery.Options): T\n new (data?: S | null, options?: Schemastery.Options): T\n [kSchema]: true\n uid: number\n meta: Schemastery.Meta<T>\n type: string\n sKey?: Schema\n inner?: Schema\n list?: Schema[]\n dict?: Dict<Schema>\n bits?: Dict<number>\n callback?: Function\n constructor?: string | Function\n builder?: Function\n value?: T\n refs?: Dict<Schema>\n preserve?: boolean\n '~standard': StandardSchemaV1.Props // <S, T>\n /** Format this schema as a compact TypeScript-like type string. */\n toString(inline?: boolean): string\n /** Serialize this schema, preserving shared and recursive references. */\n toJSON(): Schema<S, T>\n /** Mark nullable input as invalid unless a default supplies a fallback. */\n required(value?: boolean): Schema<S, T>\n /** Hide this schema node from UI renderers. */\n hidden(value?: boolean): Schema<S, T>\n /** Return the default value instead of throwing when validation fails. */\n loose(value?: boolean): Schema<S, T>\n /** Attach a renderer role and optional role-specific metadata. */\n role(text: string, extra?: any): Schema<S, T>\n /** Attach an external documentation link. */\n link(link: string): Schema<S, T>\n /** Set the fallback value used for nullable input. */\n default(value: T): Schema<S, T>\n /** Attach an auxiliary comment for documentation or form UIs. */\n comment(text: string): Schema<S, T>\n /** Attach a localized or plain description for documentation or form UIs. */\n description(text: string): Schema<S, T>\n /** Mark this schema node as disabled for form UIs. */\n disabled(value?: boolean): Schema<S, T>\n /** Request collapsed rendering for nested form UIs. */\n collapse(value?: boolean): Schema<S, T>\n /** Add a deprecated badge to this schema node. */\n deprecated(): Schema<S, T>\n /** Add an experimental badge to this schema node. */\n experimental(): Schema<S, T>\n /** Require strings to match a regular expression. */\n pattern(regexp: RegExp): Schema<S, T>\n /** Set an inclusive maximum for numbers or collection lengths. */\n max(value: number): Schema<S, T>\n /** Set an inclusive minimum for numbers or collection lengths. */\n min(value: number): Schema<S, T>\n /** Set the numeric increment constraint. */\n step(value: number): Schema<S, T>\n /** Add or replace an object property schema. */\n set(key: string, value: Schema): Schema<S, T>\n /** Append a tuple, union, or intersection member schema. */\n push(value: Schema): Schema<S, T>\n /** Remove values equal to schema defaults from normalized output. */\n simplify(value?: any): any\n /** Return a schema clone with descriptions merged from locale messages. */\n i18n(messages: Dict): Schema<S, T>\n /** Attach arbitrary metadata consumed by form renderers and downstream tools. */\n extra<K extends keyof Schemastery.Meta>(key: K, value: Schemastery.Meta[K]): Schema<S, T>\n }\n}\n\ndeclare namespace globalThis {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n export let __schemastery_index__: number\n export let __schemastery_refs__: Record<number, Schema> | undefined\n}\n\nglobalThis.__schemastery_index__ ??= 0\nglobalThis.__schemastery_refs__ = undefined\n\nclass ValidationError extends TypeError {\n name = 'ValidationError'\n\n constructor(message: string, public options: Schemastery.Options) {\n let prefix = '$'\n for (const segment of options.path || []) {\n if (typeof segment === 'string') {\n prefix += '.' + segment\n } else if (typeof segment === 'number') {\n prefix += '[' + segment + ']'\n } else if (typeof segment === 'symbol') {\n prefix += `[Symbol(${segment.toString()})]`\n }\n }\n if (prefix.startsWith('.')) prefix = prefix.slice(1)\n super((prefix === '$' ? '' : `${prefix} `) + message)\n }\n\n static is(error: any): error is ValidationError {\n return !!error?.[kValidationError]\n }\n}\n\nObject.defineProperty(ValidationError.prototype, kValidationError, {\n value: true,\n})\n\ntype Schema<S = any, T = S> = Schemastery<S, T>\n\nconst Schema = function (options: Schema) {\n const schema = function (data: any, options: Schemastery.Options = {}) {\n return Schema.resolve(data, schema, options)[0]\n } as Schema\n\n if (options.refs) {\n const refs = valueMap(options.refs, options => new Schema(options))\n const getRef = (uid: any) => refs[uid]!\n for (const key in refs) {\n const options = refs[key]!\n options.sKey = getRef(options.sKey)\n options.inner = getRef(options.inner)\n options.list = options.list && options.list.map(getRef)\n options.dict = options.dict && valueMap(options.dict, getRef)\n }\n return refs[options.uid!]\n }\n\n Object.assign(schema, options)\n if (typeof schema.callback === 'string') {\n try {\n // eslint-disable-next-line no-new-func\n schema.callback = new Function('return ' + schema.callback)()\n } catch {}\n }\n Object.defineProperty(schema, 'uid', { value: globalThis.__schemastery_index__++ })\n Object.setPrototypeOf(schema, Schema.prototype)\n schema.meta ||= {}\n schema.toString = schema.toString.bind(schema)\n return schema\n} as Schemastery.Static\n\nSchema.prototype = Object.create(Function.prototype)\n\nSchema.prototype[kSchema] = true\n\nObject.defineProperty(Schema.prototype, '~standard', {\n get(this: Schema) {\n return {\n version: 1,\n vendor: 'schemastery',\n validate: (value: unknown) => {\n try {\n return { value: Schema.resolve(value, this, {})[0] }\n } catch (error) {\n if (ValidationError.is(error)) {\n return { issues: [{ message: error.message, path: error.options.path }] }\n }\n throw error\n }\n },\n }\n },\n})\n\nSchema.ValidationError = ValidationError\n\nSchema.prototype.toJSON = function toJSON() {\n if (globalThis.__schemastery_refs__) {\n globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this }))\n return this.uid as any\n }\n\n globalThis.__schemastery_refs__ = { [this.uid]: { ...this } as Schema }\n globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this }))\n const result = { uid: this.uid, refs: globalThis.__schemastery_refs__ }\n globalThis.__schemastery_refs__ = undefined\n return result\n}\n\nSchema.prototype.set = function set(key, value) {\n this.dict![key] = value\n return this\n}\n\nSchema.prototype.push = function push(value) {\n this.list!.push(value)\n return this\n}\n\nfunction mergeDesc(original: undefined | string | Dict<string>, messages: Dict) {\n const result: Dict<string> = typeof original === 'string' ? { '': original } : { ...original }\n for (const locale in messages) {\n const value = messages[locale]\n if (value?.$description || value?.$desc) {\n result[locale] = value.$description || value.$desc\n } else if (typeof value === 'string') {\n result[locale] = value\n }\n }\n return result\n}\n\nfunction getInner(value: any) {\n return value?.$value ?? value?.$inner\n}\n\nfunction extractKeys(data: any) {\n return filterKeys(data ?? {}, key => !key.startsWith('$'))\n}\n\nSchema.prototype.i18n = function i18n(messages) {\n const schema = Schema(this)\n const desc = mergeDesc(schema.meta.description, messages)\n if (Object.keys(desc).length) schema.meta.description = desc\n if (schema.dict) {\n schema.dict = valueMap(schema.dict, (inner, key) => {\n return inner.i18n(valueMap(messages, (data) => getInner(data)?.[key] ?? data?.[key]))\n })\n }\n if (schema.list) {\n schema.list = schema.list!.map((inner, index) => {\n return inner.i18n(valueMap(messages, (data = {}) => {\n if (Array.isArray(getInner(data))) return getInner(data)[index]\n if (Array.isArray(data)) return data[index]\n return extractKeys(data)\n }))\n })\n }\n if (schema.inner) {\n schema.inner = schema.inner.i18n(valueMap(messages, (data) => {\n if (getInner(data)) return getInner(data)\n return extractKeys(data)\n }))\n }\n if (schema.sKey) {\n schema.sKey = schema.sKey.i18n(valueMap(messages, (data) => data?.$key))\n }\n return schema\n}\n\nSchema.prototype.extra = function extra(key, value) {\n const schema = Schema(this)\n schema.meta = { ...schema.meta, [key]: value }\n return schema\n}\n\nfor (const key of ['required', 'disabled', 'collapse', 'hidden', 'loose']) {\n Object.assign(Schema.prototype, {\n [key](this: Schema, value = true) {\n const schema = Schema(this)\n schema.meta = { ...schema.meta, [key]: value }\n return schema\n },\n })\n}\n\nSchema.prototype.deprecated = function deprecated() {\n const schema = Schema(this)\n schema.meta.badges ||= []\n schema.meta.badges.push({ text: 'deprecated', type: 'danger' })\n return schema\n}\n\nSchema.prototype.experimental = function experimental() {\n const schema = Schema(this)\n schema.meta.badges ||= []\n schema.meta.badges.push({ text: 'experimental', type: 'warning' })\n return schema\n}\n\nSchema.prototype.pattern = function pattern(regexp) {\n const schema = Schema(this)\n const pattern = pick(regexp, ['source', 'flags'])\n schema.meta = { ...schema.meta, pattern }\n return schema\n}\n\nSchema.prototype.simplify = function simplify(this: Schema, value) {\n if (deepEqual(value, this.meta.default, this.type === 'dict')) return null\n if (isNullable(value)) return value\n if (this.type === 'object' || this.type === 'dict') {\n const result: Dict = {}\n for (const key in value) {\n const schema = this.type === 'object' ? this.dict![key] : this.inner\n const item = schema?.simplify(value[key])\n if (this.type === 'dict' || !isNullable(item)) result[key] = item\n }\n if (deepEqual(result, this.meta.default, this.type === 'dict')) return null\n return result\n } else if (this.type === 'array' || this.type === 'tuple') {\n const result: any[] = []\n ;(value as any[]).forEach((value, index) => {\n const schema = this.type === 'array' ? this.inner : this.list![index]\n const item = schema ? schema.simplify(value) : value\n result.push(item)\n })\n return result\n } else if (this.type === 'intersect') {\n const result: Dict = {}\n for (const item of this.list!) {\n Object.assign(result, item.simplify(value))\n }\n return result\n } else if (this.type === 'union') {\n for (const schema of this.list!) {\n try {\n Schema.resolve(value, schema, {})\n return schema.simplify(value)\n } catch {}\n }\n }\n return value\n}\n\nSchema.prototype.toString = function toString(inline?: boolean) {\n return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`\n}\n\nSchema.prototype.role = function role(role, extra) {\n const schema = Schema(this)\n schema.meta = { ...schema.meta, role, extra }\n return schema\n}\n\nfor (const key of ['default', 'link', 'comment', 'description', 'max', 'min', 'step']) {\n Object.assign(Schema.prototype, {\n [key](this: Schema, value: any) {\n const schema = Schema(this)\n schema.meta = { ...schema.meta, [key]: value }\n return schema\n },\n })\n}\n\nconst resolvers: Dict<Schemastery.Resolve> = {}\n\nSchema.extend = function extend(type, resolve) {\n resolvers[type] = resolve\n}\n\nSchema.resolve = function resolve(data, schema, options = {}, strict = false) {\n if (!schema) return [data]\n if (options.ignore?.(data, schema)) return [data]\n\n if (isNullable(data) && schema.type !== 'lazy') {\n if (schema.meta.required) throw new ValidationError(`missing required value`, options)\n let current = schema\n let fallback = schema.meta.default\n while (current?.type === 'intersect' && isNullable(fallback)) {\n current = current.list![0]\n fallback = current?.meta.default\n }\n if (isNullable(fallback)) return [data]\n data = clone(fallback)\n }\n\n const callback = resolvers[schema.type]\n if (!callback) throw new ValidationError(`unsupported type \"${schema.type}\"`, options)\n\n try {\n return callback(data, schema, options, strict)\n } catch (error) {\n if (!schema.meta.loose) throw error\n return [schema.meta.default]\n }\n}\n\nSchema.from = function from(source: any) {\n if (isNullable(source)) {\n return Schema.any()\n } else if (['string', 'number', 'boolean'].includes(typeof source)) {\n return Schema.const(source).required()\n } else if (source[kSchema]) {\n return source\n } else if (typeof source === 'function') {\n switch (source) {\n case String: return Schema.string().required()\n case Number: return Schema.number().required()\n case Boolean: return Schema.boolean().required()\n case Function: return Schema.function().required()\n default: return Schema.is(source).required()\n }\n } else {\n throw new TypeError(`cannot infer schema from ${source}`)\n }\n}\n\nSchema.lazy = function lazy(builder) {\n const toJSON = () => {\n if (!schema.inner![kSchema]) {\n schema.inner = schema.builder!()\n schema.inner!.meta = { ...schema.meta, ...schema.inner!.meta }\n }\n return schema.inner!.toJSON()\n }\n const schema = new Schema({ type: 'lazy', builder, inner: { toJSON } as any })\n return schema as any\n}\n\nSchema.natural = function natural() {\n return Schema.number().step(1).min(0)\n}\n\nSchema.percent = function percent() {\n return Schema.number().step(0.01).min(0).max(1).role('slider')\n}\n\nSchema.date = function date() {\n return Schema.union([\n Schema.is(Date),\n Schema.transform(Schema.string().role('datetime'), (value, options) => {\n const date = new Date(value)\n if (isNaN(+date)) throw new ValidationError(`invalid date \"${value}\"`, options)\n return date\n }, true),\n ])\n}\n\nSchema.regExp = function regExp(flag = '') {\n return Schema.union([\n Schema.is(RegExp),\n Schema.transform(Schema.string().role('regexp', { flag }), (value, options) => {\n try {\n return new RegExp(value, flag)\n } catch (e: any) {\n throw new ValidationError(e.message, options)\n }\n }, true),\n ])\n}\n\nSchema.arrayBuffer = function arrayBuffer(encoding?: 'hex' | 'base64'): any {\n return Schema.union([\n Schema.is(ArrayBuffer),\n Schema.is(SharedArrayBuffer),\n Schema.transform(Schema.any<ArrayBufferView>(), (value, options) => {\n if (Binary.isSource(value)) return Binary.fromSource(value)\n throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options)\n }, true),\n ...encoding ? [Schema.transform(Schema.string(), (value, options) => {\n try {\n return encoding === 'base64'\n ? Binary.fromBase64(value)\n : Binary.fromHex(value)\n } catch (e: any) {\n throw new ValidationError(e.message, options)\n }\n }, true)] as const : [],\n ])\n}\n\nSchema.extend('lazy', (data, schema, options, strict) => {\n if (!schema.inner![kSchema]) {\n schema.inner = schema.builder!()\n schema.inner!.meta = { ...schema.meta, ...schema.inner!.meta }\n }\n return Schema.resolve(data, schema.inner!, options, strict)\n})\n\nSchema.extend('any', (data) => {\n return [data]\n})\n\nSchema.extend('never', (data, _, options) => {\n throw new ValidationError(`expected nullable but got ${data}`, options)\n})\n\nSchema.extend('const', (data, { value }, options) => {\n if (deepEqual(data, value)) return [value]\n throw new ValidationError(`expected ${value} but got ${data}`, options)\n})\n\nfunction checkWithinRange(data: number, meta: Schemastery.Meta<any>, description: string, options: Schemastery.Options, skipMin = false) {\n const { max = Infinity, min = -Infinity } = meta\n if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options)\n if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options)\n}\n\nSchema.extend('string', (data, { meta }, options) => {\n if (typeof data !== 'string') throw new ValidationError(`expected string but got ${data}`, options)\n if (meta.pattern) {\n const regexp = new RegExp(meta.pattern.source, meta.pattern.flags)\n if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options)\n }\n checkWithinRange(data.length, meta, 'string length', options)\n return [data]\n})\n\nfunction decimalShift(data: number, digits: number) {\n const str = data.toString()\n if (str.includes('e')) return data * Math.pow(10, digits)\n const index = str.indexOf('.')\n if (index === -1) return data * Math.pow(10, digits)\n const frac = str.slice(index + 1)\n const integer = str.slice(0, index)\n if (frac.length <= digits) return +(integer + frac.padEnd(digits, '0'))\n return +(integer + frac.slice(0, digits) + '.' + frac.slice(digits))\n}\n\nfunction isMultipleOf(data: number, min: number, step: number) {\n step = Math.abs(step)\n if (!/^\\d+\\.\\d+$/.test(step.toString())) {\n return (data - min) % step === 0\n }\n const index = step.toString().indexOf('.')\n const digits = step.toString().slice(index + 1).length\n return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0\n}\n\nSchema.extend('number', (data, { meta }, options) => {\n if (typeof data !== 'number') throw new ValidationError(`expected number but got ${data}`, options)\n checkWithinRange(data, meta, 'number', options)\n const { step } = meta\n if (step && !isMultipleOf(data, meta.min ?? 0, step)) {\n throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options)\n }\n return [data]\n})\n\nSchema.extend('boolean', (data, _, options) => {\n if (typeof data === 'boolean') return [data]\n throw new ValidationError(`expected boolean but got ${data}`, options)\n})\n\nSchema.extend('bitset', (data, { bits, meta }, options) => {\n let value = 0, keys: string[] = []\n if (typeof data === 'number') {\n value = data\n for (const key in bits!) {\n if (data & bits![key]!) {\n keys.push(key)\n }\n }\n } else if (Array.isArray(data)) {\n keys = data\n for (const key of keys) {\n if (typeof key !== 'string') throw new ValidationError(`expected string but got ${key}`, options)\n if (key in bits!) value |= bits![key]!\n }\n } else {\n throw new ValidationError(`expected number or array but got ${data}`, options)\n }\n if (value === meta.default) return [value]\n return [value, keys]\n})\n\nSchema.extend('function', (data, _, options) => {\n if (typeof data === 'function') return [data]\n throw new ValidationError(`expected function but got ${data}`, options)\n})\n\nSchema.extend('is', (data, { constructor }, options) => {\n if (typeof constructor === 'function') {\n if (data instanceof constructor) return [data]\n throw new ValidationError(`expected ${constructor.name} but got ${data}`, options)\n } else {\n if (isNullable(data)) {\n throw new ValidationError(`expected ${constructor} but got ${data}`, options)\n }\n let prototype = Object.getPrototypeOf(data)\n while (prototype) {\n if (prototype.constructor?.name === constructor) return [data]\n prototype = Object.getPrototypeOf(prototype)\n }\n throw new ValidationError(`expected ${constructor} but got ${data}`, options)\n }\n})\n\nfunction property(data: any, key: keyof any, schema: Schema, options: Schemastery.Options) {\n try {\n const [value, adapted] = Schema.resolve(data[key], schema, {\n ...options,\n path: [...options.path || [], key],\n })\n if (adapted !== undefined) data[key] = adapted\n return value\n } catch (e) {\n if (!options?.autofix) throw e\n delete data[key]\n return schema.meta.default\n }\n}\n\nSchema.extend('array', (data, { inner, meta }, options) => {\n if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options)\n checkWithinRange(data.length, meta, 'array length', options, !isNullable(inner!.meta.default))\n return [data.map((_, index) => property(data, index, inner!, options))]\n})\n\nSchema.extend('dict', (data, { inner, sKey }, options, strict) => {\n if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options)\n const result: any = {}\n for (const key in data) {\n let rKey: string\n try {\n rKey = Schema.resolve(key, sKey!, options)[0]\n } catch (error) {\n if (strict) continue\n throw error\n }\n result[rKey] = property(data, key, inner!, options)\n data[rKey] = data[key]\n if (key !== rKey) delete data[key]\n }\n return [result]\n})\n\nSchema.extend('tuple', (data, { list }, options, strict) => {\n if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options)\n const result = list!.map((inner, index) => property(data, index, inner, options))\n if (strict) return [result]\n result.push(...data.slice(list!.length))\n return [result]\n})\n\nfunction merge(result: any, data: any) {\n for (const key in data) {\n if (key in result) continue\n result[key] = data[key]\n }\n}\n\nSchema.extend('object', (data, { dict }, options, strict) => {\n if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options)\n const result: any = {}\n for (const key in dict) {\n const value = property(data, key, dict![key]!, options)\n if (!isNullable(value) || key in data) {\n result[key] = value\n }\n }\n if (!strict) merge(result, data)\n return [result]\n})\n\nSchema.extend('union', (data, { list, toString }, options, strict) => {\n const messages: any[] = []\n for (const inner of list!) {\n try {\n return Schema.resolve(data, inner, options, strict)\n } catch (error) {\n messages.push(error)\n }\n }\n throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)\n})\n\nSchema.extend('intersect', (data, { list, toString }, options, strict) => {\n if (!list!.length) return [data]\n let result\n for (const inner of list!) {\n const value: any = Schema.resolve(data, inner, options, true)[0]\n if (isNullable(value)) continue\n if (isNullable(result)) {\n result = value\n } else if (typeof result !== typeof value) {\n throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)\n } else if (typeof value === 'object') {\n merge(result ??= {}, value)\n } else if (result !== value) {\n throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options)\n }\n }\n if (!strict && isPlainObject(data)) merge(result, data)\n return [result]\n})\n\nSchema.extend('transform', (data, { inner, callback, preserve }, options) => {\n const [result, adapted = data] = Schema.resolve(data, inner!, options, true)\n if (preserve) {\n return [callback!(result)]\n // } else if (isPlainObject(data)) {\n // const temp: any = {}\n // for (const key in result) {\n // if (!(key in data)) continue\n // temp[key] = data[key]\n // delete data[key]\n // }\n // Object.assign(data, callback!(temp))\n // return [callback!(result)]\n } else {\n return [callback!(result), callback!(adapted)]\n }\n})\n\ntype Formatter = (schema: Schema, inline?: boolean) => string\nconst formatters: Dict<Formatter> = {}\n\nfunction defineMethod(name: string, keys: (keyof Schema)[], format: Formatter) {\n formatters[name] = format\n Object.assign(Schema, {\n [name](...args: any[]) {\n const schema = new Schema({ type: name } as Schema)\n keys.forEach((key, index) => {\n switch (key) {\n case 'sKey': schema.sKey = args[index] ?? Schema.string(); break\n case 'inner': schema.inner = Schema.from(args[index]); break\n case 'list': schema.list = args[index].map(Schema.from); break\n case 'dict': schema.dict = valueMap(args[index], Schema.from); break\n case 'bits': {\n schema.bits = {}\n for (const key in args[index]) {\n if (typeof args[index][key] !== 'number') continue\n schema.bits[key] = args[index][key]\n }\n break\n }\n case 'callback': {\n const callback = schema.callback = args[index]\n ;callback['toJSON'] ||= () => callback.toString()\n break\n }\n case 'constructor': {\n const constructor = schema.constructor = args[index]\n if (typeof constructor === 'function') {\n ;constructor['toJSON'] ||= () => constructor['name']\n }\n break\n }\n default: schema[key] = args[index] as never\n }\n })\n if (name === 'object' || name === 'dict') {\n schema.meta.default = {}\n } else if (name === 'array' || name === 'tuple') {\n schema.meta.default = []\n } else if (name === 'bitset') {\n schema.meta.default = 0\n }\n return schema\n },\n })\n}\n\ndefineMethod('is', ['constructor'], ({ constructor }) => {\n if (typeof constructor === 'function') {\n return constructor.name\n } else {\n return constructor!\n }\n})\n\ndefineMethod('any', [], () => 'any')\ndefineMethod('never', [], () => 'never')\ndefineMethod('const', ['value'], ({ value }) => typeof value === 'string' ? JSON.stringify(value) : value)\ndefineMethod('string', [], () => 'string')\ndefineMethod('number', [], () => 'number')\ndefineMethod('boolean', [], () => 'boolean')\ndefineMethod('bitset', ['bits'], () => 'bitset')\ndefineMethod('function', [], () => 'function')\ndefineMethod('array', ['inner'], ({ inner }) => `${inner!.toString(true)}[]`)\ndefineMethod('dict', ['inner', 'sKey'], ({ inner, sKey }) => `{ [key: ${sKey!.toString()}]: ${inner!.toString()} }`)\ndefineMethod('tuple', ['list'], ({ list }) => `[${list!.map((inner) => inner.toString()).join(', ')}]`)\n\ndefineMethod('object', ['dict'], ({ dict }) => {\n if (Object.keys(dict!).length === 0) return '{}'\n return `{ ${Object.entries(dict!).map(([key, inner]) => {\n return `${key}${inner!.meta.required ? '' : '?'}: ${inner!.toString()}`\n }).join(', ')} }`\n})\n\ndefineMethod('union', ['list'], ({ list }, inline) => {\n const result = list!.map(({ toString: format }) => format()).join(' | ')\n return inline ? `(${result})` : result\n})\n\ndefineMethod('intersect', ['list'], ({ list }) => {\n return `${list!.map((inner) => inner.toString(true)).join(' & ')}`\n})\n\ndefineMethod('transform', ['inner', 'callback', 'preserve'], ({ inner }, isInner) => inner!.toString(isInner))\n\nexport default Schema\n","import z from '@deepseek-ai/schemastery'\nimport type { CircuitHealth, FailoverSettings, QueueRoute } from './types.ts'\n\n/** Plugin config accepted from cordis.yml / the bundle patch. */\nexport interface Config {\n /** Milliseconds an Open circuit waits before a HalfOpen probe. Default 60000. */\n cooldownMs?: number\n /** Consecutive failures that open a Closed breaker. Default 2. */\n failureThreshold?: number\n /** Consecutive HalfOpen successes that close the breaker. Default 2. */\n successThreshold?: number\n /**\n * Failure codes that skip remaining same-route retries, open the circuit\n * immediately, and jump to the next P. Default includes 5xx / timeout /\n * transport so a backup P is used instead of waiting out `llm-retry`.\n */\n immediateCodes?: string[]\n}\n\n/** Config after schema defaults. */\nexport interface ResolvedConfig {\n cooldownMs: number\n failureThreshold: number\n successThreshold: number\n immediateCodes: readonly string[]\n}\n\n/**\n * Codes that mean this route cannot serve the request now.\n * `EMPTY_RESPONSE` stays on same-route `llm-retry`.\n */\nexport const DEFAULT_IMMEDIATE_CODES = [\n 'AUTH',\n 'RATE_LIMIT',\n 'NO_ADAPTER',\n 'SERVER',\n 'TIMEOUT',\n 'TRANSPORT',\n] as const\n\n/** Runtime schema. */\nexport const Config: z<Config> = z.object({\n cooldownMs: z.number().min(0).default(60_000),\n failureThreshold: z.number().min(1).default(2),\n successThreshold: z.number().min(1).default(2),\n immediateCodes: z.array(z.string()).default([...DEFAULT_IMMEDIATE_CODES]),\n})\n\n/**\n * Apply schema defaults.\n * @param config - raw plugin config, possibly partial.\n */\nexport function resolveConfig(config: Config = {}): ResolvedConfig {\n return Config(config) as ResolvedConfig\n}\n\n/** Settings namespace (hyphenated; settings forbids dots). */\nexport const SETTINGS_NAMESPACE = 'dsh-failover-queue'\n\nconst QueueRouteSchema: z<QueueRoute> = z.object({\n provider: z.string(),\n model: z.string(),\n label: z.string().default(''),\n})\n\nconst CircuitHealthSchema: z<CircuitHealth> = z.object({\n provider: z.string(),\n model: z.string(),\n state: z.string().default('closed'),\n failures: z.number().min(0).default(0),\n})\n\n/** Persisted user document. */\nexport const FailoverSettingsSchema: z<FailoverSettings> = z.object({\n enabled: z.boolean().default(false),\n currentIndex: z.number().step(1).min(0).default(0),\n queue: z.array(QueueRouteSchema).default([]),\n circuits: z.array(CircuitHealthSchema).default([]),\n})\n\n/** Empty queue, failover off. */\nexport const DEFAULT_SETTINGS: FailoverSettings = {\n enabled: false,\n currentIndex: 0,\n queue: [],\n circuits: [],\n}\n","import type { FailoverCandidate, FailoverSettings, QueueRoute } from '../types.ts'\nimport { DEFAULT_SETTINGS } from '../config.ts'\nimport { clampIndex, dedupeQueue } from '../queue.ts'\n\n/** Live snapshot published to the chip via the inject hooks seat. */\nexport interface FailoverSnapshot extends FailoverSettings {\n /** Catalog rows the add list can pick. */\n readonly candidates: readonly FailoverCandidate[]\n /** False until the first catalog/slash-command fetch finishes. */\n readonly candidatesLoaded: boolean\n}\n\nconst listeners = new Set<() => void>()\nlet snapshot: FailoverSnapshot = {\n ...DEFAULT_SETTINGS,\n circuits: [],\n candidates: [],\n candidatesLoaded: false,\n}\n\nfunction publish(next: FailoverSnapshot): void {\n snapshot = next\n for (const listener of [...listeners]) listener()\n}\n\n/** Bare observable the slot renderer binds to `useFailover`. */\nexport const failoverSource = {\n subscribe(listener: () => void): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n getSnapshot(): FailoverSnapshot {\n return snapshot\n },\n}\n\n/**\n * Replace settings fields, keep candidates.\n * @param settings - persisted document.\n */\nexport function replaceSettings(settings: FailoverSettings): void {\n const queue = dedupeQueue(settings.queue)\n publish({\n enabled: settings.enabled,\n queue,\n currentIndex: clampIndex(settings.currentIndex, queue.length),\n circuits: settings.circuits ?? [],\n candidates: snapshot.candidates,\n candidatesLoaded: snapshot.candidatesLoaded,\n })\n}\n\n/**\n * Replace the add-list catalog.\n * @param candidates - advertised provider+model rows.\n */\nexport function replaceCandidates(candidates: readonly FailoverCandidate[]): void {\n publish({ ...snapshot, candidates, candidatesLoaded: true })\n}\n\n/** Read the current snapshot (event-handler path). */\nexport function peek(): FailoverSnapshot {\n return snapshot\n}\n\nexport type { FailoverCandidate, FailoverSettings, QueueRoute }\n","/**\n * Browser half of dsh-failover-queue: a P1/P- chip on the composer tool row\n * and a Settings left-nav page. The chip still opens the drag-reorder popover.\n */\nimport type { Context } from '@deepseek-ai/cordis'\nimport { candidatesFromCatalog, candidatesFromText } from '../candidates.ts'\nimport type { FailoverSettings } from '../types.ts'\nimport { FailoverChip, FailoverSettingsCard } from './FailoverChip.tsx'\nimport { en, NS, zh, type FailoverKey } from './locales.ts'\nimport { failoverSource, replaceCandidates, replaceSettings } from './state.ts'\nimport { STYLE } from './styles.ts'\n\n/** Browser plugin context used here. Extra services are ignored. */\ninterface FailoverClientContext {\n effect(fn: () => (() => void) | void, name?: string): () => void\n locale: {\n register: (ns: string, packs: { zh: typeof zh; en: typeof en }) => () => void\n bind: (ns: string) => (key: FailoverKey, params?: Record<string, string | number>) => string\n }\n slots: {\n inject: (name: string, factory: () => () => void) => void\n register: (options: Record<string, unknown>, component: unknown) => () => void\n }\n settingsScope: {\n bind: (spec: { namespace: string }) => {\n getSnapshot: () => { value?: FailoverSettings; writable: boolean }\n set: (field: string, value: unknown) => Promise<void>\n subscribe: (cb: () => void) => () => void\n }\n }\n remote: {\n commands: {\n execute: (sessionId: string, line: string, attachments: unknown[]) => Promise<{\n ok: boolean\n value?: { text?: string } | string\n error?: { message: string; code: string }\n }>\n }\n session?: {\n modelCatalog: () => Promise<{\n ok: boolean\n value?: unknown\n error?: { message: string }\n }>\n }\n }\n}\n\n/** Required services for the composer chip and settings page. */\nexport const inject = ['slots', 'locale', 'settingsScope', 'remote', 'remote.commands', 'remote.session']\n\n\ninterface SessionList {\n list?: { getSnapshot: () => { current?: string } }\n}\n\nfunction currentSessionId(ctx: Context, sessionId?: string): string {\n if (typeof sessionId === 'string' && sessionId !== '') return sessionId\n // Property access throws without inject; get() is the optional read.\n const sessions = ctx.get('sessions') as SessionList | undefined\n const current = sessions?.list?.getSnapshot?.().current\n return typeof current === 'string' ? current : ''\n}\n\nfunction circuitState(value: unknown): 'closed' | 'open' | 'half_open' {\n if (value === 'open' || value === 'half_open' || value === 'closed') return value\n return 'closed'\n}\n\nfunction settingsFromUnknown(value: unknown): FailoverSettings | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const record = value as { enabled?: unknown; currentIndex?: unknown; queue?: unknown; circuits?: unknown }\n if (typeof record.enabled !== 'boolean') return undefined\n if (typeof record.currentIndex !== 'number') return undefined\n if (!Array.isArray(record.queue)) return undefined\n const queue = record.queue.flatMap((row) => {\n if (typeof row !== 'object' || row === null) return []\n const item = row as { provider?: unknown; model?: unknown; label?: unknown }\n if (typeof item.provider !== 'string' || typeof item.model !== 'string') return []\n return [{\n provider: item.provider,\n model: item.model,\n ...typeof item.label === 'string' ? { label: item.label } : {},\n }]\n })\n const circuits = Array.isArray(record.circuits)\n ? record.circuits.flatMap((row) => {\n if (typeof row !== 'object' || row === null) return []\n const item = row as { provider?: unknown; model?: unknown; state?: unknown; failures?: unknown }\n if (typeof item.provider !== 'string' || typeof item.model !== 'string') return []\n return [{\n provider: item.provider,\n model: item.model,\n state: circuitState(item.state),\n failures: typeof item.failures === 'number' && item.failures > 0 ? item.failures : 0,\n }]\n })\n : []\n return { enabled: record.enabled, currentIndex: record.currentIndex, queue, circuits }\n}\n\n/**\n * Register dictionaries, the composer chip, and the Settings left-nav page.\n * @param ctx - browser plugin context.\n */\nexport function apply(ctx: Context): void {\n const client = ctx as unknown as FailoverClientContext\n const scope = client.settingsScope.bind({ namespace: 'dsh-failover-queue' })\n\n const pull = (): void => {\n const value = settingsFromUnknown(scope.getSnapshot().value)\n if (value !== undefined) replaceSettings(value)\n }\n pull()\n\n const api = {\n setEnabled: async (enabled: boolean) => {\n await scope.set('enabled', enabled)\n },\n setQueue: async (queue: FailoverSettings['queue'], currentIndex: number) => {\n await scope.set('queue', queue)\n await scope.set('currentIndex', currentIndex)\n },\n }\n\n const loadCandidates = async (sessionId: string): Promise<void> => {\n const catalog = await client.remote.session?.modelCatalog()\n if (catalog?.ok) {\n const rows = candidatesFromCatalog(catalog.value)\n if (rows.length > 0) {\n replaceCandidates(rows)\n return\n }\n }\n if (sessionId === '') return\n const result = await client.remote.commands.execute(sessionId, '/failover __candidates', [])\n if (!result.ok) return\n const text = typeof result.value === 'string'\n ? result.value\n : typeof result.value?.text === 'string' ? result.value.text : ''\n if (text === '') return\n replaceCandidates(candidatesFromText(text))\n }\n\n const injected = (sessionId?: string) => ({\n hooks: { failover: failoverSource },\n api,\n loadCandidates,\n getSessionId: () => currentSessionId(ctx, sessionId),\n })\n\n client.effect(() => {\n const style = document.createElement('style')\n style.dataset.plugin = 'dsh-failover-queue'\n style.textContent = STYLE\n document.head.appendChild(style)\n return () => { style.remove() }\n }, 'dsh-failover-queue: styles')\n\n client.effect(() => client.locale.register(NS, { zh, en }), 'dsh-failover-queue: dictionaries')\n client.effect(() => scope.subscribe(pull), 'dsh-failover-queue: settings')\n\n client.slots.inject('conversation.input.right', () => client.slots.register({\n name: 'conversation.input.right',\n id: 'dsh-failover-queue',\n order: 40,\n locale: NS,\n inject: injected,\n }, FailoverChip))\n\n client.slots.inject('settings.section', () => client.slots.register({\n name: 'settings.section',\n id: 'failover',\n order: 17,\n locale: NS,\n label: () => client.locale.bind(NS)('settings.tab'),\n inject: injected,\n }, FailoverSettingsCard))\n}\n"],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -50,7 +50,8 @@ interface Config {
50
50
  successThreshold?: number;
51
51
  /**
52
52
  * Failure codes that skip remaining same-route retries, open the circuit
53
- * immediately, and jump to the next P. Default `AUTH`, `RATE_LIMIT`, `NO_ADAPTER`.
53
+ * immediately, and jump to the next P. Default includes 5xx / timeout /
54
+ * transport so a backup P is used instead of waiting out `llm-retry`.
54
55
  */
55
56
  immediateCodes?: string[];
56
57
  }
@@ -61,6 +62,11 @@ interface ResolvedConfig {
61
62
  successThreshold: number;
62
63
  immediateCodes: readonly string[];
63
64
  }
65
+ /**
66
+ * Codes that mean this route cannot serve the request now.
67
+ * `EMPTY_RESPONSE` stays on same-route `llm-retry`.
68
+ */
69
+ declare const DEFAULT_IMMEDIATE_CODES: readonly ["AUTH", "RATE_LIMIT", "NO_ADAPTER", "SERVER", "TIMEOUT", "TRANSPORT"];
64
70
  /** Runtime schema. */
65
71
  declare const Config: z<Config>;
66
72
  /**
@@ -146,8 +152,9 @@ interface CircuitPick {
146
152
  * One route's Closed / Open / HalfOpen breaker.
147
153
  *
148
154
  * HalfOpen allows a single in-flight probe. Open becomes HalfOpen after
149
- * `timeoutMs`. Immediate failures (AUTH / RATE_LIMIT / NO_ADAPTER) open on
150
- * the first hit. Memory-only: a process restart starts Closed.
155
+ * `timeoutMs`. Immediate failures (AUTH / RATE_LIMIT / NO_ADAPTER / SERVER /
156
+ * TIMEOUT / TRANSPORT) open on the first hit. Memory-only: a process restart
157
+ * starts Closed.
151
158
  */
152
159
  declare class CircuitBreaker {
153
160
  private readonly config;
@@ -271,4 +278,4 @@ declare const inject: string[];
271
278
  */
272
279
  declare function apply(ctx: Context, config?: Config): void;
273
280
  //#endregion
274
- export { CircuitBank, CircuitBreaker, type CircuitHealth, type CircuitState, Config, type Config as ConfigInput, type FailoverCandidate, type FailoverSettings, type QueueRoute, type ResolvedConfig, SETTINGS_NAMESPACE, advanceIndex, apply, circuitTone, clampIndex, dedupeQueue, firstAvailableIndex, healthFor, indexAfterReorder, inject, name, parseFailoverArg, pickFirstAvailable, reorderQueue, resolveConfig, routeDisplay, routeKey };
281
+ export { CircuitBank, CircuitBreaker, type CircuitHealth, type CircuitState, Config, type Config as ConfigInput, DEFAULT_IMMEDIATE_CODES, type FailoverCandidate, type FailoverSettings, type QueueRoute, type ResolvedConfig, SETTINGS_NAMESPACE, advanceIndex, apply, circuitTone, clampIndex, dedupeQueue, firstAvailableIndex, healthFor, indexAfterReorder, inject, name, parseFailoverArg, pickFirstAvailable, reorderQueue, resolveConfig, routeDisplay, routeKey };
package/lib/index.js CHANGED
@@ -118,8 +118,9 @@ function routeDisplay(route, candidates = []) {
118
118
  * One route's Closed / Open / HalfOpen breaker.
119
119
  *
120
120
  * HalfOpen allows a single in-flight probe. Open becomes HalfOpen after
121
- * `timeoutMs`. Immediate failures (AUTH / RATE_LIMIT / NO_ADAPTER) open on
122
- * the first hit. Memory-only: a process restart starts Closed.
121
+ * `timeoutMs`. Immediate failures (AUTH / RATE_LIMIT / NO_ADAPTER / SERVER /
122
+ * TIMEOUT / TRANSPORT) open on the first hit. Memory-only: a process restart
123
+ * starts Closed.
123
124
  */
124
125
  var CircuitBreaker = class {
125
126
  state = "closed";
@@ -340,16 +341,24 @@ function parseFailoverArg(rawInput) {
340
341
 
341
342
  //#endregion
342
343
  //#region src/config.ts
344
+ /**
345
+ * Codes that mean this route cannot serve the request now.
346
+ * `EMPTY_RESPONSE` stays on same-route `llm-retry`.
347
+ */
348
+ const DEFAULT_IMMEDIATE_CODES = [
349
+ "AUTH",
350
+ "RATE_LIMIT",
351
+ "NO_ADAPTER",
352
+ "SERVER",
353
+ "TIMEOUT",
354
+ "TRANSPORT"
355
+ ];
343
356
  /** Runtime schema. */
344
357
  const Config = z.object({
345
358
  cooldownMs: z.number().min(0).default(6e4),
346
359
  failureThreshold: z.number().min(1).default(2),
347
360
  successThreshold: z.number().min(1).default(2),
348
- immediateCodes: z.array(z.string()).default([
349
- "AUTH",
350
- "RATE_LIMIT",
351
- "NO_ADAPTER"
352
- ])
361
+ immediateCodes: z.array(z.string()).default([...DEFAULT_IMMEDIATE_CODES])
353
362
  });
354
363
  /**
355
364
  * Apply schema defaults.
@@ -571,4 +580,4 @@ async function listCandidates(ctx) {
571
580
  }
572
581
 
573
582
  //#endregion
574
- export { CircuitBank, CircuitBreaker, Config, SETTINGS_NAMESPACE, advanceIndex, apply, circuitTone, clampIndex, dedupeQueue, firstAvailableIndex, healthFor, indexAfterReorder, inject, name, parseFailoverArg, pickFirstAvailable, reorderQueue, resolveConfig, routeDisplay, routeKey };
583
+ export { CircuitBank, CircuitBreaker, Config, DEFAULT_IMMEDIATE_CODES, SETTINGS_NAMESPACE, advanceIndex, apply, circuitTone, clampIndex, dedupeQueue, firstAvailableIndex, healthFor, indexAfterReorder, inject, name, parseFailoverArg, pickFirstAvailable, reorderQueue, resolveConfig, routeDisplay, routeKey };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x1a0f3n9/dsh-failover-queue",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "CC Switch-style P1/P2/P3 model failover for DeepSeek Harness. Circuit probe failback to P1.",
5
5
  "author": "LunFengChen",
6
6
  "license": "MIT",