dsh-grok-subscription 1.0.1 → 1.0.3
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/CONTRIBUTING.md +42 -0
- package/README.en.md +218 -0
- package/README.md +144 -120
- package/docs/assets/composer-quota.webp +0 -0
- package/docs/assets/grok-subscription-overview.webp +0 -0
- package/docs/assets/settings-account.webp +0 -0
- package/docs/assets/settings-usage.webp +0 -0
- package/lib/client.js +178 -90
- package/package.json +4 -1
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Bug reports, focused fixes, and compatibility updates are welcome.
|
|
4
|
+
|
|
5
|
+
## Before changing code
|
|
6
|
+
|
|
7
|
+
- Keep one pull request focused on one problem. Do not bundle unrelated
|
|
8
|
+
refactors, generated artifacts, or release preparation.
|
|
9
|
+
- Never commit credentials. This plugin reads a real Grok Build session, so no
|
|
10
|
+
`~/.grok/auth.json` contents, access or refresh tokens, account identifiers,
|
|
11
|
+
or raw subscription responses belong in the repository, tests, or issues.
|
|
12
|
+
- Reuse DSH's native model, settings, tool, and plugin-lifecycle contracts
|
|
13
|
+
instead of introducing a parallel subsystem.
|
|
14
|
+
|
|
15
|
+
## Local verification
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install
|
|
19
|
+
npm test
|
|
20
|
+
npm run build
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`lib/` is committed and generated by the build — never edit it by hand. Run
|
|
24
|
+
`npm run build` and commit the result whenever `src/` changes; CI fails if the
|
|
25
|
+
committed `lib/` differs from a fresh build.
|
|
26
|
+
|
|
27
|
+
Changes that affect the DSH UI or the plugin lifecycle also need a check in a
|
|
28
|
+
real DSH installation; source tests alone are not installed-product acceptance.
|
|
29
|
+
The host-side adapter is loaded into memory, so restart `dsh web` before judging
|
|
30
|
+
a host change, and hard-refresh the browser for client changes.
|
|
31
|
+
|
|
32
|
+
## Pull requests
|
|
33
|
+
|
|
34
|
+
Describe the user-visible problem, the smallest implemented change, the checks
|
|
35
|
+
you ran, and any remaining compatibility risk. When user instructions change,
|
|
36
|
+
keep `README.md` and `README.en.md` behaviourally aligned.
|
|
37
|
+
|
|
38
|
+
The READMEs are user documentation. They explain the product and its supported
|
|
39
|
+
use, not internal debugging history or private design discussion.
|
|
40
|
+
|
|
41
|
+
A merged pull request does not imply an immediate npm release; maintainers batch
|
|
42
|
+
fixes into planned releases.
|
package/README.en.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# DSH Grok Subscription — Use SuperGrok / X Premium subscriptions in DeepSeek Harness
|
|
4
|
+
|
|
5
|
+
[简体中文](https://github.com/BaronCyrus/dsh-grok-subscription/blob/main/README.md) · **English**
|
|
6
|
+
|
|
7
|
+
**Use your SuperGrok / X Premium (Grok Build) subscription directly in DeepSeek Harness**
|
|
8
|
+
|
|
9
|
+
Reuse the official Grok Build CLI session — no `XAI_API_KEY` needed.
|
|
10
|
+
Models, reasoning effort, and weekly quota all stay inside DSH.
|
|
11
|
+
|
|
12
|
+
[](https://github.com/BaronCyrus/dsh-grok-subscription/actions/workflows/ci.yml)
|
|
13
|
+
[](https://www.npmjs.com/package/dsh-grok-subscription)
|
|
14
|
+
[](https://www.npmjs.com/package/dsh-grok-subscription)
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
[](https://github.com/BaronCyrus/dsh-grok-subscription/stargazers)
|
|
17
|
+
|
|
18
|
+
[Three-step start](#three-step-start) · [Install](#install) · [Contribute](CONTRIBUTING.md) · [Update and uninstall](#update-and-uninstall)
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<img src="docs/assets/grok-subscription-overview.webp" width="900" alt="Select Grok 4.7 in DeepSeek Harness and chat through a SuperGrok subscription">
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
## Three-step start
|
|
27
|
+
|
|
28
|
+
1. **Install the plugin.** Run the command below; to select a candidate version, enter the full `package@version`, for example `dsh-grok-subscription@1.0.3`.
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
2. **Sign in to the subscription.** Open **Settings → Grok Subscription** and click **CLI login** or **Device-code login**, then finish the official prompt in the terminal that started DSH. If you already ran `grok login` yourself, just click **Pull from Grok CLI** — nothing has to be pasted.
|
|
35
|
+
3. **Start using it.** Pick a model such as Grok 4.7 in the model picker. The round badge next to the picker shows weekly remaining quota, and the model menu offers reasoning effort levels.
|
|
36
|
+
|
|
37
|
+
Restart `dsh web` after installing or upgrading, otherwise the old `lib/` keeps running.
|
|
38
|
+
|
|
39
|
+
## Why this plugin
|
|
40
|
+
|
|
41
|
+
| Capability | What you get |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| **Direct subscription routing** | Reuse the official Grok Build CLI session — no `XAI_API_KEY` needed |
|
|
44
|
+
| **Real model catalog** | Read the models the account can actually use (such as `grok-4.7`, `grok-4.6`, `grok-4.5`) from `/v1/models-v2`; nothing is exposed while signed out |
|
|
45
|
+
| **Reasoning effort** | The model picker offers `low` / `medium` / `high` / `xhigh`, defaulting to `high`, matching the Codex interaction |
|
|
46
|
+
| **Composer quota** | A badge beside the model picker shows weekly remaining percentage; hover or click for "Weekly quota · N% left · resets M/D HH:mm" |
|
|
47
|
+
| **Usage panel (experimental)** | Settings shows the used and remaining percentages the backend reports, and never invents numbers when the read fails |
|
|
48
|
+
| **Credentials stay local** | Only the short-lived access token from `~/.grok/auth.json` is read on the host; no token is handed to browser RPC |
|
|
49
|
+
| **Sign-in state refreshes the UI** | Login, pull, and logout emit `llm/adapters-updated`, so the chat model list updates with them |
|
|
50
|
+
| **Failures stay visible** | When subscription routing is unavailable it reports an error instead of silently using another paid route |
|
|
51
|
+
|
|
52
|
+
These capabilities reuse the same local Grok Build sign-in.
|
|
53
|
+
|
|
54
|
+
## Product screen
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<img src="docs/assets/settings-account.webp" width="820" alt="The Grok Subscription page in DSH Settings: sign-in status, account, login buttons and credential notes">
|
|
58
|
+
</p>
|
|
59
|
+
|
|
60
|
+
The **Settings → Grok Subscription** screen uses a status chip for the sign-in state, and an account card offering CLI login, device-code login, pull from the Grok CLI, and logout; how credentials are read lives in a collapsible "How signing in works" disclosure. It is styled with DSH's own design tokens, so it follows the light and dark theme. Account and time values in the screenshot are demo data.
|
|
61
|
+
|
|
62
|
+
<p align="center">
|
|
63
|
+
<img src="docs/assets/settings-usage.webp" width="820" alt="The experimental usage panel in Grok Subscription settings: 6% used, about 94% remaining">
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
The experimental usage panel comes from an undocumented subscription billing endpoint (`/v1/billing?format=credits`): the remaining share is drawn as a progress bar and per-product rows are listed separately. It is informational: the endpoint may change or disappear, a failed read never shows an invented percentage, and chat is unaffected.
|
|
67
|
+
|
|
68
|
+
## Prepare DSH
|
|
69
|
+
|
|
70
|
+
This plugin supports the latest DeepSeek Harness release recorded in its package metadata and requires a **SuperGrok or X Premium** account that currently has Grok Build access.
|
|
71
|
+
|
|
72
|
+
- **Already able to run `dsh`**: use the standard command below;
|
|
73
|
+
- **Prefer the official path**: see the [DeepSeek Harness documentation](https://github.com/deepseek-ai/deepseek-harness#run).
|
|
74
|
+
|
|
75
|
+
The plugin is strict about `~/.grok/auth.json`: it refuses symbolic links, files readable by group or others, and files not owned by the current user. If permissions are wrong:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
chmod 600 "${GROK_HOME:-$HOME/.grok}/auth.json"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Install
|
|
82
|
+
|
|
83
|
+
### Standard DSH command
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
You can also install the version published on npm:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
dsh plugin --profile web add dsh-grok-subscription@1.0.3
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
DSH handles target selection, the profile lock, dependency resolution, and bundle activation.
|
|
96
|
+
|
|
97
|
+
### Headless
|
|
98
|
+
|
|
99
|
+
Sign in and select a Grok model once in the Web UI, then install the same plugin into the standard DSH Headless profile:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
dsh plugin --profile headless add BaronCyrus/dsh-grok-subscription
|
|
103
|
+
dsh --profile headless "reply with exactly: ok"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
<details>
|
|
107
|
+
<summary>Official npm route (Node.js installed)</summary>
|
|
108
|
+
|
|
109
|
+
The official `npx @deepseek-ai/dsh web` does not create a global `dsh` command, so keep the full `npx` prefix when installing the plugin:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile web add BaronCyrus/dsh-grok-subscription
|
|
113
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile web list dsh-grok-subscription --depth 0
|
|
114
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 --profile web --dump-config
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
</details>
|
|
118
|
+
|
|
119
|
+
<details>
|
|
120
|
+
<summary>Verify the install when <code>dsh</code> already works</summary>
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
dsh plugin --profile web list dsh-grok-subscription --depth 0
|
|
124
|
+
dsh --profile web --dump-config
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The package list should contain exactly one `dsh-grok-subscription`, and the config exactly one `grok-build` route.
|
|
128
|
+
|
|
129
|
+
</details>
|
|
130
|
+
|
|
131
|
+
Restart DSH manually afterwards, then:
|
|
132
|
+
|
|
133
|
+
1. Open **Settings → Grok Subscription**;
|
|
134
|
+
2. Sign in with an account that has Grok Build access (browser login or device-code login);
|
|
135
|
+
3. Select a Grok model in the model picker.
|
|
136
|
+
|
|
137
|
+
## Features
|
|
138
|
+
|
|
139
|
+
- Reuses the official Grok Build CLI session; credentials stay local and the account is identified by a partially masked email;
|
|
140
|
+
- Models appear directly in DSH sessions with no `XAI_API_KEY`, and no token is exposed to the browser;
|
|
141
|
+
- The model catalog is pulled after sign-in; a failed or timed-out read falls back to a built-in list and records the error, and it stays empty while signed out;
|
|
142
|
+
- The model menu offers `low` / `medium` / `high` / `xhigh` reasoning effort, defaulting to `high`;
|
|
143
|
+
- A weekly remaining quota badge sits beside the model picker in the composer, with remaining percentage and reset time on hover or click;
|
|
144
|
+
- Settings can show the used and remaining percentages the backend reports, and says so plainly instead of guessing when the read fails;
|
|
145
|
+
- Supports CLI login, device-code login, pull from the Grok CLI, and logout; the chat model list refreshes whenever sign-in state changes;
|
|
146
|
+
- When subscription routing is unavailable it reports an error instead of silently switching to another paid route.
|
|
147
|
+
|
|
148
|
+
### Composer quota
|
|
149
|
+
|
|
150
|
+
<p align="center">
|
|
151
|
+
<img src="docs/assets/composer-quota.webp" width="820" alt="DSH composer: weekly remaining quota badge beside the Grok 4.7 model picker">
|
|
152
|
+
</p>
|
|
153
|
+
|
|
154
|
+
The badge appears only when the current session's provider is `grok-build` and the usage read succeeds; hover or click for "Weekly quota · N% left · resets M/D HH:mm". It reflects only the weekly quota the backend returns, and when the read fails the badge is simply hidden — chat is unaffected.
|
|
155
|
+
|
|
156
|
+
### Reasoning effort
|
|
157
|
+
|
|
158
|
+
After selecting a Grok model, the model menu exposes a reasoning effort submenu: `low` / `medium` / `high` / `xhigh`, defaulting to `high`. The levels come from `model.reasoning` metadata (`efforts` + `defaultEffort`), so the interaction matches Codex in DSH; the levels actually available depend on the account's model catalog.
|
|
159
|
+
|
|
160
|
+
### Model catalog and sign-in state
|
|
161
|
+
|
|
162
|
+
After sign-in the plugin reads the model catalog the account can actually use from the subscription proxy; while signed out it registers no models at all. If the read fails or times out it falls back to a built-in list (`grok-4.7` / `grok-4.6` / `grok-4.5`) and records the error in status, so the catalog is never left empty and plugin startup is never blocked.
|
|
163
|
+
|
|
164
|
+
## Update and uninstall
|
|
165
|
+
|
|
166
|
+
### Update and verify
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
dsh plugin --profile web update dsh-grok-subscription
|
|
170
|
+
dsh plugin --profile web list dsh-grok-subscription --depth 0
|
|
171
|
+
dsh --profile web --dump-config
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Uninstall
|
|
175
|
+
|
|
176
|
+
Confirm you want the plugin removed, then run:
|
|
177
|
+
|
|
178
|
+
```sh
|
|
179
|
+
dsh plugin --profile web remove dsh-grok-subscription
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
These operations keep the DSH profile, other plugins, and the sign-in stored in `~/.grok/auth.json`.
|
|
183
|
+
|
|
184
|
+
<details>
|
|
185
|
+
<summary>Official npm fallback</summary>
|
|
186
|
+
|
|
187
|
+
```sh
|
|
188
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile web update dsh-grok-subscription
|
|
189
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile web remove dsh-grok-subscription
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
</details>
|
|
193
|
+
|
|
194
|
+
## Troubleshooting
|
|
195
|
+
|
|
196
|
+
- **`dsh` is not recognized**: the official npm route never creates a global `dsh` command — use the full `npx -y @deepseek-ai/dsh@0.1.5-rc.2 ...` command above;
|
|
197
|
+
- **The model list is empty**: nothing is exposed while signed out. Finish signing in, then click **Pull from Grok CLI**;
|
|
198
|
+
- **Nothing changed after upgrading**: the plugin keeps running the old `lib/` — reinstall the plugin, restart `dsh web`, and hard-refresh (Ctrl+Shift+R);
|
|
199
|
+
- **It reports `auth.json` permissions**: apply the `chmod 600` above; the plugin refuses symlinks and group- or other-readable files;
|
|
200
|
+
- **"No reply" after sending a message**: upgrade to `1.0.1` or later. `1.0.0` had a defect where tool-calling turns aborted with a non-serializable stream chunk, leaving no reply in the UI at all.
|
|
201
|
+
|
|
202
|
+
## Scope and support
|
|
203
|
+
|
|
204
|
+
The Grok subscription backend and DSH can change independently; this is a community project with no affiliation or endorsement from DeepSeek or xAI.
|
|
205
|
+
|
|
206
|
+
For sensitive issues read [SECURITY.md](SECURITY.md) first. For bug reports use [Issues](https://github.com/BaronCyrus/dsh-grok-subscription/issues).
|
|
207
|
+
|
|
208
|
+
### Development checks
|
|
209
|
+
|
|
210
|
+
```sh
|
|
211
|
+
npm install
|
|
212
|
+
npm test
|
|
213
|
+
npm run build
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`lib/` is a committed build artifact, so run `npm run build` after changing `src/`.
|
|
217
|
+
|
|
218
|
+
[MIT](LICENSE)
|
package/README.md
CHANGED
|
@@ -1,194 +1,218 @@
|
|
|
1
|
-
#
|
|
1
|
+
# DSH Grok Subscription — 在 DeepSeek Harness 使用 SuperGrok / X Premium 订阅
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<div align="center">
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**简体中文** · [English](https://github.com/BaronCyrus/dsh-grok-subscription/blob/main/README.en.md)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- 通过 DSH credentials 仅保存短期 access token;refresh token 不离开 Grok CLI 文件。
|
|
9
|
-
- 推理使用 OpenAI Responses:`https://cli-chat-proxy.grok.com/v1/responses`,不是 `api.x.ai`。
|
|
10
|
-
- 登录后从 `GET https://cli-chat-proxy.grok.com/v1/models-v2` 获取账号可用模型;实时目录不可用或为空时使用小型静态目录(包含 `grok-4.7`)。`grok-4.7` 优先来自实时 `models-v2` 返回。
|
|
11
|
-
- 未登录时仍注册 adapter,但模型列表为 **0**(fail closed)。
|
|
12
|
-
- 设置页显示脱敏账户、登录状态、模型与最近一次目录错误,并提供 CLI 登录、设备码登录、从 Grok CLI 拉取、退出登录。
|
|
13
|
-
- **实验性用量显示**:登录后从未文档化的 `GET /v1/billing?format=credits` 读取 `config.creditUsagePercent`(兼容顶层)与周期结束时间;失败时显示「不可用」且**绝不编造百分比**。不影响 Chat。
|
|
14
|
-
- Pull / 登录 / 退出 / 目录刷新后通过 `llm/adapters-updated` 通知 Web 客户端刷新 Chat / New Session 模型选择器(emit 延后,避免与 Pull RPC 重入)。
|
|
15
|
-
- 设置页 Pull **零出站网络、内存优先**:只读本地 auth.json,同步写入 `memoryAccessToken` 后立即返回;credentials.set / credentialRef 延后(带超时),不堵 Pull RPC;目录与用量由后台及客户端 fire-and-forget 的 `catalog/refresh` / `usage/refresh` 更新(不占用全局 busy);`status` / `currentToken` 优先内存。
|
|
7
|
+
**把 SuperGrok / X Premium(Grok Build)订阅直接接入 DeepSeek Harness**
|
|
16
8
|
|
|
17
|
-
|
|
9
|
+
复用官方 Grok Build CLI 的登录会话,不需要 `XAI_API_KEY`。
|
|
10
|
+
模型、推理档位和每周额度都留在 DSH 里。
|
|
18
11
|
|
|
19
|
-
|
|
12
|
+
[](https://github.com/BaronCyrus/dsh-grok-subscription/actions/workflows/ci.yml)
|
|
13
|
+
[](https://www.npmjs.com/package/dsh-grok-subscription)
|
|
14
|
+
[](https://www.npmjs.com/package/dsh-grok-subscription)
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
[](https://github.com/BaronCyrus/dsh-grok-subscription/stargazers)
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
grok login
|
|
23
|
-
# 从 GitHub 安装(推荐)
|
|
24
|
-
dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
|
|
25
|
-
# 或本地路径
|
|
26
|
-
# dsh plugin --profile web add /absolute/path/to/dsh-grok-subscription
|
|
27
|
-
# 或 npm(发布后)
|
|
28
|
-
# dsh plugin --profile web add dsh-grok-subscription@1.0.1
|
|
29
|
-
```
|
|
18
|
+
[三步开始](#三步开始) · [安装](#安装) · [参与贡献](CONTRIBUTING.md) · [更新与卸载](#更新与卸载)
|
|
30
19
|
|
|
31
|
-
|
|
20
|
+
</div>
|
|
32
21
|
|
|
33
|
-
|
|
22
|
+
<p align="center">
|
|
23
|
+
<img src="docs/assets/grok-subscription-overview.webp" width="900" alt="在 DeepSeek Harness 中选择 Grok 4.7 并使用 SuperGrok 订阅进行多轮对话">
|
|
24
|
+
</p>
|
|
34
25
|
|
|
35
|
-
|
|
26
|
+
## 三步开始
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
chmod 600 "${GROK_HOME:-$HOME/.grok}/auth.json"
|
|
39
|
-
```
|
|
28
|
+
1. **安装插件**:在终端运行下面的命令;指定候选版本时填写完整的 `包名@版本`,例如 `dsh-grok-subscription@1.0.3`。
|
|
40
29
|
|
|
41
|
-
|
|
30
|
+
```sh
|
|
31
|
+
dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
|
|
32
|
+
```
|
|
42
33
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
npm test
|
|
46
|
-
npm run build
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## v1.0.1
|
|
50
|
-
|
|
51
|
-
修复 grok-build 路由「发第二条消息没有回复」:`/v1/responses` 只在 `response.output_item.added` 与 `function_call_arguments.done` 上给函数名,参数增量事件不带 `name`,于是工具调用块带着 `name: undefined` 发给宿主。DSH 会拒绝任何无法无损 JSON 序列化的流片段,并以「Assistant stream chunk must be losslessly JSON-serializable」结束整轮,界面上完全没有回复——走 grok-build 的工具调用轮次都会这样,纯文本回复则正常。现:按 call id 记住工具名;采用 `arguments.done` / `response.completed` 的权威参数;从终止快照恢复只出现在 `completed` 里的调用;用量合计保持有限值、错误状态仅在其为数字时附带;出口再统一剔除 `undefined` / 非有限值兜底。附 8 个基于真实抓包帧的回归测试。
|
|
52
|
-
|
|
53
|
-
## v1.0.0
|
|
34
|
+
2. **登录订阅**:打开 **设置 → Grok 订阅**,点击 **CLI 登录** 或 **设备码登录**,在启动 DSH 的终端里完成官方提示。已经自己跑过 `grok login` 的话,直接点 **从 Grok CLI 拉取** 即可,不需要粘贴任何 token。
|
|
35
|
+
3. **开始使用**:在模型选择器中选择 Grok 4.7 等模型。输入框旁的圆形徽章显示每周剩余额度,模型菜单里有推理档位。
|
|
54
36
|
|
|
55
|
-
|
|
37
|
+
安装或升级后需要重启 `dsh web`,否则会继续运行旧的 `lib/`。
|
|
56
38
|
|
|
57
|
-
##
|
|
39
|
+
## 核心优势
|
|
58
40
|
|
|
59
|
-
|
|
41
|
+
| 能力 | 用户得到什么 |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| **订阅直连** | 复用官方 Grok Build CLI 会话,不需要 `XAI_API_KEY` |
|
|
44
|
+
| **真实模型目录** | 登录后从 `/v1/models-v2` 读取账号实际可用的模型(如 `grok-4.7`、`grok-4.6`、`grok-4.5`);未登录时不暴露任何模型 |
|
|
45
|
+
| **推理档位** | 模型选择器内置 `low` / `medium` / `high` / `xhigh` 子菜单,默认 `high`,与 Codex 的交互一致 |
|
|
46
|
+
| **输入框额度** | 模型选择器旁的徽章直接显示每周剩余比例,悬停或点击查看「每周额度 剩余 N% · 重置于 M/D HH:mm」 |
|
|
47
|
+
| **用量面板(实验性)** | 设置页显示服务端返回的已用与剩余百分比,读取失败时不猜数字、不虚构额度 |
|
|
48
|
+
| **凭据留在本机** | 只在主机侧读取 `~/.grok/auth.json` 的短期 access token;不会把 token 交给浏览器 RPC |
|
|
49
|
+
| **登录状态会刷新界面** | 登录、拉取或登出后自动派发 `llm/adapters-updated`,Chat 模型列表随之更新 |
|
|
50
|
+
| **失败可见** | 订阅路由不可用时明确报错,不会静默改用其他付费路由 |
|
|
60
51
|
|
|
61
|
-
|
|
52
|
+
这些能力共用同一份本机 Grok Build 登录。
|
|
62
53
|
|
|
63
|
-
|
|
54
|
+
## 实际界面
|
|
64
55
|
|
|
65
|
-
|
|
56
|
+
<p align="center">
|
|
57
|
+
<img src="docs/assets/settings-account.webp" width="820" alt="DSH 设置中的 Grok 订阅页面:登录状态、账号、登录按钮与凭据说明">
|
|
58
|
+
</p>
|
|
66
59
|
|
|
67
|
-
|
|
60
|
+
上图为 **设置 → Grok 订阅** 主界面:顶部状态胶囊显示登录状态,账户卡片提供 CLI 登录、设备码登录、从 Grok CLI 拉取和登出,凭据读取方式收在可展开的「登录方式说明」里。样式沿用 DSH 自身的设计变量,因此跟随主题明暗切换。截图中的账号与时间均为演示数据。
|
|
68
61
|
|
|
69
|
-
|
|
62
|
+
<p align="center">
|
|
63
|
+
<img src="docs/assets/settings-usage.webp" width="820" alt="Grok 订阅设置页中的实验性用量面板:已用 6%、剩余约 94%">
|
|
64
|
+
</p>
|
|
70
65
|
|
|
71
|
-
|
|
66
|
+
实验性用量面板来自未公开的订阅计费接口(`/v1/billing?format=credits`):剩余比例以进度条呈现,产品明细逐行列出。它仅供参考:接口可能随时变化或消失,读取失败时不会显示编造的百分比,也不影响聊天。
|
|
72
67
|
|
|
73
|
-
|
|
68
|
+
## 准备 DSH
|
|
74
69
|
|
|
75
|
-
|
|
70
|
+
本插件支持软件包元数据中记录的最新版 DeepSeek Harness,并需要一个具有 Grok Build 使用资格的 **SuperGrok 或 X Premium** 账号。
|
|
76
71
|
|
|
77
|
-
|
|
72
|
+
- **已经能运行 `dsh`**:直接使用下面的标准命令;
|
|
73
|
+
- **想按官方方式运行**:查看 [DeepSeek Harness 官方说明](https://github.com/deepseek-ai/deepseek-harness#run)。
|
|
78
74
|
|
|
79
|
-
|
|
75
|
+
插件读取 `~/.grok/auth.json` 时较为严格:拒绝符号链接、拒绝组或其他用户可读的文件、拒绝非当前用户拥有的文件。如果权限不正确:
|
|
80
76
|
|
|
81
|
-
|
|
77
|
+
```sh
|
|
78
|
+
chmod 600 "${GROK_HOME:-$HOME/.grok}/auth.json"
|
|
79
|
+
```
|
|
82
80
|
|
|
83
|
-
##
|
|
81
|
+
## 安装
|
|
84
82
|
|
|
85
|
-
|
|
83
|
+
### DSH 标准命令
|
|
86
84
|
|
|
87
|
-
|
|
85
|
+
```sh
|
|
86
|
+
dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
|
|
87
|
+
```
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
也可以按 npm 上的已发布版本安装:
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
```sh
|
|
92
|
+
dsh plugin --profile web add dsh-grok-subscription@1.0.3
|
|
93
|
+
```
|
|
92
94
|
|
|
93
|
-
|
|
95
|
+
目标选择、profile 锁、依赖解析和 bundle 激活均由 DSH 负责。
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
### Headless
|
|
96
98
|
|
|
97
|
-
|
|
99
|
+
先在 Web 中完成登录并选择一次 Grok 模型,再把同一个插件安装到 DSH 的标准 Headless profile:
|
|
98
100
|
|
|
99
|
-
|
|
101
|
+
```sh
|
|
102
|
+
dsh plugin --profile headless add BaronCyrus/dsh-grok-subscription
|
|
103
|
+
dsh --profile headless "只回复:ok"
|
|
104
|
+
```
|
|
100
105
|
|
|
101
|
-
|
|
106
|
+
<details>
|
|
107
|
+
<summary>官方 npm 方式(已安装 Node.js)</summary>
|
|
102
108
|
|
|
103
|
-
|
|
109
|
+
官方的 `npx @deepseek-ai/dsh web` 不会创建全局 `dsh` 命令,因此安装插件时也要保留完整的 `npx` 前缀:
|
|
104
110
|
|
|
105
|
-
|
|
111
|
+
```sh
|
|
112
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile web add BaronCyrus/dsh-grok-subscription
|
|
113
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile web list dsh-grok-subscription --depth 0
|
|
114
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 --profile web --dump-config
|
|
115
|
+
```
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
- Pull / 登录 / 退出 / 目录刷新后发出 `llm/adapters-updated`,让选择器刷新。
|
|
117
|
+
</details>
|
|
109
118
|
|
|
110
|
-
|
|
119
|
+
<details>
|
|
120
|
+
<summary>已经能运行 <code>dsh</code> 时检查安装结果</summary>
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
```sh
|
|
123
|
+
dsh plugin --profile web list dsh-grok-subscription --depth 0
|
|
124
|
+
dsh --profile web --dump-config
|
|
125
|
+
```
|
|
113
126
|
|
|
114
|
-
-
|
|
115
|
-
- 订阅账号用于非官方客户端可能处于供应商条款灰色地带;**只使用你自己的账号**,风险自担。
|
|
116
|
-
- 官方文档没有发布完整 HTTP wire protocol;代理协议、请求头、模型 ID 或权限规则可能随时改变。
|
|
117
|
-
- 用量面板依赖的 `/v1/billing?format=credits` **未公开文档**,属实验性功能;字段形状或可用性可能变化,失败时仅显示不可用。
|
|
118
|
-
- 设置页发起 CLI 登录时,浏览器/设备码提示由官方 CLI 处理;远程部署请优先用 `grok login --device-auth`。
|
|
127
|
+
安装列表中应只有一个 `dsh-grok-subscription`,配置中应只有一个 `grok-build` 路由。
|
|
119
128
|
|
|
120
|
-
|
|
129
|
+
</details>
|
|
121
130
|
|
|
122
|
-
|
|
131
|
+
安装完成后手动重启 DSH,然后:
|
|
123
132
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
133
|
+
1. 打开 **设置 → Grok 订阅**;
|
|
134
|
+
2. 登录具有 Grok Build 资格的账号(浏览器登录或设备码登录);
|
|
135
|
+
3. 在模型选择器中选择 Grok 模型。
|
|
127
136
|
|
|
128
|
-
|
|
137
|
+
## 功能
|
|
129
138
|
|
|
130
|
-
|
|
139
|
+
- 复用官方 Grok Build CLI 会话登录,凭据保留在本机;账号以部分隐藏的邮箱区分;
|
|
140
|
+
- 模型直接出现在 DSH 会话中,无需 `XAI_API_KEY`,也不向浏览器暴露 token;
|
|
141
|
+
- 模型目录登录后自动拉取;读取失败或超时时回退到内置列表并记录错误,未登录时保持为空;
|
|
142
|
+
- 模型菜单提供 `low` / `medium` / `high` / `xhigh` 推理档位,默认 `high`;
|
|
143
|
+
- 输入框模型选择器旁显示每周剩余额度徽章,悬停或点击查看剩余比例与重置时间;
|
|
144
|
+
- 设置页可查看服务端返回的用量与剩余百分比,失败时明确提示而不是显示猜测值;
|
|
145
|
+
- 支持 CLI 登录、设备码登录、从 Grok CLI 拉取和登出;登录状态变化后 Chat 模型列表自动刷新;
|
|
146
|
+
- 订阅路由不可用时明确报错,不会静默切换到其他付费路由。
|
|
131
147
|
|
|
132
|
-
|
|
148
|
+
### 输入框额度
|
|
133
149
|
|
|
134
|
-
|
|
150
|
+
<p align="center">
|
|
151
|
+
<img src="docs/assets/composer-quota.webp" width="820" alt="DSH 输入框:Grok 4.7 模型选择器旁的每周剩余额度徽章">
|
|
152
|
+
</p>
|
|
135
153
|
|
|
136
|
-
|
|
154
|
+
仅当当前会话的 provider 为 `grok-build` 且用量读取成功时显示徽章;悬停或点击可查看「每周额度 剩余 N% · 重置于 M/D HH:mm」。徽章只反映服务端返回的每周额度;读取失败时徽章不显示,聊天不受影响。
|
|
137
155
|
|
|
138
|
-
###
|
|
156
|
+
### 推理档位
|
|
139
157
|
|
|
140
|
-
|
|
158
|
+
选择 Grok 模型后,模型菜单里会出现推理档位子菜单:`low` / `medium` / `high` / `xhigh`,默认 `high`。档位通过 `model.reasoning`(`efforts` + `defaultEffort`)元数据提供,因此与 Codex 在 DSH 中的交互一致;具体可用档位以账号模型目录为准。
|
|
141
159
|
|
|
142
|
-
|
|
160
|
+
### 模型目录与登录状态
|
|
143
161
|
|
|
144
|
-
|
|
162
|
+
登录后插件从订阅代理读取账号实际可用的模型目录;未登录时不注册任何模型。读取失败或超时时回退到内置列表(`grok-4.7` / `grok-4.6` / `grok-4.5`)并在状态里记录错误,因此目录不会留空,也不会让插件启动卡住。
|
|
145
163
|
|
|
146
|
-
|
|
164
|
+
## 更新与卸载
|
|
147
165
|
|
|
148
|
-
|
|
166
|
+
### 更新并检查
|
|
149
167
|
|
|
150
|
-
|
|
168
|
+
```sh
|
|
169
|
+
dsh plugin --profile web update dsh-grok-subscription
|
|
170
|
+
dsh plugin --profile web list dsh-grok-subscription --depth 0
|
|
171
|
+
dsh --profile web --dump-config
|
|
172
|
+
```
|
|
151
173
|
|
|
152
|
-
###
|
|
174
|
+
### 卸载
|
|
153
175
|
|
|
154
|
-
|
|
176
|
+
确认需要移除插件后再运行:
|
|
155
177
|
|
|
156
|
-
|
|
178
|
+
```sh
|
|
179
|
+
dsh plugin --profile web remove dsh-grok-subscription
|
|
180
|
+
```
|
|
157
181
|
|
|
158
|
-
|
|
182
|
+
这些操作会保留 DSH profile、其他插件和 `~/.grok/auth.json` 中的登录信息。
|
|
159
183
|
|
|
160
|
-
|
|
161
|
-
|
|
184
|
+
<details>
|
|
185
|
+
<summary>官方 npm 备用方式</summary>
|
|
162
186
|
|
|
163
|
-
|
|
164
|
-
|
|
187
|
+
```sh
|
|
188
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile web update dsh-grok-subscription
|
|
189
|
+
npx -y @deepseek-ai/dsh@0.1.5-rc.2 plugin --profile web remove dsh-grok-subscription
|
|
190
|
+
```
|
|
165
191
|
|
|
166
|
-
|
|
167
|
-
Fixes experimental usage parsing: live `/v1/billing?format=credits` nests `creditUsagePercent`, `currentPeriod`, and `productUsage` under `config` (not top-level). 0.1.4 failed QA with Unavailable. Parser now accepts `config.*` and top-level; unavailable reasons include top-level key names. Never invents percentages.
|
|
192
|
+
</details>
|
|
168
193
|
|
|
169
|
-
|
|
170
|
-
Experimental SuperGrok weekly usage in Settings: read-only `GET /v1/billing?format=credits` with the same OAuth + CLI fingerprint headers; shows used % and period end; RPC `usage` / `usage/refresh` never return tokens; fail closed to Unavailable. The billing API is undocumented and may change.
|
|
194
|
+
## 常见问题
|
|
171
195
|
|
|
172
|
-
|
|
173
|
-
|
|
196
|
+
- **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh@0.1.5-rc.2 ...` 命令;
|
|
197
|
+
- **模型列表是空的**:未登录时插件不暴露任何模型。先完成登录,再点 **从 Grok CLI 拉取**;
|
|
198
|
+
- **升级后界面没变化**:插件会继续运行旧的 `lib/`,请重新安装插件并重启 `dsh web`,然后硬刷新(Ctrl+Shift+R);
|
|
199
|
+
- **提示 `auth.json` 权限不正确**:按上面的 `chmod 600` 处理;插件拒绝读取符号链接或组/其他用户可读的文件;
|
|
200
|
+
- **出现「没有回复」**:请升级到 `1.0.1` 或更高版本。`1.0.0` 存在一个缺陷:工具调用轮次会因流片段无法无损序列化而整轮中止,界面上完全没有回复。
|
|
174
201
|
|
|
175
|
-
##
|
|
202
|
+
## 边界与支持
|
|
176
203
|
|
|
177
|
-
|
|
204
|
+
Grok 订阅后端和 DSH 可能独立变化;本项目为社区项目,与 DeepSeek、xAI 无隶属或背书关系。
|
|
178
205
|
|
|
179
|
-
|
|
180
|
-
- Pull 后 Chat / New Session 是否出现 `grok-4.7` 等 `grok-build` 模型并可发起推理
|
|
181
|
-
- `PiAiAdapter` 对 `grok-build` 路由的流式映射(若宿主没有 `@deepseek-ai/dsh-llm-pi-ai` / `@earendil-works/pi-ai`,插件会降级到自带的 Responses SSE MVP adapter)
|
|
182
|
-
- 官方 CLI `grok login` / `grok login --device-auth` 从 Settings 按钮拉起后的终端交互
|
|
183
|
-
- 实时 `GET /v1/models-v2` 是否返回 `grok-4.7`(目录为空时使用静态回退)
|
|
184
|
-
- Settings「用量(实验性)」:登录后刷新是否显示已用 % 与周期结束时间;401/网络失败是否显示「不可用」且无假百分比;Chat 在用量失败时仍可正常对话
|
|
206
|
+
敏感问题请先阅读 [SECURITY.md](SECURITY.md)。问题反馈请使用 [Issues](https://github.com/BaronCyrus/dsh-grok-subscription/issues)。
|
|
185
207
|
|
|
186
|
-
|
|
208
|
+
### 开发检查
|
|
187
209
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
210
|
+
```sh
|
|
211
|
+
npm install
|
|
212
|
+
npm test
|
|
213
|
+
npm run build
|
|
214
|
+
```
|
|
191
215
|
|
|
192
|
-
|
|
216
|
+
`lib/` 是提交进仓库的构建产物,改动 `src/` 后请运行 `npm run build`。
|
|
193
217
|
|
|
194
218
|
[MIT](LICENSE)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -34,7 +34,7 @@ var import_react2 = require("react");
|
|
|
34
34
|
var zh = {
|
|
35
35
|
nav: "Grok \u8BA2\u9605",
|
|
36
36
|
title: "Grok \u8BA2\u9605",
|
|
37
|
-
subtitle: "\u7528 SuperGrok / X Premium\uFF08Grok Build\uFF09\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F XAI_API_KEY\u3002\xB7 1.0.
|
|
37
|
+
subtitle: "\u7528 SuperGrok / X Premium\uFF08Grok Build\uFF09\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F XAI_API_KEY\u3002\xB7 1.0.3",
|
|
38
38
|
signedIn: "\u5DF2\u767B\u5F55",
|
|
39
39
|
signedOut: "\u672A\u767B\u5F55",
|
|
40
40
|
account: "\u8D26\u6237",
|
|
@@ -52,6 +52,8 @@ var zh = {
|
|
|
52
52
|
loginHint: "\u4F1A\u5728\u542F\u52A8 DSH \u7684\u7EC8\u7AEF\u4E2D\u8FD0\u884C grok login\u3002\u8BF7\u5728\u7EC8\u7AEF\u6216\u6D4F\u89C8\u5668\u4E2D\u5B8C\u6210\u6388\u6743\uFF0C\u7136\u540E\u7B49\u5F85\u540C\u6B65\u3002",
|
|
53
53
|
deviceHint: "\u8BBE\u5907\u7801\u63D0\u793A\u4F1A\u51FA\u73B0\u5728 DSH \u7EC8\u7AEF\u3002\u4E5F\u53EF\u624B\u52A8\u8FD0\u884C grok login --device-auth\uFF0C\u5B8C\u6210\u540E\u70B9\u201C\u4ECE Grok CLI \u62C9\u53D6\u201D\u3002",
|
|
54
54
|
pullHint: "\u5B89\u5168\u8BFB\u53D6 ~/.grok/auth.json\uFF08\u62D2\u7EDD\u7B26\u53F7\u94FE\u63A5\u4E0E\u7EC4/\u5176\u4ED6\u4EBA\u53EF\u8BFB\uFF09\uFF0C\u53EA\u628A\u77ED\u671F access token \u5199\u5165 DSH\u3002",
|
|
55
|
+
loginHelp: "\u767B\u5F55\u65B9\u5F0F\u8BF4\u660E",
|
|
56
|
+
refreshCatalog: "\u5237\u65B0\u6A21\u578B\u76EE\u5F55",
|
|
55
57
|
busy: "\u5904\u7406\u4E2D\u2026",
|
|
56
58
|
busyCatalog: "\u6B63\u5728\u5237\u65B0\u6A21\u578B\u76EE\u5F55\u2026",
|
|
57
59
|
busyUsage: "\u6B63\u5728\u5237\u65B0\u7528\u91CF\u2026",
|
|
@@ -81,7 +83,7 @@ var zh = {
|
|
|
81
83
|
var en = {
|
|
82
84
|
nav: "Grok Subscription",
|
|
83
85
|
title: "Grok Subscription",
|
|
84
|
-
subtitle: "Use a SuperGrok / X Premium (Grok Build) session, not XAI_API_KEY. \xB7 1.0.
|
|
86
|
+
subtitle: "Use a SuperGrok / X Premium (Grok Build) session, not XAI_API_KEY. \xB7 1.0.3",
|
|
85
87
|
signedIn: "Signed in",
|
|
86
88
|
signedOut: "Signed out",
|
|
87
89
|
account: "Account",
|
|
@@ -99,6 +101,8 @@ var en = {
|
|
|
99
101
|
loginHint: "Runs grok login in the terminal that started DSH. Finish the browser or CLI prompt there, then wait for sync.",
|
|
100
102
|
deviceHint: "The device-code prompt appears in the DSH terminal. You can also run grok login --device-auth yourself, then Pull from Grok CLI.",
|
|
101
103
|
pullHint: "Reads ~/.grok/auth.json securely (refuses symlinks and group/other-readable files) and stores only the short-lived access token in DSH.",
|
|
104
|
+
loginHelp: "How signing in works",
|
|
105
|
+
refreshCatalog: "Refresh model catalog",
|
|
102
106
|
busy: "Working\u2026",
|
|
103
107
|
busyCatalog: "Refreshing model catalog\u2026",
|
|
104
108
|
busyUsage: "Refreshing usage\u2026",
|
|
@@ -165,6 +169,83 @@ var REQUEST_IMAGE_PIXEL_BUDGET = 2048 * 2048;
|
|
|
165
169
|
var REQUEST_IMAGE_MAX_BYTES = 1024 * 1024;
|
|
166
170
|
var FALLBACK_MODEL_IDS = Object.freeze(["grok-4.7", "grok-4.6", "grok-4.5"]);
|
|
167
171
|
|
|
172
|
+
// src/client-settings-style.js
|
|
173
|
+
var SETTINGS_STYLE = `
|
|
174
|
+
.grokSubscription{display:flex;flex-direction:column;gap:10px;max-width:720px;color:var(--dsw-alias-label-primary);container-type:inline-size}
|
|
175
|
+
.grokSubscription h2,.grokSubscription h3,.grokSubscription p{margin:0}
|
|
176
|
+
.grokSubscription h2{font-size:16px;line-height:24px;font-weight:500}
|
|
177
|
+
.grokSubscription h3{font-size:15px;line-height:22px;font-weight:600}
|
|
178
|
+
|
|
179
|
+
.gsHead{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
|
|
180
|
+
.gsLead{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}
|
|
181
|
+
|
|
182
|
+
.gsCard{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);border-radius:16px;padding:14px 16px;display:flex;flex-direction:column;gap:12px}
|
|
183
|
+
.gsCardHead{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
184
|
+
.gsCardHead .gsSpacer{flex:1;min-width:0}
|
|
185
|
+
|
|
186
|
+
.gsChip{display:inline-flex;align-items:center;gap:6px;border-radius:999px;padding:2px 10px;font-size:12px;line-height:18px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);white-space:nowrap}
|
|
187
|
+
.gsChip--ok{color:var(--dsw-alias-state-success-primary)}
|
|
188
|
+
.gsChip--off{color:var(--dsw-alias-label-tertiary)}
|
|
189
|
+
.gsChip--warn{color:var(--dsw-alias-state-warn-label)}
|
|
190
|
+
.gsChip--error{color:var(--dsw-alias-label-error)}
|
|
191
|
+
.gsDot{width:6px;height:6px;border-radius:50%;background:currentColor;flex:none}
|
|
192
|
+
|
|
193
|
+
.gsAccount{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
|
|
194
|
+
|
|
195
|
+
.gsActions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
|
|
196
|
+
.gsBtn{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border:.5px solid var(--dsw-alias-border-l3);border-radius:18px;display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0 14px;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary);background:0 0;transition:background .16s,border-color .16s,color .16s}
|
|
197
|
+
.gsBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
198
|
+
.gsBtn:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}
|
|
199
|
+
.gsBtn:disabled{opacity:.45;cursor:not-allowed}
|
|
200
|
+
.gsBtn--primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:transparent}
|
|
201
|
+
.gsBtn--primary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}
|
|
202
|
+
.gsBtn--danger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}
|
|
203
|
+
|
|
204
|
+
.gsStatus{display:flex;align-items:flex-start;gap:8px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}
|
|
205
|
+
.gsStatus--ok{color:var(--dsw-alias-state-success-primary)}
|
|
206
|
+
.gsStatus--error{color:var(--dsw-alias-label-error)}
|
|
207
|
+
.gsStatus--warn{color:var(--dsw-alias-state-warn-label)}
|
|
208
|
+
.gsStatus--busy{color:var(--dsw-alias-label-tertiary)}
|
|
209
|
+
|
|
210
|
+
.gsDisclosure{margin:0}
|
|
211
|
+
.gsDisclosure>summary{display:flex;align-items:center;gap:8px;min-height:28px;cursor:pointer;list-style:none;font-size:13px;line-height:20px;color:var(--dsw-alias-label-secondary)}
|
|
212
|
+
.gsDisclosure>summary::-webkit-details-marker{display:none}
|
|
213
|
+
.gsDisclosure>summary:hover{color:var(--dsw-alias-label-primary)}
|
|
214
|
+
.gsDisclosure>summary:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:4px;border-radius:4px}
|
|
215
|
+
.gsChevron{flex:none;transition:transform .16s}
|
|
216
|
+
.gsDisclosure[open] .gsChevron{transform:rotate(180deg)}
|
|
217
|
+
.gsDisclosureBody{display:flex;flex-direction:column;gap:6px;padding-top:8px;margin-top:8px;border-top:.5px solid var(--dsw-alias-border-l2)}
|
|
218
|
+
.gsDisclosureBody p{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
|
|
219
|
+
|
|
220
|
+
.gsGauge{display:flex;flex-direction:column;gap:8px}
|
|
221
|
+
.gsGaugeTop{display:flex;align-items:baseline;gap:8px}
|
|
222
|
+
.gsGaugeValue{font-size:24px;line-height:30px;font-weight:600;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums}
|
|
223
|
+
.gsGaugeLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary)}
|
|
224
|
+
.gsBar{height:6px;border-radius:999px;background:color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent);overflow:hidden}
|
|
225
|
+
.gsBar>span{display:block;height:100%;border-radius:999px;background:var(--dsw-alias-brand-primary);transition:width .2s}
|
|
226
|
+
.gsGaugeMeta{display:flex;flex-wrap:wrap;gap:4px 10px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary)}
|
|
227
|
+
.gsGaugeMeta code{font-size:11px;color:var(--dsw-alias-label-tertiary)}
|
|
228
|
+
|
|
229
|
+
.gsRows{display:flex;flex-direction:column;gap:0}
|
|
230
|
+
.gsRow{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:7px 0;font-size:13px;line-height:20px;border-top:.5px solid var(--dsw-alias-border-l2)}
|
|
231
|
+
.gsRow:first-child{border-top:none}
|
|
232
|
+
.gsRowValue{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap}
|
|
233
|
+
|
|
234
|
+
.gsModels{display:flex;flex-wrap:wrap;gap:6px}
|
|
235
|
+
.gsModel{display:inline-flex;align-items:baseline;gap:6px;border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:4px 10px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary)}
|
|
236
|
+
.gsModel code{font-size:11px;color:var(--dsw-alias-label-tertiary)}
|
|
237
|
+
|
|
238
|
+
.gsHint,.gsEmpty,.gsCaveat{margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}
|
|
239
|
+
.gsCaveat{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
|
|
240
|
+
.gsLink{color:var(--dsw-alias-link);font-size:13px;line-height:20px;text-decoration:none;align-self:center}
|
|
241
|
+
.gsLink:hover{text-decoration:underline}
|
|
242
|
+
|
|
243
|
+
@container (max-width: 420px){
|
|
244
|
+
.grokSubscription .gsGaugeValue{font-size:20px;line-height:26px}
|
|
245
|
+
.grokSubscription .gsBtn{flex:1 1 auto}
|
|
246
|
+
}
|
|
247
|
+
`;
|
|
248
|
+
|
|
168
249
|
// src/client-composer-quota.jsx
|
|
169
250
|
var import_react = require("react");
|
|
170
251
|
var import_react_dom = require("react-dom");
|
|
@@ -533,60 +614,66 @@ async function callRpc(rpc, endpoint, payload = {}) {
|
|
|
533
614
|
if (timer) clearTimeout(timer);
|
|
534
615
|
}
|
|
535
616
|
}
|
|
617
|
+
function Chevron() {
|
|
618
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { className: "gsChevron", width: "12", height: "12", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4 6l4 4 4-4", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round" }) });
|
|
619
|
+
}
|
|
620
|
+
function Chip({ tone = "off", children }) {
|
|
621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: `gsChip gsChip--${tone}`, children: [
|
|
622
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gsDot" }),
|
|
623
|
+
children
|
|
624
|
+
] });
|
|
625
|
+
}
|
|
536
626
|
function UsagePanel({ usage, t, usageBusy, onRefresh, signedIn }) {
|
|
537
627
|
const ok = usage?.status === "ok";
|
|
538
628
|
const used = ok ? formatPercent(usage.usedPercent) : void 0;
|
|
539
629
|
const remaining = ok ? formatPercent(usage.remainingPercent) : void 0;
|
|
540
630
|
const resetLabel = usage?.periodEndLocal || usage?.periodEnd;
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("
|
|
549
|
-
|
|
631
|
+
const gaugeValue = remaining ?? (used !== void 0 ? formatPercent(100 - Number(used)) : void 0);
|
|
632
|
+
const gaugeLabel = remaining !== void 0 ? t("usageRemaining") : t("usageUsed");
|
|
633
|
+
const fill = typeof gaugeValue === "number" && Number.isFinite(gaugeValue) ? Math.min(100, Math.max(0, gaugeValue)) : 0;
|
|
634
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsCard", children: [
|
|
635
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gsCardHead", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { children: t("usageTitle") }) }),
|
|
636
|
+
ok && (used !== void 0 || remaining !== void 0) ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsGauge", children: [
|
|
637
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsGaugeTop", children: [
|
|
638
|
+
gaugeValue !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gsGaugeValue", children: [
|
|
639
|
+
gaugeValue,
|
|
550
640
|
"%"
|
|
551
|
-
] }),
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
641
|
+
] }) : null,
|
|
642
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gsGaugeLabel", children: gaugeLabel })
|
|
643
|
+
] }),
|
|
644
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gsBar", role: "img", "aria-label": `${gaugeLabel} ${gaugeValue ?? 0}%`, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { width: `${fill}%` } }) }),
|
|
645
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsGaugeMeta", children: [
|
|
646
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
647
|
+
t("usageUsed"),
|
|
555
648
|
" ",
|
|
556
|
-
|
|
649
|
+
used ?? "\u2014",
|
|
557
650
|
"%"
|
|
558
|
-
] })
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
usage.periodEnd && usage.periodEndLocal ? /* @__PURE__ */ (0, import_jsx_runtime2.
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
")"
|
|
568
|
-
] }) : null
|
|
569
|
-
] }) : null,
|
|
570
|
-
Array.isArray(usage.productUsage) && usage.productUsage.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
571
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("usageProduct") }),
|
|
572
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { children: usage.productUsage.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { children: [
|
|
573
|
-
row.name ?? "\u2014",
|
|
574
|
-
typeof row.usedPercent === "number" ? ` \xB7 ${formatPercent(row.usedPercent)}%` : ""
|
|
575
|
-
] }, `${row.name ?? "row"}-${index}`)) })
|
|
576
|
-
] }) : null,
|
|
577
|
-
usage.fetchedAt ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "muted", children: [
|
|
578
|
-
t("usageFetchedAt"),
|
|
579
|
-
": ",
|
|
580
|
-
usage.fetchedAt
|
|
581
|
-
] }) : null
|
|
582
|
-
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
|
|
651
|
+
] }),
|
|
652
|
+
resetLabel ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
|
|
653
|
+
t("usageReset"),
|
|
654
|
+
" ",
|
|
655
|
+
resetLabel
|
|
656
|
+
] }) : null,
|
|
657
|
+
usage.periodEnd && usage.periodEndLocal ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: usage.periodEnd }) : null
|
|
658
|
+
] })
|
|
659
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "gsEmpty", children: [
|
|
583
660
|
t("usageUnavailable"),
|
|
584
661
|
usage?.reason ? `: ${usage.reason}` : ""
|
|
585
662
|
] }),
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("
|
|
589
|
-
|
|
663
|
+
Array.isArray(usage.productUsage) && usage.productUsage.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gsRows", children: usage.productUsage.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsRow", children: [
|
|
664
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: row.name ?? "\u2014" }),
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gsRowValue", children: typeof row.usedPercent === "number" ? `${formatPercent(row.usedPercent)}%` : "\u2014" })
|
|
666
|
+
] }, `${row.name ?? "row"}-${index}`)) }) : null,
|
|
667
|
+
usage.fetchedAt ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "gsHint", children: [
|
|
668
|
+
t("usageFetchedAt"),
|
|
669
|
+
": ",
|
|
670
|
+
usage.fetchedAt
|
|
671
|
+
] }) : null,
|
|
672
|
+
usageBusy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsStatus gsStatus--busy", children: t("busyUsage") }) : null,
|
|
673
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsHint", children: t("usageSubtitle") }),
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsActions", children: [
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "gsBtn", type: "button", disabled: Boolean(usageBusy) || !signedIn, onClick: onRefresh, children: t("usageRefresh") }),
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { className: "gsLink", href: USAGE_PAGE_URL, target: "_blank", rel: "noreferrer", children: t("usageOpenGrok") })
|
|
590
677
|
] })
|
|
591
678
|
] });
|
|
592
679
|
}
|
|
@@ -660,7 +747,8 @@ function GrokSubscriptionSection({ rpc, t }) {
|
|
|
660
747
|
"login/cli": "loginOk",
|
|
661
748
|
"login/device": "loginOk",
|
|
662
749
|
logout: "logoutOk",
|
|
663
|
-
"usage/refresh": "usageRefreshOk"
|
|
750
|
+
"usage/refresh": "usageRefreshOk",
|
|
751
|
+
"catalog/refresh": "catalogRefreshOk"
|
|
664
752
|
}[endpoint];
|
|
665
753
|
if (successKey) setNotice(t(successKey));
|
|
666
754
|
if (endpoint === "usage/refresh" && value?.ok !== false && !value?.error) {
|
|
@@ -682,47 +770,43 @@ function GrokSubscriptionSection({ rpc, t }) {
|
|
|
682
770
|
const models = catalog?.models ?? [];
|
|
683
771
|
const signedIn = account?.signedIn === true;
|
|
684
772
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "grokSubscription", children: [
|
|
685
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children:
|
|
686
|
-
|
|
687
|
-
.grokSubscription h2 { margin: 0 0 4px; font-size: 1.15rem; }
|
|
688
|
-
.grokSubscription p, .grokSubscription li { line-height: 1.5; }
|
|
689
|
-
.grokSubscription .muted { opacity: 0.78; font-size: 0.92rem; }
|
|
690
|
-
.grokSubscription .row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
|
691
|
-
.grokSubscription button { cursor: pointer; }
|
|
692
|
-
.grokSubscription .error { color: #b42318; }
|
|
693
|
-
.grokSubscription .notice { color: #067647; }
|
|
694
|
-
.grokSubscription ul { margin: 0; padding-left: 1.2rem; }
|
|
695
|
-
.grokSubscription .usageBlock { display: grid; gap: 8px; padding: 10px 0; border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent); }
|
|
696
|
-
.grokSubscription a { color: inherit; }
|
|
697
|
-
` }),
|
|
698
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
773
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: SETTINGS_STYLE }),
|
|
774
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsHead", children: [
|
|
699
775
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: t("title") }),
|
|
700
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
776
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Chip, { tone: signedIn ? "ok" : "off", children: signedIn ? t("signedIn") : t("signedOut") })
|
|
701
777
|
] }),
|
|
702
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
": "
|
|
778
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsLead", children: t("subtitle") }),
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsCard", children: [
|
|
780
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsCardHead", children: [
|
|
781
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { children: t("account") }),
|
|
782
|
+
signedIn && account?.maskedAccount ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gsAccount", children: account.maskedAccount }) : null
|
|
706
783
|
] }),
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("
|
|
784
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsActions", children: [
|
|
785
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "gsBtn gsBtn--primary", type: "button", disabled: Boolean(busy), onClick: () => void run("login/cli"), children: t("loginCli") }),
|
|
786
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "gsBtn", type: "button", disabled: Boolean(busy), onClick: () => void run("login/device"), children: t("loginDevice") }),
|
|
787
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "gsBtn", type: "button", disabled: Boolean(busy), onClick: () => void run("pull"), children: t("pull") }),
|
|
788
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "gsBtn gsBtn--danger", type: "button", disabled: Boolean(busy) || !signedIn, onClick: () => void run("logout"), children: t("logout") })
|
|
789
|
+
] }),
|
|
790
|
+
busy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsStatus gsStatus--busy", children: t("busy") }) : null,
|
|
791
|
+
notice ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsStatus gsStatus--ok", children: notice }) : null,
|
|
792
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "gsStatus gsStatus--error", children: [
|
|
793
|
+
t("error"),
|
|
794
|
+
": ",
|
|
795
|
+
error
|
|
796
|
+
] }) : null,
|
|
797
|
+
status?.cliAvailable === false ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsStatus gsStatus--warn", children: t("cliMissing") }) : null,
|
|
798
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("details", { className: "gsDisclosure", children: [
|
|
799
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("summary", { children: [
|
|
800
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Chevron, {}),
|
|
801
|
+
t("loginHelp")
|
|
802
|
+
] }),
|
|
803
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsDisclosureBody", children: [
|
|
804
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: t("loginHint") }),
|
|
805
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: t("deviceHint") }),
|
|
806
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: t("pullHint") })
|
|
807
|
+
] })
|
|
808
|
+
] })
|
|
714
809
|
] }),
|
|
715
|
-
busy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("busy") }) : null,
|
|
716
|
-
notice ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "notice", children: notice }) : null,
|
|
717
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "error", children: [
|
|
718
|
-
t("error"),
|
|
719
|
-
": ",
|
|
720
|
-
error
|
|
721
|
-
] }) : null,
|
|
722
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("loginHint") }),
|
|
723
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("deviceHint") }),
|
|
724
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("pullHint") }),
|
|
725
|
-
status?.cliAvailable === false ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("cliMissing") }) : null,
|
|
726
810
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
727
811
|
UsagePanel,
|
|
728
812
|
{
|
|
@@ -733,21 +817,25 @@ function GrokSubscriptionSection({ rpc, t }) {
|
|
|
733
817
|
onRefresh: () => void run("usage/refresh")
|
|
734
818
|
}
|
|
735
819
|
),
|
|
736
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
|
|
737
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
738
|
-
|
|
739
|
-
|
|
820
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsCard", children: [
|
|
821
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gsCardHead", children: [
|
|
822
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { children: t("models") }),
|
|
823
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gsSpacer" }),
|
|
824
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Chip, { tone: catalog?.source === "live" ? "ok" : catalog?.source === "fallback" ? "warn" : "off", children: sourceLabel(catalog?.source, t) })
|
|
825
|
+
] }),
|
|
826
|
+
models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsEmpty", children: t("noModels") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gsModels", children: models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gsModel", children: [
|
|
740
827
|
model.name,
|
|
741
828
|
" ",
|
|
742
829
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: model.id })
|
|
743
830
|
] }, model.id)) }),
|
|
744
|
-
catalog?.error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "error", children: [
|
|
831
|
+
catalog?.error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "gsStatus gsStatus--error", children: [
|
|
745
832
|
t("catalogError"),
|
|
746
833
|
": ",
|
|
747
834
|
catalog.error
|
|
748
|
-
] }) : null
|
|
835
|
+
] }) : null,
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gsActions", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { className: "gsBtn", type: "button", disabled: !signedIn, onClick: () => void run("catalog/refresh"), children: t("refreshCatalog") }) })
|
|
749
837
|
] }),
|
|
750
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "
|
|
838
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "gsCaveat", children: t("caveats") })
|
|
751
839
|
] });
|
|
752
840
|
}
|
|
753
841
|
function apply(ctx) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-grok-subscription",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Use a SuperGrok or X Premium Grok Build subscription in DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -12,8 +12,11 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"lib",
|
|
15
|
+
"docs/assets",
|
|
15
16
|
"cordis.patch.yml",
|
|
16
17
|
"README.md",
|
|
18
|
+
"README.en.md",
|
|
19
|
+
"CONTRIBUTING.md",
|
|
17
20
|
"SECURITY.md",
|
|
18
21
|
"LICENSE"
|
|
19
22
|
],
|