dsh-oauth-login 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/INSTALL.md CHANGED
@@ -2,21 +2,34 @@
2
2
 
3
3
  [中文](INSTALL.zh.md). Product pages: [README.md](README.md) (中文), [README.en.md](README.en.md).
4
4
 
5
- Stock DeepSeek Harness **0.1.7-rc.1** users install with official `dsh` and **pnpm**:
5
+ ## DSH Studio desktop app (recommended)
6
+
7
+ Open **Settings → Plugins → Add plugin** and enter this in “Package name or address”:
8
+
9
+ ```text
10
+ github:aa2246740/dsh-oauth-login#v0.2.7
11
+ ```
12
+
13
+ The in-app plugin manager owns the Desktop profile and bundled package manager. This release includes built `lib/`; normal use needs no clone, build, or DSHX installation. Follow the app if it asks you to reload or reopen.
14
+
15
+ ## Web CLI
16
+
17
+ Stock DeepSeek Harness **0.2.0-rc.2** users install to the Web profile with the official CLI:
6
18
 
7
19
  ```sh
8
- dsh plugin --profile web add github:aa2246740/dsh-oauth-login
20
+ dsh plugin --profile web add github:aa2246740/dsh-oauth-login#v0.2.7
9
21
  ```
10
22
 
11
23
  If `dsh` is not on PATH:
12
24
 
13
25
  ```sh
14
- npx @deepseek-ai/dsh plugin --profile web add github:aa2246740/dsh-oauth-login
26
+ npx @deepseek-ai/dsh plugin --profile web add github:aa2246740/dsh-oauth-login#v0.2.7
15
27
  ```
16
28
 
17
29
  That `github:` spec works because the package declares `dsh.bundle.patch` and
18
30
  commits built `lib/`. Official add runs pnpm in `$DSH_HOME/profiles/web` and
19
- appends the package to `dsh.profile.bundles`. Then restart that Host and reload
31
+ appends the package to `dsh.profile.bundles`. This command writes only `web`,
32
+ not the Desktop App profile. Reopen an already-running Web Host once and reload
20
33
  the page. You do not need Creator Mode or a second toolchain.
21
34
 
22
35
  Use `file:` only when editing a local clone. Keep the prefix. A bare
package/INSTALL.zh.md CHANGED
@@ -2,19 +2,31 @@
2
2
 
3
3
  [English](INSTALL.md)。说明和截图在 [README.md](README.md),英文在 [README.en.md](README.en.md)。
4
4
 
5
- 官方 DeepSeek Harness **0.1.7-rc.1** 用户用官方 `dsh` 和 **pnpm** 安装:
5
+ ## DSH Studio 桌面 App(推荐)
6
+
7
+ 打开 **设置 → 插件 → 添加插件**,在“包名或地址”中输入:
8
+
9
+ ```text
10
+ github:aa2246740/dsh-oauth-login#v0.2.7
11
+ ```
12
+
13
+ 应用内插件管理器负责 Desktop profile 和内置包管理器。本发布已包含编译好的 `lib/`;普通使用不需要 clone、构建或安装 DSHX。若应用提示刷新或重新打开,请按提示完成。
14
+
15
+ ## Web CLI
16
+
17
+ 官方 DeepSeek Harness **0.2.0-rc.2** 用户用官方 CLI 安装到 Web profile:
6
18
 
7
19
  ```sh
8
- dsh plugin --profile web add github:aa2246740/dsh-oauth-login
20
+ dsh plugin --profile web add github:aa2246740/dsh-oauth-login#v0.2.7
9
21
  ```
10
22
 
11
23
  没有 `dsh` 时:
12
24
 
13
25
  ```sh
14
- npx @deepseek-ai/dsh plugin --profile web add github:aa2246740/dsh-oauth-login
26
+ npx @deepseek-ai/dsh plugin --profile web add github:aa2246740/dsh-oauth-login#v0.2.7
15
27
  ```
16
28
 
17
- 这条 `github:` 命令能装上,是因为包装了 `dsh.bundle.patch`,并且仓库提交了编好的 `lib/`。官方 add 在 `$DSH_HOME/profiles/web` 里跑 pnpm,再把这个包装进 `dsh.profile.bundles`。装完重启这个 Host,刷新页面。不需要 Creator Mode,也不需要另装一套工具。
29
+ 这条 `github:` 命令能装上,是因为包装了 `dsh.bundle.patch`,并且仓库提交了编好的 `lib/`。官方 add 在 `$DSH_HOME/profiles/web` 里跑 pnpm,再把这个包装进 `dsh.profile.bundles`。这条命令只写 `web` profile,不能修改 Desktop App 的 profile;已运行的 Web Host 需要重新打开一次,再刷新网页。不需要 Creator Mode,也不需要另装一套工具。
18
30
 
19
31
  本机改源码时再用 `file:`,并且必须保留前缀。直接写 `./dsh-oauth-login` 会变成符号链接;本插件有意从 profile 复用 DSH 运行时的 peer dependency,因此必须使用 `file:` 副本,才能正确解析依赖。
20
32
 
package/README.en.md CHANGED
@@ -2,11 +2,25 @@
2
2
 
3
3
  [中文](README.md) | English
4
4
 
5
+ ## Install
6
+
7
+ ### DSH Studio desktop app (recommended)
8
+
9
+ Open **Settings → Plugins → Add plugin** and enter this in “Package name or address”:
10
+
11
+ ```text
12
+ github:aa2246740/dsh-oauth-login#v0.2.7
13
+ ```
14
+
15
+ The desktop plugin manager owns the Desktop profile and bundled package manager. This release includes built `lib/`; normal use needs no clone, build, or DSHX installation. Follow the app if it asks you to reload or reopen after installation.
16
+
17
+ ### Web CLI
18
+
5
19
  ```sh
6
- dsh plugin --profile web add github:aa2246740/dsh-oauth-login
20
+ dsh plugin --profile web add github:aa2246740/dsh-oauth-login#v0.2.7
7
21
  ```
8
22
 
9
- You need official `dsh` on PATH (or `npx @deepseek-ai/dsh`) and **pnpm**. Then restart that Host and reload the page. `dsh plugin add` writes the profile. It does not hot-load a running Host.
23
+ This official CLI command writes only the `web` profile; it cannot modify the Desktop App profile. For an already-running Web Host, reopen that Host once and reload the page.
10
24
 
11
25
  OAuth login for ChatGPT, Claude, Grok, Copilot, OpenRouter, and Kimi on [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness), plus Zhipu GLM Coding Plan via its official plan API key. Credentials go only to `$DSH_HOME/.dsh-oauth-auth.json`.
12
26
 
@@ -26,17 +40,17 @@ The UI is **Settings → 订阅登录**.
26
40
 
27
41
  ## Install
28
42
 
29
- Node 22.19+ and official DeepSeek Harness **0.1.7-rc.1** (`@deepseek-ai/dsh@0.1.7-rc.1`, tag `dsh-v0.1.7-rc.1`).
43
+ Node 22.19+ and official DeepSeek Harness **0.2.0-rc.2** (`@deepseek-ai/dsh@0.2.0-rc.2`, tag `dsh-v0.2.0-rc.2`, SHA `639ed015397290b3745d163aafe02ffee4aa3f84`). The `@deepseek-ai/dsh` peer is `>=0.2.0-rc.1 <0.2.1`: it accepts `0.2.0-rc.2` and stable `0.2.0`, and rejects `0.2.0` alphas and `0.1.7-rc.2`.
30
44
 
31
- That `github:` command works because this package declares `dsh.bundle.patch` and commits built `lib/`. Official `dsh plugin add` runs pnpm in `$DSH_HOME/profiles/web` and appends this package to `dsh.profile.bundles`. You do not need Creator Mode or a second toolchain.
45
+ That `github:` command works because this package declares `dsh.bundle.patch` and commits built `lib/`. You do not need Creator Mode or a second toolchain.
32
46
 
33
47
  If `dsh` is not on PATH:
34
48
 
35
49
  ```sh
36
- npx @deepseek-ai/dsh plugin --profile web add github:aa2246740/dsh-oauth-login
50
+ npx @deepseek-ai/dsh plugin --profile web add github:aa2246740/dsh-oauth-login#v0.2.7
37
51
  ```
38
52
 
39
- Use `file:` only when you are editing a local clone (do not drop the prefix):
53
+ Use `file:` only when you are editing a local clone (development/local testing; do not drop the prefix):
40
54
 
41
55
  ```sh
42
56
  git clone https://github.com/aa2246740/dsh-oauth-login.git
package/README.md CHANGED
@@ -2,11 +2,25 @@
2
2
 
3
3
  中文 | [English](README.en.md)
4
4
 
5
+ ## 安装
6
+
7
+ ### DSH Studio 桌面 App(推荐)
8
+
9
+ 打开 **设置 → 插件 → 添加插件**,在“包名或地址”中输入:
10
+
11
+ ```text
12
+ github:aa2246740/dsh-oauth-login#v0.2.7
13
+ ```
14
+
15
+ 桌面端插件管理器负责 Desktop profile 和内置包管理器。本发布已包含编译好的 `lib/`;普通使用不需要 clone、构建或安装 DSHX。若应用提示刷新或重新打开,请按提示完成。
16
+
17
+ ### Web CLI
18
+
5
19
  ```sh
6
- dsh plugin --profile web add github:aa2246740/dsh-oauth-login
20
+ dsh plugin --profile web add github:aa2246740/dsh-oauth-login#v0.2.7
7
21
  ```
8
22
 
9
- PATH 上需要官方 `dsh`(没有的话用 `npx @deepseek-ai/dsh`)和 **pnpm**。装完重启这个 Host,刷新页面。`dsh plugin add` 只写 profile,不会热挂正在跑的 Host。
23
+ 这条官方 CLI 命令只写入 `web` profile,不能修改 Desktop App 的 profile。对于已经运行的 Web Host,请重新打开该 Host 一次,再刷新网页。
10
24
 
11
25
  把 ChatGPT、Claude、Grok、Copilot、OpenRouter、Kimi 的 OAuth 登录和智谱 GLM Coding Plan 接到 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)。凭据只写 `$DSH_HOME/.dsh-oauth-auth.json`。
12
26
 
@@ -26,17 +40,17 @@ PATH 上需要官方 `dsh`(没有的话用 `npx @deepseek-ai/dsh`)和 **pnpm
26
40
 
27
41
  ## 安装
28
42
 
29
- 需要 Node 22.19+,以及能跑起来的官方 DeepSeek Harness **0.1.7-rc.1**(`@deepseek-ai/dsh@0.1.7-rc.1`,tag `dsh-v0.1.7-rc.1`)。
43
+ 需要 Node 22.19+,以及能跑起来的官方 DeepSeek Harness **0.2.0-rc.2**(`@deepseek-ai/dsh@0.2.0-rc.2`,tag `dsh-v0.2.0-rc.2`,SHA `639ed015397290b3745d163aafe02ffee4aa3f84`)。`@deepseek-ai/dsh` peer 为 `>=0.2.0-rc.1 <0.2.1`:接受 `0.2.0-rc.2` 和稳定版 `0.2.0`,拒绝 `0.2.0` alpha,也拒绝 `0.1.7-rc.2`。
30
44
 
31
- 这条 `github:` 命令能装上,是因为包装了 `dsh.bundle.patch`,并且仓库提交了编好的 `lib/`。官方 `dsh plugin add` 在 `$DSH_HOME/profiles/web` 里跑 pnpm,再把这个包装进 `dsh.profile.bundles`。不需要 Creator Mode,也不需要另装一套工具。
45
+ 这条 `github:` 命令能装上,是因为包装了 `dsh.bundle.patch`,并且仓库提交了编好的 `lib/`。不需要 Creator Mode,也不需要另装一套工具。
32
46
 
33
47
  没有 `dsh` 时:
34
48
 
35
49
  ```sh
36
- npx @deepseek-ai/dsh plugin --profile web add github:aa2246740/dsh-oauth-login
50
+ npx @deepseek-ai/dsh plugin --profile web add github:aa2246740/dsh-oauth-login#v0.2.7
37
51
  ```
38
52
 
39
- 本机改源码时再用 `file:`(不要写成裸的 `./`):
53
+ 本机改源码时再用 `file:`(开发/本地测试;不要写成裸的 `./`):
40
54
 
41
55
  ```sh
42
56
  git clone https://github.com/aa2246740/dsh-oauth-login.git
package/lib/bin.js CHANGED
@@ -4,7 +4,7 @@ import { realpathSync } from "node:fs";
4
4
  import { createInterface } from "node:readline/promises";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { LlmError, RetryPolicySchema } from "@deepseek-ai/dsh-llm";
7
- import { createModels } from "@earendil-works/pi-ai";
7
+ import { createModels, getCurrentTools, normalizeContext } from "@earendil-works/pi-ai";
8
8
  import "@deepseek-ai/dsh-llm-pi-ai";
9
9
  import { AsyncLocalStorage } from "node:async_hooks";
10
10
  import { basename, dirname, join, resolve } from "node:path";
@@ -543,6 +543,10 @@ const OPENROUTER_REFRESH_MS = 9e5;
543
543
  const OPENROUTER_COOLDOWN_MS = 6e4;
544
544
  //#endregion
545
545
  //#region src/native-tools.ts
546
+ /**
547
+ * OAuth routes that already have provider-hosted search / image tools.
548
+ * DSH's web_search function tool would hide those and bill a second key.
549
+ */
546
550
  /** DSH model-facing tools that steal traffic from a subscribed provider. */
547
551
  const DSH_WEB_TOOL_NAMES = ["web_search", "web_fetch"];
548
552
  /** Matching tool-web prompt sections. */
@@ -665,10 +669,15 @@ function wrapOnPayload(existing, providerId, api, policy = DEFAULT_NATIVE_TOOL_P
665
669
  };
666
670
  }
667
671
  function filterPiContext(context, providerId, api, policy = DEFAULT_NATIVE_TOOL_POLICY) {
668
- if (nativePlan(providerId, api, policy) === void 0 || context.tools === void 0) return context;
672
+ if (nativePlan(providerId, api, policy) === void 0) return context;
669
673
  return {
670
674
  ...context,
671
- tools: context.tools.filter((tool) => !isDshWebToolName(tool.name))
675
+ ...context.tools === void 0 ? {} : { tools: context.tools.filter((tool) => !isDshWebToolName(tool.name)) },
676
+ messages: context.messages.map((message) => message.role !== "system" ? message : {
677
+ ...message,
678
+ ...message.toolsAdded === void 0 ? {} : { toolsAdded: message.toolsAdded.filter((tool) => !isDshWebToolName(tool.name)) },
679
+ ...message.toolsRemoved === void 0 ? {} : { toolsRemoved: message.toolsRemoved.filter((tool) => !isDshWebToolName(tool.name)) }
680
+ })
672
681
  };
673
682
  }
674
683
  /**
@@ -680,7 +689,7 @@ function filterPiContext(context, providerId, api, policy = DEFAULT_NATIVE_TOOL_
680
689
  * when the provider serializer later emits `tools: []`.
681
690
  */
682
691
  function prepareNativeToolRequest(context, options, providerId, api, policy = DEFAULT_NATIVE_TOOL_POLICY) {
683
- if (context.tools === void 0 || nativePlan(providerId, api, policy) === void 0) return {
692
+ if (context.tools === void 0 && getCurrentTools(context.messages).length === 0 || nativePlan(providerId, api, policy) === void 0) return {
684
693
  context,
685
694
  options
686
695
  };
@@ -1382,12 +1391,12 @@ function harnessProvider(spec, native = DEFAULT_NATIVE_TOOL_POLICY, catalog) {
1382
1391
  stream: (model, context, options) => {
1383
1392
  const request = prepareNativeToolRequest(context, options ?? {}, spec.id, model.api, native);
1384
1393
  const guarded = spec.id === "openrouter" ? prepareOpenRouterOptions(model, request.options, catalog) : request.options;
1385
- return base.stream(model, request.context, guarded);
1394
+ return base.stream(model, normalizeContext(request.context), guarded);
1386
1395
  },
1387
1396
  streamSimple: (model, context, options) => {
1388
1397
  const request = prepareNativeToolRequest(context, options ?? {}, spec.id, model.api, native);
1389
1398
  const guarded = spec.id === "openrouter" ? prepareOpenRouterOptions(model, request.options, catalog) : request.options;
1390
- return base.streamSimple(model, request.context, guarded);
1399
+ return base.streamSimple(model, normalizeContext(request.context), guarded);
1391
1400
  }
1392
1401
  };
1393
1402
  }
package/lib/client.js CHANGED
@@ -1897,7 +1897,7 @@ window.__ModuleLoader__.load({
1897
1897
  load: () => {
1898
1898
  if (available) directory.load().catch(() => {});
1899
1899
  },
1900
- select: (selection) => available ? directory.select(selection).then(() => true, () => false) : Promise.resolve(false),
1900
+ select: (selection) => available ? directory.select(selection) : Promise.resolve(void 0),
1901
1901
  ts
1902
1902
  };
1903
1903
  }
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useId","useState","useCallback","STYLE_ID","useState","useRef","useCallback","useSyncExternalStore","useMemo","useState","useRef","useId"],"sources":["../src/client/draft-input.ts","../src/client/OpenRouterSyncStatus.tsx","../src/proxy-config.ts","../src/client/proxy-draft.ts","../src/client/ProxySettings.tsx","../src/client/login-input-copy.ts","../src/client/login-window.ts","../src/client/PiLoginSettings.tsx","../src/client/model-filter.ts","../src/openrouter-types.ts","../src/client/SearchableModelSelect.tsx","../src/client/locales.ts","../src/client/openrouter-store.ts","../src/client/index.tsx"],"sourcesContent":["export type Drafts = Record<string, string>\nexport type DraftUpdater = (current: Drafts) => Drafts\nexport type DraftSetter = (updater: DraftUpdater) => void\n\nexport function applyDraftChange(\n providerId: string,\n event: { currentTarget: { value: string } },\n setDrafts: DraftSetter,\n): void {\n const value = event.currentTarget.value\n setDrafts(current => ({ ...current, [providerId]: value }))\n}\n","import { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { OpenRouterCatalogClient } from './openrouter-store.ts'\nimport type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'\n\nconst CSS = [\n '.dsh-or-sync{display:flex;flex-direction:column;gap:4px;padding:6px 8px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);min-width:0}',\n '.dsh-or-sync-row{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:4px 8px}',\n '.dsh-or-sync-copy{min-width:0;overflow-wrap:anywhere}',\n '.dsh-or-sync time{font-variant-numeric:tabular-nums}',\n '.dsh-or-refresh{min-height:28px;padding:3px 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer}',\n '.dsh-or-refresh:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}',\n '.dsh-or-refresh:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}',\n '.dsh-or-refresh:disabled{opacity:.55;cursor:default}',\n '.dsh-or-sync-error{color:color-mix(in srgb,var(--dsw-alias-state-warn-label) 50%,var(--dsw-alias-label-primary))}',\n].join('\\n')\n\nexport interface OpenRouterSyncStatusProps {\n catalog: OpenRouterCatalogClient\n ts: TranslateNS<'model-search'>\n details?: boolean\n}\n\nexport function OpenRouterSyncStatus({ catalog, ts, details = false }: OpenRouterSyncStatusProps) {\n const state = useSyncExternalStore(catalog.subscribe, catalog.getSnapshot)\n const [now, setNow] = useState(Date.now)\n const data = state.data\n const retryAt = data?.retryAt ?? 0\n useEffect(() => {\n setNow(Date.now())\n if (retryAt <= Date.now()) return\n const timer = setTimeout(() => { setNow(Date.now()) }, retryAt - Date.now() + 20)\n return () => { clearTimeout(timer) }\n }, [retryAt])\n const cooling = retryAt > now\n const working = state.loading || data?.refreshing === true\n const unavailable = state.error !== null || data?.error !== null && data?.error !== undefined\n const timestamp = data?.lastUpdatedAt\n return (\n <div className=\"dsh-or-sync\" data-ud-check={details ? 'openrouter-settings-sync' : 'openrouter-menu-sync'} data-ud-min-gap=\"4\">\n <style>{CSS}</style>\n <div className=\"dsh-or-sync-row\">\n <span className=\"dsh-or-sync-copy\" role=\"status\" aria-live=\"polite\">\n {working ? ts('syncing') : data?.connected ? ts('syncSchedule') : ts('syncSignIn')}\n </span>\n <button type=\"button\" className=\"dsh-or-refresh\"\n disabled={working || cooling || data?.connected !== true}\n onClick={() => { void catalog.load(true) }}\n >{working ? ts('syncing') : cooling ? ts('syncCooldown') : ts('syncRefresh')}</button>\n </div>\n {timestamp != null && (\n <span className=\"dsh-or-sync-copy\">{ts('syncUpdated')}{' '}\n <time dateTime={new Date(timestamp).toISOString()}>{new Date(timestamp).toLocaleString()}</time>\n {data?.stale ? ' · ' + ts('syncStale') : ''}\n </span>\n )}\n {timestamp == null && data?.connected && <span>{ts('syncBuiltin')}</span>}\n {unavailable && <span role=\"status\" className=\"dsh-or-sync-copy dsh-or-sync-error\">\n {ts(state.error === 'restart' ? 'syncRestart' : data?.error === 'save' ? 'syncSaveError' : 'syncError')}\n </span>}\n {details && <>\n <span>{ts('freeHelp')}</span>\n <span>{ts('forcedPluginWarning')}</span>\n </>}\n </div>\n )\n}\n","/** Shared, credential-free settings for this plugin's two outbound transports. */\n\nexport const PROXY_SETTINGS_PATH = '/plugins/dsh-oauth-login/network/settings'\nexport const PROXY_SETTINGS_FILENAME = '.dsh-oauth-proxy.json'\n\nexport interface ProxyChannelSettings {\n /** False means direct, even when proxy environment variables are set. */\n enabled: boolean\n /** Empty keeps environment/system discovery; otherwise this URL wins. */\n url: string\n}\n\nexport interface ProxySettings {\n http: ProxyChannelSettings\n websocket: ProxyChannelSettings\n}\n\nexport interface ProxySettingsSnapshot extends ProxySettings {\n revision: number\n}\n\nexport function defaultProxySettings(): ProxySettingsSnapshot {\n return { revision: 0, http: { enabled: true, url: '' }, websocket: { enabled: true, url: '' } }\n}\n\nfunction object(value: unknown, keys: readonly string[], label: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)\n || Object.keys(value).some(key => !keys.includes(key))) {\n throw new Error(`${label}: invalid settings object`)\n }\n return value as Record<string, unknown>\n}\n\nfunction channel(value: unknown, label: string): ProxyChannelSettings {\n const raw = object(value, ['enabled', 'url'], label)\n if (typeof raw.enabled !== 'boolean' || typeof raw.url !== 'string' || raw.url.length > 1024) {\n throw new Error(`${label}: expected enabled and proxy URL`)\n }\n const text = raw.url.trim()\n if (text === '') return { enabled: raw.enabled, url: '' }\n let parsed: URL\n try { parsed = new URL(text) } catch { throw new Error(`${label}: enter a valid HTTP proxy address and port`) }\n if (!['http:', 'https:'].includes(parsed.protocol) || !parsed.hostname\n || parsed.username || parsed.password || parsed.search || parsed.hash\n || parsed.pathname !== '/' || parsed.port === '0') {\n throw new Error(`${label}: use an HTTP(S) proxy without credentials, path, query or fragment`)\n }\n return { enabled: raw.enabled, url: parsed.origin }\n}\n\nexport function parseProxySettings(value: unknown): ProxySettingsSnapshot {\n const raw = object(value, ['revision', 'http', 'websocket'], 'Network')\n if (typeof raw.revision !== 'number' || !Number.isSafeInteger(raw.revision) || raw.revision < 0) {\n throw new Error('Network: invalid revision')\n }\n return {\n revision: raw.revision,\n http: channel(raw.http, 'HTTP'),\n websocket: channel(raw.websocket, 'WebSocket'),\n }\n}\n","import { parseProxySettings } from '../proxy-config.ts'\nimport type { ProxyChannelSettings, ProxySettingsSnapshot } from '../proxy-config.ts'\n\nexport interface ProxyChannelDraft {\n enabled: boolean\n address: string\n port: string\n}\n\nexport type ProxyDraft = Record<'http' | 'websocket', ProxyChannelDraft>\n\nexport const DEFAULT_PROXY_ADDRESS = 'http://127.0.0.1'\n\nexport function isAutomaticProxyDraft({ address, port }: ProxyChannelDraft): boolean {\n const host = address.trim().replace(/\\/$/, '')\n return port.trim() === '' && (host === '' || host === DEFAULT_PROXY_ADDRESS || host === '127.0.0.1')\n}\n\nexport function proxyDraft(settings: ProxySettingsSnapshot): ProxyDraft {\n const channel = ({ enabled, url }: ProxyChannelSettings): ProxyChannelDraft => {\n if (url === '') return { enabled, address: DEFAULT_PROXY_ADDRESS, port: '' }\n const parsed = new URL(url)\n return {\n enabled,\n address: `${parsed.protocol}//${parsed.hostname}`,\n port: parsed.port || (parsed.protocol === 'https:' ? '443' : '80'),\n }\n }\n return { http: channel(settings.http), websocket: channel(settings.websocket) }\n}\n\nexport function proxyDraftSettings(draft: ProxyDraft, revision: number): ProxySettingsSnapshot {\n const channel = (value: ProxyChannelDraft): ProxyChannelSettings => {\n const { enabled, address, port } = value\n const host = address.trim()\n const portText = port.trim()\n if (isAutomaticProxyDraft(value)) return { enabled, url: '' }\n if (host === '' || (portText !== '' && (!/^\\d{1,5}$/.test(portText)\n || Number(portText) < 1 || Number(portText) > 65535))) {\n throw new Error('Enter a proxy address and a port from 1 to 65535')\n }\n const parsed = new URL(host.includes('://') ? host : `http://${host}`)\n // URL.port omits explicit default ports (80/443), so retain the pasted port.\n const pastedPort = /:(\\d+)\\/?$/.exec(host)?.[1] ?? ''\n if (portText === '' && pastedPort === '') {\n throw new Error('Enter a proxy port from 1 to 65535')\n }\n if (portText !== '') {\n if (pastedPort !== '' && Number(pastedPort) !== Number(portText)) {\n throw new Error('The address and port fields specify different ports')\n }\n parsed.port = portText\n }\n return { enabled, url: parsed.href }\n }\n return parseProxySettings({ revision, http: channel(draft.http), websocket: channel(draft.websocket) })\n}\n","import { useCallback, useEffect, useId, useState } from 'react'\nimport { PROXY_SETTINGS_PATH, parseProxySettings } from '../proxy-config.ts'\nimport type { ProxySettingsSnapshot } from '../proxy-config.ts'\nimport { DEFAULT_PROXY_ADDRESS, isAutomaticProxyDraft, proxyDraft, proxyDraftSettings } from './proxy-draft.ts'\nimport type { ProxyChannelDraft, ProxyDraft } from './proxy-draft.ts'\nimport type { PiLoginKey } from './locales.ts'\n\ntype Translate = (key: PiLoginKey) => string\n\n/** Independent of account loading, so a broken network never hides its settings. */\nexport function ProxySettings({ t }: { t: Translate }) {\n const id = useId()\n const [settings, setSettings] = useState<ProxySettingsSnapshot>()\n const [draft, setDraft] = useState<ProxyDraft>()\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<PiLoginKey>()\n const [saved, setSaved] = useState(false)\n\n const load = useCallback(async (signal?: AbortSignal) => {\n setBusy(true)\n setError(undefined)\n setSaved(false)\n try {\n const response = await fetch(PROXY_SETTINGS_PATH, { credentials: 'same-origin', signal })\n if (!response.ok) throw new Error('Settings unavailable')\n const value = parseProxySettings(await response.json())\n if (signal?.aborted) return\n setSettings(value)\n setDraft(proxyDraft(value))\n } catch {\n if (!signal?.aborted) setError('proxyLoadFailed')\n } finally {\n if (!signal?.aborted) setBusy(false)\n }\n }, [])\n\n useEffect(() => {\n const controller = new AbortController()\n void load(controller.signal)\n return () => { controller.abort() }\n }, [load])\n\n const change = (channel: keyof ProxyDraft, patch: Partial<ProxyChannelDraft>) => {\n setDraft(current => current === undefined ? current : { ...current, [channel]: { ...current[channel], ...patch } })\n setError(undefined)\n setSaved(false)\n }\n\n const save = async () => {\n if (draft === undefined || settings === undefined) return\n let value: ProxySettingsSnapshot\n try { value = proxyDraftSettings(draft, settings.revision) } catch {\n setError('proxyInvalid')\n return\n }\n setBusy(true)\n setError(undefined)\n setSaved(false)\n try {\n const response = await fetch(PROXY_SETTINGS_PATH, {\n method: 'POST', credentials: 'same-origin',\n headers: { 'content-type': 'application/json' }, body: JSON.stringify(value),\n })\n if (response.status === 409) { setError('proxyConflict'); return }\n if (!response.ok) throw new Error('Settings save failed')\n const updated = parseProxySettings(await response.json())\n setSettings(updated)\n setDraft(proxyDraft(updated))\n setSaved(true)\n } catch { setError('proxySaveFailed') } finally { setBusy(false) }\n }\n\n const dirty = settings !== undefined && draft !== undefined\n && JSON.stringify(draft) !== JSON.stringify(proxyDraft(settings))\n return (\n <section className=\"dsh-pi-login-card dsh-oauth-network\" aria-labelledby={`${id}-title`}>\n <h3 id={`${id}-title`} className=\"dsh-pi-login-name\">{t('proxyTitle')}</h3>\n <p className=\"dsh-pi-login-body\">{t('proxyScope')}</p>\n {draft === undefined && busy ? <p className=\"dsh-pi-login-body\">{t('proxyLoading')}</p> : null}\n {draft === undefined ? null : (['http', 'websocket'] as const).map(channel => (\n <fieldset className=\"dsh-oauth-proxy-channel\" key={channel} disabled={busy}>\n <legend className=\"dsh-pi-login-name\">{channel === 'http' ? 'HTTP / HTTPS' : 'WebSocket (WS / WSS)'}</legend>\n <label className=\"dsh-oauth-proxy-switch\" htmlFor={`${id}-${channel}-enabled`}>\n <input id={`${id}-${channel}-enabled`} type=\"checkbox\" role=\"switch\"\n checked={draft[channel].enabled}\n onChange={event => change(channel, { enabled: event.currentTarget.checked })} />\n {t(channel === 'http' ? 'proxyHttpEnabled' : 'proxyWsEnabled')}\n </label>\n <p className=\"dsh-pi-login-body\">{t(channel === 'http' ? 'proxyHttpHelp' : 'proxyWsHelp')}</p>\n <div className=\"dsh-oauth-proxy-fields\">\n <label htmlFor={`${id}-${channel}-address`}>\n <span>{t('proxyAddress')}</span>\n <input className=\"dsh-pi-login-input\" id={`${id}-${channel}-address`}\n autoComplete=\"off\" spellCheck={false} placeholder={DEFAULT_PROXY_ADDRESS}\n value={draft[channel].address} disabled={!draft[channel].enabled}\n onChange={event => change(channel, { address: event.currentTarget.value })} />\n </label>\n <label htmlFor={`${id}-${channel}-port`}>\n <span>{t('proxyPort')}</span>\n <input className=\"dsh-pi-login-input\" id={`${id}-${channel}-port`}\n autoComplete=\"off\" inputMode=\"numeric\" placeholder={t('proxyPortPlaceholder')}\n value={draft[channel].port} disabled={!draft[channel].enabled}\n onChange={event => change(channel, { port: event.currentTarget.value })} />\n </label>\n </div>\n <p className=\"dsh-pi-login-body\">{t(!draft[channel].enabled ? 'proxyDirect'\n : isAutomaticProxyDraft(draft[channel]) ? 'proxyAuto' : 'proxyExplicit')}</p>\n </fieldset>\n ))}\n <p className=\"dsh-pi-login-body\">{t('proxyApplyHelp')}</p>\n <div aria-live=\"polite\">\n {error === undefined ? null : <p className=\"dsh-pi-login-error\" role=\"alert\">{t(error)}</p>}\n {saved ? <p className=\"dsh-pi-login-body\">{t('proxySaved')}</p> : null}\n </div>\n <div className=\"dsh-pi-login-row dsh-oauth-proxy-actions\">\n <button type=\"button\" className=\"dsh-pi-login-btn dsh-pi-login-btn-secondary\" disabled={busy}\n onClick={() => { void load() }}>{t('proxyReload')}</button>\n <button type=\"button\" className=\"dsh-pi-login-btn dsh-pi-login-btn-primary\"\n disabled={busy || !dirty} onClick={() => { void save() }}>{t(busy ? 'working' : 'proxySave')}</button>\n </div>\n </section>\n )\n}\n","import type { PiLoginKey } from './locales.ts'\n\nexport type LoginAuthType = 'oauth' | 'api_key'\nexport type LoginChallengeType = 'secret' | 'text' | 'manual_code'\n\nexport interface LoginInputCopy {\n waiting: PiLoginKey\n help: PiLoginKey\n placeholder: PiLoginKey\n action: PiLoginKey\n required: PiLoginKey\n}\n\nconst PLAN_COPY: LoginInputCopy = {\n waiting: 'waitingForCredential', help: 'credentialHelp', placeholder: 'credentialPlaceholder',\n action: 'saveCredential', required: 'credentialRequired',\n}\n\nconst CALLBACK_COPY: LoginInputCopy = {\n waiting: 'waitingForCallback', help: 'callbackHelp', placeholder: 'callbackPlaceholder',\n action: 'submitCallback', required: 'callbackRequired',\n}\n\nconst AUTH_INPUT_COPY: LoginInputCopy = {\n waiting: 'waitingForAuthInput', help: 'authInputHelp', placeholder: 'authInputPlaceholder',\n action: 'submitAuthInput', required: 'authInputRequired',\n}\n\n/** Select visible copy from the provider contract and the actual Pi challenge. */\nexport function loginInputCopy(authType: LoginAuthType, challengeType: LoginChallengeType): LoginInputCopy {\n if (authType === 'api_key') return PLAN_COPY\n if (challengeType === 'manual_code') return CALLBACK_COPY\n return AUTH_INPUT_COPY\n}\n","export interface LoginPopup {\n close(): void\n location: { replace(url: string): void }\n}\n\nexport type LoginUrlOpener = (url: string) => void\n\n/** Deliver a login challenge even when an Electron shell rejects the reserved about:blank popup. */\nexport function openLoginChallenge(\n popup: LoginPopup | null,\n url: string | undefined,\n openUrl: LoginUrlOpener,\n): 'reserved' | 'fallback' | 'none' {\n if (url === undefined) {\n popup?.close()\n return 'none'\n }\n if (popup !== null) {\n popup.location.replace(url)\n return 'reserved'\n }\n openUrl(url)\n return 'fallback'\n}\n","/** Plugin-owned Pi login page inside the dsh Settings shell. */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { applyDraftChange } from './draft-input.ts'\nimport type { Drafts } from './draft-input.ts'\nimport type { PiLoginKey } from './locales.ts'\nimport type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { OpenRouterCatalogClient } from './openrouter-store.ts'\nimport { OpenRouterSyncStatus } from './OpenRouterSyncStatus.tsx'\nimport { ProxySettings } from './ProxySettings.tsx'\nimport { loginInputCopy } from './login-input-copy.ts'\nimport { openLoginChallenge } from './login-window.ts'\n\nconst STATUS_PATH = '/plugins/dsh-oauth-login/auth/status'\nconst LOGIN_PATH = '/plugins/dsh-oauth-login/auth/login'\nconst CANCEL_PATH = '/plugins/dsh-oauth-login/auth/cancel'\nconst COMPLETE_PATH = '/plugins/dsh-oauth-login/auth/complete'\nconst LOGOUT_PATH = '/plugins/dsh-oauth-login/auth/logout'\nconst POLL_INTERVAL_MS = 1_000\nconst STYLE_ID = 'dsh-pi-login-settings-theme'\n\ntype AccountState =\n | { status: 'signed-out' }\n | {\n status: 'signing-in'\n kind?: 'browser' | 'input'\n url?: string\n userCode?: string\n input?: LoginInputChallenge\n }\n | { status: 'signed-in'; models?: string[]; expiresAt?: string }\n | { status: 'error'; message: string }\n\ninterface LoginInputChallenge {\n type: 'secret' | 'text' | 'manual_code'\n message: string\n placeholder?: string\n}\n\ninterface ProviderStatus {\n id: string\n route: string\n displayName: string\n shortName: string\n authType: 'oauth' | 'api_key'\n account: AccountState\n}\n\ninterface LoginChallenge {\n provider: string\n kind: 'browser' | 'input'\n url?: string\n userCode?: string\n input?: LoginInputChallenge\n}\n\nexport interface PiLoginSettingsInjected {\n t: (key: PiLoginKey, params?: Record<string, unknown>) => string\n ts: TranslateNS<'model-search'>\n catalog: OpenRouterCatalogClient\n}\n\nexport type PiLoginSettingsProps = Partial<PiLoginSettingsInjected>\n\n/**\n * Theme tokens that track light/dark. Hardcoded white/layer fills break dark mode.\n * Mirrors ModelsSection button vocabulary so OAuth cards match the rest of Settings.\n */\nconst SETTINGS_CSS = `\n.dsh-pi-login-page { display:flex; flex-direction:column; gap:16px; max-width:640px; color:var(--dsw-alias-label-primary); }\n.dsh-pi-login-title { margin:0; font-size:20px; line-height:28px; font-weight:600; color:var(--dsw-alias-label-primary); }\n.dsh-pi-login-body { margin:0; font-size:13px; line-height:20px; color:var(--dsw-alias-label-secondary); }\n.dsh-pi-login-error { margin:0; font-size:13px; line-height:20px; color:var(--dsw-alias-state-error-primary); }\n.dsh-pi-login-stack { display:flex; flex-direction:column; gap:10px; }\n.dsh-pi-login-card {\n display:flex; flex-direction:column; gap:8px; padding:14px 16px;\n border:1px solid var(--dsw-alias-border-l2); border-radius:12px;\n background:var(--dsw-alias-bg-module-platform);\n}\n.dsh-pi-login-row { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:10px; }\n.dsh-pi-login-row-actions { display:flex; align-items:center; flex-wrap:wrap; justify-content:flex-end; gap:8px; }\n.dsh-pi-login-name { margin:0; font-size:15px; font-weight:600; color:var(--dsw-alias-label-primary); }\n.dsh-pi-login-status { display:flex; align-items:center; flex-wrap:wrap; gap:6px; font-size:13px; color:var(--dsw-alias-label-secondary); }\n.dsh-pi-login-dot { width:8px; height:8px; border-radius:50%; flex:0 0 auto; background:var(--dsw-alias-label-dimmed, #9aa0a6); }\n.dsh-pi-login-dot.is-signed-in { background:var(--dsw-alias-state-success-primary, #22a06b); }\n.dsh-pi-login-dot.is-error { background:var(--dsw-alias-state-error-primary, #d92d20); }\n.dsh-pi-login-dot.is-signing-in { background:var(--dsw-alias-brand-primary, #1677ff); }\n.dsh-pi-login-btn {\n box-sizing:border-box; display:inline-flex; align-items:center; justify-content:center;\n min-height:32px; padding:4px 14px; border-radius:16px; font:inherit; font-size:13px; line-height:20px; cursor:pointer;\n}\n.dsh-pi-login-btn:disabled { opacity:0.55; cursor:not-allowed; }\n.dsh-pi-login-btn-secondary {\n border:1px solid var(--dsw-alias-border-l2);\n background:transparent;\n color:var(--dsw-alias-label-primary);\n}\n.dsh-pi-login-btn-secondary:hover:not(:disabled) {\n background:var(--dsw-alias-interactive-bg-hover);\n}\n.dsh-pi-login-btn-primary {\n border:none;\n background:var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary));\n color:var(--dsw-alias-label-primary-foreground, #fff);\n}\n.dsh-pi-login-btn-primary:hover:not(:disabled) {\n background:var(--dsw-alias-button-primary-hover, var(--dsw-alias-brand-primary));\n}\n.dsh-pi-login-code {\n font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size:18px; letter-spacing:0.08em; font-weight:600; color:var(--dsw-alias-label-primary);\n}\n.dsh-pi-login-link { color:var(--dsw-alias-brand-primary); word-break:break-all; }\n.dsh-pi-login-form { display:flex; flex-direction:column; gap:8px; }\n.dsh-pi-login-input {\n box-sizing:border-box; width:100%; min-height:36px; padding:7px 10px;\n border:1px solid var(--dsw-alias-border-l2); border-radius:8px;\n background:var(--dsw-alias-bg-page-primary, transparent);\n color:var(--dsw-alias-label-primary); font:inherit; font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n}\n.dsh-pi-login-input:focus {\n outline:2px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 28%, transparent);\n border-color:var(--dsw-alias-brand-primary);\n}\n.dsh-pi-login-actions { display:flex; justify-content:flex-end; }\n.dsh-oauth-proxy-channel { min-width:0; margin:8px 0 0; padding:12px 0 0; border:0; border-top:1px solid var(--dsw-alias-border-l2); display:flex; flex-direction:column; gap:8px; }\n.dsh-oauth-proxy-channel legend { padding:0 8px 0 0; font-size:13px; }\n.dsh-oauth-proxy-switch { display:flex; align-items:center; gap:8px; font-size:13px; cursor:pointer; }\n.dsh-oauth-proxy-switch input { width:16px; height:16px; margin:0; accent-color:var(--dsw-alias-brand-primary); }\n.dsh-oauth-proxy-fields { display:grid; grid-template-columns:minmax(0, 1fr) 100px; gap:12px; }\n.dsh-oauth-proxy-fields label { min-width:0; display:flex; flex-direction:column; gap:6px; font-size:12px; }\n.dsh-oauth-proxy-fields input { font-size:13px; }\n.dsh-oauth-proxy-fields input:disabled { opacity:0.55; }\n.dsh-oauth-proxy-actions { justify-content:flex-end; }\n@media (max-width:360px) { .dsh-oauth-proxy-fields { grid-template-columns:minmax(0, 1fr); } }\n`\n\nfunction ensureThemeStyles(): void {\n if (typeof document === 'undefined') return\n if (document.getElementById(STYLE_ID) !== null) return\n const style = document.createElement('style')\n style.id = STYLE_ID\n style.textContent = SETTINGS_CSS\n document.head.appendChild(style)\n}\n\nasync function jsonRequest<T>(path: string, method = 'GET', body?: unknown, signal?: AbortSignal): Promise<T> {\n const response = await fetch(path, {\n method,\n headers: { accept: 'application/json', ...body === undefined ? {} : { 'content-type': 'application/json' } },\n credentials: 'same-origin',\n signal,\n ...body === undefined ? {} : { body: JSON.stringify(body) },\n })\n const value: unknown = await response.json().catch(() => undefined)\n if (!response.ok) {\n const message = typeof value === 'object' && value !== null && 'error' in value && typeof value.error === 'string'\n ? value.error\n : `HTTP ${response.status}`\n throw new Error(message)\n }\n return value as T\n}\n\nexport function PiLoginSettings({ t, ts, catalog }: PiLoginSettingsProps) {\n if (t === undefined) throw new Error('Pi login settings requires its translation function')\n const [providers, setProviders] = useState<ProviderStatus[] | undefined>(undefined)\n const [error, setError] = useState<string | undefined>(undefined)\n const [busy, setBusy] = useState<string | undefined>(undefined)\n const [drafts, setDrafts] = useState<Drafts>({})\n const [challengeUrls, setChallengeUrls] = useState<Record<string, string>>({})\n const [cancellable, setCancellable] = useState<Record<string, boolean>>({})\n const [cancelling, setCancelling] = useState<string | undefined>(undefined)\n const operationSequence = useRef(0)\n const statusSequence = useRef(0)\n const operations = useRef(new Map<string, { readonly id: number; readonly controller: AbortController; readonly popup?: Window }>())\n\n const startOperation = (provider: string, canCancel: boolean, popup?: Window): { readonly id: number; readonly controller: AbortController } => {\n const previous = operations.current.get(provider)\n previous?.controller.abort()\n previous?.popup?.close()\n const operation = { id: ++operationSequence.current, controller: new AbortController(), ...popup === undefined ? {} : { popup } }\n operations.current.set(provider, operation)\n setBusy(provider)\n setCancellable(current => ({ ...current, [provider]: canCancel }))\n return operation\n }\n const isCurrent = (provider: string, operation: { readonly id: number }): boolean => operations.current.get(provider)?.id === operation.id\n const finishOperation = (provider: string, operation: { readonly id: number }): void => {\n if (!isCurrent(provider, operation)) return\n operations.current.delete(provider)\n setBusy(undefined)\n setCancellable(current => {\n const { [provider]: _removed, ...next } = current\n return next\n })\n }\n\n useEffect(() => { ensureThemeStyles() }, [])\n\n const refresh = useCallback(async () => {\n const requestId = ++statusSequence.current\n try {\n const next = await jsonRequest<ProviderStatus[]>(STATUS_PATH)\n if (requestId !== statusSequence.current) return\n setProviders(next)\n void catalog?.load()\n setError(undefined)\n } catch (caught: unknown) {\n if (requestId !== statusSequence.current) return\n setError(caught instanceof Error ? caught.message : t('requestFailed'))\n }\n }, [t, catalog])\n\n useEffect(() => { void refresh() }, [refresh])\n const signing = providers?.some(provider => provider.account.status === 'signing-in') ?? false\n useEffect(() => {\n if (!signing) return\n const timer = window.setInterval(() => { void refresh() }, POLL_INTERVAL_MS)\n return () => { window.clearInterval(timer) }\n }, [refresh, signing])\n\n const signIn = async (id: string): Promise<void> => {\n const popup = window.open('about:blank', '_blank')\n if (popup !== null) popup.opener = null\n setChallengeUrls(current => {\n const { [id]: _removed, ...next } = current\n return next\n })\n const operation = startOperation(id, true, popup ?? undefined)\n try {\n const challenge = await jsonRequest<LoginChallenge>(LOGIN_PATH, 'POST', { provider: id }, operation.controller.signal)\n if (!isCurrent(id, operation)) return\n if (challenge.url !== undefined) {\n setChallengeUrls(current => ({ ...current, [id]: challenge.url! }))\n }\n openLoginChallenge(popup, challenge.url, url => {\n window.open(url, '_blank', 'noopener,noreferrer')\n })\n await refresh()\n } catch (caught: unknown) {\n popup?.close()\n if (isCurrent(id, operation) && !operation.controller.signal.aborted) setError(caught instanceof Error ? caught.message : t('requestFailed'))\n } finally {\n finishOperation(id, operation)\n }\n }\n\n const submitInput = async (provider: ProviderStatus): Promise<void> => {\n const value = drafts[provider.id]?.trim() ?? ''\n if (value.length === 0) {\n const challenge = provider.account.status === 'signing-in' ? provider.account.input : undefined\n setError(t(challenge === undefined ? 'authInputRequired' : loginInputCopy(provider.authType, challenge.type).required))\n return\n }\n const operation = startOperation(provider.id, true)\n try {\n await jsonRequest<{ ok: true }>(COMPLETE_PATH, 'POST', { provider: provider.id, value }, operation.controller.signal)\n if (!isCurrent(provider.id, operation)) return\n setChallengeUrls(current => {\n const { [provider.id]: _removed, ...next } = current\n return next\n })\n setDrafts(current => {\n const { [provider.id]: _removed, ...next } = current\n return next\n })\n await refresh()\n } catch (caught: unknown) {\n if (isCurrent(provider.id, operation) && !operation.controller.signal.aborted) setError(caught instanceof Error ? caught.message : t('requestFailed'))\n } finally {\n finishOperation(provider.id, operation)\n }\n }\n\n const cancelSignIn = async (id: string): Promise<void> => {\n const operation = startOperation(id, false)\n setCancelling(id)\n try {\n await jsonRequest<{ ok: true }>(CANCEL_PATH, 'POST', { provider: id }, operation.controller.signal)\n if (!isCurrent(id, operation)) return\n setChallengeUrls(current => {\n const { [id]: _removed, ...next } = current\n return next\n })\n setDrafts(current => {\n const { [id]: _removed, ...next } = current\n return next\n })\n await refresh()\n } catch (caught: unknown) {\n if (isCurrent(id, operation) && !operation.controller.signal.aborted) setError(caught instanceof Error ? caught.message : t('requestFailed'))\n } finally {\n if (isCurrent(id, operation)) setCancelling(undefined)\n finishOperation(id, operation)\n }\n }\n\n const reopenSignIn = (url: string): void => {\n openLoginChallenge(null, url, next => {\n window.open(next, '_blank', 'noopener,noreferrer')\n })\n }\n\n const signOut = async (id: string): Promise<void> => {\n setBusy(id)\n try {\n await jsonRequest<{ ok: true }>(LOGOUT_PATH, 'POST', { provider: id })\n setChallengeUrls(current => {\n const { [id]: _removed, ...next } = current\n return next\n })\n await refresh()\n } catch (caught: unknown) {\n setError(caught instanceof Error ? caught.message : t('requestFailed'))\n } finally {\n setBusy(undefined)\n }\n }\n\n return (\n <section className=\"dsh-pi-login-page\" aria-labelledby=\"pi-login-settings-title\">\n <h2 id=\"pi-login-settings-title\" className=\"dsh-pi-login-title\">{t('title')}</h2>\n <ProxySettings t={t} />\n {error !== undefined ? <p className=\"dsh-pi-login-error\">{error}</p> : null}\n {providers === undefined\n ? <p className=\"dsh-pi-login-body\">{t('loadingAccount')}</p>\n : (\n <div className=\"dsh-pi-login-stack\">\n {providers.map(provider => {\n const account = provider.account\n const inputCopy = account.status === 'signing-in' && account.input !== undefined\n ? loginInputCopy(provider.authType, account.input.type)\n : undefined\n const challengeUrl = account.status === 'signing-in'\n ? account.url ?? challengeUrls[provider.id]\n : undefined\n const label = account.status === 'signed-in'\n ? t('signedIn')\n : account.status === 'signing-in'\n ? inputCopy === undefined ? t('signingIn') : t(inputCopy.waiting)\n : account.status === 'error'\n ? t('requestFailed')\n : t('signedOut')\n const dotClass = account.status === 'signed-in'\n ? 'dsh-pi-login-dot is-signed-in'\n : account.status === 'error'\n ? 'dsh-pi-login-dot is-error'\n : account.status === 'signing-in'\n ? 'dsh-pi-login-dot is-signing-in'\n : 'dsh-pi-login-dot'\n return (\n <article key={provider.id} className=\"dsh-pi-login-card\">\n <div className=\"dsh-pi-login-row\">\n <p className=\"dsh-pi-login-name\">{provider.displayName}</p>\n {account.status === 'signed-in'\n ? (\n <button\n type=\"button\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-secondary\"\n disabled={busy !== undefined}\n onClick={() => { void signOut(provider.id) }}\n >\n {busy === provider.id ? t('working') : t('logout')}\n </button>\n )\n : account.status === 'signing-in' || cancellable[provider.id] === true\n ? (\n <div className=\"dsh-pi-login-row-actions\">\n {challengeUrl !== undefined\n ? (\n <button\n type=\"button\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-primary\"\n disabled={busy !== undefined}\n onClick={() => { reopenSignIn(challengeUrl) }}\n >\n {t('reopenAuthorization')}\n </button>\n )\n : null}\n <button\n type=\"button\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-secondary\"\n disabled={cancelling === provider.id || (busy !== undefined && busy !== provider.id)}\n onClick={() => { void cancelSignIn(provider.id) }}\n >\n {cancelling === provider.id ? t('working') : t('cancelLogin')}\n </button>\n </div>\n )\n : (\n <button\n type=\"button\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-primary\"\n disabled={busy !== undefined}\n onClick={() => { void signIn(provider.id) }}\n >\n {busy === provider.id\n ? t('working')\n : account.status === 'error'\n ? t('loginAgain')\n : provider.authType === 'api_key'\n ? t('connectPlan')\n : t('login')}\n </button>\n )}\n </div>\n <div className=\"dsh-pi-login-status\" role=\"status\">\n <span aria-hidden=\"true\" className={dotClass} />\n <span>{label}</span>\n </div>\n {provider.id === 'openrouter' && catalog !== undefined && ts !== undefined\n && <OpenRouterSyncStatus catalog={catalog} ts={ts} details />}\n {account.status === 'error' ? <p className=\"dsh-pi-login-error\">{account.message}</p> : null}\n {account.status === 'signing-in' && account.userCode !== undefined\n ? <p className=\"dsh-pi-login-body\">{t('userCode')} <span className=\"dsh-pi-login-code\">{account.userCode}</span></p>\n : null}\n {account.status === 'signing-in' && challengeUrl !== undefined\n ? (\n <p className=\"dsh-pi-login-body\">\n {provider.authType === 'api_key' && account.input !== undefined ? t('openPlanPage') : t('openUrl')}\n {' '}\n <a href={challengeUrl} target=\"_blank\" rel=\"noreferrer\" className=\"dsh-pi-login-link\">{challengeUrl}</a>\n </p>\n )\n : null}\n {account.status === 'signing-in' && account.input !== undefined\n ? (\n <form\n className=\"dsh-pi-login-form\"\n onSubmit={(event) => {\n event.preventDefault()\n void submitInput(provider)\n }}\n >\n <p className=\"dsh-pi-login-body\">{t(inputCopy?.help ?? 'authInputHelp')}</p>\n <input\n type={account.input.type === 'secret' ? 'password' : 'text'}\n className=\"dsh-pi-login-input\"\n aria-label={account.input.message}\n autoComplete=\"off\"\n spellCheck={false}\n placeholder={t(inputCopy?.placeholder ?? 'authInputPlaceholder')}\n value={drafts[provider.id] ?? ''}\n disabled={busy !== undefined}\n onChange={(event) => {\n applyDraftChange(provider.id, event, setDrafts)\n }}\n />\n <div className=\"dsh-pi-login-actions\">\n <button\n type=\"submit\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-primary\"\n disabled={busy !== undefined || (drafts[provider.id]?.trim().length ?? 0) === 0}\n >\n {busy === provider.id ? t('working') : t(inputCopy?.action ?? 'submitAuthInput')}\n </button>\n </div>\n </form>\n )\n : null}\n </article>\n )\n })}\n </div>\n )}\n </section>\n )\n}\n","/**\n * Pure filtering for the searchable composer model seat. Kept free of React\n * so the unit suite can exercise it without a DOM.\n */\n\n/** Minimal structural mirror of the host model catalog row (no runtime import). */\nexport interface FilterModel {\n id: string\n name: string\n description?: string\n}\n\n/** Minimal structural mirror of one provider group. */\nexport interface FilterGroup {\n id: string\n name: string\n models: readonly FilterModel[]\n}\n\n/**\n * Case-insensitive substring filter over model name, model id, and provider\n * name. Blank queries return the input unchanged (same array identity).\n * Groups whose every model is filtered out disappear; relative order holds.\n * @param groups - provider groups from the shared directory snapshot.\n * @param query - raw user text; trimmed and lowercased here.\n * @returns the filtered groups.\n */\nexport function filterGroups(\n groups: readonly FilterGroup[],\n query: string,\n freeModels?: ReadonlySet<string>,\n): readonly FilterGroup[] {\n const q = query.trim().toLowerCase()\n if (q === '' && freeModels === undefined) return groups\n const out: FilterGroup[] = []\n for (const group of groups) {\n if (freeModels !== undefined && group.id !== 'pi-openrouter') continue\n const groupHit = group.name.toLowerCase().includes(q)\n const matches = groupHit ? group.models : group.models.filter(model =>\n model.name.toLowerCase().includes(q) || model.id.toLowerCase().includes(q))\n const models = freeModels === undefined ? matches : matches.filter(model => freeModels.has(model.id))\n if (models.length > 0) out.push({ ...group, models })\n }\n return out\n}\n","/** Browser-safe contract. No credentials, provider URLs or server imports. */\nexport const OPENROUTER_CATALOG_PATH = '/plugins/dsh-oauth-login/openrouter/models'\nexport const OPENROUTER_REFRESH_PATH = OPENROUTER_CATALOG_PATH + '/refresh'\nexport const OPENROUTER_ROUTE = 'pi-openrouter'\nexport const OPENROUTER_REFRESH_MS = 15 * 60_000\nexport const OPENROUTER_COOLDOWN_MS = 60_000\n\nexport interface OpenRouterModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n inputModalities: string[]\n outputModalities: string[]\n supportedParameters: string[]\n tools: boolean\n reasoning: boolean\n reasoningMandatory: boolean\n supportedEfforts?: string[]\n defaultEffort?: string\n /** USD per token/unit as supplied by the official catalog, not pi-ai costs. */\n pricing: Record<string, string>\n priceStatus: 'free' | 'paid' | 'unknown'\n /** Endpoint deprecation, NEVER interpreted as a promotion deadline. */\n deprecatesAt?: string\n}\n\nexport interface OpenRouterCatalogSnapshot {\n version: 1\n connected: boolean\n refreshing: boolean\n source: 'builtin' | 'cache' | 'live'\n lastUpdatedAt: number | null\n lastAttemptAt: number | null\n nextRefreshAt: number | null\n retryAt: number | null\n stale: boolean\n error: 'fetch' | 'cache' | 'save' | null\n models: Array<OpenRouterModel & { freeOnly: boolean }>\n}\n","/**\n * SearchableModelSelect: plugin-owned shadow of the composer model seat\n * (`conversation.input.model`, registered at priority -1 so it renders over\n * the shipped ModelSelect). Behavior mirrors the official two-level menu —\n * root rows drill into the model list and the effort list over the SAME\n * shared per-session directory — and adds one thing the shipped seat lacks:\n * a local search box on the model pane that filters provider groups by model\n * name/id or provider name while typing. Selection still submits through the\n * injected `select` face, so the host stays the single fact source.\n */\nimport {\n useEffect, useId, useMemo, useRef, useState, useSyncExternalStore,\n type KeyboardEvent, type FocusEvent,\n} from 'react'\nimport type { ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types'\nimport type { ModelDirectoryState as DirectoryState, ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type { InjectFace, PropsLocale, PropsRuntime, TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'\nimport { filterGroups } from './model-filter.ts'\nimport type { FilterGroup } from './model-filter.ts'\nimport type { OpenRouterCatalogClient } from './openrouter-store.ts'\nimport { OpenRouterSyncStatus } from './OpenRouterSyncStatus.tsx'\nimport { OPENROUTER_ROUTE } from '../openrouter-types.ts'\n\n/** Which pane the dropdown shows. */\ntype Pane = 'root' | 'model' | 'effort'\n\n/** One effort row; undefined effort preserves the provider default. */\ninterface EffortChoice {\n key: string\n effort: string | undefined\n label: string\n description?: string\n}\n\n/** Component props: owner share + injected face + both translators. */\nexport interface SearchableModelSelectInjected extends ModelSelectInjected {\n catalog: OpenRouterCatalogClient\n /** Plugin `model-search` namespace translate (search box copy). */\n ts: TranslateNS<'model-search'>\n}\n\nexport type SearchableModelSelectProps = PropsRuntime<'conversation.input.model'>\n & PropsLocale<'model'>\n & InjectFace<SearchableModelSelectInjected>\n\nconst STYLE_ID = 'dsh-oauth-model-search-theme'\n\n/** Theme-token styles mirroring the shipped seat's menu vocabulary. */\nconst SEARCH_CSS = `\n.dsh-oauth-ms-root { position:relative; min-width:0; }\n.dsh-oauth-ms-trigger {\n display:flex; align-items:center; gap:4px; min-width:0;\n max-width:min(360px,45cqw); height:28px; padding:0 4px 0 8px;\n border:none; border-radius:24px; outline:none; background:transparent;\n color:var(--dsw-alias-label-secondary); font-size:13px; line-height:20px;\n font-weight:500; cursor:pointer;\n}\n.dsh-oauth-ms-trigger:hover:not(:disabled) { background:var(--dsw-alias-interactive-bg-hover); }\n.dsh-oauth-ms-trigger:focus-visible { box-shadow:0 0 0 2px var(--dsw-alias-border-l3); }\n.dsh-oauth-ms-trigger:disabled { color:var(--dsw-alias-label-dimmed); cursor:default; }\n.dsh-oauth-ms-triggerLabel { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n.dsh-oauth-ms-triggerEffort { flex:0 0 auto; color:var(--dsw-alias-label-caption); }\n.dsh-oauth-ms-chevron { flex:0 0 auto; color:var(--dsw-alias-label-caption); transition:transform 120ms ease; }\n.dsh-oauth-ms-chevronOpen { transform:rotate(180deg); }\n@media (prefers-reduced-motion: reduce) { .dsh-oauth-ms-chevron { transition:none; } }\n.dsh-oauth-ms-menu {\n position:absolute; right:0; bottom:calc(100% + 8px); z-index:20;\n display:flex; flex-direction:column;\n width:max-content; min-width:min(240px,calc(100vw - 32px));\n max-width:min(420px,calc(100vw - 32px));\n max-height:min(360px,calc(100vh - 96px)); overflow:hidden; padding:4px;\n border:1px solid var(--dsw-alias-border-inverted); border-radius:12px;\n background:var(--dsw-specific-menu); box-shadow:var(--dsw-shadow-lv3);\n color:var(--dsw-alias-label-primary);\n --dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);\n}\n.dsh-oauth-ms-status,.dsh-oauth-ms-empty { padding:10px; color:var(--dsw-alias-label-tertiary); font-size:13px; line-height:20px; }\n.dsh-oauth-ms-errorStrip {\n display:flex; align-items:flex-start; justify-content:space-between; gap:8px;\n margin-bottom:4px; padding:7px 8px; border-radius:8px;\n background:var(--dsw-alias-interactive-bg-hover-danger);\n color:var(--dsw-alias-state-error-primary); font-size:12px; line-height:18px;\n}\n.dsh-oauth-ms-warning {\n display:flex; align-items:flex-start; justify-content:space-between; gap:8px;\n margin-bottom:4px; padding:7px 8px; border-radius:8px;\n background:var(--dsw-alias-bg-module-platform);\n color:var(--dsw-alias-state-warn-label); font-size:12px; line-height:18px;\n}\n.dsh-oauth-ms-retry { flex:0 0 auto; padding:0; border:none; background:transparent; color:inherit; font:inherit; font-weight:600; cursor:pointer; }\n.dsh-oauth-ms-search {\n margin:2px 2px 4px; padding:6px 8px; border:1px solid var(--dsw-alias-border-inverted);\n border-radius:8px; background:transparent; font-size:13px;\n color:var(--dsw-alias-label-primary); outline:none;\n}\n.dsh-oauth-ms-search:focus-visible { box-shadow:0 0 0 2px var(--dsw-alias-border-l3); }\n.dsh-oauth-ms-groups { min-height:0; overflow-y:auto; }\n.dsh-oauth-ms-group + .dsh-oauth-ms-group { margin-top:4px; }\n.dsh-oauth-ms-groupTitle {\n position:sticky; top:0; z-index:1; padding:5px 8px 3px;\n background:var(--dsw-specific-menu); color:var(--dsw-alias-label-tertiary);\n font-size:12px; line-height:18px; font-weight:500;\n}\n.dsh-oauth-ms-option {\n box-sizing:border-box; display:flex; align-items:center; gap:8px;\n width:auto; min-width:100%; min-height:38px; padding:6px 8px;\n border:none; border-radius:10px; outline:none; background:transparent;\n color:inherit; text-align:left; cursor:pointer;\n}\n.dsh-oauth-ms-option:hover:not(:disabled),.dsh-oauth-ms-option:focus-visible { background:var(--dsw-alias-interactive-bg-hover); }\n.dsh-oauth-ms-option:disabled { color:var(--dsw-alias-label-dimmed); cursor:default; }\n.dsh-oauth-ms-optionCopy { display:flex; flex:1; flex-direction:column; min-width:0; }\n.dsh-oauth-ms-modelName { overflow:hidden; color:inherit; font-size:14px; line-height:20px; font-weight:500; text-overflow:ellipsis; white-space:nowrap; }\n.dsh-oauth-ms-description { overflow:hidden; color:var(--dsw-alias-label-tertiary); font-size:12px; line-height:18px; text-overflow:ellipsis; white-space:nowrap; }\n.dsh-oauth-ms-check { display:grid; place-items:center; flex:0 0 18px; color:var(--dsw-alias-label-primary); }\n.dsh-oauth-ms-cell {\n box-sizing:border-box; display:flex; align-items:center; gap:8px;\n width:auto; min-width:100%; height:40px; padding:0 10px;\n border:none; border-radius:10px; background:transparent;\n color:var(--dsw-alias-label-primary); font-size:14px; line-height:22px;\n cursor:pointer; text-align:left;\n}\n.dsh-oauth-ms-cell:hover { background:var(--dsw-alias-interactive-bg-hover); }\n.dsh-oauth-ms-cellLabel { flex:0 0 auto; white-space:nowrap; }\n.dsh-oauth-ms-cellValue { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:right; color:var(--dsw-alias-label-tertiary); }\n.dsh-oauth-ms-cellChevron { flex:0 0 auto; color:var(--dsw-alias-label-tertiary); }\n.dsh-oauth-ms-filters { display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin:2px 4px 4px; }\n.dsh-oauth-ms-filter { min-height:28px;padding:3px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:16px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer; }\n.dsh-oauth-ms-filter[aria-pressed=\"true\"] { background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l3); }\n.dsh-oauth-ms-filter:focus-visible { outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px; }\n.dsh-oauth-ms-meta { display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;margin-top:3px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px; }\n.dsh-oauth-ms-free { padding:1px 6px;border-radius:4px;color:color-mix(in srgb,var(--dsw-alias-state-success-primary) 50%,var(--dsw-alias-label-primary));background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 10%,transparent); }\n.dsh-oauth-ms-cached { color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover); }\n.dsh-oauth-ms-ended { color:color-mix(in srgb,var(--dsw-alias-state-warn-label) 50%,var(--dsw-alias-label-primary));white-space:normal; }\n.dsh-oauth-ms-help { padding:4px 8px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);white-space:normal; }\n@media (max-width:480px) { .dsh-oauth-ms-menu { width:calc(100vw - 32px);max-height:min(520px,calc(100dvh - 120px)); } .dsh-oauth-ms-option { min-height:44px; } }\n`\n\nfunction ensureStyles(): void {\n if (typeof document === 'undefined') return\n const existing = document.getElementById(STYLE_ID)\n if (existing !== null) {\n existing.textContent = SEARCH_CSS\n return\n }\n const style = document.createElement('style')\n style.id = STYLE_ID\n style.textContent = SEARCH_CSS\n document.head.appendChild(style)\n}\n\n/** Small inline chevron-down glyph (avoids importing host primitives). */\nfunction Chevron({ className }: { className: string }) {\n return (\n <svg className={className} width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\n/** Small inline chevron-right glyph. */\nfunction ChevronRight({ className }: { className: string }) {\n return (\n <svg className={className} width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 4l4 4-4 4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\n/**\n * Render the searchable composer model seat.\n * @param props - see {@link SearchableModelSelectProps}.\n * @returns the trigger and, while open, the search-enabled two-level menu.\n */\nexport function SearchableModelSelect(\n { locked, available, directory, catalog, load, select, t, ts }: SearchableModelSelectProps,\n) {\n const state = useSyncExternalStore(\n fn => directory.subscribe(fn),\n () => directory.getSnapshot(),\n ) as DirectoryState\n const catalogState = useSyncExternalStore(catalog.subscribe, catalog.getSnapshot)\n const metadata = useMemo(() => new Map(catalogState.data?.models.map(model => [model.id, model]) ?? []), [catalogState.data])\n const freeModels = useMemo(() => new Set([...metadata.values()].filter(model => model.priceStatus === 'free').map(model => model.id)), [metadata])\n const [freeOnly, setFreeOnly] = useState(false)\n const [open, setOpen] = useState(false)\n const [pane, setPane] = useState<Pane>('root')\n const [query, setQuery] = useState('')\n const lastActionRef = useRef<'load' | 'select'>('load')\n const [notice, setNotice] = useState<{ seq: number; text: string } | null>(null)\n const noticeSeq = useRef(0)\n const noticeTimer = useRef<number | undefined>(undefined)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const searchRef = useRef<HTMLInputElement | null>(null)\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([])\n const id = useId()\n\n useEffect(() => { ensureStyles() }, [])\n useEffect(() => {\n if (open && pane === 'model') searchRef.current?.focus()\n }, [open, pane])\n useEffect(() => {\n if (catalogState.data?.connected === false) setFreeOnly(false)\n }, [catalogState.data?.connected])\n useEffect(() => {\n if (available && catalogState.data?.lastUpdatedAt != null) load()\n }, [available, catalogState.data?.lastUpdatedAt, load])\n useEffect(() => () => { window.clearTimeout(noticeTimer.current) }, [])\n\n const choices = useMemo(() => state.groups.flatMap(group =>\n group.models.map(model => ({\n group,\n model,\n selection: {\n provider: group.id,\n model: model.id,\n ...model.reasoning?.defaultEffort === undefined\n ? {}\n : { reasoningEffort: model.reasoning.defaultEffort },\n } satisfies ModelSelection,\n }))), [state.groups])\n const current = state.current\n const selectedIndex = current === null\n ? -1\n : choices.findIndex(c => c.selection.provider === current.provider && c.selection.model === current.model)\n const currentChoice = choices[selectedIndex]\n const reasoning = currentChoice?.model.reasoning\n const effectiveEffort = state.current?.reasoningEffort ?? reasoning?.defaultEffort\n const effortLabel = reasoning === undefined\n ? undefined\n : effectiveEffort === undefined\n ? t('effort.providerDefault')\n : reasoning.efforts.find(level => level.id === effectiveEffort)?.name ?? effectiveEffort\n const effortChoices = useMemo<readonly EffortChoice[]>(() => reasoning === undefined\n ? []\n : [\n ...reasoning.defaultEffort === undefined\n ? [{ key: 'provider-default', effort: undefined, label: t('effort.providerDefault') }]\n : [],\n ...reasoning.efforts.map(effort => ({\n key: `effort:${effort.id}`,\n effort: effort.id,\n label: effort.name,\n ...effort.description === undefined ? {} : { description: effort.description },\n })),\n ], [reasoning, t])\n const busy = state.status === 'selecting'\n\n const filteredGroups = useMemo<readonly FilterGroup[]>(\n () => filterGroups(state.groups, query, freeOnly ? freeModels : undefined),\n [state.groups, query, freeOnly, freeModels])\n const filteredCount = useMemo(\n () => filteredGroups.reduce((sum, group) => sum + group.models.length, 0),\n [filteredGroups])\n\n const reload = (): void => {\n lastActionRef.current = 'load'\n load()\n void catalog.load()\n }\n\n // Mount-time load resolves the trigger label; every open refreshes.\n useEffect(() => {\n if (available) {\n lastActionRef.current = 'load'\n load()\n }\n }, [available, load])\n\n useEffect(() => {\n if (!open) return\n const closeOutside = (event: MouseEvent): void => {\n if (!rootRef.current?.contains(event.target as Node)) setOpen(false)\n }\n document.addEventListener('mousedown', closeOutside)\n return () => { document.removeEventListener('mousedown', closeOutside) }\n }, [open])\n\n if (!available) return null\n\n const show = (): void => {\n setPane('root')\n setQuery('')\n setNotice(null)\n setOpen(true)\n reload()\n }\n\n const close = (restoreFocus = false): void => {\n setOpen(false)\n setPane('root')\n setQuery('')\n if (restoreFocus) queueMicrotask(() => { triggerRef.current?.focus() })\n }\n\n const moveFocus = (offset: number): void => {\n const items = itemRefs.current.filter(item => item !== null && !item.disabled)\n if (items.length === 0) return\n const active = items.findIndex(item => item === document.activeElement)\n const next = (Math.max(active, 0) + offset + items.length) % items.length\n items[next]?.focus()\n }\n\n const onRootKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {\n if (event.key === 'Escape' && open) {\n event.preventDefault()\n if (pane !== 'root') setPane('root')\n else close(true)\n return\n }\n if (!open) return\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n moveFocus(event.key === 'ArrowDown' ? 1 : -1)\n }\n }\n\n const onBlur = (event: FocusEvent<HTMLDivElement>): void => {\n if (event.relatedTarget instanceof Node && rootRef.current?.contains(event.relatedTarget)) return\n close()\n }\n\n const settleSelection = (result: Awaited<ReturnType<ModelSelectInjected['select']>>): void => {\n if (result === undefined) return\n if (result.ok) {\n if (rootRef.current !== null) close(true)\n return\n }\n const { error } = result\n noticeSeq.current += 1\n window.clearTimeout(noticeTimer.current)\n setNotice({\n seq: noticeSeq.current,\n text: error.code === 'session/writer-held'\n ? t('error.sessionInUse')\n : t('error.action', { message: `${error.code}: ${error.message}` }),\n })\n noticeTimer.current = window.setTimeout(() => { setNotice(null) }, 4000)\n }\n\n const choose = (selection: ModelSelection): void => {\n const info = selection.provider === OPENROUTER_ROUTE ? metadata.get(selection.model) : undefined\n if (info?.freeOnly && info.priceStatus !== 'free') return\n const current = state.current\n if (current?.provider === selection.provider && current.model === selection.model) {\n close(true)\n return\n }\n lastActionRef.current = 'select'\n void select(selection).then(settleSelection)\n }\n\n const chooseEffort = (effort: string | undefined): void => {\n if (state.current === null) return\n if (effectiveEffort === effort) {\n close(true)\n return\n }\n const selection: ModelSelection = {\n provider: state.current.provider,\n model: state.current.model,\n ...effort === undefined ? {} : { reasoningEffort: effort },\n }\n lastActionRef.current = 'select'\n void select(selection).then(settleSelection)\n }\n\n /** Search-input keyboard: ↓ enters the list, Enter picks the first match, Escape clears then backs out. */\n const onSearchKeyDown = (event: KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n event.stopPropagation()\n itemRefs.current.find(item => item !== null)?.focus()\n return\n }\n if (event.key === 'Enter') {\n event.preventDefault()\n const first = filteredGroups[0]?.models[0]\n if (first !== undefined) choose({ provider: filteredGroups[0].id, model: first.id })\n return\n }\n if (event.key === 'Escape') {\n event.stopPropagation()\n if (query !== '') setQuery('')\n // Non-Escape propagation lets the root handler back out of the pane.\n }\n }\n\n const modelLabel = currentChoice?.model.name ?? state.current?.model ?? t('trigger.fallback')\n const triggerLabel = effortLabel === undefined ? modelLabel : `${modelLabel} · ${effortLabel}`\n const triggerAria = currentChoice === undefined\n ? t('trigger.selectAria')\n : effortLabel === undefined\n ? t('trigger.aria', { model: modelLabel })\n : t('trigger.ariaEffort', { model: modelLabel, effort: effortLabel })\n itemRefs.current = []\n let itemIndex = 0\n const itemRef = () => {\n const at = itemIndex++\n return (node: HTMLButtonElement | null) => { itemRefs.current[at] = node }\n }\n\n return (\n <div ref={rootRef} className=\"dsh-oauth-ms-root\" onKeyDown={onRootKeyDown} onBlur={onBlur}>\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"dsh-oauth-ms-trigger\"\n aria-label={triggerAria}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? `${id}-menu` : undefined}\n title={triggerLabel}\n disabled={locked}\n onClick={() => {\n if (open) close()\n else show()\n }}\n >\n <span className=\"dsh-oauth-ms-triggerLabel\">{modelLabel}</span>\n {effortLabel !== undefined && <span className=\"dsh-oauth-ms-triggerEffort\">{effortLabel}</span>}\n <Chevron className={`dsh-oauth-ms-chevron${open ? ' dsh-oauth-ms-chevronOpen' : ''}`} />\n </button>\n\n {open && (\n <div\n id={`${id}-menu`}\n className=\"dsh-oauth-ms-menu\"\n role=\"menu\"\n aria-label={t('menu.aria')}\n aria-busy={state.status === 'loading' || busy}\n >\n {pane === 'root' && (\n <>\n <button ref={itemRef()} type=\"button\" role=\"menuitem\" className=\"dsh-oauth-ms-cell\" onClick={() => { setPane('model') }}>\n <span className=\"dsh-oauth-ms-cellLabel\">{t('menu.model')}</span>\n <span className=\"dsh-oauth-ms-cellValue\">{modelLabel}</span>\n <ChevronRight className=\"dsh-oauth-ms-cellChevron\" />\n </button>\n {reasoning !== undefined && (\n <button ref={itemRef()} type=\"button\" role=\"menuitem\" className=\"dsh-oauth-ms-cell\" onClick={() => { setPane('effort') }}>\n <span className=\"dsh-oauth-ms-cellLabel\">{t('menu.effort')}</span>\n <span className=\"dsh-oauth-ms-cellValue\">{effortLabel}</span>\n <ChevronRight className=\"dsh-oauth-ms-cellChevron\" />\n </button>\n )}\n </>\n )}\n\n {pane === 'model' && (\n <>\n <input\n ref={searchRef}\n type=\"text\"\n className=\"dsh-oauth-ms-search\"\n placeholder={ts('placeholder')}\n aria-label={ts('aria')}\n value={query}\n autoComplete=\"off\"\n spellCheck={false}\n onChange={event => { setQuery(event.target.value) }}\n onKeyDown={onSearchKeyDown}\n />\n {(catalogState.data?.connected || state.groups.some(group => group.id === OPENROUTER_ROUTE)) && <>\n <div className=\"dsh-oauth-ms-filters\" role=\"group\" aria-label={ts('freeFilterAria')}>\n <button type=\"button\" className=\"dsh-oauth-ms-filter\" aria-pressed={!freeOnly} onClick={() => { setFreeOnly(false) }}>{ts('all')}</button>\n <button type=\"button\" className=\"dsh-oauth-ms-filter\" aria-pressed={freeOnly} onClick={() => { setFreeOnly(true) }}>{ts('freeOnly')} · {freeModels.size}</button>\n </div>\n <OpenRouterSyncStatus catalog={catalog} ts={ts} />\n </>}\n {state.status === 'loading' && <div className=\"dsh-oauth-ms-status\">{t('status.loading')}</div>}\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className=\"dsh-oauth-ms-errorStrip\">\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className=\"dsh-oauth-ms-retry\" onClick={reload}>{t('retry')}</button>\n </div>\n )}\n {state.failures.map(failure => (\n <div className=\"dsh-oauth-ms-warning\" key={failure.id}>\n <span>{t('warning.groupLoad', { name: failure.name, message: failure.message })}</span>\n <button type=\"button\" className=\"dsh-oauth-ms-retry\" onClick={reload}>{t('retry')}</button>\n </div>\n ))}\n <div className=\"dsh-oauth-ms-groups\">\n {filteredGroups.map((group) => {\n const headingId = `${id}-${group.id}`\n return (\n <section role=\"group\" aria-labelledby={headingId} className=\"dsh-oauth-ms-group\" key={group.id}>\n <div className=\"dsh-oauth-ms-groupTitle\" id={headingId}>{group.name}</div>\n {group.models.map(model => {\n const selected = state.current?.provider === group.id && state.current.model === model.id\n const info = group.id === OPENROUTER_ROUTE ? metadata.get(model.id) : undefined\n const blocked = info?.freeOnly === true && info.priceStatus !== 'free'\n const tokens = info === undefined ? '' : new Intl.NumberFormat(undefined, { notation: 'compact', maximumFractionDigits: 1 }).format(info.contextWindow)\n return (\n <button\n ref={itemRef()}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className=\"dsh-oauth-ms-option\"\n key={model.id}\n title={model.name}\n disabled={busy || blocked}\n onClick={() => { choose({ provider: group.id, model: model.id }) }}\n >\n <span className=\"dsh-oauth-ms-optionCopy\">\n <span className=\"dsh-oauth-ms-modelName\">{model.name}</span>\n {model.description !== undefined && (\n <span className=\"dsh-oauth-ms-description\">{model.description}</span>\n )}\n {info !== undefined && (\n <span className=\"dsh-oauth-ms-meta\">\n {info.priceStatus === 'free' && <span className={'dsh-oauth-ms-free' + (catalogState.data?.stale ? ' dsh-oauth-ms-cached' : '')}>\n {ts(catalogState.data?.stale ? 'freeCached' : 'free')}\n </span>}\n {blocked && <span className=\"dsh-oauth-ms-ended\">{ts(info.priceStatus === 'paid' ? 'freeEnded' : 'freeUnknown')}</span>}\n <span>{ts(info.tools ? 'tools' : 'chatOnly')}</span>\n <span>{ts('context', { tokens })}</span>\n </span>\n )}\n </span>\n <span className=\"dsh-oauth-ms-check\">\n {selected\n ? (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 8.5l3.2 3L13 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n : null}\n </span>\n </button>\n )\n })}\n </section>\n )\n })}\n </div>\n {state.status === 'ready' && state.groups.length > 0 && filteredCount === 0 && (\n <div className=\"dsh-oauth-ms-empty\">{freeOnly ? ts('emptyFree') : ts('empty', { query: query.trim() })}</div>\n )}\n {state.status === 'ready' && state.groups.length === 0 && (\n <div className=\"dsh-oauth-ms-empty\">{t('empty.models')}</div>\n )}\n {freeOnly && <div className=\"dsh-oauth-ms-help\">{ts('freeHelp')}</div>}\n </>\n )}\n\n {pane === 'effort' && (\n <>\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className=\"dsh-oauth-ms-errorStrip\">\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className=\"dsh-oauth-ms-retry\" onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {effortChoices.length === 0\n ? <div className=\"dsh-oauth-ms-empty\">{t('empty.efforts')}</div>\n : effortChoices.map(level => (\n <button\n ref={itemRef()}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={effectiveEffort === level.effort}\n className=\"dsh-oauth-ms-option\"\n key={level.key}\n disabled={busy}\n onClick={() => { chooseEffort(level.effort) }}\n >\n <span className=\"dsh-oauth-ms-optionCopy\">\n <span className=\"dsh-oauth-ms-modelName\">{level.label}</span>\n {level.description !== undefined && (\n <span className=\"dsh-oauth-ms-description\">{level.description}</span>\n )}\n </span>\n <span className=\"dsh-oauth-ms-check\">\n {effectiveEffort === level.effort\n ? (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 8.5l3.2 3L13 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n : null}\n </span>\n </button>\n ))}\n </>\n )}\n\n {notice !== null && (\n <div role=\"alert\" className=\"dsh-oauth-ms-errorStrip\" key={notice.seq}>{notice.text}</div>\n )}\n </div>\n )}\n </div>\n )\n}\n","export const en = {\n nav: 'Subscription Login',\n title: 'Subscription Login',\n loadingAccount: 'Loading accounts…',\n signedOut: 'Not signed in',\n signingIn: 'Waiting for authorization…',\n waitingForCredential: 'Waiting for a Plan API key…',\n waitingForCallback: 'Waiting for the authorization callback…',\n waitingForAuthInput: 'Waiting for authorization details…',\n signedIn: 'Signed in',\n login: 'Sign in',\n connectPlan: 'Connect plan',\n loginAgain: 'Sign in again',\n reopenAuthorization: 'Reopen authorization',\n cancelLogin: 'Cancel',\n logout: 'Sign out',\n working: 'Working…',\n userCode: 'Code',\n openUrl: 'Authorize',\n openPlanPage: 'Plan page',\n credentialHelp: 'Create or copy the provider-specific Plan API key, then paste it here. It stays in DSH’s private credential file.',\n credentialPlaceholder: 'Paste Plan API key',\n saveCredential: 'Save and connect',\n credentialRequired: 'Paste the Plan API key first.',\n callbackHelp: 'Paste the complete callback URL from the browser after authorization. DSH uses it only to finish this sign-in.',\n callbackPlaceholder: 'Paste the callback URL',\n submitCallback: 'Complete sign-in',\n callbackRequired: 'Paste the callback URL first.',\n authInputHelp: 'Enter the value requested by the provider to continue authorization.',\n authInputPlaceholder: 'Enter authorization value',\n submitAuthInput: 'Continue',\n authInputRequired: 'Enter the requested authorization value first.',\n requestFailed: 'The login request failed.',\n proxyTitle: 'Network proxy',\n proxyScope: 'Only applies to requests made by this subscription plugin. Does not change your system or browser proxy.',\n proxyLoading: 'Loading network settings…',\n proxyHttpEnabled: 'Use a proxy for HTTP',\n proxyWsEnabled: 'Use a proxy for WebSocket',\n proxyHttpHelp: 'Login, token refresh, model requests over HTTPS / SSE, and model catalogs.',\n proxyWsHelp: 'Model WebSocket connections. This switch controls proxy routing; it does not disable WebSocket itself.',\n proxyAddress: 'Proxy address (HTTP / HTTPS)',\n proxyPort: 'Port',\n proxyPortPlaceholder: 'e.g. 45678',\n proxyDirect: 'Off: connect directly, ignoring proxy environment variables. The address is kept for later.',\n proxyAuto: 'Default address with no port: keep automatic environment / system proxy discovery; connect directly if none is found. Port 80 is not assumed.',\n proxyExplicit: 'Use this HTTP(S) CONNECT proxy instead of the automatically detected one. SOCKS-only ports are not supported.',\n proxyApplyHelp: 'Saving applies to new requests without interrupting a running call. Sessions already using SSE stay on SSE. Original retry limits are unchanged.',\n proxySave: 'Save network settings',\n proxyReload: 'Reload settings',\n proxySaved: 'Saved. New requests use these settings.',\n proxyLoadFailed: 'Network settings could not be loaded. Reload, or activate the updated plugin backend.',\n proxySaveFailed: 'Could not confirm that network settings were saved. Reload to check their current state.',\n proxyInvalid: 'Enter an HTTP(S) proxy address without credentials or a path, and a port from 1 to 65535. If both fields specify a port, they must match.',\n proxyConflict: 'Another page changed these settings. Reload before saving again.',\n} as const\n\nexport type PiLoginKey = keyof typeof en\n\nexport const zh: { [Key in PiLoginKey]: string } = {\n nav: '订阅登录',\n title: '订阅登录',\n loadingAccount: '正在加载账户…',\n signedOut: '尚未登录',\n signingIn: '正在等待授权…',\n waitingForCredential: '等待输入套餐 API Key…',\n waitingForCallback: '等待输入授权回调地址…',\n waitingForAuthInput: '等待输入授权信息…',\n signedIn: '已登录',\n login: '登录',\n connectPlan: '连接套餐',\n loginAgain: '重新登录',\n reopenAuthorization: '重新打开授权页',\n cancelLogin: '取消',\n logout: '退出',\n working: '处理中…',\n userCode: '授权码',\n openUrl: '授权',\n openPlanPage: '套餐页面',\n credentialHelp: '请在套餐页新建或复制专用 API Key,再粘贴到这里。密钥只保存在 DSH 的私有凭据文件中。',\n credentialPlaceholder: '粘贴套餐 API Key',\n saveCredential: '保存并连接',\n credentialRequired: '请先粘贴套餐 API Key。',\n callbackHelp: '请在浏览器完成授权后,复制完整的回调地址并粘贴到这里。DSH 只用它完成本次登录。',\n callbackPlaceholder: '粘贴授权回调地址',\n submitCallback: '完成登录',\n callbackRequired: '请先粘贴授权回调地址。',\n authInputHelp: '请输入服务商要求的内容以继续授权。',\n authInputPlaceholder: '输入授权信息',\n submitAuthInput: '继续',\n authInputRequired: '请先输入服务商要求的授权信息。',\n requestFailed: '登录请求失败。',\n proxyTitle: '网络代理',\n proxyScope: '仅影响本订阅插件发出的请求,不修改系统或浏览器代理。',\n proxyLoading: '正在加载网络设置…',\n proxyHttpEnabled: 'HTTP 使用代理',\n proxyWsEnabled: 'WebSocket 使用代理',\n proxyHttpHelp: '用于登录、令牌刷新、HTTPS / SSE 模型请求和模型列表。',\n proxyWsHelp: '用于模型的 WebSocket 连接。此开关只控制是否走代理,不关闭 WebSocket 本身。',\n proxyAddress: '代理地址(HTTP / HTTPS)',\n proxyPort: '端口',\n proxyPortPlaceholder: '例如 45678',\n proxyDirect: '已关闭:直接连接,忽略代理环境变量。保留地址,方便下次开启。',\n proxyAuto: '默认地址、端口留空:沿用环境变量、系统代理等自动发现;没有找到代理时直连,不会默认使用 80 端口。',\n proxyExplicit: '优先使用此 HTTP(S) CONNECT 代理,不使用自动发现的地址。不支持纯 SOCKS 端口。',\n proxyApplyHelp: '保存后用于新请求,不中断正在进行的调用。已降级的会话继续使用 SSE,原有重试上限不变。',\n proxySave: '保存网络设置',\n proxyReload: '重新加载',\n proxySaved: '已保存,新请求将使用这些设置。',\n proxyLoadFailed: '网络设置加载失败。请重新加载,或先启用更新后的插件服务端。',\n proxySaveFailed: '未能确认网络设置已保存,请重新加载后检查当前设置。',\n proxyInvalid: '请填写不含账号密码或路径的 HTTP(S) 代理地址,端口为 1–65535。若地址中也有端口,须与端口栏一致。',\n proxyConflict: '其他页面已修改设置,请重新加载后再保存。',\n}\n\n/** `model-search` namespace: copy for the searchable composer model seat. */\nexport const searchEn = {\n placeholder: 'Search models…',\n aria: 'Filter models',\n empty: 'No models match “{query}”.',\n all: 'All',\n freeOnly: 'Free only',\n freeFilterAria: 'Model price filter (OpenRouter)',\n free: 'Free · Rate limited',\n freeCached: 'Free (cached) · Recheck pending',\n freeEnded: 'Free offer ended · Paid calls blocked',\n freeUnknown: 'Price unconfirmed · Free guard active',\n tools: 'Tool calling',\n chatOnly: 'Chat only',\n context: '{tokens} context',\n emptyFree: 'No matching free OpenRouter models. Clear the search or refresh the catalog.',\n syncSchedule: 'OpenRouter · Sync every 15 min',\n syncing: 'Syncing models…',\n syncSignIn: 'Sign in to OpenRouter to sync models.',\n syncRefresh: 'Refresh models',\n syncCooldown: 'Refreshed within 60s',\n syncUpdated: 'Last synced',\n syncStale: 'Cached · Refresh needed',\n syncBuiltin: 'Not synced yet; using built-in models.',\n syncError: 'Sync failed. Keeping the previous list; retry later.',\n syncSaveError: 'Could not save the safe catalog cache. Keeping the previous list; check DSH disk permissions.',\n syncRestart: 'Restart DSH to activate the new model-sync backend.',\n freeHelp: 'Free models have rate and daily limits. Unavailable models never fall back to paid ones.',\n forcedPluginWarning: 'Disable account-enforced paid OpenRouter plugins: DSH cannot override platform-enforced charges.',\n} as const\n\nexport type ModelSearchKey = keyof typeof searchEn\n\nexport const searchZh: { [Key in ModelSearchKey]: string } = {\n placeholder: '搜索模型…',\n aria: '筛选模型',\n empty: '没有匹配“{query}”的模型。',\n all: '全部',\n freeOnly: '仅免费',\n freeFilterAria: '模型价格筛选(OpenRouter)',\n free: '免费 · 有限额',\n freeCached: '免费缓存 · 待更新',\n freeEnded: '免费已结束 · 付费已拦截',\n freeUnknown: '价格未确认 · 免费保护中',\n tools: '支持工具调用',\n chatOnly: '仅聊天',\n context: '{tokens} 上下文',\n emptyFree: '没有匹配的 OpenRouter 免费模型。请清空搜索或刷新列表。',\n syncSchedule: 'OpenRouter · 每 15 分钟同步',\n syncing: '正在同步模型…',\n syncSignIn: '登录 OpenRouter 后自动同步模型。',\n syncRefresh: '刷新模型',\n syncCooldown: '60 秒内已刷新',\n syncUpdated: '上次同步',\n syncStale: '缓存待更新',\n syncBuiltin: '尚未同步,暂用内置模型列表。',\n syncError: '同步失败,保留上次列表;请稍后重试。',\n syncSaveError: '安全缓存保存失败,保留上次列表;请检查 DSH 目录写入权限。',\n syncRestart: '请重启 DSH,启用新的模型同步服务。',\n freeHelp: '免费模型有速率和每日限额;不可用时不会切换到付费模型。',\n forcedPluginWarning: '请关闭 OpenRouter 账户强制启用的收费插件;平台强制规则不能由 DSH 覆盖。',\n}\n","import { OPENROUTER_CATALOG_PATH, OPENROUTER_REFRESH_PATH } from '../openrouter-types.ts'\nimport type { OpenRouterCatalogSnapshot } from '../openrouter-types.ts'\n\nexport interface OpenRouterClientState {\n data: OpenRouterCatalogSnapshot | null\n loading: boolean\n error: 'unavailable' | 'restart' | null\n}\n\nfunction validSnapshot(value: unknown): value is OpenRouterCatalogSnapshot {\n if (typeof value !== 'object' || value === null) return false\n const data = value as Record<string, unknown>\n const timestamp = (entry: unknown) => entry === null\n || typeof entry === 'number' && Number.isFinite(entry) && entry > 0 && entry <= 8.64e15\n if (data.version !== 1 || typeof data.connected !== 'boolean'\n || typeof data.refreshing !== 'boolean' || typeof data.stale !== 'boolean'\n || !timestamp(data.lastUpdatedAt) || !timestamp(data.lastAttemptAt)\n || !timestamp(data.nextRefreshAt) || !timestamp(data.retryAt)\n || !Array.isArray(data.models) || data.models.length > 10_000) return false\n return data.models.every((entry: unknown) => {\n if (typeof entry !== 'object' || entry === null) return false\n const model = entry as Record<string, unknown>\n return typeof model.id === 'string' && typeof model.name === 'string'\n && typeof model.tools === 'boolean' && typeof model.freeOnly === 'boolean'\n && typeof model.contextWindow === 'number' && Number.isFinite(model.contextWindow)\n && ['free', 'paid', 'unknown'].includes(String(model.priceStatus))\n })\n}\n\n/** One metadata store/poll per browser plugin, shared by settings and menus. */\nexport class OpenRouterCatalogClient {\n private state: OpenRouterClientState = { data: null, loading: false, error: null }\n private readonly listeners = new Set<() => void>()\n private pending: Promise<void> | undefined\n private controller: AbortController | undefined\n private poll: ReturnType<typeof setTimeout> | undefined\n private lastRead = -Infinity\n private disposed = false\n\n constructor(private readonly request: typeof globalThis.fetch = (...args) => globalThis.fetch(...args)) {}\n\n getSnapshot = (): OpenRouterClientState => this.state\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n if (this.listeners.size === 1 && !this.disposed) void this.load()\n return () => {\n this.listeners.delete(listener)\n if (this.listeners.size === 0) {\n clearTimeout(this.poll)\n this.poll = undefined\n }\n }\n }\n private update(state: OpenRouterClientState): void {\n this.state = state\n for (const listener of this.listeners) listener()\n }\n private failed(error: OpenRouterClientState['error']): void {\n if (this.disposed) return\n this.update({ ...this.state, error,\n data: this.state.data === null ? null : { ...this.state.data, stale: true },\n })\n }\n\n load = (force = false): Promise<void> => {\n if (this.disposed) return Promise.resolve()\n if (this.pending !== undefined) return this.pending\n if (!force && Date.now() - this.lastRead < 1500) {\n this.schedule()\n return Promise.resolve()\n }\n this.lastRead = Date.now()\n clearTimeout(this.poll)\n this.poll = undefined\n this.controller = new AbortController()\n const signal = AbortSignal.any([this.controller.signal, AbortSignal.timeout(20_000)])\n this.update({ ...this.state, loading: true, error: null })\n const pending = this.read(force, signal).finally(() => {\n if (this.pending !== pending) return\n this.pending = undefined\n this.controller = undefined\n if (!this.disposed) {\n this.update({ ...this.state, loading: false })\n this.schedule()\n }\n })\n this.pending = pending\n return pending\n }\n private async read(force: boolean, signal: AbortSignal): Promise<void> {\n try {\n const response = await this.request(force ? OPENROUTER_REFRESH_PATH : OPENROUTER_CATALOG_PATH, {\n method: force ? 'POST' : 'GET', credentials: 'same-origin',\n headers: { accept: 'application/json' }, signal,\n })\n if (response.status === 404) {\n this.failed('restart')\n return\n }\n if (!response.ok) throw new Error('catalog unavailable')\n const data: unknown = await response.json()\n if (!validSnapshot(data)) {\n throw new Error('invalid catalog response')\n }\n if (!this.disposed) this.update({ ...this.state, data, error: null })\n } catch {\n this.failed('unavailable')\n }\n }\n private schedule(): void {\n if (this.disposed || this.listeners.size === 0) return\n clearTimeout(this.poll)\n // This is a local metadata read, NOT an upstream model refresh.\n this.poll = setTimeout(() => { void this.load() }, this.state.data?.refreshing ? 2000 : 60_000)\n }\n dispose(): void {\n this.disposed = true\n clearTimeout(this.poll)\n this.controller?.abort()\n this.listeners.clear()\n }\n}\n","/** Browser half: Pi login settings page + searchable composer model seat. */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-session/client'\nimport { PiLoginSettings } from './PiLoginSettings.tsx'\nimport type { PiLoginSettingsInjected } from './PiLoginSettings.tsx'\nimport { SearchableModelSelect } from './SearchableModelSelect.tsx'\nimport { en, zh, searchEn, searchZh } from './locales.ts'\nimport type { PiLoginKey, ModelSearchKey } from './locales.ts'\nimport { OpenRouterCatalogClient } from './openrouter-store.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'settings.pi-login': PiLoginKey\n 'model-search': ModelSearchKey\n }\n}\n\nexport const name = 'dsh-oauth-login-client'\n// directoryFor() resolves remote.session through the calling plugin's context.\nexport const inject = ['slots', 'locale', 'sessions', 'modelDirectories', 'remote', 'remote.session']\n\nexport function apply(ctx: ClientContext): void {\n const catalog = new OpenRouterCatalogClient()\n ctx.effect(() => () => catalog.dispose(), 'dsh-oauth-login: catalog metadata')\n const searchNs = 'model-search'\n ctx.effect(() => ctx.locale.register(searchNs, { zh: searchZh, en: searchEn }), 'dsh-oauth-login: model-search copy')\n const ts = ctx.locale.bind(searchNs)\n const namespace = 'settings.pi-login'\n ctx.effect(() => ctx.locale.register(namespace, { zh, en }), 'dsh-oauth-login: settings copy')\n const t = ctx.locale.bind(namespace) as PiLoginSettingsInjected['t']\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'pi-login',\n order: 17,\n label: () => t('nav'),\n inject: (): PiLoginSettingsInjected => ({ t, ts, catalog }),\n }, PiLoginSettings))\n\n // Searchable shadow of the composer model seat. Priority -1 renders over\n // the shipped ModelSelect (priority 0, lowest live entry wins); removing\n // this plugin restores the stock selector with no host restart.\n ctx.slots.inject('conversation.input.model', () => ctx.slots.register({\n name: 'conversation.input.model',\n locale: 'model',\n priority: -1,\n inject: (sessionId) => {\n const directory = ctx.modelDirectories.directoryFor(sessionId)\n const available = ctx.sessions.subagentAddress(sessionId) === undefined\n return {\n available,\n catalog,\n directory: directory.store,\n load: () => {\n if (available) directory.load().catch(() => { /* surfaced on the store */ })\n },\n select: (selection: ModelSelection) => available\n ? directory.select(selection).then(() => true, () => false)\n : Promise.resolve(false),\n ts,\n }\n },\n }, SearchableModelSelect))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":["useSyncExternalStore","useState","useId","useState","useCallback","STYLE_ID","useState","useRef","useCallback","useSyncExternalStore","useMemo","useState","useRef","useId"],"sources":["../src/client/draft-input.ts","../src/client/OpenRouterSyncStatus.tsx","../src/proxy-config.ts","../src/client/proxy-draft.ts","../src/client/ProxySettings.tsx","../src/client/login-input-copy.ts","../src/client/login-window.ts","../src/client/PiLoginSettings.tsx","../src/client/model-filter.ts","../src/openrouter-types.ts","../src/client/SearchableModelSelect.tsx","../src/client/locales.ts","../src/client/openrouter-store.ts","../src/client/index.tsx"],"sourcesContent":["export type Drafts = Record<string, string>\nexport type DraftUpdater = (current: Drafts) => Drafts\nexport type DraftSetter = (updater: DraftUpdater) => void\n\nexport function applyDraftChange(\n providerId: string,\n event: { currentTarget: { value: string } },\n setDrafts: DraftSetter,\n): void {\n const value = event.currentTarget.value\n setDrafts(current => ({ ...current, [providerId]: value }))\n}\n","import { useEffect, useState, useSyncExternalStore } from 'react'\nimport type { OpenRouterCatalogClient } from './openrouter-store.ts'\nimport type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'\n\nconst CSS = [\n '.dsh-or-sync{display:flex;flex-direction:column;gap:4px;padding:6px 8px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);min-width:0}',\n '.dsh-or-sync-row{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:4px 8px}',\n '.dsh-or-sync-copy{min-width:0;overflow-wrap:anywhere}',\n '.dsh-or-sync time{font-variant-numeric:tabular-nums}',\n '.dsh-or-refresh{min-height:28px;padding:3px 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer}',\n '.dsh-or-refresh:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}',\n '.dsh-or-refresh:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}',\n '.dsh-or-refresh:disabled{opacity:.55;cursor:default}',\n '.dsh-or-sync-error{color:color-mix(in srgb,var(--dsw-alias-state-warn-label) 50%,var(--dsw-alias-label-primary))}',\n].join('\\n')\n\nexport interface OpenRouterSyncStatusProps {\n catalog: OpenRouterCatalogClient\n ts: TranslateNS<'model-search'>\n details?: boolean\n}\n\nexport function OpenRouterSyncStatus({ catalog, ts, details = false }: OpenRouterSyncStatusProps) {\n const state = useSyncExternalStore(catalog.subscribe, catalog.getSnapshot)\n const [now, setNow] = useState(Date.now)\n const data = state.data\n const retryAt = data?.retryAt ?? 0\n useEffect(() => {\n setNow(Date.now())\n if (retryAt <= Date.now()) return\n const timer = setTimeout(() => { setNow(Date.now()) }, retryAt - Date.now() + 20)\n return () => { clearTimeout(timer) }\n }, [retryAt])\n const cooling = retryAt > now\n const working = state.loading || data?.refreshing === true\n const unavailable = state.error !== null || data?.error !== null && data?.error !== undefined\n const timestamp = data?.lastUpdatedAt\n return (\n <div className=\"dsh-or-sync\" data-ud-check={details ? 'openrouter-settings-sync' : 'openrouter-menu-sync'} data-ud-min-gap=\"4\">\n <style>{CSS}</style>\n <div className=\"dsh-or-sync-row\">\n <span className=\"dsh-or-sync-copy\" role=\"status\" aria-live=\"polite\">\n {working ? ts('syncing') : data?.connected ? ts('syncSchedule') : ts('syncSignIn')}\n </span>\n <button type=\"button\" className=\"dsh-or-refresh\"\n disabled={working || cooling || data?.connected !== true}\n onClick={() => { void catalog.load(true) }}\n >{working ? ts('syncing') : cooling ? ts('syncCooldown') : ts('syncRefresh')}</button>\n </div>\n {timestamp != null && (\n <span className=\"dsh-or-sync-copy\">{ts('syncUpdated')}{' '}\n <time dateTime={new Date(timestamp).toISOString()}>{new Date(timestamp).toLocaleString()}</time>\n {data?.stale ? ' · ' + ts('syncStale') : ''}\n </span>\n )}\n {timestamp == null && data?.connected && <span>{ts('syncBuiltin')}</span>}\n {unavailable && <span role=\"status\" className=\"dsh-or-sync-copy dsh-or-sync-error\">\n {ts(state.error === 'restart' ? 'syncRestart' : data?.error === 'save' ? 'syncSaveError' : 'syncError')}\n </span>}\n {details && <>\n <span>{ts('freeHelp')}</span>\n <span>{ts('forcedPluginWarning')}</span>\n </>}\n </div>\n )\n}\n","/** Shared, credential-free settings for this plugin's two outbound transports. */\n\nexport const PROXY_SETTINGS_PATH = '/plugins/dsh-oauth-login/network/settings'\nexport const PROXY_SETTINGS_FILENAME = '.dsh-oauth-proxy.json'\n\nexport interface ProxyChannelSettings {\n /** False means direct, even when proxy environment variables are set. */\n enabled: boolean\n /** Empty keeps environment/system discovery; otherwise this URL wins. */\n url: string\n}\n\nexport interface ProxySettings {\n http: ProxyChannelSettings\n websocket: ProxyChannelSettings\n}\n\nexport interface ProxySettingsSnapshot extends ProxySettings {\n revision: number\n}\n\nexport function defaultProxySettings(): ProxySettingsSnapshot {\n return { revision: 0, http: { enabled: true, url: '' }, websocket: { enabled: true, url: '' } }\n}\n\nfunction object(value: unknown, keys: readonly string[], label: string): Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)\n || Object.keys(value).some(key => !keys.includes(key))) {\n throw new Error(`${label}: invalid settings object`)\n }\n return value as Record<string, unknown>\n}\n\nfunction channel(value: unknown, label: string): ProxyChannelSettings {\n const raw = object(value, ['enabled', 'url'], label)\n if (typeof raw.enabled !== 'boolean' || typeof raw.url !== 'string' || raw.url.length > 1024) {\n throw new Error(`${label}: expected enabled and proxy URL`)\n }\n const text = raw.url.trim()\n if (text === '') return { enabled: raw.enabled, url: '' }\n let parsed: URL\n try { parsed = new URL(text) } catch { throw new Error(`${label}: enter a valid HTTP proxy address and port`) }\n if (!['http:', 'https:'].includes(parsed.protocol) || !parsed.hostname\n || parsed.username || parsed.password || parsed.search || parsed.hash\n || parsed.pathname !== '/' || parsed.port === '0') {\n throw new Error(`${label}: use an HTTP(S) proxy without credentials, path, query or fragment`)\n }\n return { enabled: raw.enabled, url: parsed.origin }\n}\n\nexport function parseProxySettings(value: unknown): ProxySettingsSnapshot {\n const raw = object(value, ['revision', 'http', 'websocket'], 'Network')\n if (typeof raw.revision !== 'number' || !Number.isSafeInteger(raw.revision) || raw.revision < 0) {\n throw new Error('Network: invalid revision')\n }\n return {\n revision: raw.revision,\n http: channel(raw.http, 'HTTP'),\n websocket: channel(raw.websocket, 'WebSocket'),\n }\n}\n","import { parseProxySettings } from '../proxy-config.ts'\nimport type { ProxyChannelSettings, ProxySettingsSnapshot } from '../proxy-config.ts'\n\nexport interface ProxyChannelDraft {\n enabled: boolean\n address: string\n port: string\n}\n\nexport type ProxyDraft = Record<'http' | 'websocket', ProxyChannelDraft>\n\nexport const DEFAULT_PROXY_ADDRESS = 'http://127.0.0.1'\n\nexport function isAutomaticProxyDraft({ address, port }: ProxyChannelDraft): boolean {\n const host = address.trim().replace(/\\/$/, '')\n return port.trim() === '' && (host === '' || host === DEFAULT_PROXY_ADDRESS || host === '127.0.0.1')\n}\n\nexport function proxyDraft(settings: ProxySettingsSnapshot): ProxyDraft {\n const channel = ({ enabled, url }: ProxyChannelSettings): ProxyChannelDraft => {\n if (url === '') return { enabled, address: DEFAULT_PROXY_ADDRESS, port: '' }\n const parsed = new URL(url)\n return {\n enabled,\n address: `${parsed.protocol}//${parsed.hostname}`,\n port: parsed.port || (parsed.protocol === 'https:' ? '443' : '80'),\n }\n }\n return { http: channel(settings.http), websocket: channel(settings.websocket) }\n}\n\nexport function proxyDraftSettings(draft: ProxyDraft, revision: number): ProxySettingsSnapshot {\n const channel = (value: ProxyChannelDraft): ProxyChannelSettings => {\n const { enabled, address, port } = value\n const host = address.trim()\n const portText = port.trim()\n if (isAutomaticProxyDraft(value)) return { enabled, url: '' }\n if (host === '' || (portText !== '' && (!/^\\d{1,5}$/.test(portText)\n || Number(portText) < 1 || Number(portText) > 65535))) {\n throw new Error('Enter a proxy address and a port from 1 to 65535')\n }\n const parsed = new URL(host.includes('://') ? host : `http://${host}`)\n // URL.port omits explicit default ports (80/443), so retain the pasted port.\n const pastedPort = /:(\\d+)\\/?$/.exec(host)?.[1] ?? ''\n if (portText === '' && pastedPort === '') {\n throw new Error('Enter a proxy port from 1 to 65535')\n }\n if (portText !== '') {\n if (pastedPort !== '' && Number(pastedPort) !== Number(portText)) {\n throw new Error('The address and port fields specify different ports')\n }\n parsed.port = portText\n }\n return { enabled, url: parsed.href }\n }\n return parseProxySettings({ revision, http: channel(draft.http), websocket: channel(draft.websocket) })\n}\n","import { useCallback, useEffect, useId, useState } from 'react'\nimport { PROXY_SETTINGS_PATH, parseProxySettings } from '../proxy-config.ts'\nimport type { ProxySettingsSnapshot } from '../proxy-config.ts'\nimport { DEFAULT_PROXY_ADDRESS, isAutomaticProxyDraft, proxyDraft, proxyDraftSettings } from './proxy-draft.ts'\nimport type { ProxyChannelDraft, ProxyDraft } from './proxy-draft.ts'\nimport type { PiLoginKey } from './locales.ts'\n\ntype Translate = (key: PiLoginKey) => string\n\n/** Independent of account loading, so a broken network never hides its settings. */\nexport function ProxySettings({ t }: { t: Translate }) {\n const id = useId()\n const [settings, setSettings] = useState<ProxySettingsSnapshot>()\n const [draft, setDraft] = useState<ProxyDraft>()\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<PiLoginKey>()\n const [saved, setSaved] = useState(false)\n\n const load = useCallback(async (signal?: AbortSignal) => {\n setBusy(true)\n setError(undefined)\n setSaved(false)\n try {\n const response = await fetch(PROXY_SETTINGS_PATH, { credentials: 'same-origin', signal })\n if (!response.ok) throw new Error('Settings unavailable')\n const value = parseProxySettings(await response.json())\n if (signal?.aborted) return\n setSettings(value)\n setDraft(proxyDraft(value))\n } catch {\n if (!signal?.aborted) setError('proxyLoadFailed')\n } finally {\n if (!signal?.aborted) setBusy(false)\n }\n }, [])\n\n useEffect(() => {\n const controller = new AbortController()\n void load(controller.signal)\n return () => { controller.abort() }\n }, [load])\n\n const change = (channel: keyof ProxyDraft, patch: Partial<ProxyChannelDraft>) => {\n setDraft(current => current === undefined ? current : { ...current, [channel]: { ...current[channel], ...patch } })\n setError(undefined)\n setSaved(false)\n }\n\n const save = async () => {\n if (draft === undefined || settings === undefined) return\n let value: ProxySettingsSnapshot\n try { value = proxyDraftSettings(draft, settings.revision) } catch {\n setError('proxyInvalid')\n return\n }\n setBusy(true)\n setError(undefined)\n setSaved(false)\n try {\n const response = await fetch(PROXY_SETTINGS_PATH, {\n method: 'POST', credentials: 'same-origin',\n headers: { 'content-type': 'application/json' }, body: JSON.stringify(value),\n })\n if (response.status === 409) { setError('proxyConflict'); return }\n if (!response.ok) throw new Error('Settings save failed')\n const updated = parseProxySettings(await response.json())\n setSettings(updated)\n setDraft(proxyDraft(updated))\n setSaved(true)\n } catch { setError('proxySaveFailed') } finally { setBusy(false) }\n }\n\n const dirty = settings !== undefined && draft !== undefined\n && JSON.stringify(draft) !== JSON.stringify(proxyDraft(settings))\n return (\n <section className=\"dsh-pi-login-card dsh-oauth-network\" aria-labelledby={`${id}-title`}>\n <h3 id={`${id}-title`} className=\"dsh-pi-login-name\">{t('proxyTitle')}</h3>\n <p className=\"dsh-pi-login-body\">{t('proxyScope')}</p>\n {draft === undefined && busy ? <p className=\"dsh-pi-login-body\">{t('proxyLoading')}</p> : null}\n {draft === undefined ? null : (['http', 'websocket'] as const).map(channel => (\n <fieldset className=\"dsh-oauth-proxy-channel\" key={channel} disabled={busy}>\n <legend className=\"dsh-pi-login-name\">{channel === 'http' ? 'HTTP / HTTPS' : 'WebSocket (WS / WSS)'}</legend>\n <label className=\"dsh-oauth-proxy-switch\" htmlFor={`${id}-${channel}-enabled`}>\n <input id={`${id}-${channel}-enabled`} type=\"checkbox\" role=\"switch\"\n checked={draft[channel].enabled}\n onChange={event => change(channel, { enabled: event.currentTarget.checked })} />\n {t(channel === 'http' ? 'proxyHttpEnabled' : 'proxyWsEnabled')}\n </label>\n <p className=\"dsh-pi-login-body\">{t(channel === 'http' ? 'proxyHttpHelp' : 'proxyWsHelp')}</p>\n <div className=\"dsh-oauth-proxy-fields\">\n <label htmlFor={`${id}-${channel}-address`}>\n <span>{t('proxyAddress')}</span>\n <input className=\"dsh-pi-login-input\" id={`${id}-${channel}-address`}\n autoComplete=\"off\" spellCheck={false} placeholder={DEFAULT_PROXY_ADDRESS}\n value={draft[channel].address} disabled={!draft[channel].enabled}\n onChange={event => change(channel, { address: event.currentTarget.value })} />\n </label>\n <label htmlFor={`${id}-${channel}-port`}>\n <span>{t('proxyPort')}</span>\n <input className=\"dsh-pi-login-input\" id={`${id}-${channel}-port`}\n autoComplete=\"off\" inputMode=\"numeric\" placeholder={t('proxyPortPlaceholder')}\n value={draft[channel].port} disabled={!draft[channel].enabled}\n onChange={event => change(channel, { port: event.currentTarget.value })} />\n </label>\n </div>\n <p className=\"dsh-pi-login-body\">{t(!draft[channel].enabled ? 'proxyDirect'\n : isAutomaticProxyDraft(draft[channel]) ? 'proxyAuto' : 'proxyExplicit')}</p>\n </fieldset>\n ))}\n <p className=\"dsh-pi-login-body\">{t('proxyApplyHelp')}</p>\n <div aria-live=\"polite\">\n {error === undefined ? null : <p className=\"dsh-pi-login-error\" role=\"alert\">{t(error)}</p>}\n {saved ? <p className=\"dsh-pi-login-body\">{t('proxySaved')}</p> : null}\n </div>\n <div className=\"dsh-pi-login-row dsh-oauth-proxy-actions\">\n <button type=\"button\" className=\"dsh-pi-login-btn dsh-pi-login-btn-secondary\" disabled={busy}\n onClick={() => { void load() }}>{t('proxyReload')}</button>\n <button type=\"button\" className=\"dsh-pi-login-btn dsh-pi-login-btn-primary\"\n disabled={busy || !dirty} onClick={() => { void save() }}>{t(busy ? 'working' : 'proxySave')}</button>\n </div>\n </section>\n )\n}\n","import type { PiLoginKey } from './locales.ts'\n\nexport type LoginAuthType = 'oauth' | 'api_key'\nexport type LoginChallengeType = 'secret' | 'text' | 'manual_code'\n\nexport interface LoginInputCopy {\n waiting: PiLoginKey\n help: PiLoginKey\n placeholder: PiLoginKey\n action: PiLoginKey\n required: PiLoginKey\n}\n\nconst PLAN_COPY: LoginInputCopy = {\n waiting: 'waitingForCredential', help: 'credentialHelp', placeholder: 'credentialPlaceholder',\n action: 'saveCredential', required: 'credentialRequired',\n}\n\nconst CALLBACK_COPY: LoginInputCopy = {\n waiting: 'waitingForCallback', help: 'callbackHelp', placeholder: 'callbackPlaceholder',\n action: 'submitCallback', required: 'callbackRequired',\n}\n\nconst AUTH_INPUT_COPY: LoginInputCopy = {\n waiting: 'waitingForAuthInput', help: 'authInputHelp', placeholder: 'authInputPlaceholder',\n action: 'submitAuthInput', required: 'authInputRequired',\n}\n\n/** Select visible copy from the provider contract and the actual Pi challenge. */\nexport function loginInputCopy(authType: LoginAuthType, challengeType: LoginChallengeType): LoginInputCopy {\n if (authType === 'api_key') return PLAN_COPY\n if (challengeType === 'manual_code') return CALLBACK_COPY\n return AUTH_INPUT_COPY\n}\n","export interface LoginPopup {\n close(): void\n location: { replace(url: string): void }\n}\n\nexport type LoginUrlOpener = (url: string) => void\n\n/** Deliver a login challenge even when an Electron shell rejects the reserved about:blank popup. */\nexport function openLoginChallenge(\n popup: LoginPopup | null,\n url: string | undefined,\n openUrl: LoginUrlOpener,\n): 'reserved' | 'fallback' | 'none' {\n if (url === undefined) {\n popup?.close()\n return 'none'\n }\n if (popup !== null) {\n popup.location.replace(url)\n return 'reserved'\n }\n openUrl(url)\n return 'fallback'\n}\n","/** Plugin-owned Pi login page inside the dsh Settings shell. */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { applyDraftChange } from './draft-input.ts'\nimport type { Drafts } from './draft-input.ts'\nimport type { PiLoginKey } from './locales.ts'\nimport type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { OpenRouterCatalogClient } from './openrouter-store.ts'\nimport { OpenRouterSyncStatus } from './OpenRouterSyncStatus.tsx'\nimport { ProxySettings } from './ProxySettings.tsx'\nimport { loginInputCopy } from './login-input-copy.ts'\nimport { openLoginChallenge } from './login-window.ts'\n\nconst STATUS_PATH = '/plugins/dsh-oauth-login/auth/status'\nconst LOGIN_PATH = '/plugins/dsh-oauth-login/auth/login'\nconst CANCEL_PATH = '/plugins/dsh-oauth-login/auth/cancel'\nconst COMPLETE_PATH = '/plugins/dsh-oauth-login/auth/complete'\nconst LOGOUT_PATH = '/plugins/dsh-oauth-login/auth/logout'\nconst POLL_INTERVAL_MS = 1_000\nconst STYLE_ID = 'dsh-pi-login-settings-theme'\n\ntype AccountState =\n | { status: 'signed-out' }\n | {\n status: 'signing-in'\n kind?: 'browser' | 'input'\n url?: string\n userCode?: string\n input?: LoginInputChallenge\n }\n | { status: 'signed-in'; models?: string[]; expiresAt?: string }\n | { status: 'error'; message: string }\n\ninterface LoginInputChallenge {\n type: 'secret' | 'text' | 'manual_code'\n message: string\n placeholder?: string\n}\n\ninterface ProviderStatus {\n id: string\n route: string\n displayName: string\n shortName: string\n authType: 'oauth' | 'api_key'\n account: AccountState\n}\n\ninterface LoginChallenge {\n provider: string\n kind: 'browser' | 'input'\n url?: string\n userCode?: string\n input?: LoginInputChallenge\n}\n\nexport interface PiLoginSettingsInjected {\n t: (key: PiLoginKey, params?: Record<string, unknown>) => string\n ts: TranslateNS<'model-search'>\n catalog: OpenRouterCatalogClient\n}\n\nexport type PiLoginSettingsProps = Partial<PiLoginSettingsInjected>\n\n/**\n * Theme tokens that track light/dark. Hardcoded white/layer fills break dark mode.\n * Mirrors ModelsSection button vocabulary so OAuth cards match the rest of Settings.\n */\nconst SETTINGS_CSS = `\n.dsh-pi-login-page { display:flex; flex-direction:column; gap:16px; max-width:640px; color:var(--dsw-alias-label-primary); }\n.dsh-pi-login-title { margin:0; font-size:20px; line-height:28px; font-weight:600; color:var(--dsw-alias-label-primary); }\n.dsh-pi-login-body { margin:0; font-size:13px; line-height:20px; color:var(--dsw-alias-label-secondary); }\n.dsh-pi-login-error { margin:0; font-size:13px; line-height:20px; color:var(--dsw-alias-state-error-primary); }\n.dsh-pi-login-stack { display:flex; flex-direction:column; gap:10px; }\n.dsh-pi-login-card {\n display:flex; flex-direction:column; gap:8px; padding:14px 16px;\n border:1px solid var(--dsw-alias-border-l2); border-radius:12px;\n background:var(--dsw-alias-bg-module-platform);\n}\n.dsh-pi-login-row { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:10px; }\n.dsh-pi-login-row-actions { display:flex; align-items:center; flex-wrap:wrap; justify-content:flex-end; gap:8px; }\n.dsh-pi-login-name { margin:0; font-size:15px; font-weight:600; color:var(--dsw-alias-label-primary); }\n.dsh-pi-login-status { display:flex; align-items:center; flex-wrap:wrap; gap:6px; font-size:13px; color:var(--dsw-alias-label-secondary); }\n.dsh-pi-login-dot { width:8px; height:8px; border-radius:50%; flex:0 0 auto; background:var(--dsw-alias-label-dimmed, #9aa0a6); }\n.dsh-pi-login-dot.is-signed-in { background:var(--dsw-alias-state-success-primary, #22a06b); }\n.dsh-pi-login-dot.is-error { background:var(--dsw-alias-state-error-primary, #d92d20); }\n.dsh-pi-login-dot.is-signing-in { background:var(--dsw-alias-brand-primary, #1677ff); }\n.dsh-pi-login-btn {\n box-sizing:border-box; display:inline-flex; align-items:center; justify-content:center;\n min-height:32px; padding:4px 14px; border-radius:16px; font:inherit; font-size:13px; line-height:20px; cursor:pointer;\n}\n.dsh-pi-login-btn:disabled { opacity:0.55; cursor:not-allowed; }\n.dsh-pi-login-btn-secondary {\n border:1px solid var(--dsw-alias-border-l2);\n background:transparent;\n color:var(--dsw-alias-label-primary);\n}\n.dsh-pi-login-btn-secondary:hover:not(:disabled) {\n background:var(--dsw-alias-interactive-bg-hover);\n}\n.dsh-pi-login-btn-primary {\n border:none;\n background:var(--dsw-alias-button-primary-fill, var(--dsw-alias-brand-primary));\n color:var(--dsw-alias-label-primary-foreground, #fff);\n}\n.dsh-pi-login-btn-primary:hover:not(:disabled) {\n background:var(--dsw-alias-button-primary-hover, var(--dsw-alias-brand-primary));\n}\n.dsh-pi-login-code {\n font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size:18px; letter-spacing:0.08em; font-weight:600; color:var(--dsw-alias-label-primary);\n}\n.dsh-pi-login-link { color:var(--dsw-alias-brand-primary); word-break:break-all; }\n.dsh-pi-login-form { display:flex; flex-direction:column; gap:8px; }\n.dsh-pi-login-input {\n box-sizing:border-box; width:100%; min-height:36px; padding:7px 10px;\n border:1px solid var(--dsw-alias-border-l2); border-radius:8px;\n background:var(--dsw-alias-bg-page-primary, transparent);\n color:var(--dsw-alias-label-primary); font:inherit; font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n}\n.dsh-pi-login-input:focus {\n outline:2px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 28%, transparent);\n border-color:var(--dsw-alias-brand-primary);\n}\n.dsh-pi-login-actions { display:flex; justify-content:flex-end; }\n.dsh-oauth-proxy-channel { min-width:0; margin:8px 0 0; padding:12px 0 0; border:0; border-top:1px solid var(--dsw-alias-border-l2); display:flex; flex-direction:column; gap:8px; }\n.dsh-oauth-proxy-channel legend { padding:0 8px 0 0; font-size:13px; }\n.dsh-oauth-proxy-switch { display:flex; align-items:center; gap:8px; font-size:13px; cursor:pointer; }\n.dsh-oauth-proxy-switch input { width:16px; height:16px; margin:0; accent-color:var(--dsw-alias-brand-primary); }\n.dsh-oauth-proxy-fields { display:grid; grid-template-columns:minmax(0, 1fr) 100px; gap:12px; }\n.dsh-oauth-proxy-fields label { min-width:0; display:flex; flex-direction:column; gap:6px; font-size:12px; }\n.dsh-oauth-proxy-fields input { font-size:13px; }\n.dsh-oauth-proxy-fields input:disabled { opacity:0.55; }\n.dsh-oauth-proxy-actions { justify-content:flex-end; }\n@media (max-width:360px) { .dsh-oauth-proxy-fields { grid-template-columns:minmax(0, 1fr); } }\n`\n\nfunction ensureThemeStyles(): void {\n if (typeof document === 'undefined') return\n if (document.getElementById(STYLE_ID) !== null) return\n const style = document.createElement('style')\n style.id = STYLE_ID\n style.textContent = SETTINGS_CSS\n document.head.appendChild(style)\n}\n\nasync function jsonRequest<T>(path: string, method = 'GET', body?: unknown, signal?: AbortSignal): Promise<T> {\n const response = await fetch(path, {\n method,\n headers: { accept: 'application/json', ...body === undefined ? {} : { 'content-type': 'application/json' } },\n credentials: 'same-origin',\n signal,\n ...body === undefined ? {} : { body: JSON.stringify(body) },\n })\n const value: unknown = await response.json().catch(() => undefined)\n if (!response.ok) {\n const message = typeof value === 'object' && value !== null && 'error' in value && typeof value.error === 'string'\n ? value.error\n : `HTTP ${response.status}`\n throw new Error(message)\n }\n return value as T\n}\n\nexport function PiLoginSettings({ t, ts, catalog }: PiLoginSettingsProps) {\n if (t === undefined) throw new Error('Pi login settings requires its translation function')\n const [providers, setProviders] = useState<ProviderStatus[] | undefined>(undefined)\n const [error, setError] = useState<string | undefined>(undefined)\n const [busy, setBusy] = useState<string | undefined>(undefined)\n const [drafts, setDrafts] = useState<Drafts>({})\n const [challengeUrls, setChallengeUrls] = useState<Record<string, string>>({})\n const [cancellable, setCancellable] = useState<Record<string, boolean>>({})\n const [cancelling, setCancelling] = useState<string | undefined>(undefined)\n const operationSequence = useRef(0)\n const statusSequence = useRef(0)\n const operations = useRef(new Map<string, { readonly id: number; readonly controller: AbortController; readonly popup?: Window }>())\n\n const startOperation = (provider: string, canCancel: boolean, popup?: Window): { readonly id: number; readonly controller: AbortController } => {\n const previous = operations.current.get(provider)\n previous?.controller.abort()\n previous?.popup?.close()\n const operation = { id: ++operationSequence.current, controller: new AbortController(), ...popup === undefined ? {} : { popup } }\n operations.current.set(provider, operation)\n setBusy(provider)\n setCancellable(current => ({ ...current, [provider]: canCancel }))\n return operation\n }\n const isCurrent = (provider: string, operation: { readonly id: number }): boolean => operations.current.get(provider)?.id === operation.id\n const finishOperation = (provider: string, operation: { readonly id: number }): void => {\n if (!isCurrent(provider, operation)) return\n operations.current.delete(provider)\n setBusy(undefined)\n setCancellable(current => {\n const { [provider]: _removed, ...next } = current\n return next\n })\n }\n\n useEffect(() => { ensureThemeStyles() }, [])\n\n const refresh = useCallback(async () => {\n const requestId = ++statusSequence.current\n try {\n const next = await jsonRequest<ProviderStatus[]>(STATUS_PATH)\n if (requestId !== statusSequence.current) return\n setProviders(next)\n void catalog?.load()\n setError(undefined)\n } catch (caught: unknown) {\n if (requestId !== statusSequence.current) return\n setError(caught instanceof Error ? caught.message : t('requestFailed'))\n }\n }, [t, catalog])\n\n useEffect(() => { void refresh() }, [refresh])\n const signing = providers?.some(provider => provider.account.status === 'signing-in') ?? false\n useEffect(() => {\n if (!signing) return\n const timer = window.setInterval(() => { void refresh() }, POLL_INTERVAL_MS)\n return () => { window.clearInterval(timer) }\n }, [refresh, signing])\n\n const signIn = async (id: string): Promise<void> => {\n const popup = window.open('about:blank', '_blank')\n if (popup !== null) popup.opener = null\n setChallengeUrls(current => {\n const { [id]: _removed, ...next } = current\n return next\n })\n const operation = startOperation(id, true, popup ?? undefined)\n try {\n const challenge = await jsonRequest<LoginChallenge>(LOGIN_PATH, 'POST', { provider: id }, operation.controller.signal)\n if (!isCurrent(id, operation)) return\n if (challenge.url !== undefined) {\n setChallengeUrls(current => ({ ...current, [id]: challenge.url! }))\n }\n openLoginChallenge(popup, challenge.url, url => {\n window.open(url, '_blank', 'noopener,noreferrer')\n })\n await refresh()\n } catch (caught: unknown) {\n popup?.close()\n if (isCurrent(id, operation) && !operation.controller.signal.aborted) setError(caught instanceof Error ? caught.message : t('requestFailed'))\n } finally {\n finishOperation(id, operation)\n }\n }\n\n const submitInput = async (provider: ProviderStatus): Promise<void> => {\n const value = drafts[provider.id]?.trim() ?? ''\n if (value.length === 0) {\n const challenge = provider.account.status === 'signing-in' ? provider.account.input : undefined\n setError(t(challenge === undefined ? 'authInputRequired' : loginInputCopy(provider.authType, challenge.type).required))\n return\n }\n const operation = startOperation(provider.id, true)\n try {\n await jsonRequest<{ ok: true }>(COMPLETE_PATH, 'POST', { provider: provider.id, value }, operation.controller.signal)\n if (!isCurrent(provider.id, operation)) return\n setChallengeUrls(current => {\n const { [provider.id]: _removed, ...next } = current\n return next\n })\n setDrafts(current => {\n const { [provider.id]: _removed, ...next } = current\n return next\n })\n await refresh()\n } catch (caught: unknown) {\n if (isCurrent(provider.id, operation) && !operation.controller.signal.aborted) setError(caught instanceof Error ? caught.message : t('requestFailed'))\n } finally {\n finishOperation(provider.id, operation)\n }\n }\n\n const cancelSignIn = async (id: string): Promise<void> => {\n const operation = startOperation(id, false)\n setCancelling(id)\n try {\n await jsonRequest<{ ok: true }>(CANCEL_PATH, 'POST', { provider: id }, operation.controller.signal)\n if (!isCurrent(id, operation)) return\n setChallengeUrls(current => {\n const { [id]: _removed, ...next } = current\n return next\n })\n setDrafts(current => {\n const { [id]: _removed, ...next } = current\n return next\n })\n await refresh()\n } catch (caught: unknown) {\n if (isCurrent(id, operation) && !operation.controller.signal.aborted) setError(caught instanceof Error ? caught.message : t('requestFailed'))\n } finally {\n if (isCurrent(id, operation)) setCancelling(undefined)\n finishOperation(id, operation)\n }\n }\n\n const reopenSignIn = (url: string): void => {\n openLoginChallenge(null, url, next => {\n window.open(next, '_blank', 'noopener,noreferrer')\n })\n }\n\n const signOut = async (id: string): Promise<void> => {\n setBusy(id)\n try {\n await jsonRequest<{ ok: true }>(LOGOUT_PATH, 'POST', { provider: id })\n setChallengeUrls(current => {\n const { [id]: _removed, ...next } = current\n return next\n })\n await refresh()\n } catch (caught: unknown) {\n setError(caught instanceof Error ? caught.message : t('requestFailed'))\n } finally {\n setBusy(undefined)\n }\n }\n\n return (\n <section className=\"dsh-pi-login-page\" aria-labelledby=\"pi-login-settings-title\">\n <h2 id=\"pi-login-settings-title\" className=\"dsh-pi-login-title\">{t('title')}</h2>\n <ProxySettings t={t} />\n {error !== undefined ? <p className=\"dsh-pi-login-error\">{error}</p> : null}\n {providers === undefined\n ? <p className=\"dsh-pi-login-body\">{t('loadingAccount')}</p>\n : (\n <div className=\"dsh-pi-login-stack\">\n {providers.map(provider => {\n const account = provider.account\n const inputCopy = account.status === 'signing-in' && account.input !== undefined\n ? loginInputCopy(provider.authType, account.input.type)\n : undefined\n const challengeUrl = account.status === 'signing-in'\n ? account.url ?? challengeUrls[provider.id]\n : undefined\n const label = account.status === 'signed-in'\n ? t('signedIn')\n : account.status === 'signing-in'\n ? inputCopy === undefined ? t('signingIn') : t(inputCopy.waiting)\n : account.status === 'error'\n ? t('requestFailed')\n : t('signedOut')\n const dotClass = account.status === 'signed-in'\n ? 'dsh-pi-login-dot is-signed-in'\n : account.status === 'error'\n ? 'dsh-pi-login-dot is-error'\n : account.status === 'signing-in'\n ? 'dsh-pi-login-dot is-signing-in'\n : 'dsh-pi-login-dot'\n return (\n <article key={provider.id} className=\"dsh-pi-login-card\">\n <div className=\"dsh-pi-login-row\">\n <p className=\"dsh-pi-login-name\">{provider.displayName}</p>\n {account.status === 'signed-in'\n ? (\n <button\n type=\"button\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-secondary\"\n disabled={busy !== undefined}\n onClick={() => { void signOut(provider.id) }}\n >\n {busy === provider.id ? t('working') : t('logout')}\n </button>\n )\n : account.status === 'signing-in' || cancellable[provider.id] === true\n ? (\n <div className=\"dsh-pi-login-row-actions\">\n {challengeUrl !== undefined\n ? (\n <button\n type=\"button\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-primary\"\n disabled={busy !== undefined}\n onClick={() => { reopenSignIn(challengeUrl) }}\n >\n {t('reopenAuthorization')}\n </button>\n )\n : null}\n <button\n type=\"button\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-secondary\"\n disabled={cancelling === provider.id || (busy !== undefined && busy !== provider.id)}\n onClick={() => { void cancelSignIn(provider.id) }}\n >\n {cancelling === provider.id ? t('working') : t('cancelLogin')}\n </button>\n </div>\n )\n : (\n <button\n type=\"button\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-primary\"\n disabled={busy !== undefined}\n onClick={() => { void signIn(provider.id) }}\n >\n {busy === provider.id\n ? t('working')\n : account.status === 'error'\n ? t('loginAgain')\n : provider.authType === 'api_key'\n ? t('connectPlan')\n : t('login')}\n </button>\n )}\n </div>\n <div className=\"dsh-pi-login-status\" role=\"status\">\n <span aria-hidden=\"true\" className={dotClass} />\n <span>{label}</span>\n </div>\n {provider.id === 'openrouter' && catalog !== undefined && ts !== undefined\n && <OpenRouterSyncStatus catalog={catalog} ts={ts} details />}\n {account.status === 'error' ? <p className=\"dsh-pi-login-error\">{account.message}</p> : null}\n {account.status === 'signing-in' && account.userCode !== undefined\n ? <p className=\"dsh-pi-login-body\">{t('userCode')} <span className=\"dsh-pi-login-code\">{account.userCode}</span></p>\n : null}\n {account.status === 'signing-in' && challengeUrl !== undefined\n ? (\n <p className=\"dsh-pi-login-body\">\n {provider.authType === 'api_key' && account.input !== undefined ? t('openPlanPage') : t('openUrl')}\n {' '}\n <a href={challengeUrl} target=\"_blank\" rel=\"noreferrer\" className=\"dsh-pi-login-link\">{challengeUrl}</a>\n </p>\n )\n : null}\n {account.status === 'signing-in' && account.input !== undefined\n ? (\n <form\n className=\"dsh-pi-login-form\"\n onSubmit={(event) => {\n event.preventDefault()\n void submitInput(provider)\n }}\n >\n <p className=\"dsh-pi-login-body\">{t(inputCopy?.help ?? 'authInputHelp')}</p>\n <input\n type={account.input.type === 'secret' ? 'password' : 'text'}\n className=\"dsh-pi-login-input\"\n aria-label={account.input.message}\n autoComplete=\"off\"\n spellCheck={false}\n placeholder={t(inputCopy?.placeholder ?? 'authInputPlaceholder')}\n value={drafts[provider.id] ?? ''}\n disabled={busy !== undefined}\n onChange={(event) => {\n applyDraftChange(provider.id, event, setDrafts)\n }}\n />\n <div className=\"dsh-pi-login-actions\">\n <button\n type=\"submit\"\n className=\"dsh-pi-login-btn dsh-pi-login-btn-primary\"\n disabled={busy !== undefined || (drafts[provider.id]?.trim().length ?? 0) === 0}\n >\n {busy === provider.id ? t('working') : t(inputCopy?.action ?? 'submitAuthInput')}\n </button>\n </div>\n </form>\n )\n : null}\n </article>\n )\n })}\n </div>\n )}\n </section>\n )\n}\n","/**\n * Pure filtering for the searchable composer model seat. Kept free of React\n * so the unit suite can exercise it without a DOM.\n */\n\n/** Minimal structural mirror of the host model catalog row (no runtime import). */\nexport interface FilterModel {\n id: string\n name: string\n description?: string\n}\n\n/** Minimal structural mirror of one provider group. */\nexport interface FilterGroup {\n id: string\n name: string\n models: readonly FilterModel[]\n}\n\n/**\n * Case-insensitive substring filter over model name, model id, and provider\n * name. Blank queries return the input unchanged (same array identity).\n * Groups whose every model is filtered out disappear; relative order holds.\n * @param groups - provider groups from the shared directory snapshot.\n * @param query - raw user text; trimmed and lowercased here.\n * @returns the filtered groups.\n */\nexport function filterGroups(\n groups: readonly FilterGroup[],\n query: string,\n freeModels?: ReadonlySet<string>,\n): readonly FilterGroup[] {\n const q = query.trim().toLowerCase()\n if (q === '' && freeModels === undefined) return groups\n const out: FilterGroup[] = []\n for (const group of groups) {\n if (freeModels !== undefined && group.id !== 'pi-openrouter') continue\n const groupHit = group.name.toLowerCase().includes(q)\n const matches = groupHit ? group.models : group.models.filter(model =>\n model.name.toLowerCase().includes(q) || model.id.toLowerCase().includes(q))\n const models = freeModels === undefined ? matches : matches.filter(model => freeModels.has(model.id))\n if (models.length > 0) out.push({ ...group, models })\n }\n return out\n}\n","/** Browser-safe contract. No credentials, provider URLs or server imports. */\nexport const OPENROUTER_CATALOG_PATH = '/plugins/dsh-oauth-login/openrouter/models'\nexport const OPENROUTER_REFRESH_PATH = OPENROUTER_CATALOG_PATH + '/refresh'\nexport const OPENROUTER_ROUTE = 'pi-openrouter'\nexport const OPENROUTER_REFRESH_MS = 15 * 60_000\nexport const OPENROUTER_COOLDOWN_MS = 60_000\n\nexport interface OpenRouterModel {\n id: string\n name: string\n contextWindow: number\n maxTokens: number\n inputModalities: string[]\n outputModalities: string[]\n supportedParameters: string[]\n tools: boolean\n reasoning: boolean\n reasoningMandatory: boolean\n supportedEfforts?: string[]\n defaultEffort?: string\n /** USD per token/unit as supplied by the official catalog, not pi-ai costs. */\n pricing: Record<string, string>\n priceStatus: 'free' | 'paid' | 'unknown'\n /** Endpoint deprecation, NEVER interpreted as a promotion deadline. */\n deprecatesAt?: string\n}\n\nexport interface OpenRouterCatalogSnapshot {\n version: 1\n connected: boolean\n refreshing: boolean\n source: 'builtin' | 'cache' | 'live'\n lastUpdatedAt: number | null\n lastAttemptAt: number | null\n nextRefreshAt: number | null\n retryAt: number | null\n stale: boolean\n error: 'fetch' | 'cache' | 'save' | null\n models: Array<OpenRouterModel & { freeOnly: boolean }>\n}\n","/**\n * SearchableModelSelect: plugin-owned shadow of the composer model seat\n * (`conversation.input.model`, registered at priority -1 so it renders over\n * the shipped ModelSelect). Behavior mirrors the official two-level menu —\n * root rows drill into the model list and the effort list over the SAME\n * shared per-session directory — and adds one thing the shipped seat lacks:\n * a local search box on the model pane that filters provider groups by model\n * name/id or provider name while typing. Selection still submits through the\n * injected `select` face, so the host stays the single fact source.\n */\nimport {\n useEffect, useId, useMemo, useRef, useState, useSyncExternalStore,\n type KeyboardEvent, type FocusEvent,\n} from 'react'\nimport type { ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types'\nimport type { ModelDirectoryState as DirectoryState, ModelSelectInjected } from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type { InjectFace, PropsLocale, PropsRuntime, TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'\nimport { filterGroups } from './model-filter.ts'\nimport type { FilterGroup } from './model-filter.ts'\nimport type { OpenRouterCatalogClient } from './openrouter-store.ts'\nimport { OpenRouterSyncStatus } from './OpenRouterSyncStatus.tsx'\nimport { OPENROUTER_ROUTE } from '../openrouter-types.ts'\n\n/** Which pane the dropdown shows. */\ntype Pane = 'root' | 'model' | 'effort'\n\n/** One effort row; undefined effort preserves the provider default. */\ninterface EffortChoice {\n key: string\n effort: string | undefined\n label: string\n description?: string\n}\n\n/** Component props: owner share + injected face + both translators. */\nexport interface SearchableModelSelectInjected extends ModelSelectInjected {\n catalog: OpenRouterCatalogClient\n /** Plugin `model-search` namespace translate (search box copy). */\n ts: TranslateNS<'model-search'>\n}\n\nexport type SearchableModelSelectProps = PropsRuntime<'conversation.input.model'>\n & PropsLocale<'model'>\n & InjectFace<SearchableModelSelectInjected>\n\nconst STYLE_ID = 'dsh-oauth-model-search-theme'\n\n/** Theme-token styles mirroring the shipped seat's menu vocabulary. */\nconst SEARCH_CSS = `\n.dsh-oauth-ms-root { position:relative; min-width:0; }\n.dsh-oauth-ms-trigger {\n display:flex; align-items:center; gap:4px; min-width:0;\n max-width:min(360px,45cqw); height:28px; padding:0 4px 0 8px;\n border:none; border-radius:24px; outline:none; background:transparent;\n color:var(--dsw-alias-label-secondary); font-size:13px; line-height:20px;\n font-weight:500; cursor:pointer;\n}\n.dsh-oauth-ms-trigger:hover:not(:disabled) { background:var(--dsw-alias-interactive-bg-hover); }\n.dsh-oauth-ms-trigger:focus-visible { box-shadow:0 0 0 2px var(--dsw-alias-border-l3); }\n.dsh-oauth-ms-trigger:disabled { color:var(--dsw-alias-label-dimmed); cursor:default; }\n.dsh-oauth-ms-triggerLabel { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n.dsh-oauth-ms-triggerEffort { flex:0 0 auto; color:var(--dsw-alias-label-caption); }\n.dsh-oauth-ms-chevron { flex:0 0 auto; color:var(--dsw-alias-label-caption); transition:transform 120ms ease; }\n.dsh-oauth-ms-chevronOpen { transform:rotate(180deg); }\n@media (prefers-reduced-motion: reduce) { .dsh-oauth-ms-chevron { transition:none; } }\n.dsh-oauth-ms-menu {\n position:absolute; right:0; bottom:calc(100% + 8px); z-index:20;\n display:flex; flex-direction:column;\n width:max-content; min-width:min(240px,calc(100vw - 32px));\n max-width:min(420px,calc(100vw - 32px));\n max-height:min(360px,calc(100vh - 96px)); overflow:hidden; padding:4px;\n border:1px solid var(--dsw-alias-border-inverted); border-radius:12px;\n background:var(--dsw-specific-menu); box-shadow:var(--dsw-shadow-lv3);\n color:var(--dsw-alias-label-primary);\n --dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);\n --dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);\n}\n.dsh-oauth-ms-status,.dsh-oauth-ms-empty { padding:10px; color:var(--dsw-alias-label-tertiary); font-size:13px; line-height:20px; }\n.dsh-oauth-ms-errorStrip {\n display:flex; align-items:flex-start; justify-content:space-between; gap:8px;\n margin-bottom:4px; padding:7px 8px; border-radius:8px;\n background:var(--dsw-alias-interactive-bg-hover-danger);\n color:var(--dsw-alias-state-error-primary); font-size:12px; line-height:18px;\n}\n.dsh-oauth-ms-warning {\n display:flex; align-items:flex-start; justify-content:space-between; gap:8px;\n margin-bottom:4px; padding:7px 8px; border-radius:8px;\n background:var(--dsw-alias-bg-module-platform);\n color:var(--dsw-alias-state-warn-label); font-size:12px; line-height:18px;\n}\n.dsh-oauth-ms-retry { flex:0 0 auto; padding:0; border:none; background:transparent; color:inherit; font:inherit; font-weight:600; cursor:pointer; }\n.dsh-oauth-ms-search {\n margin:2px 2px 4px; padding:6px 8px; border:1px solid var(--dsw-alias-border-inverted);\n border-radius:8px; background:transparent; font-size:13px;\n color:var(--dsw-alias-label-primary); outline:none;\n}\n.dsh-oauth-ms-search:focus-visible { box-shadow:0 0 0 2px var(--dsw-alias-border-l3); }\n.dsh-oauth-ms-groups { min-height:0; overflow-y:auto; }\n.dsh-oauth-ms-group + .dsh-oauth-ms-group { margin-top:4px; }\n.dsh-oauth-ms-groupTitle {\n position:sticky; top:0; z-index:1; padding:5px 8px 3px;\n background:var(--dsw-specific-menu); color:var(--dsw-alias-label-tertiary);\n font-size:12px; line-height:18px; font-weight:500;\n}\n.dsh-oauth-ms-option {\n box-sizing:border-box; display:flex; align-items:center; gap:8px;\n width:auto; min-width:100%; min-height:38px; padding:6px 8px;\n border:none; border-radius:10px; outline:none; background:transparent;\n color:inherit; text-align:left; cursor:pointer;\n}\n.dsh-oauth-ms-option:hover:not(:disabled),.dsh-oauth-ms-option:focus-visible { background:var(--dsw-alias-interactive-bg-hover); }\n.dsh-oauth-ms-option:disabled { color:var(--dsw-alias-label-dimmed); cursor:default; }\n.dsh-oauth-ms-optionCopy { display:flex; flex:1; flex-direction:column; min-width:0; }\n.dsh-oauth-ms-modelName { overflow:hidden; color:inherit; font-size:14px; line-height:20px; font-weight:500; text-overflow:ellipsis; white-space:nowrap; }\n.dsh-oauth-ms-description { overflow:hidden; color:var(--dsw-alias-label-tertiary); font-size:12px; line-height:18px; text-overflow:ellipsis; white-space:nowrap; }\n.dsh-oauth-ms-check { display:grid; place-items:center; flex:0 0 18px; color:var(--dsw-alias-label-primary); }\n.dsh-oauth-ms-cell {\n box-sizing:border-box; display:flex; align-items:center; gap:8px;\n width:auto; min-width:100%; height:40px; padding:0 10px;\n border:none; border-radius:10px; background:transparent;\n color:var(--dsw-alias-label-primary); font-size:14px; line-height:22px;\n cursor:pointer; text-align:left;\n}\n.dsh-oauth-ms-cell:hover { background:var(--dsw-alias-interactive-bg-hover); }\n.dsh-oauth-ms-cellLabel { flex:0 0 auto; white-space:nowrap; }\n.dsh-oauth-ms-cellValue { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:right; color:var(--dsw-alias-label-tertiary); }\n.dsh-oauth-ms-cellChevron { flex:0 0 auto; color:var(--dsw-alias-label-tertiary); }\n.dsh-oauth-ms-filters { display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin:2px 4px 4px; }\n.dsh-oauth-ms-filter { min-height:28px;padding:3px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:16px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer; }\n.dsh-oauth-ms-filter[aria-pressed=\"true\"] { background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l3); }\n.dsh-oauth-ms-filter:focus-visible { outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px; }\n.dsh-oauth-ms-meta { display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;margin-top:3px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px; }\n.dsh-oauth-ms-free { padding:1px 6px;border-radius:4px;color:color-mix(in srgb,var(--dsw-alias-state-success-primary) 50%,var(--dsw-alias-label-primary));background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 10%,transparent); }\n.dsh-oauth-ms-cached { color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover); }\n.dsh-oauth-ms-ended { color:color-mix(in srgb,var(--dsw-alias-state-warn-label) 50%,var(--dsw-alias-label-primary));white-space:normal; }\n.dsh-oauth-ms-help { padding:4px 8px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);white-space:normal; }\n@media (max-width:480px) { .dsh-oauth-ms-menu { width:calc(100vw - 32px);max-height:min(520px,calc(100dvh - 120px)); } .dsh-oauth-ms-option { min-height:44px; } }\n`\n\nfunction ensureStyles(): void {\n if (typeof document === 'undefined') return\n const existing = document.getElementById(STYLE_ID)\n if (existing !== null) {\n existing.textContent = SEARCH_CSS\n return\n }\n const style = document.createElement('style')\n style.id = STYLE_ID\n style.textContent = SEARCH_CSS\n document.head.appendChild(style)\n}\n\n/** Small inline chevron-down glyph (avoids importing host primitives). */\nfunction Chevron({ className }: { className: string }) {\n return (\n <svg className={className} width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M4 6l4 4 4-4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\n/** Small inline chevron-right glyph. */\nfunction ChevronRight({ className }: { className: string }) {\n return (\n <svg className={className} width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 4l4 4-4 4\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\n/**\n * Render the searchable composer model seat.\n * @param props - see {@link SearchableModelSelectProps}.\n * @returns the trigger and, while open, the search-enabled two-level menu.\n */\nexport function SearchableModelSelect(\n { locked, available, directory, catalog, load, select, t, ts }: SearchableModelSelectProps,\n) {\n const state = useSyncExternalStore(\n fn => directory.subscribe(fn),\n () => directory.getSnapshot(),\n ) as DirectoryState\n const catalogState = useSyncExternalStore(catalog.subscribe, catalog.getSnapshot)\n const metadata = useMemo(() => new Map(catalogState.data?.models.map(model => [model.id, model]) ?? []), [catalogState.data])\n const freeModels = useMemo(() => new Set([...metadata.values()].filter(model => model.priceStatus === 'free').map(model => model.id)), [metadata])\n const [freeOnly, setFreeOnly] = useState(false)\n const [open, setOpen] = useState(false)\n const [pane, setPane] = useState<Pane>('root')\n const [query, setQuery] = useState('')\n const lastActionRef = useRef<'load' | 'select'>('load')\n const [notice, setNotice] = useState<{ seq: number; text: string } | null>(null)\n const noticeSeq = useRef(0)\n const noticeTimer = useRef<number | undefined>(undefined)\n const rootRef = useRef<HTMLDivElement | null>(null)\n const triggerRef = useRef<HTMLButtonElement | null>(null)\n const searchRef = useRef<HTMLInputElement | null>(null)\n const itemRefs = useRef<(HTMLButtonElement | null)[]>([])\n const id = useId()\n\n useEffect(() => { ensureStyles() }, [])\n useEffect(() => {\n if (open && pane === 'model') searchRef.current?.focus()\n }, [open, pane])\n useEffect(() => {\n if (catalogState.data?.connected === false) setFreeOnly(false)\n }, [catalogState.data?.connected])\n useEffect(() => {\n if (available && catalogState.data?.lastUpdatedAt != null) load()\n }, [available, catalogState.data?.lastUpdatedAt, load])\n useEffect(() => () => { window.clearTimeout(noticeTimer.current) }, [])\n\n const choices = useMemo(() => state.groups.flatMap(group =>\n group.models.map(model => ({\n group,\n model,\n selection: {\n provider: group.id,\n model: model.id,\n ...model.reasoning?.defaultEffort === undefined\n ? {}\n : { reasoningEffort: model.reasoning.defaultEffort },\n } satisfies ModelSelection,\n }))), [state.groups])\n const current = state.current\n const selectedIndex = current === null\n ? -1\n : choices.findIndex(c => c.selection.provider === current.provider && c.selection.model === current.model)\n const currentChoice = choices[selectedIndex]\n const reasoning = currentChoice?.model.reasoning\n const effectiveEffort = state.current?.reasoningEffort ?? reasoning?.defaultEffort\n const effortLabel = reasoning === undefined\n ? undefined\n : effectiveEffort === undefined\n ? t('effort.providerDefault')\n : reasoning.efforts.find(level => level.id === effectiveEffort)?.name ?? effectiveEffort\n const effortChoices = useMemo<readonly EffortChoice[]>(() => reasoning === undefined\n ? []\n : [\n ...reasoning.defaultEffort === undefined\n ? [{ key: 'provider-default', effort: undefined, label: t('effort.providerDefault') }]\n : [],\n ...reasoning.efforts.map(effort => ({\n key: `effort:${effort.id}`,\n effort: effort.id,\n label: effort.name,\n ...effort.description === undefined ? {} : { description: effort.description },\n })),\n ], [reasoning, t])\n const busy = state.status === 'selecting'\n\n const filteredGroups = useMemo<readonly FilterGroup[]>(\n () => filterGroups(state.groups, query, freeOnly ? freeModels : undefined),\n [state.groups, query, freeOnly, freeModels])\n const filteredCount = useMemo(\n () => filteredGroups.reduce((sum, group) => sum + group.models.length, 0),\n [filteredGroups])\n\n const reload = (): void => {\n lastActionRef.current = 'load'\n load()\n void catalog.load()\n }\n\n // Mount-time load resolves the trigger label; every open refreshes.\n useEffect(() => {\n if (available) {\n lastActionRef.current = 'load'\n load()\n }\n }, [available, load])\n\n useEffect(() => {\n if (!open) return\n const closeOutside = (event: MouseEvent): void => {\n if (!rootRef.current?.contains(event.target as Node)) setOpen(false)\n }\n document.addEventListener('mousedown', closeOutside)\n return () => { document.removeEventListener('mousedown', closeOutside) }\n }, [open])\n\n if (!available) return null\n\n const show = (): void => {\n setPane('root')\n setQuery('')\n setNotice(null)\n setOpen(true)\n reload()\n }\n\n const close = (restoreFocus = false): void => {\n setOpen(false)\n setPane('root')\n setQuery('')\n if (restoreFocus) queueMicrotask(() => { triggerRef.current?.focus() })\n }\n\n const moveFocus = (offset: number): void => {\n const items = itemRefs.current.filter(item => item !== null && !item.disabled)\n if (items.length === 0) return\n const active = items.findIndex(item => item === document.activeElement)\n const next = (Math.max(active, 0) + offset + items.length) % items.length\n items[next]?.focus()\n }\n\n const onRootKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {\n if (event.key === 'Escape' && open) {\n event.preventDefault()\n if (pane !== 'root') setPane('root')\n else close(true)\n return\n }\n if (!open) return\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n moveFocus(event.key === 'ArrowDown' ? 1 : -1)\n }\n }\n\n const onBlur = (event: FocusEvent<HTMLDivElement>): void => {\n if (event.relatedTarget instanceof Node && rootRef.current?.contains(event.relatedTarget)) return\n close()\n }\n\n const settleSelection = (result: Awaited<ReturnType<ModelSelectInjected['select']>>): void => {\n if (result === undefined) return\n if (result.ok) {\n if (rootRef.current !== null) close(true)\n return\n }\n const { error } = result\n noticeSeq.current += 1\n window.clearTimeout(noticeTimer.current)\n setNotice({\n seq: noticeSeq.current,\n text: error.code === 'session/writer-held'\n ? t('error.sessionInUse')\n : t('error.action', { message: `${error.code}: ${error.message}` }),\n })\n noticeTimer.current = window.setTimeout(() => { setNotice(null) }, 4000)\n }\n\n const choose = (selection: ModelSelection): void => {\n const info = selection.provider === OPENROUTER_ROUTE ? metadata.get(selection.model) : undefined\n if (info?.freeOnly && info.priceStatus !== 'free') return\n const current = state.current\n if (current?.provider === selection.provider && current.model === selection.model) {\n close(true)\n return\n }\n lastActionRef.current = 'select'\n void select(selection).then(settleSelection)\n }\n\n const chooseEffort = (effort: string | undefined): void => {\n if (state.current === null) return\n if (effectiveEffort === effort) {\n close(true)\n return\n }\n const selection: ModelSelection = {\n provider: state.current.provider,\n model: state.current.model,\n ...effort === undefined ? {} : { reasoningEffort: effort },\n }\n lastActionRef.current = 'select'\n void select(selection).then(settleSelection)\n }\n\n /** Search-input keyboard: ↓ enters the list, Enter picks the first match, Escape clears then backs out. */\n const onSearchKeyDown = (event: KeyboardEvent<HTMLInputElement>): void => {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n event.stopPropagation()\n itemRefs.current.find(item => item !== null)?.focus()\n return\n }\n if (event.key === 'Enter') {\n event.preventDefault()\n const first = filteredGroups[0]?.models[0]\n if (first !== undefined) choose({ provider: filteredGroups[0].id, model: first.id })\n return\n }\n if (event.key === 'Escape') {\n event.stopPropagation()\n if (query !== '') setQuery('')\n // Non-Escape propagation lets the root handler back out of the pane.\n }\n }\n\n const modelLabel = currentChoice?.model.name ?? state.current?.model ?? t('trigger.fallback')\n const triggerLabel = effortLabel === undefined ? modelLabel : `${modelLabel} · ${effortLabel}`\n const triggerAria = currentChoice === undefined\n ? t('trigger.selectAria')\n : effortLabel === undefined\n ? t('trigger.aria', { model: modelLabel })\n : t('trigger.ariaEffort', { model: modelLabel, effort: effortLabel })\n itemRefs.current = []\n let itemIndex = 0\n const itemRef = () => {\n const at = itemIndex++\n return (node: HTMLButtonElement | null) => { itemRefs.current[at] = node }\n }\n\n return (\n <div ref={rootRef} className=\"dsh-oauth-ms-root\" onKeyDown={onRootKeyDown} onBlur={onBlur}>\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"dsh-oauth-ms-trigger\"\n aria-label={triggerAria}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? `${id}-menu` : undefined}\n title={triggerLabel}\n disabled={locked}\n onClick={() => {\n if (open) close()\n else show()\n }}\n >\n <span className=\"dsh-oauth-ms-triggerLabel\">{modelLabel}</span>\n {effortLabel !== undefined && <span className=\"dsh-oauth-ms-triggerEffort\">{effortLabel}</span>}\n <Chevron className={`dsh-oauth-ms-chevron${open ? ' dsh-oauth-ms-chevronOpen' : ''}`} />\n </button>\n\n {open && (\n <div\n id={`${id}-menu`}\n className=\"dsh-oauth-ms-menu\"\n role=\"menu\"\n aria-label={t('menu.aria')}\n aria-busy={state.status === 'loading' || busy}\n >\n {pane === 'root' && (\n <>\n <button ref={itemRef()} type=\"button\" role=\"menuitem\" className=\"dsh-oauth-ms-cell\" onClick={() => { setPane('model') }}>\n <span className=\"dsh-oauth-ms-cellLabel\">{t('menu.model')}</span>\n <span className=\"dsh-oauth-ms-cellValue\">{modelLabel}</span>\n <ChevronRight className=\"dsh-oauth-ms-cellChevron\" />\n </button>\n {reasoning !== undefined && (\n <button ref={itemRef()} type=\"button\" role=\"menuitem\" className=\"dsh-oauth-ms-cell\" onClick={() => { setPane('effort') }}>\n <span className=\"dsh-oauth-ms-cellLabel\">{t('menu.effort')}</span>\n <span className=\"dsh-oauth-ms-cellValue\">{effortLabel}</span>\n <ChevronRight className=\"dsh-oauth-ms-cellChevron\" />\n </button>\n )}\n </>\n )}\n\n {pane === 'model' && (\n <>\n <input\n ref={searchRef}\n type=\"text\"\n className=\"dsh-oauth-ms-search\"\n placeholder={ts('placeholder')}\n aria-label={ts('aria')}\n value={query}\n autoComplete=\"off\"\n spellCheck={false}\n onChange={event => { setQuery(event.target.value) }}\n onKeyDown={onSearchKeyDown}\n />\n {(catalogState.data?.connected || state.groups.some(group => group.id === OPENROUTER_ROUTE)) && <>\n <div className=\"dsh-oauth-ms-filters\" role=\"group\" aria-label={ts('freeFilterAria')}>\n <button type=\"button\" className=\"dsh-oauth-ms-filter\" aria-pressed={!freeOnly} onClick={() => { setFreeOnly(false) }}>{ts('all')}</button>\n <button type=\"button\" className=\"dsh-oauth-ms-filter\" aria-pressed={freeOnly} onClick={() => { setFreeOnly(true) }}>{ts('freeOnly')} · {freeModels.size}</button>\n </div>\n <OpenRouterSyncStatus catalog={catalog} ts={ts} />\n </>}\n {state.status === 'loading' && <div className=\"dsh-oauth-ms-status\">{t('status.loading')}</div>}\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className=\"dsh-oauth-ms-errorStrip\">\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className=\"dsh-oauth-ms-retry\" onClick={reload}>{t('retry')}</button>\n </div>\n )}\n {state.failures.map(failure => (\n <div className=\"dsh-oauth-ms-warning\" key={failure.id}>\n <span>{t('warning.groupLoad', { name: failure.name, message: failure.message })}</span>\n <button type=\"button\" className=\"dsh-oauth-ms-retry\" onClick={reload}>{t('retry')}</button>\n </div>\n ))}\n <div className=\"dsh-oauth-ms-groups\">\n {filteredGroups.map((group) => {\n const headingId = `${id}-${group.id}`\n return (\n <section role=\"group\" aria-labelledby={headingId} className=\"dsh-oauth-ms-group\" key={group.id}>\n <div className=\"dsh-oauth-ms-groupTitle\" id={headingId}>{group.name}</div>\n {group.models.map(model => {\n const selected = state.current?.provider === group.id && state.current.model === model.id\n const info = group.id === OPENROUTER_ROUTE ? metadata.get(model.id) : undefined\n const blocked = info?.freeOnly === true && info.priceStatus !== 'free'\n const tokens = info === undefined ? '' : new Intl.NumberFormat(undefined, { notation: 'compact', maximumFractionDigits: 1 }).format(info.contextWindow)\n return (\n <button\n ref={itemRef()}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={selected}\n className=\"dsh-oauth-ms-option\"\n key={model.id}\n title={model.name}\n disabled={busy || blocked}\n onClick={() => { choose({ provider: group.id, model: model.id }) }}\n >\n <span className=\"dsh-oauth-ms-optionCopy\">\n <span className=\"dsh-oauth-ms-modelName\">{model.name}</span>\n {model.description !== undefined && (\n <span className=\"dsh-oauth-ms-description\">{model.description}</span>\n )}\n {info !== undefined && (\n <span className=\"dsh-oauth-ms-meta\">\n {info.priceStatus === 'free' && <span className={'dsh-oauth-ms-free' + (catalogState.data?.stale ? ' dsh-oauth-ms-cached' : '')}>\n {ts(catalogState.data?.stale ? 'freeCached' : 'free')}\n </span>}\n {blocked && <span className=\"dsh-oauth-ms-ended\">{ts(info.priceStatus === 'paid' ? 'freeEnded' : 'freeUnknown')}</span>}\n <span>{ts(info.tools ? 'tools' : 'chatOnly')}</span>\n <span>{ts('context', { tokens })}</span>\n </span>\n )}\n </span>\n <span className=\"dsh-oauth-ms-check\">\n {selected\n ? (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 8.5l3.2 3L13 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n : null}\n </span>\n </button>\n )\n })}\n </section>\n )\n })}\n </div>\n {state.status === 'ready' && state.groups.length > 0 && filteredCount === 0 && (\n <div className=\"dsh-oauth-ms-empty\">{freeOnly ? ts('emptyFree') : ts('empty', { query: query.trim() })}</div>\n )}\n {state.status === 'ready' && state.groups.length === 0 && (\n <div className=\"dsh-oauth-ms-empty\">{t('empty.models')}</div>\n )}\n {freeOnly && <div className=\"dsh-oauth-ms-help\">{ts('freeHelp')}</div>}\n </>\n )}\n\n {pane === 'effort' && (\n <>\n {state.error !== null && lastActionRef.current === 'load' && (\n <div className=\"dsh-oauth-ms-errorStrip\">\n <span>{t('error.action', { message: state.error })}</span>\n <button type=\"button\" className=\"dsh-oauth-ms-retry\" onClick={reload}>{t('action.reload')}</button>\n </div>\n )}\n {effortChoices.length === 0\n ? <div className=\"dsh-oauth-ms-empty\">{t('empty.efforts')}</div>\n : effortChoices.map(level => (\n <button\n ref={itemRef()}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={effectiveEffort === level.effort}\n className=\"dsh-oauth-ms-option\"\n key={level.key}\n disabled={busy}\n onClick={() => { chooseEffort(level.effort) }}\n >\n <span className=\"dsh-oauth-ms-optionCopy\">\n <span className=\"dsh-oauth-ms-modelName\">{level.label}</span>\n {level.description !== undefined && (\n <span className=\"dsh-oauth-ms-description\">{level.description}</span>\n )}\n </span>\n <span className=\"dsh-oauth-ms-check\">\n {effectiveEffort === level.effort\n ? (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 8.5l3.2 3L13 5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n : null}\n </span>\n </button>\n ))}\n </>\n )}\n\n {notice !== null && (\n <div role=\"alert\" className=\"dsh-oauth-ms-errorStrip\" key={notice.seq}>{notice.text}</div>\n )}\n </div>\n )}\n </div>\n )\n}\n","export const en = {\n nav: 'Subscription Login',\n title: 'Subscription Login',\n loadingAccount: 'Loading accounts…',\n signedOut: 'Not signed in',\n signingIn: 'Waiting for authorization…',\n waitingForCredential: 'Waiting for a Plan API key…',\n waitingForCallback: 'Waiting for the authorization callback…',\n waitingForAuthInput: 'Waiting for authorization details…',\n signedIn: 'Signed in',\n login: 'Sign in',\n connectPlan: 'Connect plan',\n loginAgain: 'Sign in again',\n reopenAuthorization: 'Reopen authorization',\n cancelLogin: 'Cancel',\n logout: 'Sign out',\n working: 'Working…',\n userCode: 'Code',\n openUrl: 'Authorize',\n openPlanPage: 'Plan page',\n credentialHelp: 'Create or copy the provider-specific Plan API key, then paste it here. It stays in DSH’s private credential file.',\n credentialPlaceholder: 'Paste Plan API key',\n saveCredential: 'Save and connect',\n credentialRequired: 'Paste the Plan API key first.',\n callbackHelp: 'Paste the complete callback URL from the browser after authorization. DSH uses it only to finish this sign-in.',\n callbackPlaceholder: 'Paste the callback URL',\n submitCallback: 'Complete sign-in',\n callbackRequired: 'Paste the callback URL first.',\n authInputHelp: 'Enter the value requested by the provider to continue authorization.',\n authInputPlaceholder: 'Enter authorization value',\n submitAuthInput: 'Continue',\n authInputRequired: 'Enter the requested authorization value first.',\n requestFailed: 'The login request failed.',\n proxyTitle: 'Network proxy',\n proxyScope: 'Only applies to requests made by this subscription plugin. Does not change your system or browser proxy.',\n proxyLoading: 'Loading network settings…',\n proxyHttpEnabled: 'Use a proxy for HTTP',\n proxyWsEnabled: 'Use a proxy for WebSocket',\n proxyHttpHelp: 'Login, token refresh, model requests over HTTPS / SSE, and model catalogs.',\n proxyWsHelp: 'Model WebSocket connections. This switch controls proxy routing; it does not disable WebSocket itself.',\n proxyAddress: 'Proxy address (HTTP / HTTPS)',\n proxyPort: 'Port',\n proxyPortPlaceholder: 'e.g. 45678',\n proxyDirect: 'Off: connect directly, ignoring proxy environment variables. The address is kept for later.',\n proxyAuto: 'Default address with no port: keep automatic environment / system proxy discovery; connect directly if none is found. Port 80 is not assumed.',\n proxyExplicit: 'Use this HTTP(S) CONNECT proxy instead of the automatically detected one. SOCKS-only ports are not supported.',\n proxyApplyHelp: 'Saving applies to new requests without interrupting a running call. Sessions already using SSE stay on SSE. Original retry limits are unchanged.',\n proxySave: 'Save network settings',\n proxyReload: 'Reload settings',\n proxySaved: 'Saved. New requests use these settings.',\n proxyLoadFailed: 'Network settings could not be loaded. Reload, or activate the updated plugin backend.',\n proxySaveFailed: 'Could not confirm that network settings were saved. Reload to check their current state.',\n proxyInvalid: 'Enter an HTTP(S) proxy address without credentials or a path, and a port from 1 to 65535. If both fields specify a port, they must match.',\n proxyConflict: 'Another page changed these settings. Reload before saving again.',\n} as const\n\nexport type PiLoginKey = keyof typeof en\n\nexport const zh: { [Key in PiLoginKey]: string } = {\n nav: '订阅登录',\n title: '订阅登录',\n loadingAccount: '正在加载账户…',\n signedOut: '尚未登录',\n signingIn: '正在等待授权…',\n waitingForCredential: '等待输入套餐 API Key…',\n waitingForCallback: '等待输入授权回调地址…',\n waitingForAuthInput: '等待输入授权信息…',\n signedIn: '已登录',\n login: '登录',\n connectPlan: '连接套餐',\n loginAgain: '重新登录',\n reopenAuthorization: '重新打开授权页',\n cancelLogin: '取消',\n logout: '退出',\n working: '处理中…',\n userCode: '授权码',\n openUrl: '授权',\n openPlanPage: '套餐页面',\n credentialHelp: '请在套餐页新建或复制专用 API Key,再粘贴到这里。密钥只保存在 DSH 的私有凭据文件中。',\n credentialPlaceholder: '粘贴套餐 API Key',\n saveCredential: '保存并连接',\n credentialRequired: '请先粘贴套餐 API Key。',\n callbackHelp: '请在浏览器完成授权后,复制完整的回调地址并粘贴到这里。DSH 只用它完成本次登录。',\n callbackPlaceholder: '粘贴授权回调地址',\n submitCallback: '完成登录',\n callbackRequired: '请先粘贴授权回调地址。',\n authInputHelp: '请输入服务商要求的内容以继续授权。',\n authInputPlaceholder: '输入授权信息',\n submitAuthInput: '继续',\n authInputRequired: '请先输入服务商要求的授权信息。',\n requestFailed: '登录请求失败。',\n proxyTitle: '网络代理',\n proxyScope: '仅影响本订阅插件发出的请求,不修改系统或浏览器代理。',\n proxyLoading: '正在加载网络设置…',\n proxyHttpEnabled: 'HTTP 使用代理',\n proxyWsEnabled: 'WebSocket 使用代理',\n proxyHttpHelp: '用于登录、令牌刷新、HTTPS / SSE 模型请求和模型列表。',\n proxyWsHelp: '用于模型的 WebSocket 连接。此开关只控制是否走代理,不关闭 WebSocket 本身。',\n proxyAddress: '代理地址(HTTP / HTTPS)',\n proxyPort: '端口',\n proxyPortPlaceholder: '例如 45678',\n proxyDirect: '已关闭:直接连接,忽略代理环境变量。保留地址,方便下次开启。',\n proxyAuto: '默认地址、端口留空:沿用环境变量、系统代理等自动发现;没有找到代理时直连,不会默认使用 80 端口。',\n proxyExplicit: '优先使用此 HTTP(S) CONNECT 代理,不使用自动发现的地址。不支持纯 SOCKS 端口。',\n proxyApplyHelp: '保存后用于新请求,不中断正在进行的调用。已降级的会话继续使用 SSE,原有重试上限不变。',\n proxySave: '保存网络设置',\n proxyReload: '重新加载',\n proxySaved: '已保存,新请求将使用这些设置。',\n proxyLoadFailed: '网络设置加载失败。请重新加载,或先启用更新后的插件服务端。',\n proxySaveFailed: '未能确认网络设置已保存,请重新加载后检查当前设置。',\n proxyInvalid: '请填写不含账号密码或路径的 HTTP(S) 代理地址,端口为 1–65535。若地址中也有端口,须与端口栏一致。',\n proxyConflict: '其他页面已修改设置,请重新加载后再保存。',\n}\n\n/** `model-search` namespace: copy for the searchable composer model seat. */\nexport const searchEn = {\n placeholder: 'Search models…',\n aria: 'Filter models',\n empty: 'No models match “{query}”.',\n all: 'All',\n freeOnly: 'Free only',\n freeFilterAria: 'Model price filter (OpenRouter)',\n free: 'Free · Rate limited',\n freeCached: 'Free (cached) · Recheck pending',\n freeEnded: 'Free offer ended · Paid calls blocked',\n freeUnknown: 'Price unconfirmed · Free guard active',\n tools: 'Tool calling',\n chatOnly: 'Chat only',\n context: '{tokens} context',\n emptyFree: 'No matching free OpenRouter models. Clear the search or refresh the catalog.',\n syncSchedule: 'OpenRouter · Sync every 15 min',\n syncing: 'Syncing models…',\n syncSignIn: 'Sign in to OpenRouter to sync models.',\n syncRefresh: 'Refresh models',\n syncCooldown: 'Refreshed within 60s',\n syncUpdated: 'Last synced',\n syncStale: 'Cached · Refresh needed',\n syncBuiltin: 'Not synced yet; using built-in models.',\n syncError: 'Sync failed. Keeping the previous list; retry later.',\n syncSaveError: 'Could not save the safe catalog cache. Keeping the previous list; check DSH disk permissions.',\n syncRestart: 'Restart DSH to activate the new model-sync backend.',\n freeHelp: 'Free models have rate and daily limits. Unavailable models never fall back to paid ones.',\n forcedPluginWarning: 'Disable account-enforced paid OpenRouter plugins: DSH cannot override platform-enforced charges.',\n} as const\n\nexport type ModelSearchKey = keyof typeof searchEn\n\nexport const searchZh: { [Key in ModelSearchKey]: string } = {\n placeholder: '搜索模型…',\n aria: '筛选模型',\n empty: '没有匹配“{query}”的模型。',\n all: '全部',\n freeOnly: '仅免费',\n freeFilterAria: '模型价格筛选(OpenRouter)',\n free: '免费 · 有限额',\n freeCached: '免费缓存 · 待更新',\n freeEnded: '免费已结束 · 付费已拦截',\n freeUnknown: '价格未确认 · 免费保护中',\n tools: '支持工具调用',\n chatOnly: '仅聊天',\n context: '{tokens} 上下文',\n emptyFree: '没有匹配的 OpenRouter 免费模型。请清空搜索或刷新列表。',\n syncSchedule: 'OpenRouter · 每 15 分钟同步',\n syncing: '正在同步模型…',\n syncSignIn: '登录 OpenRouter 后自动同步模型。',\n syncRefresh: '刷新模型',\n syncCooldown: '60 秒内已刷新',\n syncUpdated: '上次同步',\n syncStale: '缓存待更新',\n syncBuiltin: '尚未同步,暂用内置模型列表。',\n syncError: '同步失败,保留上次列表;请稍后重试。',\n syncSaveError: '安全缓存保存失败,保留上次列表;请检查 DSH 目录写入权限。',\n syncRestart: '请重启 DSH,启用新的模型同步服务。',\n freeHelp: '免费模型有速率和每日限额;不可用时不会切换到付费模型。',\n forcedPluginWarning: '请关闭 OpenRouter 账户强制启用的收费插件;平台强制规则不能由 DSH 覆盖。',\n}\n","import { OPENROUTER_CATALOG_PATH, OPENROUTER_REFRESH_PATH } from '../openrouter-types.ts'\nimport type { OpenRouterCatalogSnapshot } from '../openrouter-types.ts'\n\nexport interface OpenRouterClientState {\n data: OpenRouterCatalogSnapshot | null\n loading: boolean\n error: 'unavailable' | 'restart' | null\n}\n\nfunction validSnapshot(value: unknown): value is OpenRouterCatalogSnapshot {\n if (typeof value !== 'object' || value === null) return false\n const data = value as Record<string, unknown>\n const timestamp = (entry: unknown) => entry === null\n || typeof entry === 'number' && Number.isFinite(entry) && entry > 0 && entry <= 8.64e15\n if (data.version !== 1 || typeof data.connected !== 'boolean'\n || typeof data.refreshing !== 'boolean' || typeof data.stale !== 'boolean'\n || !timestamp(data.lastUpdatedAt) || !timestamp(data.lastAttemptAt)\n || !timestamp(data.nextRefreshAt) || !timestamp(data.retryAt)\n || !Array.isArray(data.models) || data.models.length > 10_000) return false\n return data.models.every((entry: unknown) => {\n if (typeof entry !== 'object' || entry === null) return false\n const model = entry as Record<string, unknown>\n return typeof model.id === 'string' && typeof model.name === 'string'\n && typeof model.tools === 'boolean' && typeof model.freeOnly === 'boolean'\n && typeof model.contextWindow === 'number' && Number.isFinite(model.contextWindow)\n && ['free', 'paid', 'unknown'].includes(String(model.priceStatus))\n })\n}\n\n/** One metadata store/poll per browser plugin, shared by settings and menus. */\nexport class OpenRouterCatalogClient {\n private state: OpenRouterClientState = { data: null, loading: false, error: null }\n private readonly listeners = new Set<() => void>()\n private pending: Promise<void> | undefined\n private controller: AbortController | undefined\n private poll: ReturnType<typeof setTimeout> | undefined\n private lastRead = -Infinity\n private disposed = false\n\n constructor(private readonly request: typeof globalThis.fetch = (...args) => globalThis.fetch(...args)) {}\n\n getSnapshot = (): OpenRouterClientState => this.state\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n if (this.listeners.size === 1 && !this.disposed) void this.load()\n return () => {\n this.listeners.delete(listener)\n if (this.listeners.size === 0) {\n clearTimeout(this.poll)\n this.poll = undefined\n }\n }\n }\n private update(state: OpenRouterClientState): void {\n this.state = state\n for (const listener of this.listeners) listener()\n }\n private failed(error: OpenRouterClientState['error']): void {\n if (this.disposed) return\n this.update({ ...this.state, error,\n data: this.state.data === null ? null : { ...this.state.data, stale: true },\n })\n }\n\n load = (force = false): Promise<void> => {\n if (this.disposed) return Promise.resolve()\n if (this.pending !== undefined) return this.pending\n if (!force && Date.now() - this.lastRead < 1500) {\n this.schedule()\n return Promise.resolve()\n }\n this.lastRead = Date.now()\n clearTimeout(this.poll)\n this.poll = undefined\n this.controller = new AbortController()\n const signal = AbortSignal.any([this.controller.signal, AbortSignal.timeout(20_000)])\n this.update({ ...this.state, loading: true, error: null })\n const pending = this.read(force, signal).finally(() => {\n if (this.pending !== pending) return\n this.pending = undefined\n this.controller = undefined\n if (!this.disposed) {\n this.update({ ...this.state, loading: false })\n this.schedule()\n }\n })\n this.pending = pending\n return pending\n }\n private async read(force: boolean, signal: AbortSignal): Promise<void> {\n try {\n const response = await this.request(force ? OPENROUTER_REFRESH_PATH : OPENROUTER_CATALOG_PATH, {\n method: force ? 'POST' : 'GET', credentials: 'same-origin',\n headers: { accept: 'application/json' }, signal,\n })\n if (response.status === 404) {\n this.failed('restart')\n return\n }\n if (!response.ok) throw new Error('catalog unavailable')\n const data: unknown = await response.json()\n if (!validSnapshot(data)) {\n throw new Error('invalid catalog response')\n }\n if (!this.disposed) this.update({ ...this.state, data, error: null })\n } catch {\n this.failed('unavailable')\n }\n }\n private schedule(): void {\n if (this.disposed || this.listeners.size === 0) return\n clearTimeout(this.poll)\n // This is a local metadata read, NOT an upstream model refresh.\n this.poll = setTimeout(() => { void this.load() }, this.state.data?.refreshing ? 2000 : 60_000)\n }\n dispose(): void {\n this.disposed = true\n clearTimeout(this.poll)\n this.controller?.abort()\n this.listeners.clear()\n }\n}\n","/** Browser half: Pi login settings page + searchable composer model seat. */\n\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type { ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types'\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-model-selection/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-session/client'\nimport { PiLoginSettings } from './PiLoginSettings.tsx'\nimport type { PiLoginSettingsInjected } from './PiLoginSettings.tsx'\nimport { SearchableModelSelect } from './SearchableModelSelect.tsx'\nimport { en, zh, searchEn, searchZh } from './locales.ts'\nimport type { PiLoginKey, ModelSearchKey } from './locales.ts'\nimport { OpenRouterCatalogClient } from './openrouter-store.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n 'settings.pi-login': PiLoginKey\n 'model-search': ModelSearchKey\n }\n}\n\nexport const name = 'dsh-oauth-login-client'\n// directoryFor() resolves remote.session through the calling plugin's context.\nexport const inject = ['slots', 'locale', 'sessions', 'modelDirectories', 'remote', 'remote.session']\n\nexport function apply(ctx: ClientContext): void {\n const catalog = new OpenRouterCatalogClient()\n ctx.effect(() => () => catalog.dispose(), 'dsh-oauth-login: catalog metadata')\n const searchNs = 'model-search'\n ctx.effect(() => ctx.locale.register(searchNs, { zh: searchZh, en: searchEn }), 'dsh-oauth-login: model-search copy')\n const ts = ctx.locale.bind(searchNs)\n const namespace = 'settings.pi-login'\n ctx.effect(() => ctx.locale.register(namespace, { zh, en }), 'dsh-oauth-login: settings copy')\n const t = ctx.locale.bind(namespace) as PiLoginSettingsInjected['t']\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'pi-login',\n order: 17,\n label: () => t('nav'),\n inject: (): PiLoginSettingsInjected => ({ t, ts, catalog }),\n }, PiLoginSettings))\n\n // Searchable shadow of the composer model seat. Priority -1 renders over\n // the shipped ModelSelect (priority 0, lowest live entry wins); removing\n // this plugin restores the stock selector with no host restart.\n ctx.slots.inject('conversation.input.model', () => ctx.slots.register({\n name: 'conversation.input.model',\n locale: 'model',\n priority: -1,\n inject: (sessionId) => {\n const directory = ctx.modelDirectories.directoryFor(sessionId)\n const available = ctx.sessions.subagentAddress(sessionId) === undefined\n return {\n available,\n catalog,\n directory: directory.store,\n load: () => {\n if (available) directory.load().catch(() => { /* surfaced on the store */ })\n },\n select: (selection: ModelSelection) => available\n ? directory.select(selection)\n : Promise.resolve(undefined),\n ts,\n }\n },\n }, SearchableModelSelect))\n}\n"],"mappings":"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"}
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { LlmError, ReasoningEffortId, RetryPolicySchema, resolveRetryPolicy } from "@deepseek-ai/dsh-llm";
2
- import { createModels, defaultProviderAuthContext } from "@earendil-works/pi-ai";
2
+ import { createModels, defaultProviderAuthContext, getCurrentTools, normalizeContext } from "@earendil-works/pi-ai";
3
3
  import { PiAiAdapter } from "@deepseek-ai/dsh-llm-pi-ai";
4
4
  import { AsyncLocalStorage } from "node:async_hooks";
5
5
  import { basename, dirname, join, resolve } from "node:path";
@@ -762,6 +762,10 @@ const OPENROUTER_REFRESH_MS = 9e5;
762
762
  const OPENROUTER_COOLDOWN_MS = 6e4;
763
763
  //#endregion
764
764
  //#region src/native-tools.ts
765
+ /**
766
+ * OAuth routes that already have provider-hosted search / image tools.
767
+ * DSH's web_search function tool would hide those and bill a second key.
768
+ */
765
769
  /** DSH model-facing tools that steal traffic from a subscribed provider. */
766
770
  const DSH_WEB_TOOL_NAMES = ["web_search", "web_fetch"];
767
771
  /** Matching tool-web prompt sections. */
@@ -1041,10 +1045,15 @@ function wrapOnPayload(existing, providerId, api, policy = DEFAULT_NATIVE_TOOL_P
1041
1045
  };
1042
1046
  }
1043
1047
  function filterPiContext(context, providerId, api, policy = DEFAULT_NATIVE_TOOL_POLICY) {
1044
- if (nativePlan(providerId, api, policy) === void 0 || context.tools === void 0) return context;
1048
+ if (nativePlan(providerId, api, policy) === void 0) return context;
1045
1049
  return {
1046
1050
  ...context,
1047
- tools: context.tools.filter((tool) => !isDshWebToolName(tool.name))
1051
+ ...context.tools === void 0 ? {} : { tools: context.tools.filter((tool) => !isDshWebToolName(tool.name)) },
1052
+ messages: context.messages.map((message) => message.role !== "system" ? message : {
1053
+ ...message,
1054
+ ...message.toolsAdded === void 0 ? {} : { toolsAdded: message.toolsAdded.filter((tool) => !isDshWebToolName(tool.name)) },
1055
+ ...message.toolsRemoved === void 0 ? {} : { toolsRemoved: message.toolsRemoved.filter((tool) => !isDshWebToolName(tool.name)) }
1056
+ })
1048
1057
  };
1049
1058
  }
1050
1059
  /**
@@ -1056,7 +1065,7 @@ function filterPiContext(context, providerId, api, policy = DEFAULT_NATIVE_TOOL_
1056
1065
  * when the provider serializer later emits `tools: []`.
1057
1066
  */
1058
1067
  function prepareNativeToolRequest(context, options, providerId, api, policy = DEFAULT_NATIVE_TOOL_POLICY) {
1059
- if (context.tools === void 0 || nativePlan(providerId, api, policy) === void 0) return {
1068
+ if (context.tools === void 0 && getCurrentTools(context.messages).length === 0 || nativePlan(providerId, api, policy) === void 0) return {
1060
1069
  context,
1061
1070
  options
1062
1071
  };
@@ -1903,12 +1912,12 @@ function harnessProvider(spec, native = DEFAULT_NATIVE_TOOL_POLICY, catalog) {
1903
1912
  stream: (model, context, options) => {
1904
1913
  const request = prepareNativeToolRequest(context, options ?? {}, spec.id, model.api, native);
1905
1914
  const guarded = spec.id === "openrouter" ? prepareOpenRouterOptions(model, request.options, catalog) : request.options;
1906
- return base.stream(model, request.context, guarded);
1915
+ return base.stream(model, normalizeContext(request.context), guarded);
1907
1916
  },
1908
1917
  streamSimple: (model, context, options) => {
1909
1918
  const request = prepareNativeToolRequest(context, options ?? {}, spec.id, model.api, native);
1910
1919
  const guarded = spec.id === "openrouter" ? prepareOpenRouterOptions(model, request.options, catalog) : request.options;
1911
- return base.streamSimple(model, request.context, guarded);
1920
+ return base.streamSimple(model, normalizeContext(request.context), guarded);
1912
1921
  }
1913
1922
  };
1914
1923
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-oauth-login",
3
3
  "description": "DSH-owned subscription login powered by Pi AI adapters: OAuth plus official Plan API keys, with an independent credential store.",
4
- "version": "0.2.5",
4
+ "version": "0.2.7",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "registry": "https://registry.npmjs.org/"
@@ -90,16 +90,17 @@
90
90
  },
91
91
  "peerDependencies": {
92
92
  "@deepseek-ai/cordis": "^4.0.2",
93
+ "@deepseek-ai/dsh": ">=0.2.0-rc.2 <0.2.1",
93
94
  "@deepseek-ai/dsh-atomic-write": "*",
94
95
  "@deepseek-ai/dsh-attachment": "*",
95
- "@deepseek-ai/dsh-client-connection": ">=0.1.7-rc.1 <0.1.8",
96
+ "@deepseek-ai/dsh-client-connection": ">=0.2.0-rc.2 <0.2.1",
96
97
  "@deepseek-ai/dsh-home-paths": "*",
97
98
  "@deepseek-ai/dsh-host-webserver": "*",
98
99
  "@deepseek-ai/dsh-invariants": "*",
99
100
  "@deepseek-ai/dsh-llm": "*",
100
101
  "@deepseek-ai/dsh-llm-pi-ai": "*",
101
102
  "@deepseek-ai/schemastery": "^3.18.2",
102
- "@earendil-works/pi-ai": "^0.85.1",
103
+ "@earendil-works/pi-ai": "^0.87.1",
103
104
  "react": "^18.2.0"
104
105
  },
105
106
  "peerDependenciesMeta": {
@@ -109,6 +110,9 @@
109
110
  "@deepseek-ai/cordis": {
110
111
  "optional": true
111
112
  },
113
+ "@deepseek-ai/dsh": {
114
+ "optional": true
115
+ },
112
116
  "@deepseek-ai/dsh-atomic-write": {
113
117
  "optional": true
114
118
  },
@@ -142,32 +146,32 @@
142
146
  },
143
147
  "devDependencies": {
144
148
  "@deepseek-ai/cordis": "4.0.4",
145
- "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.1",
146
- "@deepseek-ai/dsh-atomic-write": "0.1.7-rc.1",
147
- "@deepseek-ai/dsh-attachment": "0.1.7-rc.1",
148
- "@deepseek-ai/dsh-authorization": "0.1.7-rc.1",
149
- "@deepseek-ai/dsh-brand": "0.1.7-rc.1",
150
- "@deepseek-ai/dsh-client-connection": "0.1.7-rc.1",
151
- "@deepseek-ai/dsh-client-locale": "0.1.7-rc.1",
152
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.1",
153
- "@deepseek-ai/dsh-client-ui-model-selection": "0.1.7-rc.1",
154
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.1",
155
- "@deepseek-ai/dsh-client-ui-session": "0.1.7-rc.1",
156
- "@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.1",
157
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.1",
158
- "@deepseek-ai/dsh-credentials": "0.1.7-rc.1",
159
- "@deepseek-ai/dsh-fs": "0.1.7-rc.1",
160
- "@deepseek-ai/dsh-home-paths": "0.1.7-rc.1",
161
- "@deepseek-ai/dsh-host-webserver": "0.1.7-rc.1",
162
- "@deepseek-ai/dsh-invariants": "0.1.7-rc.1",
163
- "@deepseek-ai/dsh-launch-environment": "0.1.7-rc.1",
164
- "@deepseek-ai/dsh-llm": "0.1.7-rc.1",
165
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.7-rc.1",
166
- "@deepseek-ai/dsh-settings": "0.1.7-rc.1",
167
- "@deepseek-ai/dsh-timeout": "0.1.7-rc.1",
168
- "@deepseek-ai/dsh-util-values": "0.1.7-rc.1",
149
+ "@deepseek-ai/dsh-api-session-controller": "0.2.0-rc.2",
150
+ "@deepseek-ai/dsh-atomic-write": "0.2.0-rc.2",
151
+ "@deepseek-ai/dsh-attachment": "0.2.0-rc.2",
152
+ "@deepseek-ai/dsh-authorization": "0.2.0-rc.2",
153
+ "@deepseek-ai/dsh-brand": "0.2.0-rc.2",
154
+ "@deepseek-ai/dsh-client-connection": "0.2.0-rc.2",
155
+ "@deepseek-ai/dsh-client-locale": "0.2.0-rc.2",
156
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2",
157
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.2.0-rc.2",
158
+ "@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.2",
159
+ "@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.2",
160
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2",
161
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2",
162
+ "@deepseek-ai/dsh-credentials": "0.2.0-rc.2",
163
+ "@deepseek-ai/dsh-fs": "0.2.0-rc.2",
164
+ "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
165
+ "@deepseek-ai/dsh-host-webserver": "0.2.0-rc.2",
166
+ "@deepseek-ai/dsh-invariants": "0.2.0-rc.2",
167
+ "@deepseek-ai/dsh-launch-environment": "0.2.0-rc.2",
168
+ "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
169
+ "@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2",
170
+ "@deepseek-ai/dsh-settings": "0.2.0-rc.2",
171
+ "@deepseek-ai/dsh-timeout": "0.2.0-rc.2",
172
+ "@deepseek-ai/dsh-util-values": "0.2.0-rc.2",
169
173
  "@deepseek-ai/schemastery": "3.18.4",
170
- "@earendil-works/pi-ai": "0.85.1",
174
+ "@earendil-works/pi-ai": "0.87.1",
171
175
  "@types/node": "^22.20.0",
172
176
  "@types/react": "~18.3.1",
173
177
  "@types/semver": "7.7.1",
@@ -62,8 +62,8 @@ export function apply(ctx: ClientContext): void {
62
62
  if (available) directory.load().catch(() => { /* surfaced on the store */ })
63
63
  },
64
64
  select: (selection: ModelSelection) => available
65
- ? directory.select(selection).then(() => true, () => false)
66
- : Promise.resolve(false),
65
+ ? directory.select(selection)
66
+ : Promise.resolve(undefined),
67
67
  ts,
68
68
  }
69
69
  },
@@ -3,6 +3,7 @@
3
3
  * DSH's web_search function tool would hide those and bill a second key.
4
4
  */
5
5
 
6
+ import { getCurrentTools } from '@earendil-works/pi-ai'
6
7
  import type { Context as PiContext, StreamOptions } from '@earendil-works/pi-ai'
7
8
  import type { ReplayEnvelope, StreamChunk } from '@deepseek-ai/dsh-llm'
8
9
  import { piLoginProviderByRoute } from './catalog.ts'
@@ -391,10 +392,15 @@ export function filterPiContext(
391
392
  api: string | undefined,
392
393
  policy: NativeToolPolicy = DEFAULT_NATIVE_TOOL_POLICY,
393
394
  ): PiContext {
394
- if (nativePlan(providerId, api, policy) === undefined || context.tools === undefined) return context
395
+ if (nativePlan(providerId, api, policy) === undefined) return context
395
396
  return {
396
397
  ...context,
397
- tools: context.tools.filter(tool => !isDshWebToolName(tool.name)),
398
+ ...(context.tools === undefined ? {} : { tools: context.tools.filter(tool => !isDshWebToolName(tool.name)) }),
399
+ messages: context.messages.map(message => message.role !== 'system' ? message : {
400
+ ...message,
401
+ ...(message.toolsAdded === undefined ? {} : { toolsAdded: message.toolsAdded.filter(tool => !isDshWebToolName(tool.name)) }),
402
+ ...(message.toolsRemoved === undefined ? {} : { toolsRemoved: message.toolsRemoved.filter(tool => !isDshWebToolName(tool.name)) }),
403
+ }),
398
404
  }
399
405
  }
400
406
 
@@ -413,7 +419,7 @@ export function prepareNativeToolRequest<TOptions extends StreamOptions>(
413
419
  api: string | undefined,
414
420
  policy: NativeToolPolicy = DEFAULT_NATIVE_TOOL_POLICY,
415
421
  ): { context: PiContext; options: TOptions & StreamOptions } {
416
- if (context.tools === undefined || nativePlan(providerId, api, policy) === undefined) {
422
+ if ((context.tools === undefined && getCurrentTools(context.messages).length === 0) || nativePlan(providerId, api, policy) === undefined) {
417
423
  return { context, options }
418
424
  }
419
425
  const onPayload = wrapOnPayload(options?.onPayload, providerId, api, policy)
package/src/provider.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  /** Installed pi-ai providers remapped onto independent harness routes. */
2
2
 
3
+ import { normalizeContext } from '@earendil-works/pi-ai'
3
4
  import { builtinProviders } from '@earendil-works/pi-ai/providers/all'
4
5
  import type { Api, ApiKeyAuth, Model, Provider } from '@earendil-works/pi-ai'
5
6
  import { PI_LOGIN_PROVIDERS } from './catalog.ts'
@@ -108,7 +109,7 @@ export function harnessProvider(
108
109
  ? prepareOpenRouterOptions(model, request.options, catalog) : request.options
109
110
  return base.stream(
110
111
  model,
111
- request.context,
112
+ normalizeContext(request.context),
112
113
  // pi-ai's generic ApiStreamOptions<T> is a conditional type. The
113
114
  // preparation step preserves every provider-specific field and only
114
115
  // adds StreamOptions.onPayload, but TypeScript cannot prove that for T.
@@ -121,7 +122,7 @@ export function harnessProvider(
121
122
  ? prepareOpenRouterOptions(model, request.options, catalog) : request.options
122
123
  return base.streamSimple(
123
124
  model,
124
- request.context,
125
+ normalizeContext(request.context),
125
126
  guarded,
126
127
  )
127
128
  },