coding-tool-x 3.4.12 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,101 +1,107 @@
1
- # Coding-Tool-X
1
+ # coding-tool-x
2
2
 
3
3
  > 面向 Claude Code、Codex CLI、Gemini CLI、OpenCode 的统一增强控制台
4
- > Web UI + CLI + Proxy + Config Sync + MCP/Skills/Agents/Prompts 管理
4
+ > Web UI + CLI + 多平台代理 + 配置托管 + 工作区编排 + 分析面板
5
5
 
6
- 本项目基于 [CooperJiang/coding-tool](https://github.com/CooperJiang/coding-tool) 扩展而来,在原有会话管理和渠道切换能力之上,继续补齐了多平台代理、配置同步、工作区编排、MCP 管理、Skills/Commands/Agents 管理、OAuth 凭证管理、配置导入导出、OpenCode 适配与分析面板等能力。
6
+ ![Node.js](https://img.shields.io/badge/Node.js-%3E%3D14.0.0-43853d?style=flat-square)
7
+ ![License](https://img.shields.io/badge/License-MIT-blue?style=flat-square)
8
+ ![Platforms](https://img.shields.io/badge/Platforms-Claude%20%7C%20Codex%20%7C%20Gemini%20%7C%20OpenCode-1f6feb?style=flat-square)
7
9
 
8
10
  ![Home Preview](docs/home.png)
9
11
 
10
- ## 项目定位
12
+ `coding-tool-x` 把多个 Coding CLI 的常用管理能力收拢到一套界面里: 会话查看、渠道代理、配置同步、工作区组织、MCP / Skills / Commands / Agents / Plugins 管理、OAuth 凭证托管、通知设置、统计分析和配置导入导出。
11
13
 
12
- `coding-tool-x` 不只是一个会话浏览器,而是一个多平台代理与配置中枢:
14
+ 如果你同时在用 Claude Code、Codex CLI、Gemini CLI、OpenCode,这个项目的目标就是把这些分散在不同目录、不同配置文件、不同命令里的日常操作,尽量放回一个统一入口。
13
15
 
14
- - 统一查看 Claude / Codex / Gemini / OpenCode 的项目与会话
15
- - 为各平台配置多渠道、代理、模型重定向、测速与健康检查
16
- - 管理并同步 Prompts、Skills、Commands、Agents、MCP、插件配置
17
- - 提供工作区、Git worktree、配置模板、导入导出与诊断能力
18
- - 通过 Web 面板查看实时日志、请求统计、Token/费用趋势
16
+ ## 适合做什么
19
17
 
20
- ## 当前核心能力
18
+ - 统一查看四个平台的项目和会话
19
+ - 管理多渠道代理、测速、模型探测和健康状态
20
+ - 集中托管 Prompts、Skills、Agents、Commands、MCP、Plugins 等常用配置项
21
+ - 为多项目创建工作区,必要时自动创建 Git worktree
22
+ - 统一查看请求量、Token、费用趋势与实时日志
23
+ - 导入导出整套配置,包含原生配置快照
21
24
 
22
- ### 1. 多平台会话与代理
25
+ ## 功能概览
23
26
 
24
- - 统一管理 `Claude`、`Codex`、`Gemini`、`OpenCode` 四类项目与会话
25
- - 支持会话别名、最近会话、全局搜索、会话 Fork、跨平台会话转换
26
- - 每个平台都有独立代理入口与独立端口
27
- - 支持多渠道启用/停用、测速、健康状态、优先级与模型列表探测
28
- - 支持 Claude / Codex / Gemini 的模型重定向与默认测速模型配置
29
- - OpenCode 支持网关适配与会话格式转换/导出
27
+ ### 会话与项目
30
28
 
31
- ### 2. 配置与同步中枢
29
+ - 支持 Claude、Codex、Gemini、OpenCode 四个平台的项目与会话列表
30
+ - 支持项目排序、项目搜索、会话排序、会话搜索
31
+ - 支持最近会话、收藏、别名、聊天记录查看
32
+ - 支持新建会话、删除会话、复制启动命令
33
+ - Claude / Codex / Gemini 会话支持格式转换
34
+ - 支持将 Claude / Codex / Gemini 请求转换为 OpenCode 网关请求
32
35
 
33
- - 集中存储项目配置到 `~/.cc-tool`
34
- - 自动读写平台原生配置目录,而不是替换你的平台使用方式
35
- - 支持 Prompts 预设创建、激活、停用与平台状态查看
36
- - 支持配置模板、工作区模板与导入配置时的预览
37
- - 支持 ZIP / JSON 配置导入导出
38
- - 支持 Claude / Codex / Gemini / OpenCode 的配置同步
39
-
40
- ### 3. 扩展能力
41
-
42
- - MCP 服务器管理、平台启用开关、连通性测试、预设与导入
43
- - Skills 管理:远程仓库安装、本地托管、详情查看、按平台安装
44
- - Commands 管理:当前支持 Claude / OpenCode
45
- - Agents 管理:当前支持 Claude / Codex / OpenCode
46
- - 插件系统:支持 Git 安装、启用/禁用、升级、配置
47
- - OAuth 凭证管理:集中管理 Claude / Codex / Gemini / OpenCode OAuth 数据
48
-
49
- ### 4. 运维与观测
50
-
51
- - 首页 Dashboard 按平台展示状态卡、代理状态、实时日志和快捷操作
52
- - Analytics 页面查看多平台请求数、Token、费用趋势并导出 CSV/JSON
53
- - `ctx logs` 查看 UI/代理日志,支持 `--follow` / `--lines` / `--clear`
54
- - `ctx stats` 查看总体和分平台统计
55
- - `ctx doctor` 做环境、端口、配置、日志、磁盘与进程诊断
56
- - Web UI 支持访问密码;`--host` 暴露 LAN 时默认禁止远程写操作
36
+ ### 多渠道代理
57
37
 
38
+ - 四个平台均支持独立代理端口和独立渠道配置
39
+ - 支持渠道增删改查、启用 / 停用、排序、权重、并发限制
40
+ - 支持速度测试、模型可用性探测、健康检查与故障冻结
41
+ - 支持模型重定向和默认测速模型配置
42
+ - Web UI 与 CLI 都可查看代理状态和日志
58
43
 
59
- ## 架构概览
44
+ ### 配置与托管
60
45
 
61
- ### CLI
62
-
63
- - 命令入口:`bin/ctx.js`
64
- - 主逻辑:`src/index.js`
65
- - 后台运行:PM2 管理 `ctx start / stop / restart / status`
66
-
67
- ### 服务端
68
-
69
- - Express API:`src/server/index.js`
70
- - WebSocket:用于 Dashboard / 日志 / 状态推送
71
- - API 范围覆盖:
72
- - 项目 / 会话
73
- - 渠道 / 代理
74
- - Skills / Commands / Agents / Plugins
75
- - Prompts / MCP / OAuth / Config Export / Config Sync
76
- - Dashboard / Analytics / Security / Workspace
46
+ - 集中存储在 `~/.cc-tool`
47
+ - 保留并同步各平台原生配置目录,而不是替代原生用法
48
+ - 支持 Prompts 预设管理,并同步到各平台对应提示文件
49
+ - 支持 Skills、Agents、Commands、Plugins 的中心托管与按支持的平台启停
50
+ - 支持 MCP 服务器配置、预设、连通性测试和多平台写入
51
+ - 支持 OAuth 凭证池管理与回写原生配置
52
+ - 支持 ZIP / JSON 配置导入导出
77
53
 
78
- ### 前端
54
+ ### 工作区与运维
79
55
 
80
- - Vue 3 + Vite + Pinia + Naive UI + ECharts
81
- - 主要页面:
82
- - Dashboard 首页
83
- - 四个平台的项目/会话列表
84
- - Workspaces
85
- - Config Templates
86
- - Skills
87
- - Plugins
88
- - Analytics
56
+ - 支持多项目工作区
57
+ - 支持为 Git 仓库创建 worktree
58
+ - 支持配置模板,将提示词、技能、命令、代理、MCP、插件组合成一套模板
59
+ - 支持 Dashboard、Analytics、日志、统计导出、环境诊断
60
+ - 支持面板访问密码
61
+ - LAN 模式默认禁止远程写操作,可按需开启
62
+
63
+ ### 通知
64
+
65
+ - 支持 Claude、Codex、Gemini、OpenCode 的任务完成通知托管
66
+ - 支持系统通知和弹窗模式
67
+ - 支持飞书机器人 Webhook 通知
68
+
69
+ ## 能力矩阵
70
+
71
+ | 能力 | Claude | Codex | Gemini | OpenCode |
72
+ | --- | --- | --- | --- | --- |
73
+ | 项目 / 会话查看 | 支持 | 支持 | 支持 | 支持 |
74
+ | 渠道 / 代理管理 | 支持 | 支持 | 支持 | 支持 |
75
+ | Prompts 预设同步 | 支持 | 支持 | 支持 | 支持 |
76
+ | Skills 管理 | 支持 | 支持 | 支持 | 支持 |
77
+ | Commands 管理 | 支持 | - | - | 支持 |
78
+ | Agents 管理 | 支持 | 支持 | - | 支持 |
79
+ | Plugins 管理 | 支持 | - | - | 支持 |
80
+ | OAuth 凭证托管 | 支持 | 支持 | 支持 | 支持 |
81
+ | 通知托管 | 支持 | 支持 | 支持 | 支持 |
82
+ | 请求 / 会话统计 | 支持 | 支持 | 支持 | 支持 |
83
+
84
+ 补充说明:
85
+
86
+ - Codex Agents 目前仅支持用户级代理
87
+ - OpenCode 会话读取依赖本机 `sqlite3`
88
+ - Commands 的直接 CRUD 当前面向 Claude / OpenCode
89
89
 
90
90
  ## 安装
91
91
 
92
- ### 方式 1:全局安装
92
+ ### 全局安装
93
93
 
94
94
  ```bash
95
95
  npm install -g coding-tool-x
96
96
  ```
97
97
 
98
- ### 方式 2:从源码运行
98
+ ### 国内镜像
99
+
100
+ ```bash
101
+ npm install -g coding-tool-x --registry=https://registry.npmmirror.com
102
+ ```
103
+
104
+ ### 从源码运行
99
105
 
100
106
  ```bash
101
107
  git clone https://github.com/ZeaoZhang/coding-tool.git
@@ -105,54 +111,48 @@ npm run build:web
105
111
  npm link
106
112
  ```
107
113
 
108
- ### 环境要求
114
+ ## 环境要求
109
115
 
110
- - Node.js `>= 14.0.0`(仓库当前 `package.json` 的声明)
111
- - 建议先至少运行过目标 CLI 一次,以便生成其原生配置目录
112
-
113
- ### 验证安装
114
-
115
- ```bash
116
- ctx --version
117
- ctx --help
118
- ```
116
+ - Node.js `>= 14.0.0`
117
+ - 建议至少运行过一次目标 CLI,以便生成原生配置目录
118
+ - 如需读取 OpenCode 会话,请确保系统里有可用的 `sqlite3`
119
119
 
120
120
  ## 快速开始
121
121
 
122
- ### 推荐方式:后台启动整套服务
122
+ ### 推荐方式
123
123
 
124
124
  ```bash
125
125
  ctx start
126
126
  ctx status
127
127
  ```
128
128
 
129
- 默认访问地址:
129
+ 启动后默认访问:
130
130
 
131
131
  - Web UI: `http://localhost:19999`
132
132
 
133
- ### 前台启动 Web UI
133
+ ### 前台运行
134
134
 
135
135
  ```bash
136
136
  ctx ui
137
137
  ```
138
138
 
139
- ### 开启 LAN 访问
139
+ ### 开启局域网访问
140
140
 
141
141
  ```bash
142
142
  ctx ui --host
143
143
  ```
144
144
 
145
- 说明:
145
+ LAN 模式说明:
146
146
 
147
- - `--host` 会让服务监听 `0.0.0.0`
148
- - LAN 模式下,服务端默认阻止远程写操作
149
- - 如确需允许远程写操作,可显式设置环境变量:
147
+ - 服务会监听 `0.0.0.0`
148
+ - 默认只允许本机执行写操作
149
+ - 如确需允许远程写操作,可显式设置:
150
150
 
151
151
  ```bash
152
152
  CC_TOOL_ALLOW_REMOTE_WRITE=true ctx ui --host
153
153
  ```
154
154
 
155
- ### 分平台启动代理
155
+ ### 单独控制平台代理
156
156
 
157
157
  ```bash
158
158
  ctx claude start
@@ -163,98 +163,96 @@ ctx opencode start
163
163
 
164
164
  ## 常用命令
165
165
 
166
- ### 服务与 UI
166
+ ### 服务
167
167
 
168
168
  | 命令 | 说明 |
169
169
  | --- | --- |
170
- | `ctx start` | 后台启动服务(推荐) |
170
+ | `ctx start` | 后台启动整套服务 |
171
171
  | `ctx stop` | 停止后台服务 |
172
172
  | `ctx restart` | 重启后台服务 |
173
173
  | `ctx status` | 查看后台服务状态 |
174
174
  | `ctx ui` | 前台启动 Web UI |
175
- | `ctx ui --host` | 前台启动 Web UI 并允许局域网访问 |
175
+ | `ctx ui start` | 后台启动 Web UI |
176
+ | `ctx ui stop` | 停止后台 Web UI |
177
+ | `ctx ui restart` | 重启后台 Web UI |
176
178
 
177
- ### 分平台代理
179
+ ### 平台代理
178
180
 
179
181
  | 命令 | 说明 |
180
182
  | --- | --- |
181
- | `ctx claude start|stop|restart|status` | Claude 代理管理 |
182
- | `ctx codex start|stop|restart|status` | Codex 代理管理 |
183
- | `ctx gemini start|stop|restart|status` | Gemini 代理管理 |
184
- | `ctx opencode start|stop|restart|status` | OpenCode 代理管理 |
183
+ | `ctx claude start\|stop\|restart\|status` | Claude 代理管理 |
184
+ | `ctx codex start\|stop\|restart\|status` | Codex 代理管理 |
185
+ | `ctx gemini start\|stop\|restart\|status` | Gemini 代理管理 |
186
+ | `ctx opencode start\|stop\|restart\|status` | OpenCode 代理管理 |
185
187
 
186
- ### 日志、统计、诊断
188
+ ### 日志与统计
187
189
 
188
190
  | 命令 | 说明 |
189
191
  | --- | --- |
190
- | `ctx logs` | 查看全部日志 |
192
+ | `ctx logs` | 查看所有日志 |
191
193
  | `ctx logs ui` | 查看 UI 日志 |
192
194
  | `ctx logs claude` | 查看 Claude 代理日志 |
193
195
  | `ctx logs --follow` | 实时追踪日志 |
194
196
  | `ctx logs --lines 100` | 查看最近 100 行 |
195
197
  | `ctx logs --clear` | 清空日志 |
196
198
  | `ctx stats` | 查看总体统计 |
197
- | `ctx stats claude` | 查看某个平台统计 |
199
+ | `ctx stats claude` | 查看单个平台统计 |
198
200
  | `ctx stats export` | 导出统计数据 |
199
- | `ctx doctor` | 运行系统诊断 |
201
+ | `ctx doctor` | 运行环境诊断 |
200
202
 
201
- ### 配置与维护
203
+ ### 其他
202
204
 
203
205
  | 命令 | 说明 |
204
206
  | --- | --- |
205
207
  | `ctx update` | 检查并更新版本 |
206
- | `ctx port` | 配置默认端口 |
207
- | `ctx reset` | 重置 cc-tool 配置 |
208
- | `ctx security reset` | 清除 Web UI 访问密码 |
208
+ | `ctx port` | 修改默认端口 |
209
+ | `ctx reset` | 重置 `~/.cc-tool` 配置 |
210
+ | `ctx security reset` | 关闭面板访问密码 |
209
211
  | `ctx plugin list` | 查看已安装插件 |
210
212
  | `ctx plugin install <git-url>` | 从 Git 安装插件 |
211
213
 
212
- ### 兼容命令
214
+ 兼容说明:
213
215
 
214
- `ctx proxy start|stop|status` 仍然保留,但它是偏旧的 Claude 兼容入口。当前更推荐使用按平台拆分的命令:`ctx claude ...`、`ctx codex ...`、`ctx gemini ...`、`ctx opencode ...`。
216
+ - `ctx proxy start|stop|status` 仍保留为旧入口
217
+ - 新用法更推荐 `ctx claude ...`、`ctx codex ...`、`ctx gemini ...`、`ctx opencode ...`
215
218
 
216
219
  ## Web UI 主要模块
217
220
 
218
- ### 首页 Dashboard
221
+ ### Home / Dashboard
219
222
 
220
- - 四个平台列式面板
221
- - 拖拽排序
222
- - 代理状态
223
- - 实时日志
224
- - 快捷操作
223
+ - 四个平台并列状态卡
224
+ - 支持拖拽调整平台顺序
225
+ - 展示代理状态、今日请求、Token、费用、项目数、会话数
225
226
 
226
- ### 项目 / 会话
227
+ ### 项目与会话
227
228
 
228
- - 项目列表与排序
229
- - 最近会话
230
- - 全局搜索
231
- - 会话别名
232
- - 会话 Fork
233
- - 会话详情查看
229
+ - 项目列表、会话列表
230
+ - 全局搜索和项目内搜索
231
+ - 聊天历史查看
232
+ - 收藏、别名、删除、复制启动命令,部分平台支持 Fork
234
233
 
235
- ### 工作区
234
+ ### 配置管理
236
235
 
237
- - 聚合多个项目为一个工作区
238
- - 支持为 Git 仓库创建 worktree
239
- - 支持使用工作区内配置模版
240
-
241
- ### 配置与扩展
242
-
243
- - Config Templates
244
236
  - Prompts
237
+ - MCP
245
238
  - Skills
246
239
  - Commands
247
240
  - Agents
248
- - MCP
249
241
  - Plugins
250
242
  - OAuth Credentials
251
243
  - Config Export / Import
252
244
 
245
+ ### 工作区与模板
246
+
247
+ - Workspaces
248
+ - Config Templates
249
+ - Git worktree 组织
250
+
253
251
  ### Analytics
254
252
 
255
- - 多平台统一统计
253
+ - 多平台统计汇总
256
254
  - 模型 / 渠道 / 工具维度分析
257
- - 1d / 3d / 7d / 30d / 90d / 自定义区间
255
+ - 时间范围筛选
258
256
  - CSV / JSON 导出
259
257
 
260
258
  ## 默认端口
@@ -269,40 +267,34 @@ ctx opencode start
269
267
 
270
268
  可通过 `ctx port` 修改。
271
269
 
272
- ## 目录与数据存放
270
+ ## 数据目录
273
271
 
274
- ### Coding-Tool-X 中央目录
272
+ ### 中央目录
275
273
 
276
- 默认集中存放在:
274
+ 默认位于:
277
275
 
278
276
  ```text
279
277
  ~/.cc-tool
280
278
  ```
281
279
 
282
- 其中常见文件/目录包括:
280
+ 常见内容:
283
281
 
284
- - `config/`:主配置、UI 配置、Prompts、MCP、OAuth、工作区等集中配置
285
- - `storage/`:渠道、运行时状态、统计、缓存、请求快照、托管 skills 仓库等内部数据
286
- - `logs/`:日志
287
- - `configs/`:同步管理的 skills / commands / agents / plugins
288
- - `plugins/`:插件安装与插件配置
282
+ - `config/`: 主配置、Prompts、MCP、OAuth、工作区、模板等
283
+ - `configs/`: 托管的 skills / commands / agents / plugins
284
+ - `storage/`: 渠道、缓存、统计、内部运行数据
285
+ - `logs/`: 服务与代理日志
286
+ - `plugins/`: 插件安装与插件配置
289
287
 
290
- ### 平台原生配置目录
288
+ ### 原生配置目录
291
289
 
292
- 工具会继续读写各平台的原生配置目录:
290
+ 项目会继续读写各平台原生配置:
293
291
 
294
- - Claude:`~/.claude`
295
- - Codex:`${CODEX_HOME:-~/.codex}`
296
- - Gemini:`~/.gemini`
297
- - OpenCode:按系统/XDG 规则解析,常见为:
298
- - 配置:`~/.config/opencode`
299
- - 数据:`~/.local/share/opencode`
300
-
301
- 说明:
302
-
303
- - Coding-Tool-X 负责集中管理与同步
304
- - 平台自身仍然可以直接使用原生目录
305
- - 仓库内实现对旧的 `~/.claude/cc-tool` 数据做自动迁移
292
+ - Claude: `~/.claude`
293
+ - Codex: `${CODEX_HOME:-~/.codex}`
294
+ - Gemini: `~/.gemini`
295
+ - OpenCode:
296
+ - 配置: `~/.config/opencode`
297
+ - 数据: `~/.local/share/opencode`
306
298
 
307
299
  ## 开发
308
300
 
@@ -336,24 +328,13 @@ npm run build:web
336
328
  npm test
337
329
  ```
338
330
 
339
- 当前仓库内置的测试覆盖了基础命令、API 一致性、Codex agents 与 skills provider 回归。
340
-
341
- ## 与上游仓库的关系
342
-
343
- 本仓库不是对上游 README 的原样搬运,而是在 [CooperJiang/coding-tool](https://github.com/CooperJiang/coding-tool) 的基础上继续演进。当前代码相较原始项目,重点扩展在:
344
-
345
- - 四平台统一支持:Claude / Codex / Gemini / OpenCode
346
- - 分平台代理与统计体系
347
- - OpenCode 网关适配、会话转换与导出
348
- - Skills / Commands / Agents / Prompts / MCP 的集中管理
349
- - OAuth 凭证管理与原生配置同步
350
- - 工作区、Git worktree、配置模板、配置导入导出
351
- - 更完整的 Dashboard 与 Analytics 面板
331
+ 当前仓库内置了基础命令、API 一致性、Codex Agents、Skills Provider、插件市场缓存等相关回归测试。
352
332
 
353
333
  ## 已知说明
354
334
 
355
- - `ctx ui --host` 开启 LAN 访问时,默认不允许远程写操作,这是服务端的安全保护,不是故障。
356
- - 部分高级能力依赖目标平台本身的原生目录存在;首次使用前请先启动对应 CLI。
335
+ - `ctx ui --host` 开启 LAN 访问后,默认不会允许远程写操作,这是安全保护行为
336
+ - OpenCode 部分能力依赖本机可访问的 OpenCode 配置目录和 `sqlite3`
337
+ - 配置导出包可能包含 API Key、Webhook、OAuth 等敏感信息,请妥善保管
357
338
 
358
339
  ## 相关文档
359
340
 
@@ -361,6 +342,12 @@ npm test
361
342
  - [docs/multi-channel-load-balancing.md](docs/multi-channel-load-balancing.md)
362
343
  - [src/web/README.md](src/web/README.md)
363
344
 
345
+ ## 致谢
346
+
347
+ 特别感谢 [CooperJiang/coding-tool](https://github.com/CooperJiang/coding-tool) 提供的项目基础。`coding-tool-x` 在原有能力之上持续扩展,补齐了多平台支持、配置同步、扩展管理、工作区编排与分析面板等增强能力;没有上游项目打下的基础,这个增强型分支也很难持续演进。
348
+
349
+ 也感谢所有在使用、反馈、测试和持续完善这个分支过程中提供帮助的贡献者与用户。正是这些真实场景下的需求、问题和建议,让这个项目逐步从单一工具发展成更完整的 Coding CLI 工作台。
350
+
364
351
  ## License
365
352
 
366
353
  [MIT](LICENSE)
@@ -1,4 +1,4 @@
1
- import{d as t,t as e,A as n,l as i,Q as r,f as o,g as a,w as s,B as l,h as u,i as h,v as c,aa as p,N as d,r as f,c as g,o as v,a as y,W as m,X as _,F as x,$ as w,a0 as b,Y as S,p as M,_ as T,L as C}from"./vue-vendor-3bf-fPGP.js";import{_ as I,y as D,z as k,A}from"./index-EMrm1wk-.js";import{L as P,$ as L,k as O,B as R,N as z,F as E,g as N}from"./naive-ui-Bdxp09n2.js";import{a3 as B,aA as F,aB as V}from"./icons-B5Pl4lrD.js";import"./markdown-DyTJGI4N.js";import"./vendors-CKPV1OAU.js";
1
+ import{d as t,t as e,A as n,l as i,Q as r,f as o,g as a,w as s,B as l,h as u,i as h,v as c,aa as p,N as d,r as f,c as g,o as v,a as y,W as m,X as _,F as x,$ as w,a0 as b,Y as S,p as M,_ as T,L as C}from"./vue-vendor-3bf-fPGP.js";import{_ as I,x as D,y as k,z as A}from"./index-B1ujw2sM.js";import{L as P,$ as L,k as O,B as R,N as z,F as E,g as N}from"./naive-ui-Bdxp09n2.js";import{a3 as B,aA as F,aB as V}from"./icons-B5Pl4lrD.js";import"./markdown-DyTJGI4N.js";import"./vendors-CKPV1OAU.js";
2
2
  /*! *****************************************************************************
3
3
  Copyright (c) Microsoft Corporation.
4
4
 
@@ -1 +1 @@
1
- import{_ as s,x as a}from"./index-EMrm1wk-.js";import{c as e,o,X as r,Y as t,N as i}from"./vue-vendor-3bf-fPGP.js";import{K as d}from"./naive-ui-Bdxp09n2.js";import"./vendors-CKPV1OAU.js";import"./markdown-DyTJGI4N.js";import"./icons-B5Pl4lrD.js";const m={class:"config-templates-page"},p=s({__name:"ConfigTemplates",setup:s=>(s,p)=>(o(),e("div",m,[r(i(d),{title:"配置模版管理",bordered:!1},{default:t(()=>[r(a,{"in-drawer":!1,"hide-back":!0})]),_:1})]))},[["__scopeId","data-v-a6c39fe5"]]);export{p as default};
1
+ import{_ as s,w as a}from"./index-B1ujw2sM.js";import{c as e,o,X as r,Y as t,N as i}from"./vue-vendor-3bf-fPGP.js";import{K as d}from"./naive-ui-Bdxp09n2.js";import"./vendors-CKPV1OAU.js";import"./markdown-DyTJGI4N.js";import"./icons-B5Pl4lrD.js";const m={class:"config-templates-page"},p=s({__name:"ConfigTemplates",setup:s=>(s,p)=>(o(),e("div",m,[r(i(d),{title:"配置模版管理",bordered:!1},{default:t(()=>[r(a,{"in-drawer":!1,"hide-back":!0})]),_:1})]))},[["__scopeId","data-v-a6c39fe5"]]);export{p as default};
@@ -1 +1 @@
1
- import{d as e}from"./vendors-CKPV1OAU.js";import{a8 as a,f as l,r as n,w as s,h as c,K as t,a7 as o,c as i,o as u,a as d,W as r,X as v,Y as p,N as h,a0 as y,a3 as g,_ as k,p as m,L as f,F as T,$ as b,Z as x,v as C}from"./vue-vendor-3bf-fPGP.js";import{_ as w,u as $,a as _,R as q,g as z,b as S,c as L,d as I,e as j,f as O,h as N,i as M,j as A,k as F,l as D,s as P}from"./index-EMrm1wk-.js";import{E as U,o as E,n as V,m as J,ar as K,as as G,at as R,au as Z,av as B,a9 as H,i as W,A as X,aw as Y,ax as Q,T as ee,a as ae,b as le}from"./icons-B5Pl4lrD.js";import{L as ne,N as se,B as ce,s as te,b as oe,c as ie,a as ue,Z as de}from"./naive-ui-Bdxp09n2.js";import"./markdown-DyTJGI4N.js";const re={class:"channel-column"},ve={class:"drag-handle",title:"拖拽排序"},pe={class:"header-icon"},he={class:"channel-title"},ye={key:0,class:"claude-extra-area"},ge={key:0,class:"channel-content"},ke={class:"card"},me={class:"card-header"},fe={key:0,class:"runtime-badge"},Te={class:"card-body",style:{padding:"6px 10px"}},be={class:"proxy-info-row"},xe={class:"proxy-status"},Ce={class:"proxy-port"},we={class:"channel-name"},$e={class:"channel-quick-panel"},_e={class:"panel-title"},qe={key:0,class:"no-channels"},ze={key:1,class:"channel-quick-list"},Se={class:"channel-quick-info"},Le={class:"channel-quick-name"},Ie={key:0,class:"channel-switching-tip"},je={class:"channel-metrics"},Oe={class:"metric-item"},Ne={class:"metric-value"},Me={class:"metric-item"},Ae={class:"metric-value"},Fe={class:"metric-item"},De={class:"metric-value"},Pe={class:"metric-item"},Ue={class:"card"},Ee={class:"card-header compact"},Ve={class:"card-body",style:{padding:"8px 10px"}},Je={class:"quick-access-list"},Ke={class:"access-icon"},Ge={class:"access-content"},Re={class:"access-value"},Ze={class:"access-icon"},Be={class:"access-content"},He={class:"access-value"},We={class:"access-icon"},Xe={class:"access-content"},Ye={class:"access-goto"},Qe={class:"card-header compact"},ea={class:"card-body",style:{padding:"8px 10px"}},aa={class:"stats-inline stats-3col"},la={class:"stat-inline-item stat-requests"},na={class:"stat-info"},sa={class:"stat-inline-item stat-input"},ca={class:"stat-info"},ta={class:"stat-inline-item stat-output"},oa={class:"stat-info"},ia={key:1,class:"card logs-card"},ua={class:"card-header compact"},da={class:"card-body logs-card-body"},ra={class:"logs-table-wrapper"},va={key:0,class:"empty-logs"},pa={key:0,class:"action-content"},ha={class:"action-msg"},ya={class:"action-time"},ga={key:1,class:"action-content"},ka={class:"action-msg error-msg"},ma={class:"action-time error-time"},fa={class:"locked-content"},Ta={class:"lock-icon"},ba="channelLocks",xa=w({__name:"ChannelColumn",props:{channelType:{type:String,required:!0,validator:e=>["claude","codex","gemini","opencode"].includes(e)}},setup(e){const w=e,D=a(),P=ne(),{claudeProxy:xa,codexProxy:Ca,geminiProxy:wa,opencodeProxy:$a,claudeChannels:_a,codexChannels:qa,geminiChannels:za,opencodeChannels:Sa,schedulerState:La,getProxyState:Ia,startProxy:ja,stopProxy:Oa,getLogs:Na,clearLogsForSource:Ma,loadChannels:Aa,logLimit:Fa,statsInterval:Da}=$(),{dashboardData:Pa,loadDashboard:Ua}=_(),Ea={claude:{title:"ClaudeCode",subtitle:"智能编程助手",icon:J},codex:{title:"Codex-CLI",subtitle:"高效代码生成",icon:V},gemini:{title:"Gemini-CLI",subtitle:"多模态AI助手",icon:E},opencode:{title:"OpenCode",subtitle:"AI 代码助手",icon:U}},Va=l(()=>Ea[w.channelType].title);l(()=>Ea[w.channelType].subtitle);const Ja=l(()=>Ea[w.channelType].icon),Ka=l(()=>"claude"===w.channelType?xa.value:"codex"===w.channelType?Ca.value:"gemini"===w.channelType?wa.value:"opencode"===w.channelType?$a.value:{}),Ga=l(()=>"claude"===w.channelType?"Claude":"codex"===w.channelType?"Codex":"gemini"===w.channelType?"Gemini":"opencode"===w.channelType?"OpenCode":""),Ra=n({projects:0,sessions:0}),Za=n({requests:0,tokens:0,cost:0}),Ba=n({requests:0,tokens:0,cost:0}),Ha={requests:0,tokens:0,cost:3};let Wa={requests:null,tokens:null,cost:null};const Xa=n({requests:!1,tokens:!1,cost:!1}),Ya=l(()=>{var e,a,l;const n="claude"===w.channelType?"claude":"codex"===w.channelType?"codex":"opencode"===w.channelType?"opencode":"gemini";return(null==(l=null==(a=null==(e=Pa.value)?void 0:e.todayStats)?void 0:a[n])?void 0:l.byModel)||{}});function Qa(e,a,l,n=600){Wa[e]&&cancelAnimationFrame(Wa[e]),Xa.value[e]=!0;const s=Date.now(),c=()=>{const t=Date.now()-s,o=Math.min(t/n,1),i=1-Math.pow(1-o,2),u=a+(l-a)*i,d=Ha[e]??0,r=Math.pow(10,d),v=d>0?Math.round(u*r)/r:Math.round(u);Ba.value[e]=v,o<1?Wa[e]=requestAnimationFrame(c):Xa.value[e]=!1};Wa[e]=requestAnimationFrame(c)}const el=n(!1);function al(e){try{const a=localStorage.getItem(ba),l=a?JSON.parse(a):{};l[w.channelType]=e,localStorage.setItem(ba,JSON.stringify(l))}catch(a){}}const ll=n(function(){try{const e=localStorage.getItem(ba);if(e){return JSON.parse(e)[w.channelType]||!1}}catch(e){}return!1}());async function nl(){ll.value=!ll.value,al(ll.value);try{if(await F("channelLocks",w.channelType,ll.value),Pa.value){const e=Pa.value.uiConfig||{},a={...e.channelLocks||{}};a[w.channelType]=ll.value,Pa.value={...Pa.value,uiConfig:{...e,channelLocks:a}}}}catch(e){}}const sl=n(!0);function cl(e){e.detail&&void 0!==e.detail.showLogs&&(sl.value=e.detail.showLogs)}const tl=n(Date.now()),ol=l(()=>{if(!Ka.value.running)return"";const e=Ka.value.startTime;if(!e)return"";const a=tl.value-e;if(a<=0)return"";const l=Math.floor(a/1e3),n=Math.floor(l/3600),s=Math.floor(l%3600/60),c=l%60;let t="已运行 ";return n>0&&(t+=`${n}小时`),s>0&&(t+=`${s}分`),(c>0||0===n&&0===s)&&(t+=`${c}秒`),t}),il=n(null),ul=l(()=>Fa.value),dl={claude:Na("claude"),codex:Na("codex"),gemini:Na("gemini"),opencode:Na("opencode")},rl=l(()=>((dl[w.channelType]||dl.claude).value||[]).slice(0,ul.value));let vl=null,pl=null,hl=null,yl=!1,gl=null;const kl=l(()=>{let e=[];"claude"===w.channelType?e=_a.value||[]:"codex"===w.channelType?e=qa.value||[]:"gemini"===w.channelType?e=za.value||[]:"opencode"===w.channelType&&(e=Sa.value||[]);return[...e.filter(e=>!1!==e.enabled),...e.filter(e=>!1===e.enabled)]});function ml(e){const a=La[w.channelType];if(!a||!a.channels)return 0;const l=a.channels.find(a=>a.id===e);return l?l.inflight:0}const fl=l(()=>{var e;const a=kl.value.filter(e=>!1!==e.enabled).length;return(null==(e=Ka.value.proxy)?void 0:e.running)?`${a}个渠道调度中`:kl.value.length>0?`${a}个渠道已启用`:"无渠道"}),Tl=n({});function bl(e){return Tl.value[e]||{requests:0,tokens:0,cost:0}}async function xl(){var e;try{let a;if("claude"===w.channelType?a=await z():"codex"===w.channelType?a=await S():"gemini"===w.channelType?a=await L():"opencode"===w.channelType&&(a=await I()),a&&a.byChannel){const l={};for(const[n,s]of Object.entries(a.byChannel))l[n]={requests:s.requests||0,tokens:(null==(e=s.tokens)?void 0:e.total)||0,cost:s.cost||0};Tl.value=l}}catch(a){}}async function Cl(e){var a,l;const n=Ia(w.channelType);n.value.loading=!0;try{let a;a=e?await ja(w.channelType):await Oa(w.channelType,{refreshChannelsDrawer:!0}),!1!==a.success?P.success(e?`${Va.value} 代理已启动`:`${Va.value} 代理已停止`):(P.error(a.error||"操作失败"),n.value.running=!e)}catch(s){P.error((null==(l=null==(a=s.response)?void 0:a.data)?void 0:l.error)||s.message||"操作失败"),n.value.running=!e}finally{n.value.loading=!1}}function wl(){D.push({name:`${w.channelType}-projects`})}function $l(){D.push({name:`${w.channelType}-projects`})}s(rl,e=>{var a;const l=(null==(a=e[0])?void 0:a.id)||null;if(!l||l===vl)return void(vl=l);vl=l,gl&&clearTimeout(gl),gl=setTimeout(()=>{xl()},5e3);(!il.value||il.value.scrollTop<20)&&C(()=>{il.value&&(il.value.scrollTop=0)})}),s(()=>Za.value.requests,e=>{Qa("requests",Ba.value.requests,e,600)}),s(()=>Za.value.tokens,e=>{Qa("tokens",Ba.value.tokens,e,600)}),s(()=>Za.value.cost,e=>{Qa("cost",Ba.value.cost,e,600)}),s(()=>w.channelType,()=>{var e;vl=(null==(e=rl.value[0])?void 0:e.id)||null}),s(()=>{var e,a;return null==(a=null==(e=Pa.value)?void 0:e.counts)?void 0:a[w.channelType]},()=>{Sl()}),s(Da,()=>{yl&&function(){pl&&(clearInterval(pl),pl=null);const e=Da.value||30,a=Math.max(1e3*e,1e4);pl=setInterval(()=>{Ll(),xl()},a)}()});const _l=n({});function ql(e){return!!_l.value[e]}function zl(e,a){e&&(_l.value={..._l.value,[e]:!!a})}function Sl(){var e,a;const l=null==(a=null==(e=Pa.value)?void 0:e.counts)?void 0:a[w.channelType];Ra.value.projects=(null==l?void 0:l.projectCount)||0,Ra.value.sessions=(null==l?void 0:l.sessionCount)||0}async function Ll(){if(Pa.value&&Pa.value.todayStats){const e=Pa.value.todayStats[w.channelType];e&&(Za.value.requests=e.requests||0,Za.value.tokens=e.tokens||0,Za.value.cost=e.cost||0)}Sl()}function Il(){Ma(w.channelType)}function jl(){window.dispatchEvent(new CustomEvent("open-skills-drawer",{detail:{platform:w.channelType}}))}return c(async()=>{await Promise.all([Ua().then(()=>Ll()),xl()]),async function(){var e,a;try{if(Pa.value&&Pa.value.uiConfig)sl.value=!1!==(null==(e=Pa.value.uiConfig.panelVisibility)?void 0:e.showLogs);else{const e=await j();e.success&&e.config&&(sl.value=!1!==(null==(a=e.config.panelVisibility)?void 0:a.showLogs))}}catch(l){}}(),async function(){var e,a;try{let l=!1;if(Pa.value&&Pa.value.uiConfig)l=(null==(e=Pa.value.uiConfig.channelLocks)?void 0:e[w.channelType])||!1;else{const e=await j();e.success&&e.config&&(l=(null==(a=e.config.channelLocks)?void 0:a[w.channelType])||!1)}ll.value=l,al(l)}catch(l){}}(),window.addEventListener("panel-visibility-change",cl),Ba.value={...Za.value},yl=!0,hl=setInterval(()=>{tl.value=Date.now()},1e3)}),t(()=>{yl=!1,pl&&clearInterval(pl),hl&&clearInterval(hl),gl&&clearTimeout(gl),window.removeEventListener("panel-visibility-change",cl),Object.values(Wa).forEach(e=>{e&&cancelAnimationFrame(e)})}),(a,l)=>{const n=o("n-collapse");return u(),i("div",re,[d("div",{class:f(["channel-header",e.channelType])},[d("div",ve,[v(h(se),{size:16},{default:p(()=>[v(h(K))]),_:1})]),d("div",pe,[v(h(se),{size:20},{default:p(()=>[(u(),y(g(Ja.value)))]),_:1})]),d("h2",he,k(Va.value),1),["claude","codex","gemini","opencode"].includes(e.channelType)?(u(),i("div",ye,[v(h(te),{trigger:"hover"},{trigger:p(()=>[v(h(ce),{text:"",class:"skills-button",onClick:jl,title:"Skills 技能管理"},{icon:p(()=>[v(h(se),{size:18},{default:p(()=>[v(h(U))]),_:1})]),_:1})]),default:p(()=>[l[3]||(l[3]=m(" Skills 技能管理 ",-1))]),_:1})])):r("",!0),v(h(ce),{text:"",class:"lock-button",onClick:nl,title:ll.value?"解锁此列":"锁定此列"},{icon:p(()=>[v(h(se),{size:18},{default:p(()=>[ll.value?(u(),y(h(G),{key:0})):(u(),y(h(R),{key:1}))]),_:1})]),_:1},8,["title"])],2),ll.value?r("",!0):(u(),i("div",ge,[d("div",ke,[d("div",me,[v(h(se),{size:16},{default:p(()=>[v(h(Z))]),_:1}),l[4]||(l[4]=d("h3",{class:"card-title"},"代理控制",-1)),Ka.value.running&&ol.value?(u(),i("span",fe,k(ol.value),1)):r("",!0),v(h(oe),{value:Ka.value.running,"onUpdate:value":[l[0]||(l[0]=e=>Ka.value.running=e),Cl],loading:Ka.value.loading,size:"small",style:{"margin-left":"auto"}},null,8,["value","loading"])]),d("div",Te,[d("div",be,[d("div",xe,[d("div",{class:f(["status-dot",{active:Ka.value.running}])},null,2),v(h(ie),{type:Ka.value.running?"success":"default",style:{"font-size":"12px"}},{default:p(()=>[m(k(Ka.value.running?"运行中":"已停止"),1)]),_:1},8,["type"]),d("span",Ce,"端口: "+k(Ka.value.port),1)]),v(h(de),{trigger:"click",placement:"bottom",width:320,class:"channel-popover"},{trigger:p(()=>[v(h(ce),{text:"",size:"tiny",class:"channel-status"},{default:p(()=>[d("span",we,k(fl.value),1)]),_:1})]),default:p(()=>[d("div",$e,[d("div",_e,[l[6]||(l[6]=d("span",null,"渠道快捷管理",-1)),v(h(ie),{depth:"3",style:{"font-size":"11px"}},{default:p(()=>[...l[5]||(l[5]=[m("点击开关切换状态",-1)])]),_:1})]),0===kl.value.length?(u(),i("div",qe,[v(h(ie),{depth:"3"},{default:p(()=>[...l[7]||(l[7]=[m("暂无配置渠道",-1)])]),_:1})])):(u(),i("div",ze,[(u(!0),i(T,null,b(kl.value,e=>{var a,n;return u(),i("div",{key:e.id,class:f(["channel-quick-item",{disabled:!1===e.enabled}])},[d("div",Se,[d("span",Le,k(e.name),1),"frozen"===(null==(a=e.health)?void 0:a.status)?(u(),y(h(ue),{key:0,size:"tiny",type:"error",bordered:!1},{default:p(()=>[...l[8]||(l[8]=[m(" 冻结 ",-1)])]),_:1})):r("",!0),v(h(oe),{size:"small",value:!1!==e.enabled,"onUpdate:value":a=>async function(e,a){if(e&&!ql(e.id)){zl(e.id,!0);try{let l;"claude"===w.channelType?l=O:"codex"===w.channelType?l=N:"gemini"===w.channelType?l=M:"opencode"===w.channelType&&(l=A),l&&(await l(e.id,{enabled:a}),P.success(a?`渠道「${e.name}」已启用`:`渠道「${e.name}」已停用`),await Aa())}catch(l){P.error("操作失败: "+l.message)}finally{zl(e.id,!1)}}}(e,a),loading:ql(e.id),disabled:ql(e.id),style:{"margin-left":"auto"}},null,8,["value","onUpdate:value","loading","disabled"])]),ql(e.id)?(u(),i("div",Ie," 正在切换渠道状态... ")):r("",!0),d("div",je,[d("span",Oe,[l[9]||(l[9]=d("span",{class:"metric-label"},"请求",-1)),d("span",Ne,k(bl(e.id).requests),1)]),d("span",Me,[l[10]||(l[10]=d("span",{class:"metric-label"},"Tokens",-1)),d("span",Ae,k((n=bl(e.id).tokens,n>=1e6?(n/1e6).toFixed(1)+"M":n>=1e3?(n/1e3).toFixed(1)+"K":n.toString())),1)]),d("span",Fe,[l[11]||(l[11]=d("span",{class:"metric-label"},"权重",-1)),d("span",De,k(e.weight||1),1)]),d("span",Pe,[l[12]||(l[12]=d("span",{class:"metric-label"},"并发",-1)),d("span",{class:f(["metric-value",{active:ml(e.id)>0}])},k(ml(e.id))+k(e.maxConcurrency?`/${e.maxConcurrency}`:""),3)])])],2)}),128))]))])]),_:1})])])]),d("div",Ue,[d("div",Ee,[v(h(se),{size:14},{default:p(()=>[v(h(B))]),_:1}),l[13]||(l[13]=d("h3",{class:"card-title"},"快速访问",-1))]),d("div",Ve,[d("div",Je,[d("div",{class:"access-card access-card-projects clickable",onClick:wl},[d("div",Ke,[v(h(se),{size:16},{default:p(()=>[v(h(H))]),_:1})]),d("div",Ge,[l[14]||(l[14]=d("span",{class:"access-label"},"项目",-1)),d("span",Re,k(Ra.value.projects),1)])]),d("div",{class:"access-card access-card-sessions clickable",onClick:l[1]||(l[1]=e=>el.value=!0)},[d("div",Ze,[v(h(se),{size:16},{default:p(()=>[v(h(W))]),_:1})]),d("div",Be,[l[15]||(l[15]=d("span",{class:"access-label"},"最新对话",-1)),d("span",He,k(Ra.value.sessions),1)])]),d("div",{class:"access-card access-card-goto clickable",onClick:$l},[d("div",We,[v(h(se),{size:16},{default:p(()=>[v(h(X))]),_:1})]),d("div",Xe,[l[16]||(l[16]=d("span",{class:"access-label"},"前往",-1)),d("span",Ye,k(Ga.value),1)])])])])]),d("div",{class:f(["card stats-card",`stats-card-${e.channelType}`])},[d("div",Qe,[v(h(se),{size:14},{default:p(()=>[v(h(Y))]),_:1}),l[17]||(l[17]=d("h3",{class:"card-title"},"今日数据",-1))]),d("div",ea,[d("div",aa,[d("div",la,[l[19]||(l[19]=d("div",{class:"stat-icon-dot requests"},null,-1)),d("div",na,[l[18]||(l[18]=d("span",{class:"stat-label"},"请求",-1)),d("span",{class:f(["stat-value",{animating:Xa.value.requests}])},k(Ba.value.requests),3)])]),d("div",sa,[l[21]||(l[21]=d("div",{class:"stat-icon-dot tokens"},null,-1)),d("div",ca,[l[20]||(l[20]=d("span",{class:"stat-label"},"总 Tokens",-1)),d("span",{class:f(["stat-value",{animating:Xa.value.tokens}])},k((c=Ba.value.tokens,c>=1e6?(c/1e6).toFixed(1)+"M":c>=1e3?(c/1e3).toFixed(1)+"K":c.toString())),3)])]),d("div",ta,[l[23]||(l[23]=d("div",{class:"stat-icon-dot cost"},null,-1)),d("div",oa,[l[22]||(l[22]=d("span",{class:"stat-label"},"成本 / USD",-1)),d("span",{class:f(["stat-value",{animating:Xa.value.cost}])},k((s=Ba.value.cost,!s||Number.isNaN(s)?"$0":"$"+Number(s).toFixed(3))),3)])])])])],2),Object.keys(Ya.value).length>0?(u(),i("div",{key:0,class:f(["card chart-card",`chart-card-${e.channelType}`])},[v(n,{"default-expanded-names":[],accordion:""})],2)):r("",!0),sl.value?(u(),i("div",ia,[d("div",ua,[v(h(se),{size:14},{default:p(()=>[v(h(Q))]),_:1}),l[24]||(l[24]=d("h3",{class:"card-title"},"实时日志",-1)),v(h(ce),{text:"",size:"tiny",onClick:x(Il,["stop"]),style:{"margin-left":"auto"},title:"清空日志"},{icon:p(()=>[v(h(se),{size:14},{default:p(()=>[v(h(ee))]),_:1})]),_:1})]),d("div",da,[d("div",ra,[d("div",{class:f(["logs-table-header",`logs-header-${e.channelType}`])},[d("div",{class:f(["log-col col-channel",`col-channel-${e.channelType}`])},"渠道",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"请求",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"回复",2),"claude"===e.channelType?(u(),i(T,{key:0},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"写入",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"命中",2)],64)):"codex"===e.channelType?(u(),i(T,{key:1},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"推理",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):"gemini"===e.channelType?(u(),i(T,{key:2},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):"opencode"===e.channelType?(u(),i(T,{key:3},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"推理",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):r("",!0),d("div",{class:f(["log-col col-time",`col-time-${e.channelType}`])},"时间",2)],2),d("div",{class:"logs-container",ref_key:"logsContainer",ref:il},[0===rl.value.length?(u(),i("div",va,[v(h(se),{size:32,depth:"3",style:{"margin-bottom":"8px"}},{default:p(()=>[v(h(Q))]),_:1}),v(h(ie),{depth:"3",style:{"font-size":"12px","font-weight":"500"}},{default:p(()=>[...l[25]||(l[25]=[m("暂无实时日志",-1)])]),_:1}),v(h(ie),{depth:"3",style:{"font-size":"11px","margin-top":"4px"}},{default:p(()=>[...l[26]||(l[26]=[m("开启代理后将显示请求记录",-1)])]),_:1})])):r("",!0),(u(!0),i(T,null,b(rl.value,a=>{var l,n,s,c,t,o,y,g,b,x,C,w;return u(),i("div",{key:a.id,class:f(["log-row",{"action-row":"action"===a.type,"error-row":"error"===a.status,"new-log":a.isNew}])},["action"===a.type?(u(),i("div",pa,[v(h(se),{size:12,color:"#18a058"},{default:p(()=>[v(h(ae))]),_:1}),d("span",ha,k(a.message),1),d("span",ya,k(a.time),1)])):"error"===a.status?(u(),i("div",ga,[v(h(se),{size:12,color:"#d03050"},{default:p(()=>[v(h(le))]),_:1}),d("span",ka,k(a.channel)+": "+k(a.error||a.message||"请求失败"),1),d("span",ma,k(a.time),1)])):(u(),i(T,{key:2},[d("div",{class:f(["log-col col-channel",`col-channel-${e.channelType}`])},[v(h(ue),{size:"tiny",type:"success"},{default:p(()=>[m(k(a.channel),1)]),_:2},1024)],2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(l=a.tokens)?void 0:l.input)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(n=a.tokens)?void 0:n.output)||0),3),"claude"===e.channelType?(u(),i(T,{key:0},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(s=a.tokens)?void 0:s.cacheCreation)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(c=a.tokens)?void 0:c.cacheRead)||0),3)],64)):"codex"===e.channelType?(u(),i(T,{key:1},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(t=a.tokens)?void 0:t.reasoning)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(o=a.tokens)?void 0:o.cached)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(y=a.tokens)?void 0:y.total)||0),3)],64)):"gemini"===e.channelType?(u(),i(T,{key:2},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(g=a.tokens)?void 0:g.cached)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(b=a.tokens)?void 0:b.total)||0),3)],64)):"opencode"===e.channelType?(u(),i(T,{key:3},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(x=a.tokens)?void 0:x.reasoning)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(C=a.tokens)?void 0:C.cached)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(w=a.tokens)?void 0:w.total)||0),3)],64)):r("",!0),d("div",{class:f(["log-col col-time",`col-time-${e.channelType}`])},k(a.time),3)],64))],2)}),128))],512)])])])):r("",!0)])),ll.value?(u(),i("div",{key:1,class:f(["locked-overlay",`locked-${e.channelType}`])},[d("div",fa,[d("div",Ta,[v(h(se),{size:48},{default:p(()=>[v(h(G))]),_:1})]),l[28]||(l[28]=d("h3",{class:"locked-title"},"该渠道已锁定",-1)),v(h(ie),{depth:"3",class:"locked-hint"},{default:p(()=>[...l[27]||(l[27]=[m(" 点击上方按钮解锁以查看内容 ",-1)])]),_:1})])],2)):r("",!0),v(q,{visible:el.value,"onUpdate:visible":l[2]||(l[2]=e=>el.value=e),channel:e.channelType},null,8,["visible","channel"])]);var s,c}}},[["__scopeId","data-v-0bad694b"]]),Ca=n({theme:"light",panelVisibility:{showChannels:!0,showLogs:!0},channelLocks:{claude:!1,codex:!1,gemini:!1},channelCollapse:{claude:[],codex:[],gemini:[]},channelOrder:{claude:[],codex:[],gemini:[]}});let wa=!1,$a=null;async function _a(){return wa?Ca.value:$a||($a=(async()=>{try{const e=await j();e.success&&e.config&&(Ca.value=e.config,wa=!0)}catch(e){}finally{$a=null}return Ca.value})(),$a)}const qa={class:"dashboard-container"},za="dashboardChannelOrder",Sa=w({__name:"Home",setup(a){const l=["claude","codex","gemini","opencode"],{uiConfig:s,updateConfig:t,loadUIConfig:o}=(wa||_a(),{uiConfig:Ca,loadUIConfig:_a,saveConfig:async function(e){try{const a=await P(e);return!!a.success&&(Ca.value=a.config,!0)}catch(a){return!1}},updateConfig:async function(e,a){try{const l=await D(e,a);return!!l.success&&(Ca.value=l.config,!0)}catch(l){return!1}},updateNestedConfig:async function(e,a,l){try{const n=await F(e,a,l);return!!n.success&&(Ca.value=n.config,!0)}catch(n){return!1}}});function d(e){try{localStorage.setItem(za,JSON.stringify(e))}catch(a){}}const r=n(function(){try{const e=localStorage.getItem(za);if(e){const a=JSON.parse(e);if(Array.isArray(a)&&4===a.length)return a}}catch(e){}return l}().map(e=>({type:e})));async function g(){const e=r.value.map(e=>e.type);d(e),await t("dashboardChannelOrder",e)}return c(async()=>{if(await o(),s.value.dashboardChannelOrder&&Array.isArray(s.value.dashboardChannelOrder)&&4===s.value.dashboardChannelOrder.length){const e=s.value.dashboardChannelOrder;r.value=e.map(e=>({type:e})),d(e)}}),(a,l)=>(u(),i("div",qa,[v(h(e),{modelValue:r.value,"onUpdate:modelValue":l[0]||(l[0]=e=>r.value=e),class:"dashboard-grid","item-key":"type",animation:200,handle:".drag-handle",onEnd:g},{item:p(({element:e})=>[(u(),y(xa,{"channel-type":e.type,key:e.type},null,8,["channel-type"]))]),_:1},8,["modelValue"])]))}},[["__scopeId","data-v-06100f0f"]]);export{Sa as default};
1
+ import{d as e}from"./vendors-CKPV1OAU.js";import{a8 as a,f as l,r as n,w as s,h as c,K as t,a7 as o,c as i,o as u,a as d,W as r,X as v,Y as p,N as h,a0 as y,a3 as g,_ as k,p as m,L as f,F as T,$ as b,Z as x,v as C}from"./vue-vendor-3bf-fPGP.js";import{_ as w,u as $,a as _,R as q,g as z,b as S,c as L,d as I,e as j,f as O,h as N,i as M,j as A,k as F,l as D,s as P}from"./index-B1ujw2sM.js";import{E as U,o as E,n as V,m as J,ar as K,as as G,at as R,au as Z,av as B,a9 as H,i as W,A as X,aw as Y,ax as Q,T as ee,a as ae,b as le}from"./icons-B5Pl4lrD.js";import{L as ne,N as se,B as ce,s as te,b as oe,c as ie,a as ue,Z as de}from"./naive-ui-Bdxp09n2.js";import"./markdown-DyTJGI4N.js";const re={class:"channel-column"},ve={class:"drag-handle",title:"拖拽排序"},pe={class:"header-icon"},he={class:"channel-title"},ye={key:0,class:"claude-extra-area"},ge={key:0,class:"channel-content"},ke={class:"card"},me={class:"card-header"},fe={key:0,class:"runtime-badge"},Te={class:"card-body",style:{padding:"6px 10px"}},be={class:"proxy-info-row"},xe={class:"proxy-status"},Ce={class:"proxy-port"},we={class:"channel-name"},$e={class:"channel-quick-panel"},_e={class:"panel-title"},qe={key:0,class:"no-channels"},ze={key:1,class:"channel-quick-list"},Se={class:"channel-quick-info"},Le={class:"channel-quick-name"},Ie={key:0,class:"channel-switching-tip"},je={class:"channel-metrics"},Oe={class:"metric-item"},Ne={class:"metric-value"},Me={class:"metric-item"},Ae={class:"metric-value"},Fe={class:"metric-item"},De={class:"metric-value"},Pe={class:"metric-item"},Ue={class:"card"},Ee={class:"card-header compact"},Ve={class:"card-body",style:{padding:"8px 10px"}},Je={class:"quick-access-list"},Ke={class:"access-icon"},Ge={class:"access-content"},Re={class:"access-value"},Ze={class:"access-icon"},Be={class:"access-content"},He={class:"access-value"},We={class:"access-icon"},Xe={class:"access-content"},Ye={class:"access-goto"},Qe={class:"card-header compact"},ea={class:"card-body",style:{padding:"8px 10px"}},aa={class:"stats-inline stats-3col"},la={class:"stat-inline-item stat-requests"},na={class:"stat-info"},sa={class:"stat-inline-item stat-input"},ca={class:"stat-info"},ta={class:"stat-inline-item stat-output"},oa={class:"stat-info"},ia={key:1,class:"card logs-card"},ua={class:"card-header compact"},da={class:"card-body logs-card-body"},ra={class:"logs-table-wrapper"},va={key:0,class:"empty-logs"},pa={key:0,class:"action-content"},ha={class:"action-msg"},ya={class:"action-time"},ga={key:1,class:"action-content"},ka={class:"action-msg error-msg"},ma={class:"action-time error-time"},fa={class:"locked-content"},Ta={class:"lock-icon"},ba="channelLocks",xa=w({__name:"ChannelColumn",props:{channelType:{type:String,required:!0,validator:e=>["claude","codex","gemini","opencode"].includes(e)}},setup(e){const w=e,D=a(),P=ne(),{claudeProxy:xa,codexProxy:Ca,geminiProxy:wa,opencodeProxy:$a,claudeChannels:_a,codexChannels:qa,geminiChannels:za,opencodeChannels:Sa,schedulerState:La,getProxyState:Ia,startProxy:ja,stopProxy:Oa,getLogs:Na,clearLogsForSource:Ma,loadChannels:Aa,logLimit:Fa,statsInterval:Da}=$(),{dashboardData:Pa,loadDashboard:Ua}=_(),Ea={claude:{title:"ClaudeCode",subtitle:"智能编程助手",icon:J},codex:{title:"Codex-CLI",subtitle:"高效代码生成",icon:V},gemini:{title:"Gemini-CLI",subtitle:"多模态AI助手",icon:E},opencode:{title:"OpenCode",subtitle:"AI 代码助手",icon:U}},Va=l(()=>Ea[w.channelType].title);l(()=>Ea[w.channelType].subtitle);const Ja=l(()=>Ea[w.channelType].icon),Ka=l(()=>"claude"===w.channelType?xa.value:"codex"===w.channelType?Ca.value:"gemini"===w.channelType?wa.value:"opencode"===w.channelType?$a.value:{}),Ga=l(()=>"claude"===w.channelType?"Claude":"codex"===w.channelType?"Codex":"gemini"===w.channelType?"Gemini":"opencode"===w.channelType?"OpenCode":""),Ra=n({projects:0,sessions:0}),Za=n({requests:0,tokens:0,cost:0}),Ba=n({requests:0,tokens:0,cost:0}),Ha={requests:0,tokens:0,cost:3};let Wa={requests:null,tokens:null,cost:null};const Xa=n({requests:!1,tokens:!1,cost:!1}),Ya=l(()=>{var e,a,l;const n="claude"===w.channelType?"claude":"codex"===w.channelType?"codex":"opencode"===w.channelType?"opencode":"gemini";return(null==(l=null==(a=null==(e=Pa.value)?void 0:e.todayStats)?void 0:a[n])?void 0:l.byModel)||{}});function Qa(e,a,l,n=600){Wa[e]&&cancelAnimationFrame(Wa[e]),Xa.value[e]=!0;const s=Date.now(),c=()=>{const t=Date.now()-s,o=Math.min(t/n,1),i=1-Math.pow(1-o,2),u=a+(l-a)*i,d=Ha[e]??0,r=Math.pow(10,d),v=d>0?Math.round(u*r)/r:Math.round(u);Ba.value[e]=v,o<1?Wa[e]=requestAnimationFrame(c):Xa.value[e]=!1};Wa[e]=requestAnimationFrame(c)}const el=n(!1);function al(e){try{const a=localStorage.getItem(ba),l=a?JSON.parse(a):{};l[w.channelType]=e,localStorage.setItem(ba,JSON.stringify(l))}catch(a){}}const ll=n(function(){try{const e=localStorage.getItem(ba);if(e){return JSON.parse(e)[w.channelType]||!1}}catch(e){}return!1}());async function nl(){ll.value=!ll.value,al(ll.value);try{if(await F("channelLocks",w.channelType,ll.value),Pa.value){const e=Pa.value.uiConfig||{},a={...e.channelLocks||{}};a[w.channelType]=ll.value,Pa.value={...Pa.value,uiConfig:{...e,channelLocks:a}}}}catch(e){}}const sl=n(!0);function cl(e){e.detail&&void 0!==e.detail.showLogs&&(sl.value=e.detail.showLogs)}const tl=n(Date.now()),ol=l(()=>{if(!Ka.value.running)return"";const e=Ka.value.startTime;if(!e)return"";const a=tl.value-e;if(a<=0)return"";const l=Math.floor(a/1e3),n=Math.floor(l/3600),s=Math.floor(l%3600/60),c=l%60;let t="已运行 ";return n>0&&(t+=`${n}小时`),s>0&&(t+=`${s}分`),(c>0||0===n&&0===s)&&(t+=`${c}秒`),t}),il=n(null),ul=l(()=>Fa.value),dl={claude:Na("claude"),codex:Na("codex"),gemini:Na("gemini"),opencode:Na("opencode")},rl=l(()=>((dl[w.channelType]||dl.claude).value||[]).slice(0,ul.value));let vl=null,pl=null,hl=null,yl=!1,gl=null;const kl=l(()=>{let e=[];"claude"===w.channelType?e=_a.value||[]:"codex"===w.channelType?e=qa.value||[]:"gemini"===w.channelType?e=za.value||[]:"opencode"===w.channelType&&(e=Sa.value||[]);return[...e.filter(e=>!1!==e.enabled),...e.filter(e=>!1===e.enabled)]});function ml(e){const a=La[w.channelType];if(!a||!a.channels)return 0;const l=a.channels.find(a=>a.id===e);return l?l.inflight:0}const fl=l(()=>{var e;const a=kl.value.filter(e=>!1!==e.enabled).length;return(null==(e=Ka.value.proxy)?void 0:e.running)?`${a}个渠道调度中`:kl.value.length>0?`${a}个渠道已启用`:"无渠道"}),Tl=n({});function bl(e){return Tl.value[e]||{requests:0,tokens:0,cost:0}}async function xl(){var e;try{let a;if("claude"===w.channelType?a=await z():"codex"===w.channelType?a=await S():"gemini"===w.channelType?a=await L():"opencode"===w.channelType&&(a=await I()),a&&a.byChannel){const l={};for(const[n,s]of Object.entries(a.byChannel))l[n]={requests:s.requests||0,tokens:(null==(e=s.tokens)?void 0:e.total)||0,cost:s.cost||0};Tl.value=l}}catch(a){}}async function Cl(e){var a,l;const n=Ia(w.channelType);n.value.loading=!0;try{let a;a=e?await ja(w.channelType):await Oa(w.channelType,{refreshChannelsDrawer:!0}),!1!==a.success?P.success(e?`${Va.value} 代理已启动`:`${Va.value} 代理已停止`):(P.error(a.error||"操作失败"),n.value.running=!e)}catch(s){P.error((null==(l=null==(a=s.response)?void 0:a.data)?void 0:l.error)||s.message||"操作失败"),n.value.running=!e}finally{n.value.loading=!1}}function wl(){D.push({name:`${w.channelType}-projects`})}function $l(){D.push({name:`${w.channelType}-projects`})}s(rl,e=>{var a;const l=(null==(a=e[0])?void 0:a.id)||null;if(!l||l===vl)return void(vl=l);vl=l,gl&&clearTimeout(gl),gl=setTimeout(()=>{xl()},5e3);(!il.value||il.value.scrollTop<20)&&C(()=>{il.value&&(il.value.scrollTop=0)})}),s(()=>Za.value.requests,e=>{Qa("requests",Ba.value.requests,e,600)}),s(()=>Za.value.tokens,e=>{Qa("tokens",Ba.value.tokens,e,600)}),s(()=>Za.value.cost,e=>{Qa("cost",Ba.value.cost,e,600)}),s(()=>w.channelType,()=>{var e;vl=(null==(e=rl.value[0])?void 0:e.id)||null}),s(()=>{var e,a;return null==(a=null==(e=Pa.value)?void 0:e.counts)?void 0:a[w.channelType]},()=>{Sl()}),s(Da,()=>{yl&&function(){pl&&(clearInterval(pl),pl=null);const e=Da.value||30,a=Math.max(1e3*e,1e4);pl=setInterval(()=>{Ll(),xl()},a)}()});const _l=n({});function ql(e){return!!_l.value[e]}function zl(e,a){e&&(_l.value={..._l.value,[e]:!!a})}function Sl(){var e,a;const l=null==(a=null==(e=Pa.value)?void 0:e.counts)?void 0:a[w.channelType];Ra.value.projects=(null==l?void 0:l.projectCount)||0,Ra.value.sessions=(null==l?void 0:l.sessionCount)||0}async function Ll(){if(Pa.value&&Pa.value.todayStats){const e=Pa.value.todayStats[w.channelType];e&&(Za.value.requests=e.requests||0,Za.value.tokens=e.tokens||0,Za.value.cost=e.cost||0)}Sl()}function Il(){Ma(w.channelType)}function jl(){window.dispatchEvent(new CustomEvent("open-skills-drawer",{detail:{platform:w.channelType}}))}return c(async()=>{await Promise.all([Ua().then(()=>Ll()),xl()]),async function(){var e,a;try{if(Pa.value&&Pa.value.uiConfig)sl.value=!1!==(null==(e=Pa.value.uiConfig.panelVisibility)?void 0:e.showLogs);else{const e=await j();e.success&&e.config&&(sl.value=!1!==(null==(a=e.config.panelVisibility)?void 0:a.showLogs))}}catch(l){}}(),async function(){var e,a;try{let l=!1;if(Pa.value&&Pa.value.uiConfig)l=(null==(e=Pa.value.uiConfig.channelLocks)?void 0:e[w.channelType])||!1;else{const e=await j();e.success&&e.config&&(l=(null==(a=e.config.channelLocks)?void 0:a[w.channelType])||!1)}ll.value=l,al(l)}catch(l){}}(),window.addEventListener("panel-visibility-change",cl),Ba.value={...Za.value},yl=!0,hl=setInterval(()=>{tl.value=Date.now()},1e3)}),t(()=>{yl=!1,pl&&clearInterval(pl),hl&&clearInterval(hl),gl&&clearTimeout(gl),window.removeEventListener("panel-visibility-change",cl),Object.values(Wa).forEach(e=>{e&&cancelAnimationFrame(e)})}),(a,l)=>{const n=o("n-collapse");return u(),i("div",re,[d("div",{class:f(["channel-header",e.channelType])},[d("div",ve,[v(h(se),{size:16},{default:p(()=>[v(h(K))]),_:1})]),d("div",pe,[v(h(se),{size:20},{default:p(()=>[(u(),y(g(Ja.value)))]),_:1})]),d("h2",he,k(Va.value),1),["claude","codex","gemini","opencode"].includes(e.channelType)?(u(),i("div",ye,[v(h(te),{trigger:"hover"},{trigger:p(()=>[v(h(ce),{text:"",class:"skills-button",onClick:jl,title:"Skills 技能管理"},{icon:p(()=>[v(h(se),{size:18},{default:p(()=>[v(h(U))]),_:1})]),_:1})]),default:p(()=>[l[3]||(l[3]=m(" Skills 技能管理 ",-1))]),_:1})])):r("",!0),v(h(ce),{text:"",class:"lock-button",onClick:nl,title:ll.value?"解锁此列":"锁定此列"},{icon:p(()=>[v(h(se),{size:18},{default:p(()=>[ll.value?(u(),y(h(G),{key:0})):(u(),y(h(R),{key:1}))]),_:1})]),_:1},8,["title"])],2),ll.value?r("",!0):(u(),i("div",ge,[d("div",ke,[d("div",me,[v(h(se),{size:16},{default:p(()=>[v(h(Z))]),_:1}),l[4]||(l[4]=d("h3",{class:"card-title"},"代理控制",-1)),Ka.value.running&&ol.value?(u(),i("span",fe,k(ol.value),1)):r("",!0),v(h(oe),{value:Ka.value.running,"onUpdate:value":[l[0]||(l[0]=e=>Ka.value.running=e),Cl],loading:Ka.value.loading,size:"small",style:{"margin-left":"auto"}},null,8,["value","loading"])]),d("div",Te,[d("div",be,[d("div",xe,[d("div",{class:f(["status-dot",{active:Ka.value.running}])},null,2),v(h(ie),{type:Ka.value.running?"success":"default",style:{"font-size":"12px"}},{default:p(()=>[m(k(Ka.value.running?"运行中":"已停止"),1)]),_:1},8,["type"]),d("span",Ce,"端口: "+k(Ka.value.port),1)]),v(h(de),{trigger:"click",placement:"bottom",width:320,class:"channel-popover"},{trigger:p(()=>[v(h(ce),{text:"",size:"tiny",class:"channel-status"},{default:p(()=>[d("span",we,k(fl.value),1)]),_:1})]),default:p(()=>[d("div",$e,[d("div",_e,[l[6]||(l[6]=d("span",null,"渠道快捷管理",-1)),v(h(ie),{depth:"3",style:{"font-size":"11px"}},{default:p(()=>[...l[5]||(l[5]=[m("点击开关切换状态",-1)])]),_:1})]),0===kl.value.length?(u(),i("div",qe,[v(h(ie),{depth:"3"},{default:p(()=>[...l[7]||(l[7]=[m("暂无配置渠道",-1)])]),_:1})])):(u(),i("div",ze,[(u(!0),i(T,null,b(kl.value,e=>{var a,n;return u(),i("div",{key:e.id,class:f(["channel-quick-item",{disabled:!1===e.enabled}])},[d("div",Se,[d("span",Le,k(e.name),1),"frozen"===(null==(a=e.health)?void 0:a.status)?(u(),y(h(ue),{key:0,size:"tiny",type:"error",bordered:!1},{default:p(()=>[...l[8]||(l[8]=[m(" 冻结 ",-1)])]),_:1})):r("",!0),v(h(oe),{size:"small",value:!1!==e.enabled,"onUpdate:value":a=>async function(e,a){if(e&&!ql(e.id)){zl(e.id,!0);try{let l;"claude"===w.channelType?l=O:"codex"===w.channelType?l=N:"gemini"===w.channelType?l=M:"opencode"===w.channelType&&(l=A),l&&(await l(e.id,{enabled:a}),P.success(a?`渠道「${e.name}」已启用`:`渠道「${e.name}」已停用`),await Aa())}catch(l){P.error("操作失败: "+l.message)}finally{zl(e.id,!1)}}}(e,a),loading:ql(e.id),disabled:ql(e.id),style:{"margin-left":"auto"}},null,8,["value","onUpdate:value","loading","disabled"])]),ql(e.id)?(u(),i("div",Ie," 正在切换渠道状态... ")):r("",!0),d("div",je,[d("span",Oe,[l[9]||(l[9]=d("span",{class:"metric-label"},"请求",-1)),d("span",Ne,k(bl(e.id).requests),1)]),d("span",Me,[l[10]||(l[10]=d("span",{class:"metric-label"},"Tokens",-1)),d("span",Ae,k((n=bl(e.id).tokens,n>=1e6?(n/1e6).toFixed(1)+"M":n>=1e3?(n/1e3).toFixed(1)+"K":n.toString())),1)]),d("span",Fe,[l[11]||(l[11]=d("span",{class:"metric-label"},"权重",-1)),d("span",De,k(e.weight||1),1)]),d("span",Pe,[l[12]||(l[12]=d("span",{class:"metric-label"},"并发",-1)),d("span",{class:f(["metric-value",{active:ml(e.id)>0}])},k(ml(e.id))+k(e.maxConcurrency?`/${e.maxConcurrency}`:""),3)])])],2)}),128))]))])]),_:1})])])]),d("div",Ue,[d("div",Ee,[v(h(se),{size:14},{default:p(()=>[v(h(B))]),_:1}),l[13]||(l[13]=d("h3",{class:"card-title"},"快速访问",-1))]),d("div",Ve,[d("div",Je,[d("div",{class:"access-card access-card-projects clickable",onClick:wl},[d("div",Ke,[v(h(se),{size:16},{default:p(()=>[v(h(H))]),_:1})]),d("div",Ge,[l[14]||(l[14]=d("span",{class:"access-label"},"项目",-1)),d("span",Re,k(Ra.value.projects),1)])]),d("div",{class:"access-card access-card-sessions clickable",onClick:l[1]||(l[1]=e=>el.value=!0)},[d("div",Ze,[v(h(se),{size:16},{default:p(()=>[v(h(W))]),_:1})]),d("div",Be,[l[15]||(l[15]=d("span",{class:"access-label"},"最新对话",-1)),d("span",He,k(Ra.value.sessions),1)])]),d("div",{class:"access-card access-card-goto clickable",onClick:$l},[d("div",We,[v(h(se),{size:16},{default:p(()=>[v(h(X))]),_:1})]),d("div",Xe,[l[16]||(l[16]=d("span",{class:"access-label"},"前往",-1)),d("span",Ye,k(Ga.value),1)])])])])]),d("div",{class:f(["card stats-card",`stats-card-${e.channelType}`])},[d("div",Qe,[v(h(se),{size:14},{default:p(()=>[v(h(Y))]),_:1}),l[17]||(l[17]=d("h3",{class:"card-title"},"今日数据",-1))]),d("div",ea,[d("div",aa,[d("div",la,[l[19]||(l[19]=d("div",{class:"stat-icon-dot requests"},null,-1)),d("div",na,[l[18]||(l[18]=d("span",{class:"stat-label"},"请求",-1)),d("span",{class:f(["stat-value",{animating:Xa.value.requests}])},k(Ba.value.requests),3)])]),d("div",sa,[l[21]||(l[21]=d("div",{class:"stat-icon-dot tokens"},null,-1)),d("div",ca,[l[20]||(l[20]=d("span",{class:"stat-label"},"总 Tokens",-1)),d("span",{class:f(["stat-value",{animating:Xa.value.tokens}])},k((c=Ba.value.tokens,c>=1e6?(c/1e6).toFixed(1)+"M":c>=1e3?(c/1e3).toFixed(1)+"K":c.toString())),3)])]),d("div",ta,[l[23]||(l[23]=d("div",{class:"stat-icon-dot cost"},null,-1)),d("div",oa,[l[22]||(l[22]=d("span",{class:"stat-label"},"成本 / USD",-1)),d("span",{class:f(["stat-value",{animating:Xa.value.cost}])},k((s=Ba.value.cost,!s||Number.isNaN(s)?"$0":"$"+Number(s).toFixed(3))),3)])])])])],2),Object.keys(Ya.value).length>0?(u(),i("div",{key:0,class:f(["card chart-card",`chart-card-${e.channelType}`])},[v(n,{"default-expanded-names":[],accordion:""})],2)):r("",!0),sl.value?(u(),i("div",ia,[d("div",ua,[v(h(se),{size:14},{default:p(()=>[v(h(Q))]),_:1}),l[24]||(l[24]=d("h3",{class:"card-title"},"实时日志",-1)),v(h(ce),{text:"",size:"tiny",onClick:x(Il,["stop"]),style:{"margin-left":"auto"},title:"清空日志"},{icon:p(()=>[v(h(se),{size:14},{default:p(()=>[v(h(ee))]),_:1})]),_:1})]),d("div",da,[d("div",ra,[d("div",{class:f(["logs-table-header",`logs-header-${e.channelType}`])},[d("div",{class:f(["log-col col-channel",`col-channel-${e.channelType}`])},"渠道",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"请求",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"回复",2),"claude"===e.channelType?(u(),i(T,{key:0},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"写入",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"命中",2)],64)):"codex"===e.channelType?(u(),i(T,{key:1},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"推理",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):"gemini"===e.channelType?(u(),i(T,{key:2},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):"opencode"===e.channelType?(u(),i(T,{key:3},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"推理",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"缓存",2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},"总计",2)],64)):r("",!0),d("div",{class:f(["log-col col-time",`col-time-${e.channelType}`])},"时间",2)],2),d("div",{class:"logs-container",ref_key:"logsContainer",ref:il},[0===rl.value.length?(u(),i("div",va,[v(h(se),{size:32,depth:"3",style:{"margin-bottom":"8px"}},{default:p(()=>[v(h(Q))]),_:1}),v(h(ie),{depth:"3",style:{"font-size":"12px","font-weight":"500"}},{default:p(()=>[...l[25]||(l[25]=[m("暂无实时日志",-1)])]),_:1}),v(h(ie),{depth:"3",style:{"font-size":"11px","margin-top":"4px"}},{default:p(()=>[...l[26]||(l[26]=[m("开启代理后将显示请求记录",-1)])]),_:1})])):r("",!0),(u(!0),i(T,null,b(rl.value,a=>{var l,n,s,c,t,o,y,g,b,x,C,w;return u(),i("div",{key:a.id,class:f(["log-row",{"action-row":"action"===a.type,"error-row":"error"===a.status,"new-log":a.isNew}])},["action"===a.type?(u(),i("div",pa,[v(h(se),{size:12,color:"#18a058"},{default:p(()=>[v(h(ae))]),_:1}),d("span",ha,k(a.message),1),d("span",ya,k(a.time),1)])):"error"===a.status?(u(),i("div",ga,[v(h(se),{size:12,color:"#d03050"},{default:p(()=>[v(h(le))]),_:1}),d("span",ka,k(a.channel)+": "+k(a.error||a.message||"请求失败"),1),d("span",ma,k(a.time),1)])):(u(),i(T,{key:2},[d("div",{class:f(["log-col col-channel",`col-channel-${e.channelType}`])},[v(h(ue),{size:"tiny",type:"success"},{default:p(()=>[m(k(a.channel),1)]),_:2},1024)],2),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(l=a.tokens)?void 0:l.input)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(n=a.tokens)?void 0:n.output)||0),3),"claude"===e.channelType?(u(),i(T,{key:0},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(s=a.tokens)?void 0:s.cacheCreation)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(c=a.tokens)?void 0:c.cacheRead)||0),3)],64)):"codex"===e.channelType?(u(),i(T,{key:1},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(t=a.tokens)?void 0:t.reasoning)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(o=a.tokens)?void 0:o.cached)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(y=a.tokens)?void 0:y.total)||0),3)],64)):"gemini"===e.channelType?(u(),i(T,{key:2},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(g=a.tokens)?void 0:g.cached)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(b=a.tokens)?void 0:b.total)||0),3)],64)):"opencode"===e.channelType?(u(),i(T,{key:3},[d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(x=a.tokens)?void 0:x.reasoning)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(C=a.tokens)?void 0:C.cached)||0),3),d("div",{class:f(["log-col col-token",`col-token-${e.channelType}`])},k((null==(w=a.tokens)?void 0:w.total)||0),3)],64)):r("",!0),d("div",{class:f(["log-col col-time",`col-time-${e.channelType}`])},k(a.time),3)],64))],2)}),128))],512)])])])):r("",!0)])),ll.value?(u(),i("div",{key:1,class:f(["locked-overlay",`locked-${e.channelType}`])},[d("div",fa,[d("div",Ta,[v(h(se),{size:48},{default:p(()=>[v(h(G))]),_:1})]),l[28]||(l[28]=d("h3",{class:"locked-title"},"该渠道已锁定",-1)),v(h(ie),{depth:"3",class:"locked-hint"},{default:p(()=>[...l[27]||(l[27]=[m(" 点击上方按钮解锁以查看内容 ",-1)])]),_:1})])],2)):r("",!0),v(q,{visible:el.value,"onUpdate:visible":l[2]||(l[2]=e=>el.value=e),channel:e.channelType},null,8,["visible","channel"])]);var s,c}}},[["__scopeId","data-v-0bad694b"]]),Ca=n({theme:"light",panelVisibility:{showChannels:!0,showLogs:!0},channelLocks:{claude:!1,codex:!1,gemini:!1},channelCollapse:{claude:[],codex:[],gemini:[]},channelOrder:{claude:[],codex:[],gemini:[]}});let wa=!1,$a=null;async function _a(){return wa?Ca.value:$a||($a=(async()=>{try{const e=await j();e.success&&e.config&&(Ca.value=e.config,wa=!0)}catch(e){}finally{$a=null}return Ca.value})(),$a)}const qa={class:"dashboard-container"},za="dashboardChannelOrder",Sa=w({__name:"Home",setup(a){const l=["claude","codex","gemini","opencode"],{uiConfig:s,updateConfig:t,loadUIConfig:o}=(wa||_a(),{uiConfig:Ca,loadUIConfig:_a,saveConfig:async function(e){try{const a=await P(e);return!!a.success&&(Ca.value=a.config,!0)}catch(a){return!1}},updateConfig:async function(e,a){try{const l=await D(e,a);return!!l.success&&(Ca.value=l.config,!0)}catch(l){return!1}},updateNestedConfig:async function(e,a,l){try{const n=await F(e,a,l);return!!n.success&&(Ca.value=n.config,!0)}catch(n){return!1}}});function d(e){try{localStorage.setItem(za,JSON.stringify(e))}catch(a){}}const r=n(function(){try{const e=localStorage.getItem(za);if(e){const a=JSON.parse(e);if(Array.isArray(a)&&4===a.length)return a}}catch(e){}return l}().map(e=>({type:e})));async function g(){const e=r.value.map(e=>e.type);d(e),await t("dashboardChannelOrder",e)}return c(async()=>{if(await o(),s.value.dashboardChannelOrder&&Array.isArray(s.value.dashboardChannelOrder)&&4===s.value.dashboardChannelOrder.length){const e=s.value.dashboardChannelOrder;r.value=e.map(e=>({type:e})),d(e)}}),(a,l)=>(u(),i("div",qa,[v(h(e),{modelValue:r.value,"onUpdate:modelValue":l[0]||(l[0]=e=>r.value=e),class:"dashboard-grid","item-key":"type",animation:200,handle:".drag-handle",onEnd:g},{item:p(({element:e})=>[(u(),y(xa,{"channel-type":e.type,key:e.type},null,8,["channel-type"]))]),_:1},8,["modelValue"])]))}},[["__scopeId","data-v-06100f0f"]]);export{Sa as default};
@@ -1 +1 @@
1
- import{_ as a,P as s}from"./index-EMrm1wk-.js";import{c as r,o as e,X as o,Y as i,N as d}from"./vue-vendor-3bf-fPGP.js";import{K as n}from"./naive-ui-Bdxp09n2.js";import"./vendors-CKPV1OAU.js";import"./markdown-DyTJGI4N.js";import"./icons-B5Pl4lrD.js";const t={class:"plugin-manager"},m=a({__name:"PluginManager",setup:a=>(a,m)=>(e(),r("div",t,[o(d(n),{title:"Plugins 插件管理",bordered:!1},{default:i(()=>[o(s,{"in-drawer":!1,"hide-back":!0})]),_:1})]))},[["__scopeId","data-v-6d92033b"]]);export{m as default};
1
+ import{_ as a,P as s}from"./index-B1ujw2sM.js";import{c as r,o as e,X as o,Y as i,N as d}from"./vue-vendor-3bf-fPGP.js";import{K as n}from"./naive-ui-Bdxp09n2.js";import"./vendors-CKPV1OAU.js";import"./markdown-DyTJGI4N.js";import"./icons-B5Pl4lrD.js";const t={class:"plugin-manager"},m=a({__name:"PluginManager",setup:a=>(a,m)=>(e(),r("div",t,[o(d(n),{title:"Plugins 插件管理",bordered:!1},{default:i(()=>[o(s,{"in-drawer":!1,"hide-back":!0})]),_:1})]))},[["__scopeId","data-v-6d92033b"]]);export{m as default};