@lynn123411/dsh-chat-translate 1.2.4 → 1.2.6

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.
@@ -19,8 +19,8 @@
19
19
  concurrency: 3
20
20
  aiEnabled: true
21
21
  bingEnabled: true
22
- baseUrl: http://172.24.52.126:8081/v1
23
- model: hy-mt2-1.8b
22
+ baseUrl: https://api.deepseek.com/v1
23
+ model: deepseek-chat
24
24
  targetLang: zh-Hans
25
25
  ```
26
26
 
package/lib/client.js CHANGED
@@ -129,6 +129,32 @@ var ClientCache = class {
129
129
  };
130
130
  var clientCache = new ClientCache();
131
131
 
132
+ // src/describe-error.ts
133
+ function describeError(err) {
134
+ if (err === null || err === void 0) return String(err);
135
+ const parts = [];
136
+ const push = (s) => {
137
+ const t = String(s || "").trim();
138
+ if (t && !parts.includes(t)) parts.push(t);
139
+ };
140
+ const head = err.message || String(err);
141
+ push(head);
142
+ const headCode = err.code;
143
+ if (headCode && !head.includes(headCode)) push("[" + headCode + "]");
144
+ let cause = err.cause;
145
+ for (let depth = 0; cause && depth < 4; depth++) {
146
+ const label = cause.message || String(cause);
147
+ push(cause.code && !label.includes(cause.code) ? label + " [" + cause.code + "]" : label);
148
+ if (Array.isArray(cause.errors)) {
149
+ for (const sub of cause.errors.slice(0, 3)) {
150
+ if (sub) push(sub.code || sub.message || String(sub));
151
+ }
152
+ }
153
+ cause = cause.cause;
154
+ }
155
+ return parts.join(" \u2190 ");
156
+ }
157
+
132
158
  // src/client/translate/api.ts
133
159
  async function requestTranslateBatch(texts, options = {}) {
134
160
  if (!Array.isArray(texts) || texts.length === 0) return [];
@@ -183,7 +209,7 @@ async function testServerChannel(channel) {
183
209
  });
184
210
  return await res.json();
185
211
  } catch (err) {
186
- return { ok: false, latencyMs: 0, error: err?.message || String(err) };
212
+ return { ok: false, latencyMs: 0, error: describeError(err) };
187
213
  }
188
214
  }
189
215
 
@@ -303,7 +329,13 @@ var NonDestructiveTranslationMount = class {
303
329
  // src/client/translate/viewport-observer.ts
304
330
  var StreamDebounceViewportObserver = class {
305
331
  intersectionObserver = null;
306
- streamingTimers = /* @__PURE__ */ new WeakMap();
332
+ /**
333
+ * Pending per-element streaming debounce timers. A Map (not a WeakMap)
334
+ * because disconnect() must enumerate and clear every pending timer: a
335
+ * WeakMap cannot be iterated, so a debounce armed just before the switch was
336
+ * turned off would still fire registerForViewport() afterwards.
337
+ */
338
+ streamingTimers = /* @__PURE__ */ new Map();
307
339
  pendingQueue = [];
308
340
  batchFlushTimer = null;
309
341
  options;
@@ -357,6 +389,7 @@ var StreamDebounceViewportObserver = class {
357
389
  return;
358
390
  }
359
391
  const timer = window.setTimeout(() => {
392
+ if (this.streamingTimers.get(element) !== timer) return;
360
393
  this.streamingTimers.delete(element);
361
394
  if (element.isConnected) {
362
395
  const latestText = element.textContent?.trim() || text;
@@ -405,6 +438,10 @@ var StreamDebounceViewportObserver = class {
405
438
  clearTimeout(this.batchFlushTimer);
406
439
  this.batchFlushTimer = null;
407
440
  }
441
+ for (const timer of this.streamingTimers.values()) {
442
+ clearTimeout(timer);
443
+ }
444
+ this.streamingTimers.clear();
408
445
  this.pendingQueue = [];
409
446
  if (this.intersectionObserver) {
410
447
  this.intersectionObserver.disconnect();
@@ -868,7 +905,7 @@ var SettingsStore = class {
868
905
  await this.refreshKeyStatus();
869
906
  return { ok: true };
870
907
  } catch (err) {
871
- return { ok: false, error: err?.message || String(err) };
908
+ return { ok: false, error: describeError(err) };
872
909
  }
873
910
  }
874
911
  dispose() {
package/lib/client.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/client/index.ts", "../src/client/translate/client-cache.ts", "../src/client/translate/api.ts", "../src/client/translate/mount.ts", "../src/client/translate/viewport-observer.ts", "../src/client/translate/lazy.ts", "../src/client/translate/observer.ts", "../src/client/settings/ui.tsx", "../src/client/settings/store.ts", "../src/client/settings/styles.ts"],
4
- "sourcesContent": ["import { chatTranslateObserver } from './translate/observer.ts';\nimport { setupSettingsUi } from './settings/ui.tsx';\n\n/** Client plugin name, shared with the browser bundle id. */\nexport const name = 'dsh-chat-translate';\n\n/**\n * Declared services: slots for the settings section, settingsScope for the\n * per-namespace settings mirror, and the remote + remote.credentials pair for\n * the credentials Remote namespace \u2014 the runtime withholds any service not\n * declared here, so `ctx.remote.credentials` would be undefined otherwise.\n */\nexport const inject = ['slots', 'settingsScope', 'remote', 'remote.credentials'];\n\ninterface ClientContext {\n effect(factory: () => void | (() => void), label: string): void;\n get?(serviceName: string): any;\n slots?: any;\n settingsScope?: any;\n remote?: { credentials?: any };\n}\n\n/**\n * Mount the tool-call / think-summary translation observer and the settings UI.\n * @param ctx - DSH browser client context.\n */\nexport function apply(ctx: ClientContext): void {\n // 1. Mount tool title / think summary translation observer (current session only)\n ctx.effect(() => chatTranslateObserver.start(document), 'dsh-chat-translate: title translate observer');\n\n // 2. Mount settings UI section\n ctx.effect(() => setupSettingsUi(ctx), 'dsh-chat-translate: settings section');\n}\n\nexport { chatTranslateObserver } from './translate/observer.ts';\nexport { setupSettingsUi } from './settings/ui.tsx';\nexport { NonDestructiveTranslationMount } from './translate/mount.ts';\nexport { StreamDebounceViewportObserver } from './translate/viewport-observer.ts';\nexport { clientCache } from './translate/client-cache.ts';\nexport { lazyQueue } from './translate/lazy.ts';\nexport { settingsStore } from './settings/store.ts';\n", "const CACHE_KEY = 'dsh-chat-translate:cache';\nconst MAX_LOCAL_ENTRIES = 500;\n/** Entries older than this are treated as expired. */\nconst TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days\n\ninterface CacheEntry {\n t: number; // epoch ms; 0 = legacy entry without timestamp\n v: string;\n}\n\nexport class ClientCache {\n // Map preserves insertion order in JS, enabling true LRU semantics.\n private memCache = new Map<string, CacheEntry>();\n private dirty = false;\n private saveTimer: number | null = null;\n\n constructor() {\n this.load();\n }\n\n private load(): void {\n if (typeof localStorage === 'undefined') return;\n try {\n const raw = localStorage.getItem(CACHE_KEY);\n if (raw) {\n const obj = JSON.parse(raw);\n if (obj && typeof obj === 'object') {\n for (const [k, entry] of Object.entries(obj)) {\n if (typeof entry === 'string') {\n // Legacy entry from an older release.\n this.memCache.set(k, { t: 0, v: entry });\n } else if (entry && typeof entry === 'object' && typeof (entry as CacheEntry).v === 'string') {\n this.memCache.set(k, entry as CacheEntry);\n }\n }\n }\n }\n } catch {\n // Ignore parse failure\n }\n }\n\n get(text: string): string | undefined {\n const key = text.trim().toLowerCase();\n const entry = this.memCache.get(key);\n if (entry === undefined) return undefined;\n // Drop dirty fallback entries where value equals key\n if (entry.v && entry.v.trim().toLowerCase() === key) {\n this.memCache.delete(key);\n this.dirty = true;\n this.scheduleSave();\n return undefined;\n }\n if (entry.t > 0 && Date.now() - entry.t > TTL_MS) {\n this.memCache.delete(key);\n this.dirty = true;\n this.scheduleSave();\n return undefined;\n }\n // True LRU: Re-insert to move to the end (most recently used)\n this.memCache.delete(key);\n this.memCache.set(key, entry);\n return entry.v;\n }\n\n set(text: string, translated: string): void {\n const key = text.trim().toLowerCase();\n if (this.memCache.has(key)) {\n this.memCache.delete(key);\n } else if (this.memCache.size >= MAX_LOCAL_ENTRIES) {\n // Evict least recently used (first item in Map)\n const oldestKey = this.memCache.keys().next().value;\n if (oldestKey !== undefined) {\n this.memCache.delete(oldestKey);\n }\n }\n this.memCache.set(key, { t: Date.now(), v: translated });\n this.dirty = true;\n this.scheduleSave();\n }\n\n private scheduleSave(): void {\n if (this.saveTimer !== null || typeof window === 'undefined') return;\n this.saveTimer = window.setTimeout(() => {\n this.saveTimer = null;\n this.flushSync();\n }, 2000);\n }\n\n flushSync(): void {\n if (!this.dirty || typeof localStorage === 'undefined') return;\n this.dirty = false;\n try {\n const obj: Record<string, CacheEntry> = {};\n for (const [k, v] of this.memCache.entries()) {\n obj[k] = v;\n }\n localStorage.setItem(CACHE_KEY, JSON.stringify(obj));\n } catch {\n // Ignore quota error\n }\n }\n\n clear(): void {\n this.memCache.clear();\n this.dirty = true;\n this.flushSync();\n }\n\n size(): number {\n return this.memCache.size;\n }\n}\n\nexport const clientCache = new ClientCache();", "export interface TranslateItemResult {\n original: string;\n translated: string;\n channel: string;\n cached: boolean;\n}\n\nexport interface TranslateBatchOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n}\n\nexport async function requestTranslateBatch(\n texts: string[],\n options: TranslateBatchOptions = {}\n): Promise<TranslateItemResult[]> {\n if (!Array.isArray(texts) || texts.length === 0) return [];\n \n // Filter out empty or whitespace-only texts\n const validTexts = texts.map((t) => (typeof t === 'string' ? t : ''));\n if (validTexts.length === 0) return [];\n\n const controller = new AbortController();\n const timeoutId = options.timeoutMs\n ? setTimeout(() => controller.abort(), options.timeoutMs)\n : null;\n\n const effectiveSignal = options.signal\n ? (options.signal.aborted ? options.signal : controller.signal)\n : controller.signal;\n\n if (options.signal) {\n options.signal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n\n try {\n const res = await fetch('/api/dsh-chat-translate/translate', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ texts: validTexts }),\n signal: effectiveSignal,\n });\n\n if (res.ok) {\n const data = (await res.json()) as { ok: boolean; results?: TranslateItemResult[]; error?: string };\n if (data.ok && Array.isArray(data.results) && data.results.length > 0) {\n return data.results;\n } else if (data.error) {\n console.warn(`[dsh-chat-translate] \u7FFB\u8BD1\u63A5\u53E3\u9519\u8BEF: ${data.error}`);\n }\n } else {\n console.warn(`[dsh-chat-translate] \u7FFB\u8BD1\u8BF7\u6C42\u5931\u8D25 (HTTP ${res.status})`);\n }\n } catch (err: any) {\n if (err?.name === 'AbortError') {\n // Intentionally aborted\n }\n } finally {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n }\n\n // Host route unreachable or error \u2014 leave the original text untouched\n return validTexts.map((t) => ({\n original: t,\n translated: t,\n channel: 'fallback-client',\n cached: false,\n }));\n}\n\nexport async function testServerChannel(channel: string): Promise<{ ok: boolean; latencyMs: number; error?: string }> {\n try {\n const res = await fetch('/api/dsh-chat-translate/test-channel', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ channel }),\n });\n return await res.json();\n } catch (err: any) {\n return { ok: false, latencyMs: 0, error: err?.message || String(err) };\n }\n}\n", "/**\n * Non-destructive translation DOM mount mechanism.\n *\n * Preserves the original React Fiber tree, event listeners, and nested DOM nodes\n * by wrapping them in a hidden container (<span class=\"dsh-tidy-original-hidden\">)\n * rather than destroying them with `element.textContent = translated`.\n *\n * Displays the translated text in a companion container (<span class=\"dsh-tidy-translated-block\">).\n * Clicking the translation toggles between original and translated text in-place.\n */\n\nexport const CLASS_ORIGINAL_HIDDEN = 'dsh-tidy-original-hidden';\nexport const CLASS_ORIGINAL_SHOWN = 'dsh-tidy-original-shown';\nexport const CLASS_TRANSLATED_BLOCK = 'dsh-tidy-translated-block';\n\nexport interface MountOptions {\n originalText?: string;\n interactive?: boolean;\n}\n\nexport class NonDestructiveTranslationMount {\n /**\n * Mounts a translated string onto the target element non-destructively.\n */\n static mount(\n element: HTMLElement,\n translated: string,\n options: MountOptions = {}\n ): void {\n if (!element || !element.ownerDocument) return;\n const doc = element.ownerDocument;\n\n // Check if already mounted\n let transWrapper = element.querySelector<HTMLElement>(`:scope > .${CLASS_TRANSLATED_BLOCK}`);\n let origWrapper = element.querySelector<HTMLElement>(\n `:scope > .${CLASS_ORIGINAL_HIDDEN}, :scope > .${CLASS_ORIGINAL_SHOWN}`\n );\n\n if (transWrapper && origWrapper) {\n // Update existing translation\n transWrapper.textContent = translated;\n element.dataset.tidyTranslated = 'true';\n if (options.originalText) element.dataset.original = options.originalText;\n return;\n }\n\n const originalText = options.originalText ?? this.extractVisibleText(element);\n\n // Create wrapper for original children\n origWrapper = doc.createElement('span');\n origWrapper.className = CLASS_ORIGINAL_HIDDEN;\n origWrapper.style.display = 'none';\n\n // Move all existing child nodes into origWrapper\n while (element.firstChild) {\n origWrapper.appendChild(element.firstChild);\n }\n\n // Create translation block\n transWrapper = doc.createElement('span');\n transWrapper.className = CLASS_TRANSLATED_BLOCK;\n transWrapper.textContent = translated;\n\n // Interactive bilingual toggle\n const interactive = options.interactive !== false;\n if (interactive) {\n\n const showOriginal = (e: MouseEvent): void => {\n e.stopPropagation();\n if (!origWrapper || !transWrapper) return;\n origWrapper.style.display = 'inline';\n origWrapper.className = CLASS_ORIGINAL_SHOWN;\n transWrapper.style.display = 'none';\n };\n\n const showTranslated = (e: MouseEvent): void => {\n e.stopPropagation();\n if (!origWrapper || !transWrapper) return;\n origWrapper.style.display = 'none';\n origWrapper.className = CLASS_ORIGINAL_HIDDEN;\n transWrapper.style.display = 'inline';\n };\n\n transWrapper.addEventListener('click', showOriginal);\n origWrapper.addEventListener('click', showTranslated);\n }\n\n // Append both to target element\n element.appendChild(transWrapper);\n element.appendChild(origWrapper);\n\n element.dataset.tidyTranslated = 'true';\n element.dataset.original = originalText;\n }\n\n /**\n * Unmounts translation and restores original DOM nodes completely.\n */\n static unmount(element: HTMLElement): void {\n if (!element) return;\n\n const origWrapper = element.querySelector<HTMLElement>(\n `:scope > .${CLASS_ORIGINAL_HIDDEN}, :scope > .${CLASS_ORIGINAL_SHOWN}`\n );\n const transWrapper = element.querySelector<HTMLElement>(`:scope > .${CLASS_TRANSLATED_BLOCK}`);\n\n if (origWrapper) {\n // Move all original children back to element\n while (origWrapper.firstChild) {\n element.insertBefore(origWrapper.firstChild, origWrapper);\n }\n origWrapper.remove();\n }\n\n if (transWrapper) {\n transWrapper.remove();\n }\n\n // Fallback if no wrapper was created but text was modified directly\n if (!origWrapper && element.dataset.original) {\n element.textContent = element.dataset.original;\n }\n\n delete element.dataset.tidyTranslated;\n delete element.dataset.original;\n }\n\n /**\n * Checks if an element has non-destructive translation mounted.\n */\n static isMounted(element: HTMLElement): boolean {\n return (\n element.dataset.tidyTranslated === 'true' &&\n !!element.querySelector(`:scope > .${CLASS_TRANSLATED_BLOCK}`)\n );\n }\n\n /**\n * Gets the original text recorded on the element or contained in origWrapper.\n */\n static getOriginal(element: HTMLElement): string | undefined {\n if (element.dataset.original) return element.dataset.original;\n const origWrapper = element.querySelector<HTMLElement>(\n `:scope > .${CLASS_ORIGINAL_HIDDEN}, :scope > .${CLASS_ORIGINAL_SHOWN}`\n );\n return origWrapper ? origWrapper.textContent?.trim() : undefined;\n }\n\n /**\n * Extracts text content excluding our own translation wrappers.\n */\n static extractVisibleText(element: HTMLElement): string {\n const origWrapper = element.querySelector<HTMLElement>(\n `:scope > .${CLASS_ORIGINAL_HIDDEN}, :scope > .${CLASS_ORIGINAL_SHOWN}`\n );\n if (origWrapper) {\n return origWrapper.textContent?.trim() || '';\n }\n const transWrapper = element.querySelector<HTMLElement>(`:scope > .${CLASS_TRANSLATED_BLOCK}`);\n if (transWrapper) {\n return transWrapper.textContent?.trim() || '';\n }\n return element.textContent?.trim() || '';\n }\n}", "/**\n * StreamDebounceViewportObserver\n *\n * Combines:\n * 1. True IntersectionObserver for viewport visibility detection (rootMargin: '150px 0px').\n * 2. Typing/streaming debounce (default 400ms) to avoid translating partial streaming sentences.\n * 3. Batch queuing to group multiple visible elements into efficient batch requests.\n */\n\nexport interface ViewportObserverOptions {\n rootMargin?: string;\n debounceMs?: number;\n onVisibleBatch: (items: Array<{ element: HTMLElement; text: string }>) => void;\n}\n\nexport class StreamDebounceViewportObserver {\n private intersectionObserver: IntersectionObserver | null = null;\n private streamingTimers = new WeakMap<HTMLElement, number>();\n private pendingQueue: Array<{ element: HTMLElement; text: string }> = [];\n private batchFlushTimer: number | null = null;\n private options: Required<Omit<ViewportObserverOptions, 'onVisibleBatch'>> & {\n onVisibleBatch: ViewportObserverOptions['onVisibleBatch'];\n };\n\n constructor(options: ViewportObserverOptions) {\n this.options = {\n rootMargin: options.rootMargin ?? '150px 0px',\n debounceMs: options.debounceMs ?? 400,\n onVisibleBatch: options.onVisibleBatch,\n };\n this.initIntersectionObserver();\n }\n\n private initIntersectionObserver(): void {\n if (typeof window === 'undefined' || typeof IntersectionObserver === 'undefined') {\n return;\n }\n\n this.intersectionObserver = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target instanceof HTMLElement) {\n const el = entry.target;\n // Stop observing once it enters viewport and is queued\n this.intersectionObserver?.unobserve(el);\n const text = el.dataset.tidyPendingText || el.textContent?.trim() || '';\n if (text) {\n delete el.dataset.tidyPendingText;\n this.enqueueBatch(el, text);\n }\n }\n }\n },\n {\n root: null, // viewport\n rootMargin: this.options.rootMargin,\n threshold: 0,\n }\n );\n }\n\n /**\n * Observe an element with streaming debounce.\n * If streaming updates characterData repeatedly within debounceMs, the timer resets.\n */\n observeWithDebounce(element: HTMLElement, text: string, immediate = false): void {\n if (!element || !text) return;\n\n // Clear any active streaming timer for this element\n const existingTimer = this.streamingTimers.get(element);\n if (existingTimer !== undefined) {\n clearTimeout(existingTimer);\n this.streamingTimers.delete(element);\n }\n\n if (immediate || this.options.debounceMs <= 0) {\n this.registerForViewport(element, text);\n return;\n }\n\n const timer = window.setTimeout(() => {\n this.streamingTimers.delete(element);\n if (element.isConnected) {\n // Read latest text content after streaming settles\n const latestText = element.textContent?.trim() || text;\n this.registerForViewport(element, latestText);\n }\n }, this.options.debounceMs);\n\n this.streamingTimers.set(element, timer);\n }\n\n private registerForViewport(element: HTMLElement, text: string): void {\n if (!element.isConnected) return;\n\n if (!this.intersectionObserver) {\n // Fallback if IntersectionObserver is unsupported: enqueue immediately\n this.enqueueBatch(element, text);\n return;\n }\n\n element.dataset.tidyPendingText = text;\n this.intersectionObserver.observe(element);\n }\n\n private enqueueBatch(element: HTMLElement, text: string): void {\n this.pendingQueue.push({ element, text });\n if (this.batchFlushTimer === null && typeof window !== 'undefined') {\n this.batchFlushTimer = window.setTimeout(() => {\n this.batchFlushTimer = null;\n this.flushQueue();\n }, 50);\n }\n }\n\n private flushQueue(): void {\n if (this.pendingQueue.length === 0) return;\n const batch = [...this.pendingQueue];\n this.pendingQueue = [];\n this.options.onVisibleBatch(batch);\n }\n\n unobserve(element: HTMLElement): void {\n const timer = this.streamingTimers.get(element);\n if (timer !== undefined) {\n clearTimeout(timer);\n this.streamingTimers.delete(element);\n }\n delete element.dataset.tidyPendingText;\n if (this.intersectionObserver) {\n this.intersectionObserver.unobserve(element);\n }\n }\n\n disconnect(): void {\n if (this.batchFlushTimer !== null) {\n clearTimeout(this.batchFlushTimer);\n this.batchFlushTimer = null;\n }\n this.pendingQueue = [];\n if (this.intersectionObserver) {\n this.intersectionObserver.disconnect();\n this.initIntersectionObserver();\n }\n }\n}\n", "import { clientCache } from './client-cache.ts';\nimport { requestTranslateBatch } from './api.ts';\nimport { NonDestructiveTranslationMount } from './mount.ts';\nimport { StreamDebounceViewportObserver } from './viewport-observer.ts';\n\ntype TranslateTask = {\n element: HTMLElement;\n text: string;\n};\n\nclass LazyTranslationQueue {\n private enabled = true;\n private viewportObserver: StreamDebounceViewportObserver;\n\n constructor() {\n this.viewportObserver = new StreamDebounceViewportObserver({\n rootMargin: '150px 0px',\n debounceMs: 400,\n onVisibleBatch: (items) => this.handleVisibleBatch(items),\n });\n }\n\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n if (!enabled) {\n this.viewportObserver.disconnect();\n }\n }\n\n observe(element: HTMLElement, text: string, immediate = false): void {\n if (!this.enabled || !element.isConnected) return;\n\n // 1. If cached, apply immediately non-destructively\n const cached = clientCache.get(text);\n if (cached) {\n this.applyTranslation(element, cached, text);\n return;\n }\n\n // 2. Delegate to streaming-debounced viewport observer\n this.viewportObserver.observeWithDebounce(element, text, immediate);\n }\n\n private async handleVisibleBatch(items: TranslateTask[]): Promise<void> {\n if (!this.enabled || items.length === 0) return;\n\n // Document order: translations appear in reading order (top-to-bottom),\n // never out-of-order even when IntersectionObserver fires entries randomly.\n const sorted = [...items].sort((a, b) => {\n if (a.element === b.element) return 0;\n const pos = a.element.compareDocumentPosition(b.element);\n return pos & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;\n });\n\n // Group elements by text to deduplicate API requests\n const textMap = new Map<string, HTMLElement[]>();\n for (const item of sorted) {\n if (!item.element.isConnected) continue;\n\n const cached = clientCache.get(item.text);\n if (cached) {\n this.applyTranslation(item.element, cached, item.text);\n continue;\n }\n\n const list = textMap.get(item.text) || [];\n list.push(item.element);\n textMap.set(item.text, list);\n }\n\n const uniqueTexts = Array.from(textMap.keys());\n if (uniqueTexts.length === 0) return;\n\n const results = await requestTranslateBatch(uniqueTexts);\n\n for (const res of results) {\n if (\n res.translated &&\n res.translated.trim() &&\n res.channel !== 'fallback' &&\n res.channel !== 'fallback-client' &&\n res.translated.trim() !== res.original.trim()\n ) {\n clientCache.set(res.original, res.translated);\n const entries = textMap.get(res.original) || [];\n for (const entry of entries) {\n if (entry.isConnected && this.enabled) {\n this.applyTranslation(entry, res.translated, res.original);\n }\n }\n } else if (res.channel === 'fallback' || res.channel === 'fallback-client') {\n console.debug(`[dsh-chat-translate] \u7FFB\u8BD1\u672A\u6210\u529F (\u964D\u7EA7\u4FDD\u7559\u539F\u6587): \"${res.original.slice(0, 40)}\"`);\n }\n }\n }\n\n private applyTranslation(element: HTMLElement, translated: string, original: string): void {\n if (!element.isConnected || !this.enabled) return;\n NonDestructiveTranslationMount.mount(element, translated, {\n originalText: original,\n });\n }\n\n disconnect(): void {\n this.viewportObserver.disconnect();\n }\n}\n\nexport const lazyQueue = new LazyTranslationQueue();", "import { clientCache } from './client-cache.ts';\nimport { lazyQueue } from './lazy.ts';\nimport { NonDestructiveTranslationMount } from './mount.ts';\n\n// Case-insensitive match: DSH builds vary the summary class casing across\n// versions \u2014 lowercase \"summary\" for tool-call rows (MISisG_summary /\n// _48RFeq_summary) vs camelCase \"thinkSummary\" for the Think card row.\n// Attribute values are matched case-sensitively by default in HTML, which is\n// why the old lowercase-only selector silently missed think summaries.\nconst TOOL_TITLE_SELECTOR = '[class*=\"summary\" i]';\n\n/**\n * Current-session scroll container (the conversation layout re-renders this\n * whole subtree when the active session changes), falling back to the chat\n * flow. Both are emitted by the DSH web UI.\n */\nconst SESSION_ROOT_SELECTOR = '[data-conversation-scroll], [data-chat-flow]';\n\n/** How often (ms) we re-check that the observed root is still the live one. */\nconst ROOT_CHECK_INTERVAL_MS = 3000;\n\nfunction isToolSummarySpan(span: HTMLElement): boolean {\n if (!span || span.nodeType !== 1) return false;\n if (span.hasAttribute('aria-hidden')) return false;\n\n // Never match parent rows or containers that contain title, leading icon, chevron or nested summary\n if (span.querySelector?.('[class*=\"title\"], [class*=\"leading\"], [class*=\"chevron\"], [class*=\"sep\"], [class*=\"summary\" i]')) {\n return false;\n }\n\n const cls = span.className || '';\n if (/title|leading|icon|badge|chevron|separator|sep\\b|row\\b|root\\b|card\\b/i.test(cls)) return false;\n\n // Never translate fold toggle (\"\u5C55\u5F00\"/\"\u6536\u8D77\") or Think card's own title badge (\"Think\"/\"\u601D\u8003\")\n const rawToggle = (span.textContent || '').trim();\n if (\n rawToggle.length <= 12 &&\n /^(\u5C55\u5F00|\u6536\u8D77|\u5C55\u5F00\u5168\u90E8|\u6536\u8D77\u5168\u90E8|Expand|Collapse|Show more|Show less|Think|\u601D\u8003)$/i.test(rawToggle)\n ) {\n return false;\n }\n if (rawToggle === 'Think' || rawToggle === '\u601D\u8003') return false;\n if (\n span.closest('button, [role=\"button\"]') &&\n rawToggle.length <= 12 &&\n /\u5C55\u5F00|\u6536\u8D77|Expand|Collapse|Think|\u601D\u8003/i.test(rawToggle)\n ) {\n return false;\n }\n\n // Must belong to tool call or think block card\n if (\n span.closest(\n '[data-chat-call-id], [data-slot=\"tool.call.toolview\"], [data-sample], [data-variant], [data-tool], [data-disclosure-row]'\n )\n ) {\n return true;\n }\n return false;\n}\n\n/**\n * DSH's Think card (ReasoningRow) carries `data-state=\"running\"` on its root\n * while the reasoning block is still streaming and flips it to `\"ok\"` once it\n * has finished. While running, the collapsed summary follows the live tail of\n * the reasoning text (`.summary[data-follow-end]`), so translating it would\n * capture an intermediate line that is replaced by the stable first-line\n * summary when the block ends. Defer instead: the observed `data-state`\n * mutation re-scans this span, at which point the final summary is processed.\n */\nfunction thinkBlockStillRunning(span: HTMLElement): boolean {\n const thinkRoot = span.closest<HTMLElement>('[data-variant=\"think\"]');\n return !!thinkRoot && thinkRoot.dataset.state === 'running';\n}\n\nexport class ChatTranslateObserver {\n private observer: MutationObserver | null = null;\n private rootElement: HTMLElement | null = null;\n private rootCheckTimer: number | null = null;\n private isEnabled = true;\n\n constructor() {\n this.handleMutations = this.handleMutations.bind(this);\n }\n\n setEnabled(enabled: boolean): void {\n this.isEnabled = enabled;\n if (enabled) {\n lazyQueue.setEnabled(true);\n this.start();\n } else {\n this.restoreOriginals();\n this.disconnect();\n lazyQueue.setEnabled(false);\n }\n }\n\n private restoreOriginals(): void {\n const scope = this.rootElement ?? document;\n const spans = scope.querySelectorAll<HTMLElement>('[data-tidy-translated=\"true\"]');\n for (const span of spans) {\n NonDestructiveTranslationMount.unmount(span);\n }\n }\n\n /**\n * The active session's scroll container. Only the currently-viewed session\n * is translated; switching sessions replaces this subtree and the observer\n * naturally follows the new content.\n */\n private isVisible(el: HTMLElement): boolean {\n if (el.hasAttribute('hidden')) return false;\n if (el.style.display === 'none') return false;\n try {\n return el.getClientRects().length > 0;\n } catch {\n return true;\n }\n }\n\n private findRoot(documentRef: Document): HTMLElement {\n if (!documentRef.body) {\n return documentRef.documentElement;\n }\n const candidates = documentRef.querySelectorAll<HTMLElement>(SESSION_ROOT_SELECTOR);\n for (const el of candidates) {\n if (this.isVisible(el)) {\n return el;\n }\n }\n return documentRef.body;\n }\n\n start(documentRef: Document = document): () => void {\n if (!this.isEnabled || typeof window === 'undefined') {\n return () => {};\n }\n\n const findAndObserveRoot = () => {\n const root = this.findRoot(documentRef);\n\n this.rootElement = root;\n\n // 1. Initial scan of existing tool elements\n this.scanContainer(root);\n\n // 2. Setup MutationObserver\n if (!this.observer) {\n this.observer = new MutationObserver(this.handleMutations);\n this.observer.observe(root, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n attributeFilter: ['data-state', 'data-tool', 'data-variant', 'data-sample', 'aria-expanded'],\n });\n }\n };\n\n findAndObserveRoot();\n\n // Defense: if the observed root is detached or hidden (e.g. the user\n // switched to another view), re-probe for the live session container.\n this.scheduleRootCheck();\n\n return () => {\n this.disconnect();\n };\n }\n\n private scheduleRootCheck(): void {\n if (this.rootCheckTimer !== null || typeof window === 'undefined') return;\n this.rootCheckTimer = window.setInterval(() => {\n if (this.rootElement && this.rootElement.isConnected && this.isVisible(this.rootElement)) {\n return;\n }\n this.restart();\n }, ROOT_CHECK_INTERVAL_MS);\n }\n\n private restart(): void {\n if (typeof window === 'undefined') return;\n const wasEnabled = this.isEnabled;\n this.disconnect();\n if (wasEnabled) {\n this.start();\n }\n }\n\n private handleMutations(mutations: MutationRecord[]): void {\n if (!this.isEnabled) return;\n\n for (const mutation of mutations) {\n if (mutation.type === 'childList') {\n for (let i = 0; i < mutation.addedNodes.length; i++) {\n const node = mutation.addedNodes[i];\n if (node instanceof HTMLElement) {\n if (\n node.classList?.contains('dsh-tidy-translated-block') ||\n node.classList?.contains('dsh-tidy-original-hidden') ||\n node.classList?.contains('dsh-tidy-original-shown')\n ) {\n continue;\n }\n this.scanNode(node);\n }\n }\n } else if (mutation.type === 'attributes') {\n const target = mutation.target;\n if (target instanceof HTMLElement) {\n if (\n target.classList?.contains('dsh-tidy-translated-block') ||\n target.classList?.contains('dsh-tidy-original-hidden') ||\n target.classList?.contains('dsh-tidy-original-shown')\n ) {\n continue;\n }\n this.scanNode(target);\n }\n } else if (mutation.type === 'characterData') {\n const parent = mutation.target.parentElement;\n if (parent instanceof HTMLElement) {\n if (\n parent.classList?.contains('dsh-tidy-translated-block') ||\n parent.classList?.contains('dsh-tidy-original-hidden') ||\n parent.classList?.contains('dsh-tidy-original-shown')\n ) {\n continue;\n }\n this.scanNode(parent);\n }\n }\n }\n }\n\n private scanContainer(container: HTMLElement): void {\n const spans = container.querySelectorAll<HTMLElement>(TOOL_TITLE_SELECTOR);\n spans.forEach((span) => {\n if (isToolSummarySpan(span)) {\n this.processSpan(span);\n }\n });\n }\n\n private scanNode(node: HTMLElement): void {\n if (node.matches?.(TOOL_TITLE_SELECTOR) && isToolSummarySpan(node)) {\n this.processSpan(node);\n }\n\n const spans = node.querySelectorAll<HTMLElement>(TOOL_TITLE_SELECTOR);\n spans.forEach((span) => {\n if (isToolSummarySpan(span)) {\n this.processSpan(span);\n }\n });\n }\n\n private processSpan(span: HTMLElement): void {\n // Think summaries are translated only after the reasoning block has fully\n // finished streaming \u2014 never while `data-state=\"running\"` (the summary is\n // then a live tail line that would be replaced moments later). The\n // transition to \"ok\" triggers a re-scan via the observed data-state\n // attribute, which is when this span becomes processable.\n if (thinkBlockStillRunning(span)) return;\n\n if (NonDestructiveTranslationMount.isMounted(span)) {\n const original = NonDestructiveTranslationMount.getOriginal(span);\n if (original) {\n const cached = clientCache.get(original);\n if (cached) return;\n }\n return;\n }\n\n const text = NonDestructiveTranslationMount.extractVisibleText(span);\n if (!text) return;\n\n // Check fast client cache\n const cached = clientCache.get(text);\n if (cached) {\n NonDestructiveTranslationMount.mount(span, cached, {\n originalText: text,\n });\n return;\n }\n\n // Send to viewport lazy queue\n lazyQueue.observe(span, text);\n }\n\n disconnect(): void {\n if (this.rootCheckTimer !== null) {\n clearInterval(this.rootCheckTimer);\n this.rootCheckTimer = null;\n }\n if (this.observer) {\n this.observer.disconnect();\n this.observer = null;\n }\n lazyQueue.disconnect();\n this.rootElement = null;\n }\n}\n\nexport const chatTranslateObserver = new ChatTranslateObserver();\n", "import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { settingsStore, SETTINGS_NAMESPACE, type ClientSettingsState } from './store.ts';\nimport { SETTINGS_CSS } from './styles.ts';\nlet stylesInjected = false;\nfunction ensureSettingsStyles(): void {\n if (stylesInjected || typeof document === 'undefined') return;\n const el = document.createElement('style');\n el.dataset.tidySettings = 'true';\n el.textContent = SETTINGS_CSS;\n document.head.appendChild(el);\n stylesInjected = true;\n}\n\nfunction Switch(props: { checked: boolean; onChange: () => void; label: string }): React.ReactElement {\n return (\n <button\n type=\"button\"\n className=\"dsh-tidy-switch\"\n role=\"switch\"\n aria-checked={props.checked}\n onClick={props.onChange}\n aria-label={props.label}\n />\n );\n}\n\nexport function TidySettingsPanel(): React.ReactElement {\n ensureSettingsStyles();\n\n const [state, setState] = useState<ClientSettingsState>(() => settingsStore.getState());\n const [testing, setTesting] = useState<{ channel: string; running: boolean; ok?: boolean; message?: string } | null>(null);\n const [apiKeyInput, setApiKeyInput] = useState('');\n const [savingKey, setSavingKey] = useState(false);\n const [keyMsg, setKeyMsg] = useState<{ ok: boolean; text: string } | null>(null);\n\n useEffect(() => {\n return settingsStore.subscribe(() => {\n setState(settingsStore.getState());\n });\n }, []);\n\n const runTest = async (channel: string): Promise<void> => {\n setTesting({ channel, running: true });\n const res = await settingsStore.testChannel(channel);\n const message = res.ok\n ? `\u8FDE\u63A5\u6B63\u5E38\uFF0C\u5EF6\u8FDF ${res.latencyMs}ms`\n : `\u5931\u8D25\uFF1A${res.error || '\u672A\u77E5\u9519\u8BEF'}`;\n setTesting({ channel, running: false, ok: res.ok, message });\n };\n\n const handleSaveKey = async (): Promise<void> => {\n setSavingKey(true);\n setKeyMsg(null);\n const res = await settingsStore.saveApiKey(apiKeyInput);\n setSavingKey(false);\n if (res.ok) {\n const cleared = !apiKeyInput.trim();\n setKeyMsg({\n ok: true,\n text: cleared\n ? '\u5DF2\u6E05\u9664 API Key\uFF08AI \u901A\u9053\u5C06\u4E0D\u53EF\u7528\uFF0CBing \u515C\u5E95\uFF09'\n : '\u5DF2\u4FDD\u5B58\u5230 ~/.dsh/.credentials.yaml\uFF0C\u7ACB\u5373\u751F\u6548',\n });\n setApiKeyInput('');\n } else {\n setKeyMsg({ ok: false, text: `\u4FDD\u5B58\u5931\u8D25\uFF1A${res.error || '\u672A\u77E5\u9519\u8BEF'}` });\n }\n };\n\n return (\n <div className=\"dsh-tidy-settings\">\n {/* 1. \u603B\u5F00\u5173 */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-title\">\n <span>\u5DE5\u5177\u8C03\u7528\u4E0E\u601D\u8003\u6458\u8981\u7FFB\u8BD1</span>\n <Switch\n checked={state.enabled}\n onChange={() => settingsStore.update({ enabled: !state.enabled })}\n label=\"\u542F\u7528\u5DE5\u5177\u8C03\u7528\u4E0E\u6458\u8981\u7FFB\u8BD1\"\n />\n </div>\n <div className=\"dsh-tidy-desc\">\n \u81EA\u52A8\u5C06\u5F53\u524D\u4F1A\u8BDD\u4E2D\u5DE5\u5177\u8C03\u7528\u6807\u9898\u4E0E\u601D\u8003\u6298\u53E0\u6458\u8981\uFF08\u5982 <code>Locate DSH home directory structure</code>\uFF09\u7FFB\u8BD1\u4E3A\u4E2D\u6587\uFF0C\n \u70B9\u51FB\u8BD1\u6587\u53EF\u539F\u5730\u5207\u6362\u539F\u6587/\u8BD1\u6587\u3002\u601D\u8003\u6298\u53E0\u6458\u8981\u4EC5\u5728\u601D\u8003\u5B8C\u5168\u7ED3\u675F\u540E\u624D\u7FFB\u8BD1\uFF08\u4E0D\u7FFB\u8BD1\u6D41\u5F0F\u4E2D\u95F4\u6001\uFF09\u3002\n \u4EC5\u4F5C\u7528\u4E8E\u5F53\u524D\u67E5\u770B\u7684\u4F1A\u8BDD\uFF0C\u5BF9\u8BDD\u6B63\u6587\u6C38\u4E0D\u7FFB\u8BD1\u3002\n </div>\n </div>\n\n {state.enabled && (\n <>\n {/* 2. AI \u901A\u9053 */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-title\">\n <span>AI \u7FFB\u8BD1\uFF08OpenAI \u517C\u5BB9\u534F\u8BAE\uFF09</span>\n <Switch\n checked={state.aiEnabled}\n onChange={() => settingsStore.update({ aiEnabled: !state.aiEnabled })}\n label=\"\u542F\u7528 AI \u7FFB\u8BD1\u901A\u9053\"\n />\n </div>\n <div className=\"dsh-tidy-desc\">\n <span className={`dsh-tidy-badge ${state.aiConfigured ? 'dsh-tidy-badge-ok' : 'dsh-tidy-badge-warn'}`}>\n {state.aiConfigured ? '\u5DF2\u914D\u7F6E' : '\u672A\u914D\u7F6E'}\n </span>{' '}\n \u672A\u914D\u7F6E\u65F6 AI \u901A\u9053\u81EA\u52A8\u8DF3\u8FC7\uFF0C\u7531 Bing \u515C\u5E95\u3002\n </div>\n\n {state.aiEnabled && (\n <>\n <div className=\"dsh-tidy-row\">\n <div className=\"dsh-tidy-row-info\">\n <div className=\"dsh-tidy-row-title\">API Key</div>\n <div className=\"dsh-tidy-row-desc\">\n \u4FDD\u5B58\u81F3 <code>~/.dsh/.credentials.yaml</code> \u7684 <code>TRANSLATE_API_KEY</code>\uFF0C\u4FDD\u5B58\u540E\u7ACB\u5373\u751F\u6548\uFF1B\u7559\u7A7A\u4FDD\u5B58 = \u6E05\u9664\n </div>\n </div>\n <div className=\"dsh-tidy-input-row\">\n <input\n type=\"password\"\n className=\"dsh-tidy-input\"\n placeholder={state.aiConfigured ? '\u5DF2\u914D\u7F6E\uFF08\u5982\u9700\u66F4\u6362\u8BF7\u76F4\u63A5\u8F93\u5165\uFF09' : 'sk-...'}\n value={apiKeyInput}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setApiKeyInput(e.target.value)}\n style={{ width: '260px' }}\n aria-label=\"API Key\"\n />\n <button type=\"button\" className=\"dsh-tidy-btn\" disabled={savingKey} onClick={handleSaveKey}>\n {savingKey ? '\u4FDD\u5B58\u4E2D\u2026' : '\u4FDD\u5B58'}\n </button>\n </div>\n </div>\n {keyMsg && (\n <div className={`dsh-tidy-test-result ${keyMsg.ok ? 'ok' : 'fail'}`}>{keyMsg.text}</div>\n )}\n\n <div className=\"dsh-tidy-row\">\n <div className=\"dsh-tidy-row-info\">\n <div className=\"dsh-tidy-row-title\">Base URL</div>\n <div className=\"dsh-tidy-row-desc\">\n \u4EFB\u610F OpenAI \u517C\u5BB9\u670D\u52A1\u7AEF\u70B9\uFF0C\u5982 <code>https://api.openai.com/v1</code>\u3001{' '}\n <code>https://api.deepseek.com/v1</code>\n </div>\n </div>\n <input\n type=\"text\"\n className=\"dsh-tidy-input\"\n placeholder=\"https://api.openai.com/v1\"\n value={state.baseUrl}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n settingsStore.update({ baseUrl: e.target.value })\n }\n style={{ width: '260px' }}\n aria-label=\"AI Base URL\"\n />\n </div>\n <div className=\"dsh-tidy-row\">\n <div className=\"dsh-tidy-row-info\">\n <div className=\"dsh-tidy-row-title\">\u6A21\u578B</div>\n <div className=\"dsh-tidy-row-desc\">\n \u5982 <code>gpt-4o-mini</code>\u3001<code>deepseek-chat</code>\uFF1B\u7559\u7A7A\u89C6\u4E3A\u672A\u914D\u7F6E\n </div>\n </div>\n <input\n type=\"text\"\n className=\"dsh-tidy-input\"\n placeholder=\"gpt-4o-mini\"\n value={state.model}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n settingsStore.update({ model: e.target.value })\n }\n style={{ width: '260px' }}\n aria-label=\"AI \u6A21\u578B\"\n />\n </div>\n <div className=\"dsh-tidy-row\">\n <button\n type=\"button\"\n className=\"dsh-tidy-btn\"\n disabled={testing?.running}\n onClick={() => runTest('openai')}\n >\n {testing?.running ? '\u6D4B\u8BD5\u4E2D\u2026' : '\u6D4B\u8BD5 AI \u901A\u9053'}\n </button>\n {testing?.channel === 'openai' && !testing.running && (\n <span className={`dsh-tidy-test-result ${testing.ok ? 'ok' : 'fail'}`}>{testing.message}</span>\n )}\n </div>\n </>\n )}\n </div>\n\n {/* 3. Bing \u901A\u9053 */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-title\">\n <span>Bing \u7F51\u9875\u7FFB\u8BD1\uFF08\u514D Key \u515C\u5E95\uFF09</span>\n <Switch\n checked={state.bingEnabled}\n onChange={() => settingsStore.update({ bingEnabled: !state.bingEnabled })}\n label=\"\u542F\u7528 Bing \u7FFB\u8BD1\u901A\u9053\"\n />\n </div>\n <div className=\"dsh-tidy-desc\">\n \u5185\u7F6E\u514D Key \u7FFB\u8BD1\u901A\u9053\uFF0C\u65E0\u9700\u4EFB\u4F55\u914D\u7F6E\u3002AI \u672A\u914D\u7F6E\u6216\u8BF7\u6C42\u5931\u8D25\u65F6\u81EA\u52A8\u515C\u5E95\uFF1BAI \u4E0E Bing \u540C\u65F6\u5173\u95ED\u5219\u4E0D\u7FFB\u8BD1\u3002\n </div>\n </div>\n\n {/* 4. \u884C\u4E3A\u8BF4\u660E */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-row-title\">\u901A\u9053\u884C\u4E3A</div>\n <ul className=\"dsh-tidy-desc dsh-tidy-behavior-list\">\n <li>AI \u5F00\u542F\u4E14\u5DF2\u914D\u7F6E \u2192 AI \u4F18\u5148\u7FFB\u8BD1\uFF0C\u5931\u8D25\u81EA\u52A8\u964D\u7EA7 Bing</li>\n <li>AI \u5F00\u542F\u4F46\u672A\u914D\u7F6E + Bing \u5F00\u542F \u2192 \u7531 Bing \u7FFB\u8BD1</li>\n <li>AI \u5F00\u542F\u4F46\u672A\u914D\u7F6E + Bing \u5173\u95ED \u2192 \u4E0D\u7FFB\u8BD1</li>\n <li>AI \u5173\u95ED + Bing \u5F00\u542F \u2192 \u76F4\u63A5\u4F7F\u7528 Bing</li>\n <li>AI \u5173\u95ED + Bing \u5173\u95ED \u2192 \u4E0D\u7FFB\u8BD1</li>\n </ul>\n </div>\n\n {/* 5. \u5E76\u53D1\u63A7\u5236 */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-row\">\n <div className=\"dsh-tidy-row-info\">\n <div className=\"dsh-tidy-row-title\">\u6700\u5927\u7FFB\u8BD1\u5E76\u53D1\u6570</div>\n <div className=\"dsh-tidy-row-desc\">\n \u63A7\u5236\u89C6\u53E3\u6EDA\u52A8\u4E0E\u591A\u5DE5\u5177\u5361\u7247\u65F6\u7684\u6700\u5927\u5E76\u884C\u8BF7\u6C42\u6570\uFF08\u8303\u56F4 1-100\uFF0C\u63A8\u8350 3\uFF09\u3002\n </div>\n </div>\n <input\n type=\"number\"\n className=\"dsh-tidy-input\"\n min={1}\n max={100}\n step={1}\n value={state.concurrency}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n const val = parseInt(e.target.value, 10);\n if (!Number.isFinite(val)) return;\n settingsStore.update({ concurrency: Math.min(Math.max(val, 1), 100) });\n }}\n style={{ width: '88px' }}\n aria-label=\"\u6700\u5927\u7FFB\u8BD1\u5E76\u53D1\u6570\"\n />\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n\nexport function setupSettingsUi(ctx: any): void {\n if (typeof window === 'undefined') return;\n\n // Ride DSH's own settings surface: the `settingsScope` service mirrors the\n // host document (per-namespace describe) and the `credentials` Remote API\n // writes the API key. No custom config HTTP endpoint since 1.2.\n try {\n // Declared via inject: 'settingsScope' and 'remote.credentials' (plus the\n // 'remote' root). Fall back to optional lookup so a degraded environment\n // degrades to an in-memory store instead of failing loudly.\n const settingsScope = ctx?.settingsScope || (ctx?.get ? ctx.get('settingsScope') : null);\n const remoteCredentials =\n ctx?.remote?.credentials || (ctx?.get ? ctx.get('remote.credentials') : null);\n if (settingsScope && typeof settingsScope.bind === 'function') {\n const scope = settingsScope.bind({ namespace: SETTINGS_NAMESPACE });\n settingsStore.attach(scope, remoteCredentials ?? null);\n }\n } catch (err) {\n console.warn('[dsh-chat-translate] Failed to bind settings scope:', err);\n }\n\n try {\n const slots = ctx?.slots || (ctx?.get ? ctx.get('slots') : null);\n if (!slots || typeof slots.inject !== 'function') return;\n\n slots.inject('settings.section', () => {\n return slots.register(\n {\n name: 'settings.section',\n id: 'dsh-chat-translate',\n // \u7EA6\u5B9A\uFF1A\u81EA\u6709\u63D2\u4EF6\u8BBE\u7F6E\u9879 order \u4ECE 110 \u8D77\u6B65\u8FDB 10\uFF08\u539F\u751F\u6700\u5927 100=\u684C\u9762\u8BBE\u7F6E\uFF09\uFF0C\u4FDD\u8BC1\u6392\u5728\u6240\u6709\u539F\u751F\u9879\u4E4B\u4E0B\n order: 110,\n label: () => '\u804A\u5929\u7FFB\u8BD1',\n },\n TidySettingsPanel\n );\n });\n } catch (err) {\n console.warn('[dsh-chat-translate] Failed to inject settings section:', err);\n }\n}\n", "import { chatTranslateObserver } from '../translate/observer.ts';\nimport { testServerChannel } from '../translate/api.ts';\n\nexport interface ClientSettingsState {\n enabled: boolean;\n concurrency: number;\n aiEnabled: boolean;\n bingEnabled: boolean;\n baseUrl: string;\n model: string;\n aiConfigured: boolean;\n}\n\n/** Settings namespace + credentials ref, mirroring the host constants. */\nexport const SETTINGS_NAMESPACE = 'dsh-chat-translate';\nexport const TRANSLATE_API_KEY_REF = 'TRANSLATE_API_KEY';\n\n/**\n * Minimal structural shapes of the DSH browser services this store rides on:\n * `settingsScope` (from @deepseek-ai/dsh-client-ui-settings) and the\n * `credentials` Remote namespace. Keeping them structural keeps this bundle\n * free of host-service imports and lets tests inject fakes.\n */\nexport interface SettingsScopeLike {\n getSnapshot(): {\n status: string;\n value?: Record<string, unknown>;\n writable: boolean;\n };\n subscribe(listener: () => void): () => void;\n set(field: string, value: unknown): Promise<unknown>;\n unset(field: string): Promise<unknown>;\n}\n\n/** Shape of every DSH client Remote call: {ok, value} / {ok, error} wrapper. */\nexport type RemoteResult<T> =\n | { ok: true; value: T }\n | { ok: false; error: { code?: string; message: string; details?: unknown } };\n\nexport interface CredentialsRemoteLike {\n describe(\n refs: string[]\n ): Promise<RemoteResult<Record<string, { configured: boolean; source?: string; writable: boolean }>>>;\n set(ref: string, value: string): Promise<RemoteResult<void>>;\n unset(ref: string): Promise<RemoteResult<void>>;\n}\n\nconst DEFAULT_STATE: ClientSettingsState = {\n enabled: true,\n concurrency: 3,\n aiEnabled: true,\n bingEnabled: true,\n baseUrl: '',\n model: '',\n aiConfigured: false,\n};\n\n/**\n * Client settings store backed by the DSH settings namespace.\n *\n * Since 1.2 there is no localStorage overlay and no custom config HTTP\n * endpoint: the store derives from the bound `settingsScope` (which mirrors\n * the host document and folds every write answer back), and writes go\n * through `scope.set` \u2014 serialized, revision-checked, persisted by DSH.\n * Without a bound scope (e.g. non-loopback pages, unit tests) it degrades to\n * an in-memory store with the same semantics DSH itself uses for memory\n * persistence.\n */\nclass SettingsStore {\n private state: ClientSettingsState = { ...DEFAULT_STATE };\n private listeners = new Set<() => void>();\n private scope: SettingsScopeLike | null = null;\n private credentials: CredentialsRemoteLike | null = null;\n private unsubscribeScope: (() => void) | null = null;\n private keyConfigured = false;\n private writeTimer: number | null = null;\n private pendingFields = new Set<string>();\n\n /**\n * Bind the DSH services. Called once from the settings UI setup; re-binding\n * (e.g. after a reconnect) detaches the previous subscription first.\n */\n attach(scope: SettingsScopeLike | null, credentials: CredentialsRemoteLike | null): void {\n if (this.unsubscribeScope) {\n this.unsubscribeScope();\n this.unsubscribeScope = null;\n }\n this.scope = scope;\n this.credentials = credentials;\n if (scope) {\n this.unsubscribeScope = scope.subscribe(() => this.derive());\n this.derive();\n }\n void this.refreshKeyStatus();\n }\n\n getState(): ClientSettingsState {\n return { ...this.state };\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** Map the resolved namespace value into client state and notify. */\n private derive(): void {\n if (!this.scope) return;\n const snap = this.scope.getSnapshot();\n const value = snap.value;\n if (!value || typeof value !== 'object') return;\n const next: ClientSettingsState = { ...this.state };\n if (typeof value.enabled === 'boolean') next.enabled = value.enabled;\n const c = value.concurrency;\n if (typeof c === 'number' && Number.isFinite(c)) {\n next.concurrency = Math.min(Math.max(Math.round(c), 1), 100);\n }\n if (typeof value.aiEnabled === 'boolean') next.aiEnabled = value.aiEnabled;\n if (typeof value.bingEnabled === 'boolean') next.bingEnabled = value.bingEnabled;\n if (typeof value.baseUrl === 'string') next.baseUrl = value.baseUrl;\n if (typeof value.model === 'string') next.model = value.model;\n this.applyState(next);\n }\n\n private applyState(next: ClientSettingsState): void {\n next.aiConfigured = Boolean(next.baseUrl && next.model && this.keyConfigured);\n const enabledChanged = next.enabled !== this.state.enabled;\n this.state = next;\n if (enabledChanged) {\n try {\n chatTranslateObserver.setEnabled(this.state.enabled);\n } catch {}\n }\n this.notify();\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n try {\n listener();\n } catch {}\n }\n }\n\n /** Pull the key's status-only view and re-derive aiConfigured. */\n private async refreshKeyStatus(): Promise<void> {\n if (!this.credentials) return;\n try {\n const res = await this.credentials.describe([TRANSLATE_API_KEY_REF]);\n if (!res.ok) return;\n const info = res.value[TRANSLATE_API_KEY_REF];\n const configured = Boolean(info?.configured);\n if (configured !== this.keyConfigured) {\n this.keyConfigured = configured;\n this.applyState({ ...this.state });\n }\n } catch {\n // Credentials surface unavailable \u2014 keep the last known status.\n }\n }\n\n /**\n * Optimistically apply locally, then persist each touched field through the\n * settings scope. Writes are trailing-debounced (300ms) so typing in the\n * baseUrl/model inputs collapses into a single queued mutation instead of\n * one write per keystroke \u2014 which would otherwise flash stale mirror values\n * back into the inputs between commits. A failed write makes the scope\n * reload its mirror, which re-derives this store from the host document\n * (conflict-safe recovery).\n */\n async update(partial: Partial<ClientSettingsState>): Promise<void> {\n let sanitizedConcurrency = this.state.concurrency;\n if (typeof partial.concurrency === 'number' && Number.isFinite(partial.concurrency)) {\n sanitizedConcurrency = Math.min(Math.max(Math.round(partial.concurrency), 1), 100);\n }\n const next: ClientSettingsState = {\n ...this.state,\n ...partial,\n concurrency: sanitizedConcurrency,\n };\n this.applyState(next);\n\n if (this.scope) {\n const fields = ['enabled', 'concurrency', 'aiEnabled', 'bingEnabled', 'baseUrl', 'model'] as const;\n for (const field of fields) {\n if (partial[field] !== undefined) {\n this.pendingFields.add(field);\n }\n }\n this.scheduleWrite();\n }\n }\n\n private scheduleWrite(): void {\n if (this.writeTimer !== null || typeof window === 'undefined') return;\n this.writeTimer = window.setTimeout(() => {\n this.writeTimer = null;\n void this.flushWrite();\n }, 300);\n }\n\n private async flushWrite(): Promise<void> {\n if (!this.scope) return;\n const fields = [...this.pendingFields];\n this.pendingFields.clear();\n const writes: Promise<unknown>[] = [];\n for (const field of fields) {\n writes.push(this.scope.set(field, this.state[field as keyof ClientSettingsState]));\n }\n await Promise.all(writes).catch(() => {});\n }\n\n async testChannel(channel: string): Promise<{ ok: boolean; latencyMs: number; error?: string }> {\n return testServerChannel(channel);\n }\n\n /** Write (or clear) the API key through the credentials Remote API. */\n async saveApiKey(apiKey: string): Promise<{ ok: boolean; error?: string }> {\n if (!this.credentials) {\n return { ok: false, error: '\u51ED\u636E\u670D\u52A1\u4E0D\u53EF\u7528\uFF08\u975E\u56DE\u73AF\u9875\u9762\uFF09' };\n }\n try {\n const key = apiKey.trim();\n // Remote calls resolve with {ok:false} instead of rejecting on refusal\n // (e.g. env-shadowed refs), so the .ok check decides the outcome.\n const res = key\n ? await this.credentials.set(TRANSLATE_API_KEY_REF, key)\n : await this.credentials.unset(TRANSLATE_API_KEY_REF);\n if (!res.ok) {\n return { ok: false, error: res.error?.message || '\u4FDD\u5B58\u5931\u8D25' };\n }\n await this.refreshKeyStatus();\n return { ok: true };\n } catch (err: any) {\n return { ok: false, error: err?.message || String(err) };\n }\n }\n\n dispose(): void {\n if (this.writeTimer !== null && typeof window !== 'undefined') {\n clearTimeout(this.writeTimer);\n this.writeTimer = null;\n }\n this.pendingFields.clear();\n if (this.unsubscribeScope) {\n this.unsubscribeScope();\n this.unsubscribeScope = null;\n }\n this.scope = null;\n this.credentials = null;\n this.listeners.clear();\n }\n}\n\nexport const settingsStore = new SettingsStore();\n", "export const SETTINGS_CSS = String.raw`\n.dsh-tidy-settings {\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 580px;\n padding-bottom: 32px;\n color: var(--dsw-alias-label-primary, inherit);\n font-family: inherit;\n}\n\n.dsh-tidy-card {\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.2));\n border-radius: 12px;\n padding: 16px 18px;\n background: var(--dsw-alias-bg-card, rgba(128, 128, 128, 0.05));\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.dsh-tidy-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, inherit);\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.dsh-tidy-desc {\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary, rgba(128, 128, 128, 0.8));\n}\n\n.dsh-tidy-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding: 8px 0;\n}\n\n.dsh-tidy-row + .dsh-tidy-row {\n border-top: 1px solid var(--dsw-alias-border-l3, rgba(128, 128, 128, 0.1));\n}\n\n.dsh-tidy-row-info {\n flex: 1;\n min-width: 0;\n}\n\n.dsh-tidy-row-title {\n font-size: 13px;\n font-weight: 500;\n}\n\n.dsh-tidy-row-desc {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, rgba(128, 128, 128, 0.7));\n margin-top: 2px;\n line-height: 1.4;\n}\n\n/* Switch */\n.dsh-tidy-switch {\n position: relative;\n width: 38px;\n height: 22px;\n flex: none;\n cursor: pointer;\n border-radius: 999px;\n border: none;\n background: rgba(128, 128, 128, 0.3);\n transition: background 0.15s ease;\n padding: 0;\n outline: none;\n}\n\n.dsh-tidy-switch[aria-checked=\"true\"] {\n background: #3b82f6;\n}\n\n.dsh-tidy-switch::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: #ffffff;\n transition: transform 0.15s ease;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n}\n\n.dsh-tidy-switch[aria-checked=\"true\"]::after {\n transform: translateX(16px);\n}\n\n/* Inputs */\n.dsh-tidy-input-group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dsh-tidy-label {\n font-size: 12px;\n font-weight: 500;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.dsh-tidy-input-row {\n display: flex;\n gap: 8px;\n}\n\n.dsh-tidy-input {\n flex: 1;\n min-width: 0;\n padding: 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n background: var(--dsw-alias-bg-input, rgba(0, 0, 0, 0.05));\n color: inherit;\n font-size: 12px;\n outline: none;\n transition: border-color 0.15s;\n}\n\n.dsh-tidy-input:focus {\n border-color: #3b82f6;\n}\n\n.dsh-tidy-btn {\n padding: 6px 14px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));\n background: transparent;\n color: inherit;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.dsh-tidy-btn:hover {\n background: rgba(128, 128, 128, 0.1);\n border-color: rgba(128, 128, 128, 0.5);\n}\n\n.dsh-tidy-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.dsh-tidy-badge {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 4px;\n font-weight: 500;\n}\n\n.dsh-tidy-badge-ok {\n background: rgba(34, 197, 94, 0.15);\n color: #22c55e;\n}\n\n.dsh-tidy-badge-none {\n background: rgba(156, 163, 175, 0.15);\n color: #9ca3af;\n}\n\n.dsh-tidy-badge-warn {\n background: rgba(245, 158, 11, 0.15);\n color: #f59e0b;\n}\n\n.dsh-tidy-test-result {\n font-size: 12px;\n margin-left: 10px;\n}\n\n.dsh-tidy-test-result.ok {\n color: #22c55e;\n}\n\n.dsh-tidy-test-result.fail {\n color: #ef4444;\n}\n\n.dsh-tidy-behavior-list {\n padding-left: 18px;\n margin: 4px 0 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n/* Priority list */\n.dsh-tidy-priority-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.dsh-tidy-priority-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n border-radius: 8px;\n background: rgba(128, 128, 128, 0.06);\n border: 1px solid var(--dsw-alias-border-l3, rgba(128, 128, 128, 0.12));\n}\n\n.dsh-tidy-priority-name {\n font-size: 12px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dsh-tidy-order-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: #3b82f6;\n color: #ffffff;\n font-size: 11px;\n font-weight: 600;\n}\n\n.dsh-tidy-btn-group {\n display: flex;\n gap: 4px;\n}\n\n.dsh-tidy-icon-btn {\n width: 26px;\n height: 26px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n border: 1px solid rgba(128, 128, 128, 0.2);\n background: transparent;\n color: inherit;\n cursor: pointer;\n font-size: 12px;\n}\n\n.dsh-tidy-icon-btn:hover:not(:disabled) {\n background: rgba(128, 128, 128, 0.15);\n}\n\n.dsh-tidy-icon-btn:disabled {\n opacity: 0.3;\n cursor: default;\n}\n\n/* Slider / Select */\n.dsh-tidy-select {\n padding: 6px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));\n background: var(--dsw-alias-bg-input, rgba(0, 0, 0, 0.05));\n color: inherit;\n font-size: 12px;\n outline: none;\n}\n`;\n"],
5
- "mappings": "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",
3
+ "sources": ["../src/client/index.ts", "../src/client/translate/client-cache.ts", "../src/describe-error.ts", "../src/client/translate/api.ts", "../src/client/translate/mount.ts", "../src/client/translate/viewport-observer.ts", "../src/client/translate/lazy.ts", "../src/client/translate/observer.ts", "../src/client/settings/ui.tsx", "../src/client/settings/store.ts", "../src/client/settings/styles.ts"],
4
+ "sourcesContent": ["import { chatTranslateObserver } from './translate/observer.ts';\nimport { setupSettingsUi } from './settings/ui.tsx';\n\n/** Client plugin name, shared with the browser bundle id. */\nexport const name = 'dsh-chat-translate';\n\n/**\n * Declared services: slots for the settings section, settingsScope for the\n * per-namespace settings mirror, and the remote + remote.credentials pair for\n * the credentials Remote namespace \u2014 the runtime withholds any service not\n * declared here, so `ctx.remote.credentials` would be undefined otherwise.\n */\nexport const inject = ['slots', 'settingsScope', 'remote', 'remote.credentials'];\n\ninterface ClientContext {\n effect(factory: () => void | (() => void), label: string): void;\n get?(serviceName: string): any;\n slots?: any;\n settingsScope?: any;\n remote?: { credentials?: any };\n}\n\n/**\n * Mount the tool-call / think-summary translation observer and the settings UI.\n * @param ctx - DSH browser client context.\n */\nexport function apply(ctx: ClientContext): void {\n // 1. Mount tool title / think summary translation observer (current session only)\n ctx.effect(() => chatTranslateObserver.start(document), 'dsh-chat-translate: title translate observer');\n\n // 2. Mount settings UI section\n ctx.effect(() => setupSettingsUi(ctx), 'dsh-chat-translate: settings section');\n}\n\nexport { chatTranslateObserver } from './translate/observer.ts';\nexport { setupSettingsUi } from './settings/ui.tsx';\nexport { NonDestructiveTranslationMount } from './translate/mount.ts';\nexport { StreamDebounceViewportObserver } from './translate/viewport-observer.ts';\nexport { clientCache } from './translate/client-cache.ts';\nexport { lazyQueue } from './translate/lazy.ts';\nexport { settingsStore } from './settings/store.ts';\n", "const CACHE_KEY = 'dsh-chat-translate:cache';\nconst MAX_LOCAL_ENTRIES = 500;\n/** Entries older than this are treated as expired. */\nconst TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days\n\ninterface CacheEntry {\n t: number; // epoch ms; 0 = legacy entry without timestamp\n v: string;\n}\n\nexport class ClientCache {\n // Map preserves insertion order in JS, enabling true LRU semantics.\n private memCache = new Map<string, CacheEntry>();\n private dirty = false;\n private saveTimer: number | null = null;\n\n constructor() {\n this.load();\n }\n\n private load(): void {\n if (typeof localStorage === 'undefined') return;\n try {\n const raw = localStorage.getItem(CACHE_KEY);\n if (raw) {\n const obj = JSON.parse(raw);\n if (obj && typeof obj === 'object') {\n for (const [k, entry] of Object.entries(obj)) {\n if (typeof entry === 'string') {\n // Legacy entry from an older release.\n this.memCache.set(k, { t: 0, v: entry });\n } else if (entry && typeof entry === 'object' && typeof (entry as CacheEntry).v === 'string') {\n this.memCache.set(k, entry as CacheEntry);\n }\n }\n }\n }\n } catch {\n // Ignore parse failure\n }\n }\n\n get(text: string): string | undefined {\n const key = text.trim().toLowerCase();\n const entry = this.memCache.get(key);\n if (entry === undefined) return undefined;\n // Drop dirty fallback entries where value equals key\n if (entry.v && entry.v.trim().toLowerCase() === key) {\n this.memCache.delete(key);\n this.dirty = true;\n this.scheduleSave();\n return undefined;\n }\n if (entry.t > 0 && Date.now() - entry.t > TTL_MS) {\n this.memCache.delete(key);\n this.dirty = true;\n this.scheduleSave();\n return undefined;\n }\n // True LRU: Re-insert to move to the end (most recently used)\n this.memCache.delete(key);\n this.memCache.set(key, entry);\n return entry.v;\n }\n\n set(text: string, translated: string): void {\n const key = text.trim().toLowerCase();\n if (this.memCache.has(key)) {\n this.memCache.delete(key);\n } else if (this.memCache.size >= MAX_LOCAL_ENTRIES) {\n // Evict least recently used (first item in Map)\n const oldestKey = this.memCache.keys().next().value;\n if (oldestKey !== undefined) {\n this.memCache.delete(oldestKey);\n }\n }\n this.memCache.set(key, { t: Date.now(), v: translated });\n this.dirty = true;\n this.scheduleSave();\n }\n\n private scheduleSave(): void {\n if (this.saveTimer !== null || typeof window === 'undefined') return;\n this.saveTimer = window.setTimeout(() => {\n this.saveTimer = null;\n this.flushSync();\n }, 2000);\n }\n\n flushSync(): void {\n if (!this.dirty || typeof localStorage === 'undefined') return;\n this.dirty = false;\n try {\n const obj: Record<string, CacheEntry> = {};\n for (const [k, v] of this.memCache.entries()) {\n obj[k] = v;\n }\n localStorage.setItem(CACHE_KEY, JSON.stringify(obj));\n } catch {\n // Ignore quota error\n }\n }\n\n clear(): void {\n this.memCache.clear();\n this.dirty = true;\n this.flushSync();\n }\n\n size(): number {\n return this.memCache.size;\n }\n}\n\nexport const clientCache = new ClientCache();", "/**\n * \u628A fetch / \u7F51\u7EDC\u5931\u8D25\u7684\u53EF\u8BFB\u539F\u56E0\u5C55\u5F00\u6210\u5355\u884C\u6587\u672C\uFF08\u5BBF\u4E3B\u4E0E\u5BA2\u6237\u7AEF\u5171\u7528\uFF09\u3002\n *\n * \u80CC\u666F\uFF1ANode 18+ \u4E0E\u6D4F\u89C8\u5668\u7684 fetch \u5728\u7F51\u7EDC\u5C42\u5931\u8D25\u65F6\u53EA\u7ED9\u4E00\u53E5 `TypeError: fetch failed`\n * \uFF08\u6D4F\u89C8\u5668\u662F `Failed to fetch`\uFF09\uFF0C\u771F\u5B9E\u539F\u56E0\u85CF\u5728 `err.cause` \u91CC\u2014\u2014\u4F8B\u5982\n * `connect ENETUNREACH 172.24.52.126:8081`\u3001`other side closed [UND_ERR_SOCKET]`\u3001\n * `getaddrinfo ENOTFOUND`\u3002\u53EA\u4E0A\u62A5 `err.message` \u4F1A\u8BA9\u300C\u7AEF\u70B9\u4E0D\u53EF\u8FBE / \u88AB\u4EE3\u7406\u65AD\u5F00\u300D\u548C\n * \u300C\u63D2\u4EF6\u81EA\u8EAB\u51FA\u9519\u300D\u957F\u5F97\u4E00\u6A21\u4E00\u6837\uFF1A\u7528\u6237\u53EA\u770B\u5230\u65E0\u4FE1\u606F\u91CF\u7684 fetch failed\uFF0C\u65E0\u4ECE\u5224\u65AD\u8BE5\u6539\u4EC0\u4E48\u3002\n *\n * \u8FD9\u91CC\u628A message \u4E0E cause \u94FE\uFF08\u542B AggregateError \u7684\u591A\u5730\u5740\u5931\u8D25\uFF09\u62FC\u6210 `A \u2190 B \u2190 C`\u3002\n */\nexport function describeError(err: unknown): string {\n if (err === null || err === undefined) return String(err);\n const parts: string[] = [];\n const push = (s: string): void => {\n const t = String(s || '').trim();\n if (t && !parts.includes(t)) parts.push(t);\n };\n const head = (err as { message?: string }).message || String(err);\n push(head);\n const headCode = (err as { code?: string }).code;\n if (headCode && !head.includes(headCode)) push('[' + headCode + ']');\n let cause = (err as { cause?: unknown }).cause as\n | { message?: string; code?: string; cause?: unknown; errors?: unknown }\n | undefined;\n for (let depth = 0; cause && depth < 4; depth++) {\n const label = cause.message || String(cause);\n push(cause.code && !label.includes(cause.code) ? label + ' [' + cause.code + ']' : label);\n // AggregateError\uFF1A\u591A\u5730\u5740\u5168\u90E8\u5931\u8D25\uFF08happy-eyeballs \u53CC\u6808\u5E38\u89C1\uFF09\uFF0C\u5C55\u5F00\u524D\u51E0\u6761\n if (Array.isArray(cause.errors)) {\n for (const sub of (cause.errors as { message?: string; code?: string }[]).slice(0, 3)) {\n if (sub) push(sub.code || sub.message || String(sub));\n }\n }\n cause = cause.cause as typeof cause;\n }\n return parts.join(' \u2190 ');\n}", "import { describeError } from '../../describe-error.ts';\n\nexport interface TranslateItemResult {\n original: string;\n translated: string;\n channel: string;\n cached: boolean;\n}\n\nexport interface TranslateBatchOptions {\n signal?: AbortSignal;\n timeoutMs?: number;\n}\n\nexport async function requestTranslateBatch(\n texts: string[],\n options: TranslateBatchOptions = {}\n): Promise<TranslateItemResult[]> {\n if (!Array.isArray(texts) || texts.length === 0) return [];\n \n // Filter out empty or whitespace-only texts\n const validTexts = texts.map((t) => (typeof t === 'string' ? t : ''));\n if (validTexts.length === 0) return [];\n\n const controller = new AbortController();\n const timeoutId = options.timeoutMs\n ? setTimeout(() => controller.abort(), options.timeoutMs)\n : null;\n\n const effectiveSignal = options.signal\n ? (options.signal.aborted ? options.signal : controller.signal)\n : controller.signal;\n\n if (options.signal) {\n options.signal.addEventListener('abort', () => controller.abort(), { once: true });\n }\n\n try {\n const res = await fetch('/api/dsh-chat-translate/translate', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ texts: validTexts }),\n signal: effectiveSignal,\n });\n\n if (res.ok) {\n const data = (await res.json()) as { ok: boolean; results?: TranslateItemResult[]; error?: string };\n if (data.ok && Array.isArray(data.results) && data.results.length > 0) {\n return data.results;\n } else if (data.error) {\n console.warn(`[dsh-chat-translate] \u7FFB\u8BD1\u63A5\u53E3\u9519\u8BEF: ${data.error}`);\n }\n } else {\n console.warn(`[dsh-chat-translate] \u7FFB\u8BD1\u8BF7\u6C42\u5931\u8D25 (HTTP ${res.status})`);\n }\n } catch (err: any) {\n if (err?.name === 'AbortError') {\n // Intentionally aborted\n }\n } finally {\n if (timeoutId !== null) {\n clearTimeout(timeoutId);\n }\n }\n\n // Host route unreachable or error \u2014 leave the original text untouched\n return validTexts.map((t) => ({\n original: t,\n translated: t,\n channel: 'fallback-client',\n cached: false,\n }));\n}\n\nexport async function testServerChannel(channel: string): Promise<{ ok: boolean; latencyMs: number; error?: string }> {\n try {\n const res = await fetch('/api/dsh-chat-translate/test-channel', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ channel }),\n });\n return await res.json();\n } catch (err: any) {\n return { ok: false, latencyMs: 0, error: describeError(err) };\n }\n}\n", "/**\n * Non-destructive translation DOM mount mechanism.\n *\n * Preserves the original React Fiber tree, event listeners, and nested DOM nodes\n * by wrapping them in a hidden container (<span class=\"dsh-tidy-original-hidden\">)\n * rather than destroying them with `element.textContent = translated`.\n *\n * Displays the translated text in a companion container (<span class=\"dsh-tidy-translated-block\">).\n * Clicking the translation toggles between original and translated text in-place.\n */\n\nexport const CLASS_ORIGINAL_HIDDEN = 'dsh-tidy-original-hidden';\nexport const CLASS_ORIGINAL_SHOWN = 'dsh-tidy-original-shown';\nexport const CLASS_TRANSLATED_BLOCK = 'dsh-tidy-translated-block';\n\nexport interface MountOptions {\n originalText?: string;\n interactive?: boolean;\n}\n\nexport class NonDestructiveTranslationMount {\n /**\n * Mounts a translated string onto the target element non-destructively.\n */\n static mount(\n element: HTMLElement,\n translated: string,\n options: MountOptions = {}\n ): void {\n if (!element || !element.ownerDocument) return;\n const doc = element.ownerDocument;\n\n // Check if already mounted\n let transWrapper = element.querySelector<HTMLElement>(`:scope > .${CLASS_TRANSLATED_BLOCK}`);\n let origWrapper = element.querySelector<HTMLElement>(\n `:scope > .${CLASS_ORIGINAL_HIDDEN}, :scope > .${CLASS_ORIGINAL_SHOWN}`\n );\n\n if (transWrapper && origWrapper) {\n // Update existing translation\n transWrapper.textContent = translated;\n element.dataset.tidyTranslated = 'true';\n if (options.originalText) element.dataset.original = options.originalText;\n return;\n }\n\n const originalText = options.originalText ?? this.extractVisibleText(element);\n\n // Create wrapper for original children\n origWrapper = doc.createElement('span');\n origWrapper.className = CLASS_ORIGINAL_HIDDEN;\n origWrapper.style.display = 'none';\n\n // Move all existing child nodes into origWrapper\n while (element.firstChild) {\n origWrapper.appendChild(element.firstChild);\n }\n\n // Create translation block\n transWrapper = doc.createElement('span');\n transWrapper.className = CLASS_TRANSLATED_BLOCK;\n transWrapper.textContent = translated;\n\n // Interactive bilingual toggle\n const interactive = options.interactive !== false;\n if (interactive) {\n\n const showOriginal = (e: MouseEvent): void => {\n e.stopPropagation();\n if (!origWrapper || !transWrapper) return;\n origWrapper.style.display = 'inline';\n origWrapper.className = CLASS_ORIGINAL_SHOWN;\n transWrapper.style.display = 'none';\n };\n\n const showTranslated = (e: MouseEvent): void => {\n e.stopPropagation();\n if (!origWrapper || !transWrapper) return;\n origWrapper.style.display = 'none';\n origWrapper.className = CLASS_ORIGINAL_HIDDEN;\n transWrapper.style.display = 'inline';\n };\n\n transWrapper.addEventListener('click', showOriginal);\n origWrapper.addEventListener('click', showTranslated);\n }\n\n // Append both to target element\n element.appendChild(transWrapper);\n element.appendChild(origWrapper);\n\n element.dataset.tidyTranslated = 'true';\n element.dataset.original = originalText;\n }\n\n /**\n * Unmounts translation and restores original DOM nodes completely.\n */\n static unmount(element: HTMLElement): void {\n if (!element) return;\n\n const origWrapper = element.querySelector<HTMLElement>(\n `:scope > .${CLASS_ORIGINAL_HIDDEN}, :scope > .${CLASS_ORIGINAL_SHOWN}`\n );\n const transWrapper = element.querySelector<HTMLElement>(`:scope > .${CLASS_TRANSLATED_BLOCK}`);\n\n if (origWrapper) {\n // Move all original children back to element\n while (origWrapper.firstChild) {\n element.insertBefore(origWrapper.firstChild, origWrapper);\n }\n origWrapper.remove();\n }\n\n if (transWrapper) {\n transWrapper.remove();\n }\n\n // Fallback if no wrapper was created but text was modified directly\n if (!origWrapper && element.dataset.original) {\n element.textContent = element.dataset.original;\n }\n\n delete element.dataset.tidyTranslated;\n delete element.dataset.original;\n }\n\n /**\n * Checks if an element has non-destructive translation mounted.\n */\n static isMounted(element: HTMLElement): boolean {\n return (\n element.dataset.tidyTranslated === 'true' &&\n !!element.querySelector(`:scope > .${CLASS_TRANSLATED_BLOCK}`)\n );\n }\n\n /**\n * Gets the original text recorded on the element or contained in origWrapper.\n */\n static getOriginal(element: HTMLElement): string | undefined {\n if (element.dataset.original) return element.dataset.original;\n const origWrapper = element.querySelector<HTMLElement>(\n `:scope > .${CLASS_ORIGINAL_HIDDEN}, :scope > .${CLASS_ORIGINAL_SHOWN}`\n );\n return origWrapper ? origWrapper.textContent?.trim() : undefined;\n }\n\n /**\n * Extracts text content excluding our own translation wrappers.\n */\n static extractVisibleText(element: HTMLElement): string {\n const origWrapper = element.querySelector<HTMLElement>(\n `:scope > .${CLASS_ORIGINAL_HIDDEN}, :scope > .${CLASS_ORIGINAL_SHOWN}`\n );\n if (origWrapper) {\n return origWrapper.textContent?.trim() || '';\n }\n const transWrapper = element.querySelector<HTMLElement>(`:scope > .${CLASS_TRANSLATED_BLOCK}`);\n if (transWrapper) {\n return transWrapper.textContent?.trim() || '';\n }\n return element.textContent?.trim() || '';\n }\n}", "/**\n * StreamDebounceViewportObserver\n *\n * Combines:\n * 1. True IntersectionObserver for viewport visibility detection (rootMargin: '150px 0px').\n * 2. Typing/streaming debounce (default 400ms) to avoid translating partial streaming sentences.\n * 3. Batch queuing to group multiple visible elements into efficient batch requests.\n */\n\nexport interface ViewportObserverOptions {\n rootMargin?: string;\n debounceMs?: number;\n onVisibleBatch: (items: Array<{ element: HTMLElement; text: string }>) => void;\n}\n\nexport class StreamDebounceViewportObserver {\n private intersectionObserver: IntersectionObserver | null = null;\n /**\n * Pending per-element streaming debounce timers. A Map (not a WeakMap)\n * because disconnect() must enumerate and clear every pending timer: a\n * WeakMap cannot be iterated, so a debounce armed just before the switch was\n * turned off would still fire registerForViewport() afterwards.\n */\n private streamingTimers = new Map<HTMLElement, number>();\n private pendingQueue: Array<{ element: HTMLElement; text: string }> = [];\n private batchFlushTimer: number | null = null;\n private options: Required<Omit<ViewportObserverOptions, 'onVisibleBatch'>> & {\n onVisibleBatch: ViewportObserverOptions['onVisibleBatch'];\n };\n\n constructor(options: ViewportObserverOptions) {\n this.options = {\n rootMargin: options.rootMargin ?? '150px 0px',\n debounceMs: options.debounceMs ?? 400,\n onVisibleBatch: options.onVisibleBatch,\n };\n this.initIntersectionObserver();\n }\n\n private initIntersectionObserver(): void {\n if (typeof window === 'undefined' || typeof IntersectionObserver === 'undefined') {\n return;\n }\n\n this.intersectionObserver = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting && entry.target instanceof HTMLElement) {\n const el = entry.target;\n // Stop observing once it enters viewport and is queued\n this.intersectionObserver?.unobserve(el);\n const text = el.dataset.tidyPendingText || el.textContent?.trim() || '';\n if (text) {\n delete el.dataset.tidyPendingText;\n this.enqueueBatch(el, text);\n }\n }\n }\n },\n {\n root: null, // viewport\n rootMargin: this.options.rootMargin,\n threshold: 0,\n }\n );\n }\n\n /**\n * Observe an element with streaming debounce.\n * If streaming updates characterData repeatedly within debounceMs, the timer resets.\n */\n observeWithDebounce(element: HTMLElement, text: string, immediate = false): void {\n if (!element || !text) return;\n\n // Clear any active streaming timer for this element\n const existingTimer = this.streamingTimers.get(element);\n if (existingTimer !== undefined) {\n clearTimeout(existingTimer);\n this.streamingTimers.delete(element);\n }\n\n if (immediate || this.options.debounceMs <= 0) {\n this.registerForViewport(element, text);\n return;\n }\n\n const timer = window.setTimeout(() => {\n // Stale-callback guard: disconnect() clears the map, so a callback that\n // is no longer the registered timer must not re-enter the observer.\n if (this.streamingTimers.get(element) !== timer) return;\n this.streamingTimers.delete(element);\n if (element.isConnected) {\n // Read latest text content after streaming settles\n const latestText = element.textContent?.trim() || text;\n this.registerForViewport(element, latestText);\n }\n }, this.options.debounceMs);\n\n this.streamingTimers.set(element, timer);\n }\n\n private registerForViewport(element: HTMLElement, text: string): void {\n if (!element.isConnected) return;\n\n if (!this.intersectionObserver) {\n // Fallback if IntersectionObserver is unsupported: enqueue immediately\n this.enqueueBatch(element, text);\n return;\n }\n\n element.dataset.tidyPendingText = text;\n this.intersectionObserver.observe(element);\n }\n\n private enqueueBatch(element: HTMLElement, text: string): void {\n this.pendingQueue.push({ element, text });\n if (this.batchFlushTimer === null && typeof window !== 'undefined') {\n this.batchFlushTimer = window.setTimeout(() => {\n this.batchFlushTimer = null;\n this.flushQueue();\n }, 50);\n }\n }\n\n private flushQueue(): void {\n if (this.pendingQueue.length === 0) return;\n const batch = [...this.pendingQueue];\n this.pendingQueue = [];\n this.options.onVisibleBatch(batch);\n }\n\n unobserve(element: HTMLElement): void {\n const timer = this.streamingTimers.get(element);\n if (timer !== undefined) {\n clearTimeout(timer);\n this.streamingTimers.delete(element);\n }\n delete element.dataset.tidyPendingText;\n if (this.intersectionObserver) {\n this.intersectionObserver.unobserve(element);\n }\n }\n\n disconnect(): void {\n if (this.batchFlushTimer !== null) {\n clearTimeout(this.batchFlushTimer);\n this.batchFlushTimer = null;\n }\n // Drop every pending streaming debounce: after a disable none of them may\n // fire registerForViewport() (the Map is iterable, so this is exhaustive).\n for (const timer of this.streamingTimers.values()) {\n clearTimeout(timer);\n }\n this.streamingTimers.clear();\n this.pendingQueue = [];\n if (this.intersectionObserver) {\n this.intersectionObserver.disconnect();\n this.initIntersectionObserver();\n }\n }\n}\n", "import { clientCache } from './client-cache.ts';\nimport { requestTranslateBatch } from './api.ts';\nimport { NonDestructiveTranslationMount } from './mount.ts';\nimport { StreamDebounceViewportObserver } from './viewport-observer.ts';\n\ntype TranslateTask = {\n element: HTMLElement;\n text: string;\n};\n\nclass LazyTranslationQueue {\n private enabled = true;\n private viewportObserver: StreamDebounceViewportObserver;\n\n constructor() {\n this.viewportObserver = new StreamDebounceViewportObserver({\n rootMargin: '150px 0px',\n debounceMs: 400,\n onVisibleBatch: (items) => this.handleVisibleBatch(items),\n });\n }\n\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n if (!enabled) {\n this.viewportObserver.disconnect();\n }\n }\n\n observe(element: HTMLElement, text: string, immediate = false): void {\n if (!this.enabled || !element.isConnected) return;\n\n // 1. If cached, apply immediately non-destructively\n const cached = clientCache.get(text);\n if (cached) {\n this.applyTranslation(element, cached, text);\n return;\n }\n\n // 2. Delegate to streaming-debounced viewport observer\n this.viewportObserver.observeWithDebounce(element, text, immediate);\n }\n\n private async handleVisibleBatch(items: TranslateTask[]): Promise<void> {\n if (!this.enabled || items.length === 0) return;\n\n // Document order: translations appear in reading order (top-to-bottom),\n // never out-of-order even when IntersectionObserver fires entries randomly.\n const sorted = [...items].sort((a, b) => {\n if (a.element === b.element) return 0;\n const pos = a.element.compareDocumentPosition(b.element);\n return pos & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;\n });\n\n // Group elements by text to deduplicate API requests\n const textMap = new Map<string, HTMLElement[]>();\n for (const item of sorted) {\n if (!item.element.isConnected) continue;\n\n const cached = clientCache.get(item.text);\n if (cached) {\n this.applyTranslation(item.element, cached, item.text);\n continue;\n }\n\n const list = textMap.get(item.text) || [];\n list.push(item.element);\n textMap.set(item.text, list);\n }\n\n const uniqueTexts = Array.from(textMap.keys());\n if (uniqueTexts.length === 0) return;\n\n const results = await requestTranslateBatch(uniqueTexts);\n\n for (const res of results) {\n if (\n res.translated &&\n res.translated.trim() &&\n res.channel !== 'fallback' &&\n res.channel !== 'fallback-client' &&\n res.translated.trim() !== res.original.trim()\n ) {\n clientCache.set(res.original, res.translated);\n const entries = textMap.get(res.original) || [];\n for (const entry of entries) {\n if (entry.isConnected && this.enabled) {\n this.applyTranslation(entry, res.translated, res.original);\n }\n }\n } else if (res.channel === 'fallback' || res.channel === 'fallback-client') {\n console.debug(`[dsh-chat-translate] \u7FFB\u8BD1\u672A\u6210\u529F (\u964D\u7EA7\u4FDD\u7559\u539F\u6587): \"${res.original.slice(0, 40)}\"`);\n }\n }\n }\n\n private applyTranslation(element: HTMLElement, translated: string, original: string): void {\n if (!element.isConnected || !this.enabled) return;\n NonDestructiveTranslationMount.mount(element, translated, {\n originalText: original,\n });\n }\n\n disconnect(): void {\n this.viewportObserver.disconnect();\n }\n}\n\nexport const lazyQueue = new LazyTranslationQueue();", "import { clientCache } from './client-cache.ts';\nimport { lazyQueue } from './lazy.ts';\nimport { NonDestructiveTranslationMount } from './mount.ts';\n\n// Case-insensitive match: DSH builds vary the summary class casing across\n// versions \u2014 lowercase \"summary\" for tool-call rows (MISisG_summary /\n// _48RFeq_summary) vs camelCase \"thinkSummary\" for the Think card row.\n// Attribute values are matched case-sensitively by default in HTML, which is\n// why the old lowercase-only selector silently missed think summaries.\nconst TOOL_TITLE_SELECTOR = '[class*=\"summary\" i]';\n\n/**\n * Current-session scroll container (the conversation layout re-renders this\n * whole subtree when the active session changes), falling back to the chat\n * flow. Both are emitted by the DSH web UI.\n */\nconst SESSION_ROOT_SELECTOR = '[data-conversation-scroll], [data-chat-flow]';\n\n/** How often (ms) we re-check that the observed root is still the live one. */\nconst ROOT_CHECK_INTERVAL_MS = 3000;\n\nfunction isToolSummarySpan(span: HTMLElement): boolean {\n if (!span || span.nodeType !== 1) return false;\n if (span.hasAttribute('aria-hidden')) return false;\n\n // Never match parent rows or containers that contain title, leading icon, chevron or nested summary\n if (span.querySelector?.('[class*=\"title\"], [class*=\"leading\"], [class*=\"chevron\"], [class*=\"sep\"], [class*=\"summary\" i]')) {\n return false;\n }\n\n const cls = span.className || '';\n if (/title|leading|icon|badge|chevron|separator|sep\\b|row\\b|root\\b|card\\b/i.test(cls)) return false;\n\n // Never translate fold toggle (\"\u5C55\u5F00\"/\"\u6536\u8D77\") or Think card's own title badge (\"Think\"/\"\u601D\u8003\")\n const rawToggle = (span.textContent || '').trim();\n if (\n rawToggle.length <= 12 &&\n /^(\u5C55\u5F00|\u6536\u8D77|\u5C55\u5F00\u5168\u90E8|\u6536\u8D77\u5168\u90E8|Expand|Collapse|Show more|Show less|Think|\u601D\u8003)$/i.test(rawToggle)\n ) {\n return false;\n }\n if (rawToggle === 'Think' || rawToggle === '\u601D\u8003') return false;\n if (\n span.closest('button, [role=\"button\"]') &&\n rawToggle.length <= 12 &&\n /\u5C55\u5F00|\u6536\u8D77|Expand|Collapse|Think|\u601D\u8003/i.test(rawToggle)\n ) {\n return false;\n }\n\n // Must belong to tool call or think block card\n if (\n span.closest(\n '[data-chat-call-id], [data-slot=\"tool.call.toolview\"], [data-sample], [data-variant], [data-tool], [data-disclosure-row]'\n )\n ) {\n return true;\n }\n return false;\n}\n\n/**\n * DSH's Think card (ReasoningRow) carries `data-state=\"running\"` on its root\n * while the reasoning block is still streaming and flips it to `\"ok\"` once it\n * has finished. While running, the collapsed summary follows the live tail of\n * the reasoning text (`.summary[data-follow-end]`), so translating it would\n * capture an intermediate line that is replaced by the stable first-line\n * summary when the block ends. Defer instead: the observed `data-state`\n * mutation re-scans this span, at which point the final summary is processed.\n */\nfunction thinkBlockStillRunning(span: HTMLElement): boolean {\n const thinkRoot = span.closest<HTMLElement>('[data-variant=\"think\"]');\n return !!thinkRoot && thinkRoot.dataset.state === 'running';\n}\n\nexport class ChatTranslateObserver {\n private observer: MutationObserver | null = null;\n private rootElement: HTMLElement | null = null;\n private rootCheckTimer: number | null = null;\n private isEnabled = true;\n\n constructor() {\n this.handleMutations = this.handleMutations.bind(this);\n }\n\n setEnabled(enabled: boolean): void {\n this.isEnabled = enabled;\n if (enabled) {\n lazyQueue.setEnabled(true);\n this.start();\n } else {\n this.restoreOriginals();\n this.disconnect();\n lazyQueue.setEnabled(false);\n }\n }\n\n private restoreOriginals(): void {\n const scope = this.rootElement ?? document;\n const spans = scope.querySelectorAll<HTMLElement>('[data-tidy-translated=\"true\"]');\n for (const span of spans) {\n NonDestructiveTranslationMount.unmount(span);\n }\n }\n\n /**\n * The active session's scroll container. Only the currently-viewed session\n * is translated; switching sessions replaces this subtree and the observer\n * naturally follows the new content.\n */\n private isVisible(el: HTMLElement): boolean {\n if (el.hasAttribute('hidden')) return false;\n if (el.style.display === 'none') return false;\n try {\n return el.getClientRects().length > 0;\n } catch {\n return true;\n }\n }\n\n private findRoot(documentRef: Document): HTMLElement {\n if (!documentRef.body) {\n return documentRef.documentElement;\n }\n const candidates = documentRef.querySelectorAll<HTMLElement>(SESSION_ROOT_SELECTOR);\n for (const el of candidates) {\n if (this.isVisible(el)) {\n return el;\n }\n }\n return documentRef.body;\n }\n\n start(documentRef: Document = document): () => void {\n if (!this.isEnabled || typeof window === 'undefined') {\n return () => {};\n }\n\n const findAndObserveRoot = () => {\n const root = this.findRoot(documentRef);\n\n this.rootElement = root;\n\n // 1. Initial scan of existing tool elements\n this.scanContainer(root);\n\n // 2. Setup MutationObserver\n if (!this.observer) {\n this.observer = new MutationObserver(this.handleMutations);\n this.observer.observe(root, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n attributeFilter: ['data-state', 'data-tool', 'data-variant', 'data-sample', 'aria-expanded'],\n });\n }\n };\n\n findAndObserveRoot();\n\n // Defense: if the observed root is detached or hidden (e.g. the user\n // switched to another view), re-probe for the live session container.\n this.scheduleRootCheck();\n\n return () => {\n this.disconnect();\n };\n }\n\n private scheduleRootCheck(): void {\n if (this.rootCheckTimer !== null || typeof window === 'undefined') return;\n this.rootCheckTimer = window.setInterval(() => {\n if (this.rootElement && this.rootElement.isConnected && this.isVisible(this.rootElement)) {\n return;\n }\n this.restart();\n }, ROOT_CHECK_INTERVAL_MS);\n }\n\n private restart(): void {\n if (typeof window === 'undefined') return;\n const wasEnabled = this.isEnabled;\n this.disconnect();\n if (wasEnabled) {\n this.start();\n }\n }\n\n private handleMutations(mutations: MutationRecord[]): void {\n if (!this.isEnabled) return;\n\n for (const mutation of mutations) {\n if (mutation.type === 'childList') {\n for (let i = 0; i < mutation.addedNodes.length; i++) {\n const node = mutation.addedNodes[i];\n if (node instanceof HTMLElement) {\n if (\n node.classList?.contains('dsh-tidy-translated-block') ||\n node.classList?.contains('dsh-tidy-original-hidden') ||\n node.classList?.contains('dsh-tidy-original-shown')\n ) {\n continue;\n }\n this.scanNode(node);\n }\n }\n } else if (mutation.type === 'attributes') {\n const target = mutation.target;\n if (target instanceof HTMLElement) {\n if (\n target.classList?.contains('dsh-tidy-translated-block') ||\n target.classList?.contains('dsh-tidy-original-hidden') ||\n target.classList?.contains('dsh-tidy-original-shown')\n ) {\n continue;\n }\n this.scanNode(target);\n }\n } else if (mutation.type === 'characterData') {\n const parent = mutation.target.parentElement;\n if (parent instanceof HTMLElement) {\n if (\n parent.classList?.contains('dsh-tidy-translated-block') ||\n parent.classList?.contains('dsh-tidy-original-hidden') ||\n parent.classList?.contains('dsh-tidy-original-shown')\n ) {\n continue;\n }\n this.scanNode(parent);\n }\n }\n }\n }\n\n private scanContainer(container: HTMLElement): void {\n const spans = container.querySelectorAll<HTMLElement>(TOOL_TITLE_SELECTOR);\n spans.forEach((span) => {\n if (isToolSummarySpan(span)) {\n this.processSpan(span);\n }\n });\n }\n\n private scanNode(node: HTMLElement): void {\n if (node.matches?.(TOOL_TITLE_SELECTOR) && isToolSummarySpan(node)) {\n this.processSpan(node);\n }\n\n const spans = node.querySelectorAll<HTMLElement>(TOOL_TITLE_SELECTOR);\n spans.forEach((span) => {\n if (isToolSummarySpan(span)) {\n this.processSpan(span);\n }\n });\n }\n\n private processSpan(span: HTMLElement): void {\n // Think summaries are translated only after the reasoning block has fully\n // finished streaming \u2014 never while `data-state=\"running\"` (the summary is\n // then a live tail line that would be replaced moments later). The\n // transition to \"ok\" triggers a re-scan via the observed data-state\n // attribute, which is when this span becomes processable.\n if (thinkBlockStillRunning(span)) return;\n\n if (NonDestructiveTranslationMount.isMounted(span)) {\n const original = NonDestructiveTranslationMount.getOriginal(span);\n if (original) {\n const cached = clientCache.get(original);\n if (cached) return;\n }\n return;\n }\n\n const text = NonDestructiveTranslationMount.extractVisibleText(span);\n if (!text) return;\n\n // Check fast client cache\n const cached = clientCache.get(text);\n if (cached) {\n NonDestructiveTranslationMount.mount(span, cached, {\n originalText: text,\n });\n return;\n }\n\n // Send to viewport lazy queue\n lazyQueue.observe(span, text);\n }\n\n disconnect(): void {\n if (this.rootCheckTimer !== null) {\n clearInterval(this.rootCheckTimer);\n this.rootCheckTimer = null;\n }\n if (this.observer) {\n this.observer.disconnect();\n this.observer = null;\n }\n lazyQueue.disconnect();\n this.rootElement = null;\n }\n}\n\nexport const chatTranslateObserver = new ChatTranslateObserver();\n", "import { useState, useEffect } from 'react';\nimport * as React from 'react';\nimport { settingsStore, SETTINGS_NAMESPACE, type ClientSettingsState } from './store.ts';\nimport { SETTINGS_CSS } from './styles.ts';\nlet stylesInjected = false;\nfunction ensureSettingsStyles(): void {\n if (stylesInjected || typeof document === 'undefined') return;\n const el = document.createElement('style');\n el.dataset.tidySettings = 'true';\n el.textContent = SETTINGS_CSS;\n document.head.appendChild(el);\n stylesInjected = true;\n}\n\nfunction Switch(props: { checked: boolean; onChange: () => void; label: string }): React.ReactElement {\n return (\n <button\n type=\"button\"\n className=\"dsh-tidy-switch\"\n role=\"switch\"\n aria-checked={props.checked}\n onClick={props.onChange}\n aria-label={props.label}\n />\n );\n}\n\nexport function TidySettingsPanel(): React.ReactElement {\n ensureSettingsStyles();\n\n const [state, setState] = useState<ClientSettingsState>(() => settingsStore.getState());\n const [testing, setTesting] = useState<{ channel: string; running: boolean; ok?: boolean; message?: string } | null>(null);\n const [apiKeyInput, setApiKeyInput] = useState('');\n const [savingKey, setSavingKey] = useState(false);\n const [keyMsg, setKeyMsg] = useState<{ ok: boolean; text: string } | null>(null);\n\n useEffect(() => {\n return settingsStore.subscribe(() => {\n setState(settingsStore.getState());\n });\n }, []);\n\n const runTest = async (channel: string): Promise<void> => {\n setTesting({ channel, running: true });\n const res = await settingsStore.testChannel(channel);\n const message = res.ok\n ? `\u8FDE\u63A5\u6B63\u5E38\uFF0C\u5EF6\u8FDF ${res.latencyMs}ms`\n : `\u5931\u8D25\uFF1A${res.error || '\u672A\u77E5\u9519\u8BEF'}`;\n setTesting({ channel, running: false, ok: res.ok, message });\n };\n\n const handleSaveKey = async (): Promise<void> => {\n setSavingKey(true);\n setKeyMsg(null);\n const res = await settingsStore.saveApiKey(apiKeyInput);\n setSavingKey(false);\n if (res.ok) {\n const cleared = !apiKeyInput.trim();\n setKeyMsg({\n ok: true,\n text: cleared\n ? '\u5DF2\u6E05\u9664 API Key\uFF08AI \u901A\u9053\u5C06\u4E0D\u53EF\u7528\uFF0CBing \u515C\u5E95\uFF09'\n : '\u5DF2\u4FDD\u5B58\u5230 ~/.dsh/.credentials.yaml\uFF0C\u7ACB\u5373\u751F\u6548',\n });\n setApiKeyInput('');\n } else {\n setKeyMsg({ ok: false, text: `\u4FDD\u5B58\u5931\u8D25\uFF1A${res.error || '\u672A\u77E5\u9519\u8BEF'}` });\n }\n };\n\n return (\n <div className=\"dsh-tidy-settings\">\n {/* 1. \u603B\u5F00\u5173 */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-title\">\n <span>\u5DE5\u5177\u8C03\u7528\u4E0E\u601D\u8003\u6458\u8981\u7FFB\u8BD1</span>\n <Switch\n checked={state.enabled}\n onChange={() => settingsStore.update({ enabled: !state.enabled })}\n label=\"\u542F\u7528\u5DE5\u5177\u8C03\u7528\u4E0E\u6458\u8981\u7FFB\u8BD1\"\n />\n </div>\n <div className=\"dsh-tidy-desc\">\n \u81EA\u52A8\u5C06\u5F53\u524D\u4F1A\u8BDD\u4E2D\u5DE5\u5177\u8C03\u7528\u6807\u9898\u4E0E\u601D\u8003\u6298\u53E0\u6458\u8981\uFF08\u5982 <code>Locate DSH home directory structure</code>\uFF09\u7FFB\u8BD1\u4E3A\u4E2D\u6587\uFF0C\n \u70B9\u51FB\u8BD1\u6587\u53EF\u539F\u5730\u5207\u6362\u539F\u6587/\u8BD1\u6587\u3002\u601D\u8003\u6298\u53E0\u6458\u8981\u4EC5\u5728\u601D\u8003\u5B8C\u5168\u7ED3\u675F\u540E\u624D\u7FFB\u8BD1\uFF08\u4E0D\u7FFB\u8BD1\u6D41\u5F0F\u4E2D\u95F4\u6001\uFF09\u3002\n \u4EC5\u4F5C\u7528\u4E8E\u5F53\u524D\u67E5\u770B\u7684\u4F1A\u8BDD\uFF0C\u5BF9\u8BDD\u6B63\u6587\u6C38\u4E0D\u7FFB\u8BD1\u3002\n </div>\n </div>\n\n {state.enabled && (\n <>\n {/* 2. AI \u901A\u9053 */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-title\">\n <span>AI \u7FFB\u8BD1\uFF08OpenAI \u517C\u5BB9\u534F\u8BAE\uFF09</span>\n <Switch\n checked={state.aiEnabled}\n onChange={() => settingsStore.update({ aiEnabled: !state.aiEnabled })}\n label=\"\u542F\u7528 AI \u7FFB\u8BD1\u901A\u9053\"\n />\n </div>\n <div className=\"dsh-tidy-desc\">\n <span className={`dsh-tidy-badge ${state.aiConfigured ? 'dsh-tidy-badge-ok' : 'dsh-tidy-badge-warn'}`}>\n {state.aiConfigured ? '\u5DF2\u914D\u7F6E' : '\u672A\u914D\u7F6E'}\n </span>{' '}\n \u672A\u914D\u7F6E\u65F6 AI \u901A\u9053\u81EA\u52A8\u8DF3\u8FC7\uFF0C\u7531 Bing \u515C\u5E95\u3002\n </div>\n\n {state.aiEnabled && (\n <>\n <div className=\"dsh-tidy-row\">\n <div className=\"dsh-tidy-row-info\">\n <div className=\"dsh-tidy-row-title\">API Key</div>\n <div className=\"dsh-tidy-row-desc\">\n \u4FDD\u5B58\u81F3 <code>~/.dsh/.credentials.yaml</code> \u7684 <code>TRANSLATE_API_KEY</code>\uFF0C\u4FDD\u5B58\u540E\u7ACB\u5373\u751F\u6548\uFF1B\u7559\u7A7A\u4FDD\u5B58 = \u6E05\u9664\n </div>\n </div>\n <div className=\"dsh-tidy-input-row\">\n <input\n type=\"password\"\n className=\"dsh-tidy-input\"\n placeholder={state.aiConfigured ? '\u5DF2\u914D\u7F6E\uFF08\u5982\u9700\u66F4\u6362\u8BF7\u76F4\u63A5\u8F93\u5165\uFF09' : 'sk-...'}\n value={apiKeyInput}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => setApiKeyInput(e.target.value)}\n style={{ width: '260px' }}\n aria-label=\"API Key\"\n />\n <button type=\"button\" className=\"dsh-tidy-btn\" disabled={savingKey} onClick={handleSaveKey}>\n {savingKey ? '\u4FDD\u5B58\u4E2D\u2026' : '\u4FDD\u5B58'}\n </button>\n </div>\n </div>\n {keyMsg && (\n <div className={`dsh-tidy-test-result ${keyMsg.ok ? 'ok' : 'fail'}`}>{keyMsg.text}</div>\n )}\n\n <div className=\"dsh-tidy-row\">\n <div className=\"dsh-tidy-row-info\">\n <div className=\"dsh-tidy-row-title\">Base URL</div>\n <div className=\"dsh-tidy-row-desc\">\n \u4EFB\u610F OpenAI \u517C\u5BB9\u670D\u52A1\u7AEF\u70B9\uFF0C\u5982 <code>https://api.openai.com/v1</code>\u3001{' '}\n <code>https://api.deepseek.com/v1</code>\n </div>\n </div>\n <input\n type=\"text\"\n className=\"dsh-tidy-input\"\n placeholder=\"https://api.openai.com/v1\"\n value={state.baseUrl}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n settingsStore.update({ baseUrl: e.target.value })\n }\n style={{ width: '260px' }}\n aria-label=\"AI Base URL\"\n />\n </div>\n <div className=\"dsh-tidy-row\">\n <div className=\"dsh-tidy-row-info\">\n <div className=\"dsh-tidy-row-title\">\u6A21\u578B</div>\n <div className=\"dsh-tidy-row-desc\">\n \u5982 <code>gpt-4o-mini</code>\u3001<code>deepseek-chat</code>\uFF1B\u7559\u7A7A\u89C6\u4E3A\u672A\u914D\u7F6E\n </div>\n </div>\n <input\n type=\"text\"\n className=\"dsh-tidy-input\"\n placeholder=\"gpt-4o-mini\"\n value={state.model}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n settingsStore.update({ model: e.target.value })\n }\n style={{ width: '260px' }}\n aria-label=\"AI \u6A21\u578B\"\n />\n </div>\n <div className=\"dsh-tidy-row\">\n <button\n type=\"button\"\n className=\"dsh-tidy-btn\"\n disabled={testing?.running}\n onClick={() => runTest('openai')}\n >\n {testing?.running ? '\u6D4B\u8BD5\u4E2D\u2026' : '\u6D4B\u8BD5 AI \u901A\u9053'}\n </button>\n {testing?.channel === 'openai' && !testing.running && (\n <span className={`dsh-tidy-test-result ${testing.ok ? 'ok' : 'fail'}`}>{testing.message}</span>\n )}\n </div>\n </>\n )}\n </div>\n\n {/* 3. Bing \u901A\u9053 */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-title\">\n <span>Bing \u7F51\u9875\u7FFB\u8BD1\uFF08\u514D Key \u515C\u5E95\uFF09</span>\n <Switch\n checked={state.bingEnabled}\n onChange={() => settingsStore.update({ bingEnabled: !state.bingEnabled })}\n label=\"\u542F\u7528 Bing \u7FFB\u8BD1\u901A\u9053\"\n />\n </div>\n <div className=\"dsh-tidy-desc\">\n \u5185\u7F6E\u514D Key \u7FFB\u8BD1\u901A\u9053\uFF0C\u65E0\u9700\u4EFB\u4F55\u914D\u7F6E\u3002AI \u672A\u914D\u7F6E\u6216\u8BF7\u6C42\u5931\u8D25\u65F6\u81EA\u52A8\u515C\u5E95\uFF1BAI \u4E0E Bing \u540C\u65F6\u5173\u95ED\u5219\u4E0D\u7FFB\u8BD1\u3002\n </div>\n </div>\n\n {/* 4. \u884C\u4E3A\u8BF4\u660E */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-row-title\">\u901A\u9053\u884C\u4E3A</div>\n <ul className=\"dsh-tidy-desc dsh-tidy-behavior-list\">\n <li>AI \u5F00\u542F\u4E14\u5DF2\u914D\u7F6E \u2192 AI \u4F18\u5148\u7FFB\u8BD1\uFF0C\u5931\u8D25\u81EA\u52A8\u964D\u7EA7 Bing</li>\n <li>AI \u5F00\u542F\u4F46\u672A\u914D\u7F6E + Bing \u5F00\u542F \u2192 \u7531 Bing \u7FFB\u8BD1</li>\n <li>AI \u5F00\u542F\u4F46\u672A\u914D\u7F6E + Bing \u5173\u95ED \u2192 \u4E0D\u7FFB\u8BD1</li>\n <li>AI \u5173\u95ED + Bing \u5F00\u542F \u2192 \u76F4\u63A5\u4F7F\u7528 Bing</li>\n <li>AI \u5173\u95ED + Bing \u5173\u95ED \u2192 \u4E0D\u7FFB\u8BD1</li>\n </ul>\n </div>\n\n {/* 5. \u5E76\u53D1\u63A7\u5236 */}\n <div className=\"dsh-tidy-card\">\n <div className=\"dsh-tidy-row\">\n <div className=\"dsh-tidy-row-info\">\n <div className=\"dsh-tidy-row-title\">\u6700\u5927\u7FFB\u8BD1\u5E76\u53D1\u6570</div>\n <div className=\"dsh-tidy-row-desc\">\n \u63A7\u5236\u89C6\u53E3\u6EDA\u52A8\u4E0E\u591A\u5DE5\u5177\u5361\u7247\u65F6\u7684\u6700\u5927\u5E76\u884C\u8BF7\u6C42\u6570\uFF08\u8303\u56F4 1-100\uFF0C\u63A8\u8350 3\uFF09\u3002\n </div>\n </div>\n <input\n type=\"number\"\n className=\"dsh-tidy-input\"\n min={1}\n max={100}\n step={1}\n value={state.concurrency}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n const val = parseInt(e.target.value, 10);\n if (!Number.isFinite(val)) return;\n settingsStore.update({ concurrency: Math.min(Math.max(val, 1), 100) });\n }}\n style={{ width: '88px' }}\n aria-label=\"\u6700\u5927\u7FFB\u8BD1\u5E76\u53D1\u6570\"\n />\n </div>\n </div>\n </>\n )}\n </div>\n );\n}\n\nexport function setupSettingsUi(ctx: any): void {\n if (typeof window === 'undefined') return;\n\n // Ride DSH's own settings surface: the `settingsScope` service mirrors the\n // host document (per-namespace describe) and the `credentials` Remote API\n // writes the API key. No custom config HTTP endpoint since 1.2.\n try {\n // Declared via inject: 'settingsScope' and 'remote.credentials' (plus the\n // 'remote' root). Fall back to optional lookup so a degraded environment\n // degrades to an in-memory store instead of failing loudly.\n const settingsScope = ctx?.settingsScope || (ctx?.get ? ctx.get('settingsScope') : null);\n const remoteCredentials =\n ctx?.remote?.credentials || (ctx?.get ? ctx.get('remote.credentials') : null);\n if (settingsScope && typeof settingsScope.bind === 'function') {\n const scope = settingsScope.bind({ namespace: SETTINGS_NAMESPACE });\n settingsStore.attach(scope, remoteCredentials ?? null);\n }\n } catch (err) {\n console.warn('[dsh-chat-translate] Failed to bind settings scope:', err);\n }\n\n try {\n const slots = ctx?.slots || (ctx?.get ? ctx.get('slots') : null);\n if (!slots || typeof slots.inject !== 'function') return;\n\n slots.inject('settings.section', () => {\n return slots.register(\n {\n name: 'settings.section',\n id: 'dsh-chat-translate',\n // \u7EA6\u5B9A\uFF1A\u81EA\u6709\u63D2\u4EF6\u8BBE\u7F6E\u9879 order \u4ECE 110 \u8D77\u6B65\u8FDB 10\uFF08\u539F\u751F\u6700\u5927 100=\u684C\u9762\u8BBE\u7F6E\uFF09\uFF0C\u4FDD\u8BC1\u6392\u5728\u6240\u6709\u539F\u751F\u9879\u4E4B\u4E0B\n order: 110,\n label: () => '\u804A\u5929\u7FFB\u8BD1',\n },\n TidySettingsPanel\n );\n });\n } catch (err) {\n console.warn('[dsh-chat-translate] Failed to inject settings section:', err);\n }\n}\n", "import { describeError } from '../../describe-error.ts';\nimport { chatTranslateObserver } from '../translate/observer.ts';\nimport { testServerChannel } from '../translate/api.ts';\n\nexport interface ClientSettingsState {\n enabled: boolean;\n concurrency: number;\n aiEnabled: boolean;\n bingEnabled: boolean;\n baseUrl: string;\n model: string;\n aiConfigured: boolean;\n}\n\n/** Settings namespace + credentials ref, mirroring the host constants. */\nexport const SETTINGS_NAMESPACE = 'dsh-chat-translate';\nexport const TRANSLATE_API_KEY_REF = 'TRANSLATE_API_KEY';\n\n/**\n * Minimal structural shapes of the DSH browser services this store rides on:\n * `settingsScope` (from @deepseek-ai/dsh-client-ui-settings) and the\n * `credentials` Remote namespace. Keeping them structural keeps this bundle\n * free of host-service imports and lets tests inject fakes.\n */\nexport interface SettingsScopeLike {\n getSnapshot(): {\n status: string;\n value?: Record<string, unknown>;\n writable: boolean;\n };\n subscribe(listener: () => void): () => void;\n set(field: string, value: unknown): Promise<unknown>;\n unset(field: string): Promise<unknown>;\n}\n\n/** Shape of every DSH client Remote call: {ok, value} / {ok, error} wrapper. */\nexport type RemoteResult<T> =\n | { ok: true; value: T }\n | { ok: false; error: { code?: string; message: string; details?: unknown } };\n\nexport interface CredentialsRemoteLike {\n describe(\n refs: string[]\n ): Promise<RemoteResult<Record<string, { configured: boolean; source?: string; writable: boolean }>>>;\n set(ref: string, value: string): Promise<RemoteResult<void>>;\n unset(ref: string): Promise<RemoteResult<void>>;\n}\n\nconst DEFAULT_STATE: ClientSettingsState = {\n enabled: true,\n concurrency: 3,\n aiEnabled: true,\n bingEnabled: true,\n baseUrl: '',\n model: '',\n aiConfigured: false,\n};\n\n/**\n * Client settings store backed by the DSH settings namespace.\n *\n * Since 1.2 there is no localStorage overlay and no custom config HTTP\n * endpoint: the store derives from the bound `settingsScope` (which mirrors\n * the host document and folds every write answer back), and writes go\n * through `scope.set` \u2014 serialized, revision-checked, persisted by DSH.\n * Without a bound scope (e.g. non-loopback pages, unit tests) it degrades to\n * an in-memory store with the same semantics DSH itself uses for memory\n * persistence.\n */\nclass SettingsStore {\n private state: ClientSettingsState = { ...DEFAULT_STATE };\n private listeners = new Set<() => void>();\n private scope: SettingsScopeLike | null = null;\n private credentials: CredentialsRemoteLike | null = null;\n private unsubscribeScope: (() => void) | null = null;\n private keyConfigured = false;\n private writeTimer: number | null = null;\n private pendingFields = new Set<string>();\n\n /**\n * Bind the DSH services. Called once from the settings UI setup; re-binding\n * (e.g. after a reconnect) detaches the previous subscription first.\n */\n attach(scope: SettingsScopeLike | null, credentials: CredentialsRemoteLike | null): void {\n if (this.unsubscribeScope) {\n this.unsubscribeScope();\n this.unsubscribeScope = null;\n }\n this.scope = scope;\n this.credentials = credentials;\n if (scope) {\n this.unsubscribeScope = scope.subscribe(() => this.derive());\n this.derive();\n }\n void this.refreshKeyStatus();\n }\n\n getState(): ClientSettingsState {\n return { ...this.state };\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** Map the resolved namespace value into client state and notify. */\n private derive(): void {\n if (!this.scope) return;\n const snap = this.scope.getSnapshot();\n const value = snap.value;\n if (!value || typeof value !== 'object') return;\n const next: ClientSettingsState = { ...this.state };\n if (typeof value.enabled === 'boolean') next.enabled = value.enabled;\n const c = value.concurrency;\n if (typeof c === 'number' && Number.isFinite(c)) {\n next.concurrency = Math.min(Math.max(Math.round(c), 1), 100);\n }\n if (typeof value.aiEnabled === 'boolean') next.aiEnabled = value.aiEnabled;\n if (typeof value.bingEnabled === 'boolean') next.bingEnabled = value.bingEnabled;\n if (typeof value.baseUrl === 'string') next.baseUrl = value.baseUrl;\n if (typeof value.model === 'string') next.model = value.model;\n this.applyState(next);\n }\n\n private applyState(next: ClientSettingsState): void {\n next.aiConfigured = Boolean(next.baseUrl && next.model && this.keyConfigured);\n const enabledChanged = next.enabled !== this.state.enabled;\n this.state = next;\n if (enabledChanged) {\n try {\n chatTranslateObserver.setEnabled(this.state.enabled);\n } catch {}\n }\n this.notify();\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n try {\n listener();\n } catch {}\n }\n }\n\n /** Pull the key's status-only view and re-derive aiConfigured. */\n private async refreshKeyStatus(): Promise<void> {\n if (!this.credentials) return;\n try {\n const res = await this.credentials.describe([TRANSLATE_API_KEY_REF]);\n if (!res.ok) return;\n const info = res.value[TRANSLATE_API_KEY_REF];\n const configured = Boolean(info?.configured);\n if (configured !== this.keyConfigured) {\n this.keyConfigured = configured;\n this.applyState({ ...this.state });\n }\n } catch {\n // Credentials surface unavailable \u2014 keep the last known status.\n }\n }\n\n /**\n * Optimistically apply locally, then persist each touched field through the\n * settings scope. Writes are trailing-debounced (300ms) so typing in the\n * baseUrl/model inputs collapses into a single queued mutation instead of\n * one write per keystroke \u2014 which would otherwise flash stale mirror values\n * back into the inputs between commits. A failed write makes the scope\n * reload its mirror, which re-derives this store from the host document\n * (conflict-safe recovery).\n */\n async update(partial: Partial<ClientSettingsState>): Promise<void> {\n let sanitizedConcurrency = this.state.concurrency;\n if (typeof partial.concurrency === 'number' && Number.isFinite(partial.concurrency)) {\n sanitizedConcurrency = Math.min(Math.max(Math.round(partial.concurrency), 1), 100);\n }\n const next: ClientSettingsState = {\n ...this.state,\n ...partial,\n concurrency: sanitizedConcurrency,\n };\n this.applyState(next);\n\n if (this.scope) {\n const fields = ['enabled', 'concurrency', 'aiEnabled', 'bingEnabled', 'baseUrl', 'model'] as const;\n for (const field of fields) {\n if (partial[field] !== undefined) {\n this.pendingFields.add(field);\n }\n }\n this.scheduleWrite();\n }\n }\n\n private scheduleWrite(): void {\n if (this.writeTimer !== null || typeof window === 'undefined') return;\n this.writeTimer = window.setTimeout(() => {\n this.writeTimer = null;\n void this.flushWrite();\n }, 300);\n }\n\n private async flushWrite(): Promise<void> {\n if (!this.scope) return;\n const fields = [...this.pendingFields];\n this.pendingFields.clear();\n const writes: Promise<unknown>[] = [];\n for (const field of fields) {\n writes.push(this.scope.set(field, this.state[field as keyof ClientSettingsState]));\n }\n await Promise.all(writes).catch(() => {});\n }\n\n async testChannel(channel: string): Promise<{ ok: boolean; latencyMs: number; error?: string }> {\n return testServerChannel(channel);\n }\n\n /** Write (or clear) the API key through the credentials Remote API. */\n async saveApiKey(apiKey: string): Promise<{ ok: boolean; error?: string }> {\n if (!this.credentials) {\n return { ok: false, error: '\u51ED\u636E\u670D\u52A1\u4E0D\u53EF\u7528\uFF08\u975E\u56DE\u73AF\u9875\u9762\uFF09' };\n }\n try {\n const key = apiKey.trim();\n // Remote calls resolve with {ok:false} instead of rejecting on refusal\n // (e.g. env-shadowed refs), so the .ok check decides the outcome.\n const res = key\n ? await this.credentials.set(TRANSLATE_API_KEY_REF, key)\n : await this.credentials.unset(TRANSLATE_API_KEY_REF);\n if (!res.ok) {\n return { ok: false, error: res.error?.message || '\u4FDD\u5B58\u5931\u8D25' };\n }\n await this.refreshKeyStatus();\n return { ok: true };\n } catch (err: any) {\n return { ok: false, error: describeError(err) };\n }\n }\n\n dispose(): void {\n if (this.writeTimer !== null && typeof window !== 'undefined') {\n clearTimeout(this.writeTimer);\n this.writeTimer = null;\n }\n this.pendingFields.clear();\n if (this.unsubscribeScope) {\n this.unsubscribeScope();\n this.unsubscribeScope = null;\n }\n this.scope = null;\n this.credentials = null;\n this.listeners.clear();\n }\n}\n\nexport const settingsStore = new SettingsStore();\n", "export const SETTINGS_CSS = String.raw`\n.dsh-tidy-settings {\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 580px;\n padding-bottom: 32px;\n color: var(--dsw-alias-label-primary, inherit);\n font-family: inherit;\n}\n\n.dsh-tidy-card {\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.2));\n border-radius: 12px;\n padding: 16px 18px;\n background: var(--dsw-alias-bg-card, rgba(128, 128, 128, 0.05));\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.dsh-tidy-title {\n font-size: 14px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary, inherit);\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.dsh-tidy-desc {\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary, rgba(128, 128, 128, 0.8));\n}\n\n.dsh-tidy-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 14px;\n padding: 8px 0;\n}\n\n.dsh-tidy-row + .dsh-tidy-row {\n border-top: 1px solid var(--dsw-alias-border-l3, rgba(128, 128, 128, 0.1));\n}\n\n.dsh-tidy-row-info {\n flex: 1;\n min-width: 0;\n}\n\n.dsh-tidy-row-title {\n font-size: 13px;\n font-weight: 500;\n}\n\n.dsh-tidy-row-desc {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary, rgba(128, 128, 128, 0.7));\n margin-top: 2px;\n line-height: 1.4;\n}\n\n/* Switch */\n.dsh-tidy-switch {\n position: relative;\n width: 38px;\n height: 22px;\n flex: none;\n cursor: pointer;\n border-radius: 999px;\n border: none;\n background: rgba(128, 128, 128, 0.3);\n transition: background 0.15s ease;\n padding: 0;\n outline: none;\n}\n\n.dsh-tidy-switch[aria-checked=\"true\"] {\n background: #3b82f6;\n}\n\n.dsh-tidy-switch::after {\n content: \"\";\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: #ffffff;\n transition: transform 0.15s ease;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);\n}\n\n.dsh-tidy-switch[aria-checked=\"true\"]::after {\n transform: translateX(16px);\n}\n\n/* Inputs */\n.dsh-tidy-input-group {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.dsh-tidy-label {\n font-size: 12px;\n font-weight: 500;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.dsh-tidy-input-row {\n display: flex;\n gap: 8px;\n}\n\n.dsh-tidy-input {\n flex: 1;\n min-width: 0;\n padding: 8px 12px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n background: var(--dsw-alias-bg-input, rgba(0, 0, 0, 0.05));\n color: inherit;\n font-size: 12px;\n outline: none;\n transition: border-color 0.15s;\n}\n\n.dsh-tidy-input:focus {\n border-color: #3b82f6;\n}\n\n.dsh-tidy-btn {\n padding: 6px 14px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));\n background: transparent;\n color: inherit;\n font-size: 12px;\n cursor: pointer;\n transition: all 0.15s ease;\n white-space: nowrap;\n}\n\n.dsh-tidy-btn:hover {\n background: rgba(128, 128, 128, 0.1);\n border-color: rgba(128, 128, 128, 0.5);\n}\n\n.dsh-tidy-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.dsh-tidy-badge {\n font-size: 10px;\n padding: 2px 6px;\n border-radius: 4px;\n font-weight: 500;\n}\n\n.dsh-tidy-badge-ok {\n background: rgba(34, 197, 94, 0.15);\n color: #22c55e;\n}\n\n.dsh-tidy-badge-none {\n background: rgba(156, 163, 175, 0.15);\n color: #9ca3af;\n}\n\n.dsh-tidy-badge-warn {\n background: rgba(245, 158, 11, 0.15);\n color: #f59e0b;\n}\n\n.dsh-tidy-test-result {\n font-size: 12px;\n margin-left: 10px;\n}\n\n.dsh-tidy-test-result.ok {\n color: #22c55e;\n}\n\n.dsh-tidy-test-result.fail {\n color: #ef4444;\n}\n\n.dsh-tidy-behavior-list {\n padding-left: 18px;\n margin: 4px 0 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n/* Priority list */\n.dsh-tidy-priority-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.dsh-tidy-priority-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 12px;\n border-radius: 8px;\n background: rgba(128, 128, 128, 0.06);\n border: 1px solid var(--dsw-alias-border-l3, rgba(128, 128, 128, 0.12));\n}\n\n.dsh-tidy-priority-name {\n font-size: 12px;\n font-weight: 500;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.dsh-tidy-order-badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: #3b82f6;\n color: #ffffff;\n font-size: 11px;\n font-weight: 600;\n}\n\n.dsh-tidy-btn-group {\n display: flex;\n gap: 4px;\n}\n\n.dsh-tidy-icon-btn {\n width: 26px;\n height: 26px;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n border: 1px solid rgba(128, 128, 128, 0.2);\n background: transparent;\n color: inherit;\n cursor: pointer;\n font-size: 12px;\n}\n\n.dsh-tidy-icon-btn:hover:not(:disabled) {\n background: rgba(128, 128, 128, 0.15);\n}\n\n.dsh-tidy-icon-btn:disabled {\n opacity: 0.3;\n cursor: default;\n}\n\n/* Slider / Select */\n.dsh-tidy-select {\n padding: 6px 10px;\n border-radius: 8px;\n border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));\n background: var(--dsw-alias-bg-input, rgba(0, 0, 0, 0.05));\n color: inherit;\n font-size: 12px;\n outline: none;\n}\n`;\n"],
5
+ "mappings": "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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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",
6
6
  "names": ["cached"]
7
7
  }