# dsh-agy-ui

<p align="center">
  <strong>专为 DeepSeek Harness (DSH) 中 <code>dsh-agy</code> 打造的非侵入式 UI 伴生增强插件</strong><br/>
  模型列表智能净化 · 顶栏实时配额徽章 · 毛玻璃双周期额度浮层 · 移动端抽屉自适应
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/dsh-agy-ui"><img src="https://img.shields.io/npm/v/dsh-agy-ui?color=blue&label=npm" alt="npm version"/></a>
  <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="MIT License"/></a>
  <a href="https://github.com/deepseek-ai/deepseek-harness"><img src="https://img.shields.io/badge/DeepSeek%20Harness-Plugin-orange" alt="DSH Plugin"/></a>
  <a href="https://github.com/Erick0412-dev/dsh-agy-ui/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome"/></a>
</p>

<p align="center">
  <b>🌐 语言 / Language:</b>
  <b>简体中文</b> ·
  <a href="./README.en.md">English</a>
</p>

---

## 💡 为什么需要 dsh-agy-ui？

在 [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness) 生态中，[dsh-agy](https://github.com/chaos-03x/dsh-agy) 凭借直连 Google 内部核心 API（`POST /v1internal:streamGenerateContent`）以及 DSH 原生 Tool 执行能力，提供了轻量极速的底层调用通道。

但原生使用中存在几个直接影响日常体验的痛点：

| 对比维度 | 原生 `dsh-agy` 体验 | 配合 `dsh-agy-ui` 增强后 |
| :--- | :--- | :--- |
| **模型列表选择** | 充斥内部幽灵模型（如 `chat_23310`、`tab_flash_lite_preview`） | 🧹 **自动正则净化**，彻底过滤非通用对话模型 |
| **思考档位 (Reasoning)** | 同一模型的 Low/Medium/High 被展开为多行冗长菜单 | 🎛️ **智能折叠变体**，无缝唤起 DSH 原生思考档位选择器 |
| **Tiered 模型命名** | 原始模型 ID 显示粗糙（如 `gemini-3.8-flash-tiered`） | ✨ **规范品牌化排版**，展示为 `Gemini 3.8 Flash` 等友好名称 |
| **模型优先级** | 排序散乱，主力模型难以快速定位 | 🏆 **标准优先级降序**：3.8 Flash > 3.7 > 3.6 > Pro > Claude > GPT-OSS |
| **配额感知** | 额度孤立在 `/agy` 后台管理页，对话界面无法获知 | ⚡ **顶栏常驻微型徽章**，常态直接透视最紧的那一档配额（5 小时 / 周） |
| **额度详情查看** | 需离开当前对话跳转后台 | 🪟 **悬停/点击呼出毛玻璃浮层**，按上游分组展示 5小时 / 日 / 周 / 月 全窗口额度 |
| **移动端适配** | 桌面浮层在窄屏下容易截断或溢出 | 📱 **响应式抽屉 (Drawer)**，屏幕 $\le$ 640px 自动滑出底部卡片 |

`dsh-agy-ui` 定位为一个**纯表层体验伴生增强插件**：底层网络通信、流式解析与 Tool 调度 100% 交由 `dsh-agy`，本插件专注于提供优雅直观的前端交互。

---

## 🏛️ 插件定位与系统架构

`dsh-agy-ui` 遵循 Cordis 插件规范设计，在内存中以非侵入方式包裹 LLM 适配器，并在 Web 端通过 DSH 原生 Slots 插槽注入交互组件：

```text
                    ┌────────────────────────────────────────────────────────┐
                    │               DeepSeek Harness (DSH Web)               │
                    └───────────┬────────────────────────────────┬───────────┘
                                │                                │
                        (Web Slots 注入)                 (Cordis 插件机制)
                                │                                │
                                ▼                                ▼
                    ┌────────────────────────┐      ┌─────────────────────────┐
                    │      dsh-agy-ui        │◄─────┤   适配器列表动态拦截包装  │
                    │   (顶栏徽章 + 浮层弹窗)  │      │ (净化/折叠/品牌化/排序)   │
                    └───────────┬────────────┘      └────────────┬────────────┘
                                │ RPC 管理面读取                  │ 原生模型委托
                                ▼                                ▼
                    ┌────────────────────────┐      ┌─────────────────────────┐
                    │  dsh-agy 管理面 RPC    │      │   dsh-agy 核心调用层    │
                    │ (/api/agy · account.*) │      │ (直连 Google 内部 API)  │
                    └───────────┬────────────┘      └─────────────────────────┘
                                │ account.limits 返回分组窗口
                                │ （5h / daily / weekly / monthly）
                                │
                    ┌───────────┴────────────┐
                    │      dsh-agy-link      │
                    │ (/plugins/agy-link/..) │
                    │   兼容回退通道（可选）  │
                    └────────────────────────┘
```

---

## ✨ 核心特性详解

### 1. 🧼 模型菜单智能净化与统一排版

<p align="center">
  <img src="./docs/images/clean-models.png" width="300" alt="净化后的模型列表效果图" />
  <br />
  <em>▲ 净化后的 Antigravity (agy) 原生模型选择列表效果预览</em>
</p>

- **内部幽灵模型过滤**：自动过滤 `^chat_\d+$`、`^tab_` 等非对话专用的内部调试与代码补全模型。
- **思考档位规范折叠**：将散落的 `-low`、`-medium`、`-high` 变体收敛至根模型，注入标准的 `thinkingEfforts` 声明，让 DSH 原生思考选择器生效。
- **品牌名称优雅规范**：将 Tiered 系列模型（如 `gemini-3.8-flash-tiered`）自动格式化为标准展示名（如 `Gemini 3.8 Flash`）。
- **科学降序排列**：Gemini Flash 系列（3.8 > 3.7 > 3.6 > 3.5 > 3）→ Gemini Pro（3.1 Pro）→ 2.5 系列 → Claude 4.6 → GPT-OSS。

### 2. ⚡ 顶栏实时配额徽章 (Header Badge)

<p align="center">
  <img src="./docs/images/badge.png" width="200" alt="顶栏配额徽章效果图" />
  <br />
  <em>▲ 挂载于会话顶栏的实时配额胶囊徽章（静态呼吸健康指示灯 + 动态百分比）</em>
</p>

- **非侵入插槽注入**：挂载于 `conversation.session.header.actions` 插槽，独立 ID `agy-ui-quota-badge`。
- **一目了然的配额显示**：常驻显示当前活跃账号的 最紧的那一档额度（如 `AGY · 55%`），取自 dsh-agy 的**分组窗口**（`account.limits`），而非已被上游移除的逐模型额度。
- **按「离耗尽还有多远」取数，而不是取最小值**：5 小时与周额度各自对齐自己的耗尽阈值（15% / 1%，与 dsh-agy 的轮换判定一致），所以一周快用尽时徽章会切到周额度并标注（如 `AGY · 周额度 1%`），而一周还剩一半时不会把 5 小时的数字拉低。浮层里的 `daily` / `monthly` 只展示、不参与判定，因为账号池不会因它们而停用。
- **动静相宜的呼吸微动效**：静态健康圆点平时稳定常亮（绿=正常、黄=冷却中/限流、灰=无可用账号），仅在后台数据同步或手动刷新时展示 1.2 秒平滑呼吸光效。
- **120 秒全局频率锁**：2 分钟定时轮询 + 120 秒标签页/窗口聚焦节流锁，彻底杜绝切换标签页时高频击穿后台触发 Google 429 限流。

### 3. 🪟 轻量化毛玻璃配额透视弹窗 (Popover)

<p align="center">
  <img src="./docs/images/popover.png" width="380" alt="配额透视浮层效果图" />
  <br />
  <em>▲ 点击或悬停徽章呼出的分组多窗口（5小时 / 日 / 周 / 月）配额监控面板</em>
</p>

- **悬停即现，支持钉选 (Pin)**：鼠标移入徽章毫秒级呼出，居中对齐徽章下方；点击徽章即可常驻固定。
- **按上游分组渲染的全窗口配额条**：直接透传 dsh-agy 的配额分组（当前为 `Gemini Models` 与 `Claude and GPT models`），分组内每个窗口独立成行，行标签由上游的 `window` 字段决定：
  - **5 小时周期（5h）** / **日额度（daily）** / **周额度（weekly）** / **月额度（monthly）**；上游未来新增的窗口标识会原样展示，不会被丢弃。
  - **未返回的窗口显示为 `—` 与灰色空条**，而不是 0% —— “未知”和“已用尽”是相反的事实。
- **账号健康与快捷入口**：展示当前激活账号脱敏标识及健康状态（含 `verification-required` 待验证态及其申诉链接），内置手动刷新按钮；`dsh-agy ≥ 0.3.0` 下顶栏提示改为「设置 → Antigravity」。

### 4. 📱 移动端抽屉式卡片自适应 (Mobile Drawer)
- 采用响应式设计，当屏幕宽度 $\le$ 640px 时，弹窗自动转为 iOS/Android 风格的底部抽屉（Bottom Sheet），并配有半透明遮罩与触控关闭优化。

### 5. 🛡️ 命名空间隔离与多插件共存
- 所有 CSS 均置于 `agy-ui-*` 独立前缀命名空间，杜绝全局样式污染。
- 完整兼容并可与 `dsh-agy-link` 无缝共存：额度数据遵循 **dsh-agy 分组窗口 → dsh-agy-link 家族额度 → 旧版逐模型额度** 的回退顺序。

### 6. 🔌 数据拉取通道（dsh-agy ≥ 0.3.0 适配）

`dsh-agy` 0.3.0 起把管理面从独立的 `/agy` 仪表盘迁到了 **DSH 自有 RPC 通道**：宿主注册 `/api/agy`，浏览器侧通过 `connection.rpc.call('/api', 'agy', { method, payload })` 调用，仅 `/agy/oauth-callback` 仍是普通 HTTP 路由（Google 会用 GET 跳转过去）。旧的 `/agy/api/accounts` **已被删除**。同时 5 小时 / 周额度的数据源由 `fetchAvailableModels` 的逐模型 `quotaInfo`（**不含窗口字段**，因此永远无法区分 5h 与 weekly）换成 `v1internal:retrieveUserQuotaSummary`，按账号缓存在 `cachedLimits`。

本插件因此按以下顺序取数（实现见 `src/quota-source.ts`）：

| 优先级 | 通道 | 说明 |
| :--- | :--- | :--- |
| 1 | `POST /api/agy` → `account.list` | 账号列表，并附带 `limits` / `limitsUpdatedAt`（TTL 缓存，**不产生上游请求**） |
| 1 | `POST /api/agy` → `account.limits` | 分组窗口；TTL（10 分钟）内服务端直接跳过探测，仅在过期或手动刷新（`force: true`）时才真正测量 |
| 2 | `GET /agy/api/accounts` | 旧版 dsh-agy（< 0.3.0）兼容回退 |
| 3 | `GET /plugins/agy-link/status` | 与 dsh-agy 相互独立的额度池，始终并行读取 |

- **自动轮询绝不 `force`**：TTL 内不产生上游调用；若某次探测整体失败（`measured: 0` 且 `failed > 0`），客户端会退避一整个 TTL，避免持续击穿 Google 接口。
- **RPC 不可用时自动降级**：`connection` 服务缺失或 RPC 报错时回落到旧 HTTP 通道；两者都不可用时保留上一次成功数据，而不是清空面板。

---

## 🚀 一键快速安装 (Quick Start)

> 💡 **前置要求**：请确保已经安装并配置好底层 Provider [dsh-agy](https://github.com/chaos-03x/dsh-agy)。

本项目已正式发布至 **[npm 官方仓库 (dsh-agy-ui)](https://www.npmjs.com/package/dsh-agy-ui)**。打开终端，一行命令即可全自动安装并完成 Profile 激活注册：

```bash
# 官方 CLI 一键安装注册（全自动拉取并注入 Profile）
dsh plugin --profile web add dsh-agy-ui

# 💡 若未全局安装 dsh 命令，可使用 npx 免安装执行：
npx @deepseek-ai/dsh plugin --profile web add dsh-agy-ui
```

安装完成后，启动或重启 DSH Web：
```bash
dsh web
# 或：dsh restart
```

刷新浏览器页面（`http://127.0.0.1:3080`），顶栏实时额度徽章与净化后的模型列表即刻呈现！

<details>
<summary><b>🛠️ 开发者 / 源码安装方式</b></summary>

- **从 GitHub 仓库一键直装**：
  ```bash
  dsh plugin --profile web add github:Erick0412-dev/dsh-agy-ui
  ```
- **本地克隆二次开发**：
  ```bash
  dsh plugin --profile web add /path/to/dsh-agy-ui
  ```
</details>

---

## ❓ 常见问题 (FAQ)

<details>
<summary><b>Q1: 为什么我的徽章一直显示灰色点？</b></summary>
灰色点表示当前未检测到活跃的 Antigravity 账号。`dsh-agy` 0.3.0 起请在 DSH 的 <b>设置 → Antigravity</b> 中添加账号并完成 Google 登录（上游已移除旧的 <code>/agy</code> 仪表盘）。
</details>

<details>
<summary><b>Q2: 为什么切换标签页时不会立即刷新额度？</b></summary>
为了保护您的 Google 账号不被 Google 接口报 429 速率限制（Rate Limit），插件内置了 <b>120 秒全局频率锁</b>。在 120 秒内频繁切回标签页不会发起重复网络请求。如需立即获取最新额度，可点击浮层中的刷新图标手动刷新。
</details>

<details>
<summary><b>Q3: 我同时安装了 dsh-agy-link 会发生冲突吗？</b></summary>
不会。<code>dsh-agy-ui</code> 具有独立插槽 ID 与独立的 CSS 命名空间，不仅完全兼容，还会自动读取 <code>dsh-agy-link</code> 的配额接口作为回退：优先展示 dsh-agy 的分组窗口（5h / 日 / 周 / 月），无分组数据时再使用 link 的家族额度。
</details>

---

## 🙏 致谢 (Special Thanks)

本项目站在巨人的肩膀上，在此由衷感谢以下优秀的开源项目与贡献者：

- 🌟 **[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)** (`deepseek-ai/deepseek-harness`)  
  **一切的核心基石**。DSH 优雅强大的 Cordis 微内核架构、模块化 Web UI Slots 插槽与 LLM 适配器抽象，让插件的非侵入式开发成为可能。
- ⚡ **[dsh-agy](https://github.com/chaos-03x/dsh-agy)** by [@chaos-03x](https://github.com/chaos-03x)  
  **核心上游 Provider**。以极其纯粹高效的底层设计直连 Google 内部 API，支持原生 Tool 运行与账号轮换，是本插件依托的坚实后盾。
- 🎨 **[dsh-agy-link](https://github.com/amlyczz/dsh-agy-link)** by [@amlyczz](https://github.com/amlyczz)  
  **卓越的灵感源泉与排版榜样**。其精巧绝伦的排版设计、双桶配额（5h / 7d）监控思路以及细腻的交互美感，为本插件的 UI/UX 设计提供了莫大的启发与参考！

---

## ⚖️ 开源协议与声明 (License & Compliance)

- 本项目基于 [MIT License](./LICENSE) 开源。
- 关联项目（`deepseek-harness`、`dsh-agy`、`dsh-agy-link`）均采用宽松平易的 **MIT 许可证**。本项目完全遵循相关许可协议，通过动态挂载、公开 HTTP 端点和插槽机制协同工作，不包含任何专有或侵权闭源衍生代码。
- **免责声明**：本项目为社区个人独立开源的伴生增强插件，与 Google LLC、DeepSeek 等官方实体无直接商业或从属关联。请在符合各服务商使用条款的范围内合理使用。
