dsh-opencode-go 0.1.0 → 0.1.2
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 +72 -52
- package/docs/verification.md +7 -1
- package/lib/client.js +198 -2
- package/lib/index.js +68 -0
- package/lib/types/client/UsagePill.d.ts +10 -0
- package/lib/types/client/locales.d.ts +10 -0
- package/lib/types/client/usage.d.ts +2 -0
- package/lib/types/usage-contract.d.ts +21 -0
- package/lib/types/usage.d.ts +14 -0
- package/package.json +53 -31
package/README.md
CHANGED
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
# dsh-opencode-go
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 中使用 OpenCode Go 订阅模型,支持流式回复、工具调用、图片输入和 Web 设置页。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
插件自动添加 OpenCode Go 所需的会话请求头,并从网关获取可用模型目录。通过 DSH 插件命令安装,无需修改 DSH 源码。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## 安装与使用
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
已验证兼容 **DSH `0.1.6-alpha.1`**。其他版本尚未验证。
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
在已经安装兼容版本 DSH 的环境执行:
|
|
11
|
+
### Web
|
|
14
12
|
|
|
15
13
|
```sh
|
|
16
14
|
dsh plugin --profile web add dsh-opencode-go
|
|
17
|
-
dsh --profile web --dump-config
|
|
18
|
-
dsh web
|
|
19
15
|
```
|
|
20
16
|
|
|
21
|
-
|
|
17
|
+
安装后启动或重启 `dsh web`:
|
|
18
|
+
|
|
19
|
+
1. 打开 **设置 → OpenCode Go**。
|
|
20
|
+
2. 填入 OpenCode Go API Key 并保存。
|
|
21
|
+
3. 在会话的模型选择器中选择 OpenCode Go 模型。
|
|
22
|
+
|
|
23
|
+
API Key 来自你的 OpenCode Go 订阅。安装插件不会自动更改默认模型。
|
|
24
|
+
|
|
25
|
+
### Headless
|
|
26
|
+
|
|
27
|
+
安装到 Headless profile:
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
```sh
|
|
30
|
+
dsh plugin --profile headless add dsh-opencode-go
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
将以下内容保存为 `headless.patch.yml`,选择默认模型:
|
|
24
34
|
|
|
25
35
|
```yaml
|
|
26
36
|
- id: agent-default-model
|
|
@@ -29,35 +39,31 @@ Headless 用户先把以下内容保存为当前目录下的 `headless.patch.yml
|
|
|
29
39
|
model: deepseek-v4.1-flash
|
|
30
40
|
```
|
|
31
41
|
|
|
32
|
-
|
|
42
|
+
在 Bash 或 Zsh 中读取 API Key,然后运行任务:
|
|
33
43
|
|
|
34
44
|
```sh
|
|
35
|
-
dsh plugin --profile headless add dsh-opencode-go
|
|
36
45
|
read -s OPENCODE_API_KEY
|
|
37
46
|
export OPENCODE_API_KEY
|
|
38
47
|
dsh --profile headless --patch ./headless.patch.yml "你好"
|
|
39
48
|
```
|
|
40
49
|
|
|
41
|
-
|
|
50
|
+
模型 ID 须在当前网关目录中可用。Web 和 Headless 使用各自的 profile,需要分别安装插件。
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
## 订阅用量
|
|
44
53
|
|
|
45
|
-
|
|
54
|
+
Web 中选择 `opencode-go` 提供方的模型后,模型名左侧显示 **Go · 5h 已用百分比 · 周已用百分比**。点击可查看 5 小时、每周、每月用量和本地时区的重置时间。
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
数据通过 Host 使用已配置的 API Key 查询 `GET /zen/go/v1/usage`,每分钟刷新;浏览器不接收 API Key。切换到其他提供方后隐藏,页面不可见时暂停查询。接口失败或响应缺失时显示“暂不可用”,不会填成 0%。接口返回的是账号订阅额度,不是当前会话 token 数。
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
- id: llm-opencode-go
|
|
51
|
-
disabled: true
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
无需删除原仓库代码;停用旧行后由外部安装包提供功能。
|
|
58
|
+
这个接口可在 [OpenCode 官方源码](https://github.com/anomalyco/opencode/blob/dev/packages/console/app/src/routes/zen/go/v1/usage.ts) 中查到;当前返回 `rolling`、`weekly`、`monthly` 各窗口的 `status`、`percent` 和 `resetsAt`,不返回缓存命中率。
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
底部的缓存命中率由每次模型响应的缓存 token 统计计算。插件支持 `prompt_tokens_details.cached_tokens`、`prompt_cache_hit_tokens` 和顶层 `cached_tokens`。上游未返回缓存统计时,当前 pi-ai / Harness 统计链路也可能显示 0;可在 OpenCode 控制台的使用历史中展开对应请求的输入明细进行核对。新会话首次请求出现 0 命中是可能的,同一会话后续有可复用的提示前缀才可能命中。
|
|
57
61
|
|
|
58
62
|
## 配置
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
Web 用户可直接在 **设置 → OpenCode Go** 中修改配置。启用开关立即生效;保存其他配置后,后续请求使用新值。
|
|
65
|
+
|
|
66
|
+
需要通过文件配置时,在对应 profile 的 `cordis.patch.yml` 中添加以下内容。所有字段均有默认值,通常只需配置 API Key。
|
|
61
67
|
|
|
62
68
|
```yaml
|
|
63
69
|
- id: opencode-go
|
|
@@ -72,50 +78,64 @@ dsh --profile headless --patch ./headless.patch.yml "你好"
|
|
|
72
78
|
requestImageMaxBytes: 1048576
|
|
73
79
|
```
|
|
74
80
|
|
|
75
|
-
|
|
81
|
+
`apiKeyEnv` 是凭据引用名,不是密钥。插件通过 DSH credentials 服务解析凭据;未挂载该服务时读取进程环境。Web 保存的设置可覆盖文件中的基础配置。
|
|
76
82
|
|
|
77
|
-
|
|
83
|
+
关闭插件开关或移除密钥会撤下提供方路由,设置页仍可访问。
|
|
78
84
|
|
|
79
|
-
|
|
80
|
-
- 模型目录取 pi-ai 目录及本项目补充表与网关 `/models` 的交集。未知协议的模型不会猜测加入。
|
|
81
|
-
- 实时目录获取失败时,请求目录可回退到本地表;显式模型发现会报告失败。
|
|
82
|
-
- 保留流式输出、工具调用、历史回放及支持图片的模型转换;输入图片须有 DSH attachment 服务。
|
|
83
|
-
- 模型看到会话内容和工具定义,不增加隐藏系统提示。会话请求头用于网关路由;图片编码和历史前缀影响缓存复用。
|
|
85
|
+
## 常见问题
|
|
84
86
|
|
|
85
|
-
|
|
87
|
+
### 安装提示依赖构建脚本被拦截
|
|
86
88
|
|
|
87
|
-
|
|
89
|
+
按安装器提示,在该 profile 的 `pnpm-workspace.yaml` 中逐项设置 `allowBuilds`。OpenCode Go 已验证的运行路径不需要执行 `@google/genai` 和 `protobufjs` 的安装脚本,可以将这两项设为 `false` 后重试。保留文件中的其他配置,无需全局放开安装脚本。
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
npm ci
|
|
91
|
-
npm test
|
|
92
|
-
npm pack
|
|
93
|
-
```
|
|
91
|
+
### 提示 `opencode-go` 路由已被占用
|
|
94
92
|
|
|
95
|
-
|
|
93
|
+
同一 profile 中只能有一个适配器提供 `opencode-go` 路由。如果已经通过其他插件或通用 pi-ai 配置接入 OpenCode Go,请先停用那一项配置。其他提供方可以继续使用。
|
|
96
94
|
|
|
97
|
-
|
|
95
|
+
### 没有出现预期的模型
|
|
98
96
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
npm run verify:installed -- /path/to/isolated-consumer
|
|
103
|
-
npm run verify:headless -- /path/to/isolated-consumer
|
|
104
|
-
```
|
|
97
|
+
先确认插件已启用且 API Key 已配置,再刷新设置页中的模型列表。插件仅展示本地适配表与网关实时目录的交集;尚未适配协议的新模型不会自动加入。
|
|
98
|
+
|
|
99
|
+
实时目录获取失败时,适配器可使用本地表继续处理请求;设置页中的模型发现会显示失败,便于重新尝试。
|
|
105
100
|
|
|
106
|
-
|
|
101
|
+
## 功能说明
|
|
107
102
|
|
|
108
|
-
|
|
103
|
+
- **会话请求头**:每次请求包含 Harness User-Agent 和 `x-opencode-session`。同一会话保持相同 ID,无会话 ID 的请求使用独立随机值。
|
|
104
|
+
- **流式与历史**:支持流式输出、工具调用及历史回放,协议请求由 pi-ai 执行。
|
|
105
|
+
- **图片输入**:支持目录中声明图片能力的模型,需要 DSH attachment 服务。
|
|
106
|
+
- **提示与缓存**:插件不增加隐藏系统提示;会话 ID 用于网关路由,历史前缀及图片编码影响缓存复用。
|
|
109
107
|
|
|
110
108
|
## 卸载
|
|
111
109
|
|
|
110
|
+
从对应 profile 移除插件,再重启应用:
|
|
111
|
+
|
|
112
112
|
```sh
|
|
113
113
|
dsh plugin --profile web remove dsh-opencode-go
|
|
114
|
+
# 或
|
|
114
115
|
dsh plugin --profile headless remove dsh-opencode-go
|
|
115
116
|
```
|
|
116
117
|
|
|
117
|
-
|
|
118
|
+
如果默认模型仍指向 `opencode-go`,请改选其他提供方。凭据和历史会话由 DSH 管理。
|
|
119
|
+
|
|
120
|
+
## 开发
|
|
121
|
+
|
|
122
|
+
需要 Node.js `^22.19.0 || >=24.0.0` 和 npm。
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
npm ci
|
|
126
|
+
npm run typecheck
|
|
127
|
+
npm test
|
|
128
|
+
npm pack
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`npm test` 会先构建再执行测试;`npm pack` 生成可安装的 `.tgz` 包。依赖均通过 npm 安装,不需要 DSH 源码仓库。
|
|
132
|
+
|
|
133
|
+
- [验证说明](docs/verification.md):测试范围、隔离安装与 Headless 验证方法。
|
|
134
|
+
- [架构与依赖](docs/independent-package.md):Host、Client 构建方式和转换代码的维护方式。
|
|
135
|
+
- [第三方声明](THIRD_PARTY_NOTICES.md):代码来源与许可。
|
|
136
|
+
|
|
137
|
+
自动化测试使用本地模拟网关,不会发起付费模型请求。真实账号、Desktop 和其他操作系统尚未验证。
|
|
118
138
|
|
|
119
|
-
##
|
|
139
|
+
## 许可证
|
|
120
140
|
|
|
121
|
-
|
|
141
|
+
[MIT](LICENSE)
|
package/docs/verification.md
CHANGED
|
@@ -45,6 +45,12 @@ The tarball was installed into a separate Web profile in the same temporary Harn
|
|
|
45
45
|
|
|
46
46
|
The browser-factory test additionally evaluates the distributed `lib/client.js` against the published React/store/UI module table, checks the package ID, mounts the settings section, and verifies CSS insertion.
|
|
47
47
|
|
|
48
|
-
##
|
|
48
|
+
## Subscription usage verification (0.1.1)
|
|
49
|
+
|
|
50
|
+
The usage tests invoke the actual published Typert Host gateway against a local HTTP fixture, checking the Bearer credential, credential changes, all three windows, and failure handling. Browser component tests check provider switching, polling cleanup, monthly details, and failed-refresh behavior. Adapter tests cover non-zero cached input in OpenAI, DeepSeek, and Kimi usage fields.
|
|
51
|
+
|
|
52
|
+
The local Web profile was also checked against the real read-only OpenCode Go usage endpoint. The button renders immediately before the model selector, and its details show rolling, weekly, and monthly percentages and local reset times. This check sends no model-generation request. The manual Remote codec supports both the published DSH `schema` shape and the current source build's `create()` shape.
|
|
53
|
+
|
|
54
|
+
## Remaining limits
|
|
49
55
|
|
|
50
56
|
Real paid OpenCode Go completions, Desktop, non-macOS platforms, and other DSH releases are not verified. The automated gateway tests preserve the adapter's request and replay semantics but cannot establish account validity or live provider availability.
|
package/lib/client.js
CHANGED
|
@@ -32,7 +32,7 @@ var import_react = require("react");
|
|
|
32
32
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
33
33
|
|
|
34
34
|
// plugin-css:/Users/tanglei/Desktop/dsh-opencode-go/src/client/Section.module.css
|
|
35
|
-
var id = "dsh-opencode-go/
|
|
35
|
+
var id = "dsh-opencode-go/Section.module.css";
|
|
36
36
|
if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")) {
|
|
37
37
|
const style = document.createElement("style");
|
|
38
38
|
style.dataset.plugin = "dsh-opencode-go";
|
|
@@ -40,7 +40,7 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")
|
|
|
40
40
|
style.textContent = ".BtKYva_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.BtKYva_field+.BtKYva_field{border-top:.5px solid var(--dsw-alias-border-l2)}.BtKYva_head{align-items:center;gap:8px;display:flex}.BtKYva_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.BtKYva_badges{align-items:center;gap:8px;display:inline-flex}.BtKYva_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.BtKYva_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.BtKYva_reset:disabled{cursor:default}.BtKYva_input{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.BtKYva_input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.BtKYva_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.BtKYva_inputInvalid{border-color:var(--dsw-alias-label-error);}.BtKYva_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.BtKYva_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.BtKYva_intro{color:var(--dsw-alias-label-secondary);margin:0 0 8px;font-size:13px;line-height:1.5}.BtKYva_disclosure{font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;margin:0;padding:0;display:flex}.BtKYva_disclosure:hover .BtKYva_label{color:var(--dsw-alias-brand-primary)}.BtKYva_chevron,.BtKYva_chevronOpen{color:var(--dsw-alias-label-tertiary);flex:none}.BtKYva_chevron{transform:rotate(-90deg)}.BtKYva_advanced{flex-direction:column;gap:4px;padding:4px 0 0 22px;display:flex}.BtKYva_advanced .BtKYva_field+.BtKYva_field{border-top:none}.BtKYva_chips{flex-wrap:wrap;gap:6px;display:flex}.BtKYva_actions{align-items:center;gap:8px;padding-top:12px;display:flex}.BtKYva_failedNote{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}";
|
|
41
41
|
document.head.appendChild(style);
|
|
42
42
|
}
|
|
43
|
-
var Section_default = { "
|
|
43
|
+
var Section_default = { "inputInvalid": "BtKYva_inputInvalid", "failedNote": "BtKYva_failedNote", "chips": "BtKYva_chips", "disclosure": "BtKYva_disclosure", "head": "BtKYva_head", "label": "BtKYva_label", "input": "BtKYva_input", "advanced": "BtKYva_advanced", "invalid": "BtKYva_invalid", "intro": "BtKYva_intro", "chevron": "BtKYva_chevron", "badges": "BtKYva_badges", "reset": "BtKYva_reset", "hint": "BtKYva_hint", "chevronOpen": "BtKYva_chevronOpen", "actions": "BtKYva_actions", "field": "BtKYva_field" };
|
|
44
44
|
|
|
45
45
|
// src/client/Section.tsx
|
|
46
46
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -731,6 +731,16 @@ function refOf(snapshot) {
|
|
|
731
731
|
|
|
732
732
|
// src/client/locales.ts
|
|
733
733
|
var en = {
|
|
734
|
+
usageTitle: "OpenCode Go usage",
|
|
735
|
+
usageHint: "Account usage \xB7 used percentage \xB7 refreshes every minute",
|
|
736
|
+
usageWeekShort: "week",
|
|
737
|
+
usage_rolling: "5 hours",
|
|
738
|
+
usage_weekly: "Weekly",
|
|
739
|
+
usage_monthly: "Monthly",
|
|
740
|
+
usageResets: "Resets",
|
|
741
|
+
usageLimited: "Limit reached",
|
|
742
|
+
usageLoading: "Loading usage\u2026",
|
|
743
|
+
usageUnavailable: "Unavailable",
|
|
734
744
|
nav: "OpenCode Go",
|
|
735
745
|
title: "OpenCode Go",
|
|
736
746
|
intro: "Use your OpenCode Go subscription in the harness. Paste the API key below and save; the models the gateway currently serves are listed underneath.",
|
|
@@ -776,6 +786,16 @@ var en = {
|
|
|
776
786
|
unavailable: "The OpenCode Go settings are not served in this deployment."
|
|
777
787
|
};
|
|
778
788
|
var zh = {
|
|
789
|
+
usageTitle: "OpenCode Go \u7528\u91CF",
|
|
790
|
+
usageHint: "\u8D26\u53F7\u989D\u5EA6 \xB7 \u5DF2\u7528\u767E\u5206\u6BD4 \xB7 \u6BCF\u5206\u949F\u5237\u65B0",
|
|
791
|
+
usageWeekShort: "\u5468",
|
|
792
|
+
usage_rolling: "5 \u5C0F\u65F6",
|
|
793
|
+
usage_weekly: "\u6BCF\u5468",
|
|
794
|
+
usage_monthly: "\u6BCF\u6708",
|
|
795
|
+
usageResets: "\u91CD\u7F6E\u4E8E",
|
|
796
|
+
usageLimited: "\u5DF2\u8FBE\u9650\u989D",
|
|
797
|
+
usageLoading: "\u6B63\u5728\u8BFB\u53D6\u7528\u91CF\u2026",
|
|
798
|
+
usageUnavailable: "\u6682\u4E0D\u53EF\u7528",
|
|
779
799
|
nav: "OpenCode Go",
|
|
780
800
|
title: "OpenCode Go",
|
|
781
801
|
intro: "\u5728 Harness \u4E2D\u4F7F\u7528\u4F60\u7684 OpenCode Go \u8BA2\u9605\u3002\u586B\u5165\u4E0B\u65B9 API key \u5E76\u4FDD\u5B58\u5373\u53EF\uFF1B\u7F51\u5173\u5F53\u524D\u63D0\u4F9B\u7684\u6A21\u578B\u5217\u5728\u4E0B\u9762\u3002",
|
|
@@ -821,11 +841,187 @@ var zh = {
|
|
|
821
841
|
unavailable: "\u6B64\u90E8\u7F72\u672A\u63D0\u4F9B OpenCode Go \u8BBE\u7F6E\u3002"
|
|
822
842
|
};
|
|
823
843
|
|
|
844
|
+
// src/usage-contract.ts
|
|
845
|
+
function parseGoUsage(value) {
|
|
846
|
+
if (!value || typeof value !== "object") throw new Error("Invalid OpenCode Go usage response");
|
|
847
|
+
const source = value;
|
|
848
|
+
const result = {};
|
|
849
|
+
for (const key of ["rolling", "weekly", "monthly"]) {
|
|
850
|
+
const row = source[key];
|
|
851
|
+
if (!row || row.status !== "ok" && row.status !== "rate-limited" || typeof row.percent !== "number" || !Number.isFinite(row.percent) || row.percent < 0 || typeof row.resetsAt !== "string" || !Number.isFinite(Date.parse(row.resetsAt))) {
|
|
852
|
+
throw new Error("Invalid OpenCode Go usage response");
|
|
853
|
+
}
|
|
854
|
+
result[key] = { status: row.status, percent: row.percent, resetsAt: row.resetsAt };
|
|
855
|
+
}
|
|
856
|
+
return result;
|
|
857
|
+
}
|
|
858
|
+
var usageCodec = {
|
|
859
|
+
mode: "strict",
|
|
860
|
+
typeSymbol: "dsh-opencode-go#GoUsage",
|
|
861
|
+
schema: { parse: parseGoUsage },
|
|
862
|
+
create: () => ({ parse: parseGoUsage })
|
|
863
|
+
};
|
|
864
|
+
var usageRemote = {
|
|
865
|
+
package: "dsh-opencode-go",
|
|
866
|
+
descriptors: [{
|
|
867
|
+
id: "dsh-opencode-go#opencodeGoUsage/read",
|
|
868
|
+
service: "opencodeGoUsage",
|
|
869
|
+
namespace: "opencodeGoUsage",
|
|
870
|
+
method: "read",
|
|
871
|
+
invocation: { kind: "direct" },
|
|
872
|
+
parameters: [],
|
|
873
|
+
result: usageCodec
|
|
874
|
+
}]
|
|
875
|
+
};
|
|
876
|
+
|
|
877
|
+
// src/client/UsagePill.tsx
|
|
878
|
+
var import_react2 = require("react");
|
|
879
|
+
|
|
880
|
+
// plugin-css:/Users/tanglei/Desktop/dsh-opencode-go/src/client/UsagePill.module.css
|
|
881
|
+
var id2 = "dsh-opencode-go/UsagePill.module.css";
|
|
882
|
+
if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]")) {
|
|
883
|
+
const style = document.createElement("style");
|
|
884
|
+
style.dataset.plugin = "dsh-opencode-go";
|
|
885
|
+
style.dataset.pluginCss = id2;
|
|
886
|
+
style.textContent = ".dmPm3q_root{min-width:0;display:inline-flex;position:relative}.dmPm3q_trigger{color:inherit;opacity:.75;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:12px}.dmPm3q_trigger:hover,.dmPm3q_trigger:focus-visible{opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.dmPm3q_panel{z-index:100;border:1px solid color-mix(in srgb, currentColor 18%, transparent);width:280px;max-width:calc(100vw - 32px);color:var(--dsw-alias-label-primary,CanvasText);background:var(--dsw-specific-menu,Canvas);border-radius:12px;padding:16px;font-size:12px;position:absolute;bottom:calc(100% + 12px);right:0;box-shadow:0 8px 30px #0002}.dmPm3q_hint{opacity:.65;font-size:11px;line-height:1.6}.dmPm3q_window{margin-top:14px}.dmPm3q_row{justify-content:space-between;margin-bottom:5px;display:flex}.dmPm3q_window progress{accent-color:#39a878;width:100%;height:5px;margin-bottom:5px;display:block}.dmPm3q_window progress::-webkit-progress-bar{background:color-mix(in srgb, currentColor 15%, transparent);border-radius:4px}.dmPm3q_window progress::-webkit-progress-value{background:#39a878;border-radius:4px}.dmPm3q_window progress::-moz-progress-bar{background:#39a878;border-radius:4px}";
|
|
887
|
+
document.head.appendChild(style);
|
|
888
|
+
}
|
|
889
|
+
var UsagePill_default = { "root": "dmPm3q_root", "hint": "dmPm3q_hint", "row": "dmPm3q_row", "panel": "dmPm3q_panel", "window": "dmPm3q_window", "trigger": "dmPm3q_trigger" };
|
|
890
|
+
|
|
891
|
+
// src/client/UsagePill.tsx
|
|
892
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
893
|
+
function UsagePill({ directory, ...props }) {
|
|
894
|
+
const state = (0, import_react2.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
|
|
895
|
+
return state.current?.provider === "opencode-go" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ActiveUsage, { ...props }) : null;
|
|
896
|
+
}
|
|
897
|
+
function ActiveUsage({ readUsage, t }) {
|
|
898
|
+
const [usage, setUsage] = (0, import_react2.useState)(null);
|
|
899
|
+
const [failed, setFailed] = (0, import_react2.useState)(false);
|
|
900
|
+
const [open, setOpen] = (0, import_react2.useState)(false);
|
|
901
|
+
const root = (0, import_react2.useRef)(null);
|
|
902
|
+
(0, import_react2.useEffect)(() => {
|
|
903
|
+
let alive = true;
|
|
904
|
+
let busy = false;
|
|
905
|
+
const refresh = async () => {
|
|
906
|
+
if (busy || document.visibilityState === "hidden") return;
|
|
907
|
+
busy = true;
|
|
908
|
+
try {
|
|
909
|
+
const value = await readUsage();
|
|
910
|
+
if (alive) {
|
|
911
|
+
setUsage(value);
|
|
912
|
+
setFailed(false);
|
|
913
|
+
}
|
|
914
|
+
} catch {
|
|
915
|
+
if (alive) {
|
|
916
|
+
setUsage(null);
|
|
917
|
+
setFailed(true);
|
|
918
|
+
}
|
|
919
|
+
} finally {
|
|
920
|
+
busy = false;
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
void refresh();
|
|
924
|
+
const timer = setInterval(() => {
|
|
925
|
+
void refresh();
|
|
926
|
+
}, 6e4);
|
|
927
|
+
const visible = () => {
|
|
928
|
+
void refresh();
|
|
929
|
+
};
|
|
930
|
+
document.addEventListener("visibilitychange", visible);
|
|
931
|
+
return () => {
|
|
932
|
+
alive = false;
|
|
933
|
+
clearInterval(timer);
|
|
934
|
+
document.removeEventListener("visibilitychange", visible);
|
|
935
|
+
};
|
|
936
|
+
}, [readUsage]);
|
|
937
|
+
(0, import_react2.useEffect)(() => {
|
|
938
|
+
if (!open) return;
|
|
939
|
+
const click = (event) => {
|
|
940
|
+
if (!root.current?.contains(event.target)) setOpen(false);
|
|
941
|
+
};
|
|
942
|
+
const key = (event) => {
|
|
943
|
+
if (event.key === "Escape") setOpen(false);
|
|
944
|
+
};
|
|
945
|
+
document.addEventListener("mousedown", click);
|
|
946
|
+
document.addEventListener("keydown", key);
|
|
947
|
+
return () => {
|
|
948
|
+
document.removeEventListener("mousedown", click);
|
|
949
|
+
document.removeEventListener("keydown", key);
|
|
950
|
+
};
|
|
951
|
+
}, [open]);
|
|
952
|
+
const label = usage ? `Go \xB7 5h ${usage.rolling.percent}% \xB7 ${t("usageWeekShort")} ${usage.weekly.percent}%` : `Go \xB7 ${failed ? t("usageUnavailable") : "\u2026"}`;
|
|
953
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: UsagePill_default.root, ref: root, children: [
|
|
954
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
955
|
+
"button",
|
|
956
|
+
{
|
|
957
|
+
type: "button",
|
|
958
|
+
className: UsagePill_default.trigger,
|
|
959
|
+
"aria-expanded": open,
|
|
960
|
+
"aria-haspopup": "dialog",
|
|
961
|
+
"aria-label": `${t("usageTitle")}: ${label}`,
|
|
962
|
+
onClick: () => {
|
|
963
|
+
setOpen(!open);
|
|
964
|
+
},
|
|
965
|
+
children: label
|
|
966
|
+
}
|
|
967
|
+
),
|
|
968
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), children: [
|
|
969
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("usageTitle") }),
|
|
970
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: UsagePill_default.hint, children: t("usageHint") }),
|
|
971
|
+
usage ? ["rolling", "weekly", "monthly"].map((key) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: UsagePill_default.window, children: [
|
|
972
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: UsagePill_default.row, children: [
|
|
973
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t(`usage_${key}`) }),
|
|
974
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { children: [
|
|
975
|
+
usage[key].percent,
|
|
976
|
+
"%"
|
|
977
|
+
] })
|
|
978
|
+
] }),
|
|
979
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("progress", { "aria-label": t(`usage_${key}`), max: 100, value: Math.min(100, usage[key].percent) }),
|
|
980
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: UsagePill_default.hint, children: [
|
|
981
|
+
t("usageResets"),
|
|
982
|
+
" ",
|
|
983
|
+
new Date(usage[key].resetsAt).toLocaleString()
|
|
984
|
+
] }),
|
|
985
|
+
usage[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: t("usageLimited") })
|
|
986
|
+
] }, key)) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: failed ? t("usageUnavailable") : t("usageLoading") })
|
|
987
|
+
] })
|
|
988
|
+
] });
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// src/client/usage.ts
|
|
992
|
+
function registerUsagePill(ctx) {
|
|
993
|
+
ctx.inject(["modelDirectories", "sessions", "remote.session"], (scope) => {
|
|
994
|
+
scope.effect(async () => {
|
|
995
|
+
const unmount = await scope.remote.$mount(usageRemote);
|
|
996
|
+
scope.inject(["remote.opencodeGoUsage"], (ready) => {
|
|
997
|
+
const readUsage = async () => {
|
|
998
|
+
const result = await ready.remote.opencodeGoUsage.read();
|
|
999
|
+
if (!result.ok) throw new Error("OpenCode Go usage unavailable");
|
|
1000
|
+
return result.value;
|
|
1001
|
+
};
|
|
1002
|
+
const translate = ready.locale.bind("settings.opencode-go");
|
|
1003
|
+
ready.slots.inject("conversation.input.right", () => ready.slots.register({
|
|
1004
|
+
name: "conversation.input.right",
|
|
1005
|
+
id: "opencode-go-usage",
|
|
1006
|
+
order: 1e3,
|
|
1007
|
+
inject: (sessionId) => ({
|
|
1008
|
+
directory: ready.modelDirectories.directoryFor(sessionId).store,
|
|
1009
|
+
readUsage,
|
|
1010
|
+
t: (key) => translate(key)
|
|
1011
|
+
})
|
|
1012
|
+
}, UsagePill));
|
|
1013
|
+
});
|
|
1014
|
+
return unmount;
|
|
1015
|
+
});
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
|
|
824
1019
|
// src/client/index.ts
|
|
825
1020
|
var NS = "settings.opencode-go";
|
|
826
1021
|
var inject = ["slots", "locale", "remote", "remote.credentials", "remote.llm", "settingsScope"];
|
|
827
1022
|
function apply(ctx) {
|
|
828
1023
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "llm-opencode-go: copy dictionaries");
|
|
1024
|
+
registerUsagePill(ctx);
|
|
829
1025
|
const scope = ctx.settingsScope.bind({
|
|
830
1026
|
namespace: "llm-opencode-go",
|
|
831
1027
|
decode: (section) => typeof section === "object" && section !== null ? section : void 0
|
package/lib/index.js
CHANGED
|
@@ -1035,6 +1035,73 @@ var OpencodeGoAdapter = class extends LlmAdapter {
|
|
|
1035
1035
|
}
|
|
1036
1036
|
};
|
|
1037
1037
|
|
|
1038
|
+
// src/usage.ts
|
|
1039
|
+
import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
|
|
1040
|
+
import { attributionHeaders as attributionHeaders3 } from "@deepseek-ai/dsh-llm";
|
|
1041
|
+
|
|
1042
|
+
// src/usage-contract.ts
|
|
1043
|
+
function parseGoUsage(value) {
|
|
1044
|
+
if (!value || typeof value !== "object") throw new Error("Invalid OpenCode Go usage response");
|
|
1045
|
+
const source = value;
|
|
1046
|
+
const result = {};
|
|
1047
|
+
for (const key of ["rolling", "weekly", "monthly"]) {
|
|
1048
|
+
const row = source[key];
|
|
1049
|
+
if (!row || row.status !== "ok" && row.status !== "rate-limited" || typeof row.percent !== "number" || !Number.isFinite(row.percent) || row.percent < 0 || typeof row.resetsAt !== "string" || !Number.isFinite(Date.parse(row.resetsAt))) {
|
|
1050
|
+
throw new Error("Invalid OpenCode Go usage response");
|
|
1051
|
+
}
|
|
1052
|
+
result[key] = { status: row.status, percent: row.percent, resetsAt: row.resetsAt };
|
|
1053
|
+
}
|
|
1054
|
+
return result;
|
|
1055
|
+
}
|
|
1056
|
+
var usageCodec = {
|
|
1057
|
+
mode: "strict",
|
|
1058
|
+
typeSymbol: "dsh-opencode-go#GoUsage",
|
|
1059
|
+
schema: { parse: parseGoUsage },
|
|
1060
|
+
create: () => ({ parse: parseGoUsage })
|
|
1061
|
+
};
|
|
1062
|
+
var usageRemote = {
|
|
1063
|
+
package: "dsh-opencode-go",
|
|
1064
|
+
descriptors: [{
|
|
1065
|
+
id: "dsh-opencode-go#opencodeGoUsage/read",
|
|
1066
|
+
service: "opencodeGoUsage",
|
|
1067
|
+
namespace: "opencodeGoUsage",
|
|
1068
|
+
method: "read",
|
|
1069
|
+
invocation: { kind: "direct" },
|
|
1070
|
+
parameters: [],
|
|
1071
|
+
result: usageCodec
|
|
1072
|
+
}]
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
// src/usage.ts
|
|
1076
|
+
var GoUsageService = class extends TypertRemoteService {
|
|
1077
|
+
constructor(ctx, options) {
|
|
1078
|
+
super(ctx, "opencodeGoUsage");
|
|
1079
|
+
this.options = options;
|
|
1080
|
+
ctx.inject(["typert"], (scope) => {
|
|
1081
|
+
scope.effect(() => scope.typert.register({
|
|
1082
|
+
package: usageRemote.package,
|
|
1083
|
+
face: "host",
|
|
1084
|
+
schemas: [],
|
|
1085
|
+
model: { services: [], events: [], objects: [] },
|
|
1086
|
+
invocations: usageRemote.descriptors
|
|
1087
|
+
}));
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
async read() {
|
|
1091
|
+
const baseURL = assertBaseURL(this.options.baseURL()).replace(/\/$/, "");
|
|
1092
|
+
const key = await this.options.resolveApiKey();
|
|
1093
|
+
if (!key) throw new Error("OpenCode Go API key is not configured");
|
|
1094
|
+
const response = await fetch(`${baseURL}/usage`, {
|
|
1095
|
+
headers: { ...attributionHeaders3(), Authorization: `Bearer ${key}`, Accept: "application/json" },
|
|
1096
|
+
signal: AbortSignal.timeout(1e4),
|
|
1097
|
+
redirect: "error"
|
|
1098
|
+
});
|
|
1099
|
+
if (!response.ok) throw new Error(`OpenCode Go usage unavailable (HTTP ${response.status})`);
|
|
1100
|
+
const body = await response.json();
|
|
1101
|
+
return parseGoUsage(body && typeof body === "object" ? body.usage : void 0);
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
|
|
1038
1105
|
// src/index.ts
|
|
1039
1106
|
var name = "llm-opencode-go";
|
|
1040
1107
|
var inject = ["llm"];
|
|
@@ -1053,6 +1120,7 @@ function apply(ctx, raw) {
|
|
|
1053
1120
|
"MISSING_CREDENTIAL"
|
|
1054
1121
|
);
|
|
1055
1122
|
};
|
|
1123
|
+
ctx.plugin(GoUsageService, { baseURL: () => current().baseURL, resolveApiKey });
|
|
1056
1124
|
const logger = {
|
|
1057
1125
|
fallback: ({ error }) => {
|
|
1058
1126
|
ctx.logger.warn(`llm-opencode-go: live model listing unreachable; serving the curated table until the next refresh (${String(error)})`);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store';
|
|
2
|
+
import type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client';
|
|
3
|
+
import type { GoUsage } from '../usage-contract.ts';
|
|
4
|
+
export interface UsagePillProps {
|
|
5
|
+
directory: SnapshotStore<ModelDirectoryState>;
|
|
6
|
+
readUsage: () => Promise<GoUsage>;
|
|
7
|
+
t: (key: string) => string;
|
|
8
|
+
}
|
|
9
|
+
/** Only the selected Go provider mounts a poller, so other models send no usage traffic. */
|
|
10
|
+
export declare function UsagePill({ directory, ...props }: UsagePillProps): import("react").JSX.Element | null;
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
/** Copy dictionaries for the OpenCode Go settings page. English is the key-set source of truth. */
|
|
2
2
|
export declare const en: {
|
|
3
|
+
usageTitle: string;
|
|
4
|
+
usageHint: string;
|
|
5
|
+
usageWeekShort: string;
|
|
6
|
+
usage_rolling: string;
|
|
7
|
+
usage_weekly: string;
|
|
8
|
+
usage_monthly: string;
|
|
9
|
+
usageResets: string;
|
|
10
|
+
usageLimited: string;
|
|
11
|
+
usageLoading: string;
|
|
12
|
+
usageUnavailable: string;
|
|
3
13
|
nav: string;
|
|
4
14
|
title: string;
|
|
5
15
|
intro: string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RemoteResult, TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol';
|
|
2
|
+
export interface UsageWindow {
|
|
3
|
+
status: 'ok' | 'rate-limited';
|
|
4
|
+
percent: number;
|
|
5
|
+
resetsAt: string;
|
|
6
|
+
}
|
|
7
|
+
export interface GoUsage {
|
|
8
|
+
rolling: UsageWindow;
|
|
9
|
+
weekly: UsageWindow;
|
|
10
|
+
monthly: UsageWindow;
|
|
11
|
+
}
|
|
12
|
+
/** Reject missing statistics rather than turning unavailable data into zero. */
|
|
13
|
+
export declare function parseGoUsage(value: unknown): GoUsage;
|
|
14
|
+
declare module '@deepseek-ai/dsh-typert-protocol' {
|
|
15
|
+
interface TypertRemoteNamespaceMap {
|
|
16
|
+
opencodeGoUsage: {
|
|
17
|
+
read(): Promise<RemoteResult<GoUsage>>;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export declare const usageRemote: TypertRemoteContribution;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
3
|
+
import { type GoUsage } from './usage-contract.ts';
|
|
4
|
+
interface UsageOptions {
|
|
5
|
+
baseURL: () => string;
|
|
6
|
+
resolveApiKey: () => Promise<string | undefined>;
|
|
7
|
+
}
|
|
8
|
+
/** Account statistics are fetched on the Host; credentials never enter the browser. */
|
|
9
|
+
export declare class GoUsageService extends TypertRemoteService {
|
|
10
|
+
private readonly options;
|
|
11
|
+
constructor(ctx: Context, options: UsageOptions);
|
|
12
|
+
read(): Promise<GoUsage>;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-opencode-go",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "OpenCode Go model provider and settings UI for DeepSeek Harness",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Duskriver/dsh-opencode-go.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Duskriver/dsh-opencode-go#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/Duskriver/dsh-opencode-go/issues"
|
|
14
|
+
},
|
|
7
15
|
"engines": {
|
|
8
16
|
"node": "^22.19.0 || >=24.0.0"
|
|
9
17
|
},
|
|
@@ -35,7 +43,8 @@
|
|
|
35
43
|
"inject": [
|
|
36
44
|
"@deepseek-ai/dsh-client-locale",
|
|
37
45
|
"@deepseek-ai/dsh-client-ui-settings",
|
|
38
|
-
"@deepseek-ai/dsh-api-remotes"
|
|
46
|
+
"@deepseek-ai/dsh-api-remotes",
|
|
47
|
+
"@deepseek-ai/dsh-client-ui-model-selection"
|
|
39
48
|
],
|
|
40
49
|
"platform": "web"
|
|
41
50
|
}
|
|
@@ -51,22 +60,25 @@
|
|
|
51
60
|
},
|
|
52
61
|
"peerDependencies": {
|
|
53
62
|
"@deepseek-ai/cordis": "4.0.2",
|
|
63
|
+
"@deepseek-ai/dsh-api-gateway": "0.1.6-alpha.1",
|
|
64
|
+
"@deepseek-ai/dsh-api-remotes": "0.1.6-alpha.1",
|
|
65
|
+
"@deepseek-ai/dsh-api-settings-controller": "0.1.6-alpha.1",
|
|
54
66
|
"@deepseek-ai/dsh-attachment": "0.1.6-alpha.1",
|
|
67
|
+
"@deepseek-ai/dsh-client-locale": "0.1.6-alpha.1",
|
|
68
|
+
"@deepseek-ai/dsh-client-store": "0.1.6-alpha.1",
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.6-alpha.1",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.6-alpha.1",
|
|
71
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.6-alpha.1",
|
|
72
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.6-alpha.1",
|
|
55
73
|
"@deepseek-ai/dsh-credentials": "0.1.6-alpha.1",
|
|
56
74
|
"@deepseek-ai/dsh-fs": "0.1.6-alpha.1",
|
|
57
75
|
"@deepseek-ai/dsh-launch-environment": "0.1.6-alpha.1",
|
|
58
76
|
"@deepseek-ai/dsh-llm": "0.1.6-alpha.1",
|
|
59
77
|
"@deepseek-ai/dsh-settings": "0.1.6-alpha.1",
|
|
60
78
|
"@deepseek-ai/dsh-timeout": "0.1.6-alpha.1",
|
|
61
|
-
"@deepseek-ai/dsh-
|
|
62
|
-
"@deepseek-ai/dsh-
|
|
63
|
-
"@deepseek-ai/dsh-
|
|
64
|
-
"@deepseek-ai/dsh-client-store": "0.1.6-alpha.1",
|
|
65
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.6-alpha.1",
|
|
66
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.1.6-alpha.1",
|
|
67
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.1.6-alpha.1",
|
|
68
|
-
"@deepseek-ai/dsh-client-locale": "0.1.6-alpha.1",
|
|
69
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.6-alpha.1"
|
|
79
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.6-alpha.1",
|
|
80
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.6-alpha.1",
|
|
81
|
+
"@deepseek-ai/dsh-typert-registry": "0.1.6-alpha.1"
|
|
70
82
|
},
|
|
71
83
|
"dependencies": {
|
|
72
84
|
"@deepseek-ai/dsh-brand": "0.1.6-alpha.1",
|
|
@@ -84,6 +96,8 @@
|
|
|
84
96
|
"@deepseek-ai/dsh-brand": "0.1.6-alpha.1",
|
|
85
97
|
"@deepseek-ai/dsh-client-locale": "0.1.6-alpha.1",
|
|
86
98
|
"@deepseek-ai/dsh-client-store": "0.1.6-alpha.1",
|
|
99
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.6-alpha.1",
|
|
100
|
+
"@deepseek-ai/dsh-client-ui-model-selection": "0.1.6-alpha.1",
|
|
87
101
|
"@deepseek-ai/dsh-client-ui-primitives": "0.1.6-alpha.1",
|
|
88
102
|
"@deepseek-ai/dsh-client-ui-renderer": "0.1.6-alpha.1",
|
|
89
103
|
"@deepseek-ai/dsh-client-ui-settings": "0.1.6-alpha.1",
|
|
@@ -97,38 +111,39 @@
|
|
|
97
111
|
"@deepseek-ai/dsh-settings-file": "0.1.6-alpha.1",
|
|
98
112
|
"@deepseek-ai/dsh-timeout": "0.1.6-alpha.1",
|
|
99
113
|
"@deepseek-ai/dsh-typert-protocol": "0.1.6-alpha.1",
|
|
114
|
+
"@deepseek-ai/dsh-typert-registry": "0.1.6-alpha.1",
|
|
115
|
+
"@shikijs/langs": "^4.3.1",
|
|
100
116
|
"@testing-library/react": "^16.3.2",
|
|
117
|
+
"@types/mdast": "^4.0.4",
|
|
101
118
|
"@types/node": "^22.20.0",
|
|
102
119
|
"@types/react": "~18.3.1",
|
|
103
|
-
"esbuild": "^0.25.0",
|
|
104
|
-
"jsdom": "29.1.1",
|
|
105
|
-
"lightningcss": "^1.32.0",
|
|
106
|
-
"react": "^18.2.0",
|
|
107
|
-
"react-dom": "^18.2.0",
|
|
108
|
-
"typescript": "6.0.3",
|
|
109
|
-
"vitest": "^4.1.8",
|
|
110
120
|
"@types/react-dom": "~18.3.0",
|
|
121
|
+
"anser": "^2.3.5",
|
|
111
122
|
"clsx": "^2.0.0",
|
|
112
123
|
"diff": "^9.0.0",
|
|
113
|
-
"
|
|
124
|
+
"esbuild": "^0.25.0",
|
|
125
|
+
"immer": "^10.1.1",
|
|
126
|
+
"jsdom": "29.1.1",
|
|
114
127
|
"katex": "^0.16.47",
|
|
128
|
+
"lightningcss": "^1.32.0",
|
|
129
|
+
"mdast-util-from-markdown": "^2.0.3",
|
|
130
|
+
"mdast-util-gfm": "^3.1.0",
|
|
131
|
+
"mdast-util-math": "^3.0.0",
|
|
115
132
|
"micromark-core-commonmark": "^2.0.3",
|
|
133
|
+
"micromark-extension-gfm": "^3.0.0",
|
|
134
|
+
"micromark-extension-math": "^3.1.0",
|
|
135
|
+
"micromark-factory-space": "^2.0.1",
|
|
116
136
|
"micromark-util-character": "^2.1.1",
|
|
117
137
|
"micromark-util-classify-character": "^2.0.1",
|
|
138
|
+
"micromark-util-sanitize-uri": "^2.0.1",
|
|
118
139
|
"micromark-util-symbol": "^2.0.1",
|
|
119
140
|
"micromark-util-types": "^2.0.2",
|
|
141
|
+
"react": "^18.2.0",
|
|
142
|
+
"react-dom": "^18.2.0",
|
|
120
143
|
"shiki": "^4.3.1",
|
|
121
|
-
"
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
"micromark-extension-math": "^3.1.0",
|
|
125
|
-
"mdast-util-from-markdown": "^2.0.3",
|
|
126
|
-
"mdast-util-gfm": "^3.1.0",
|
|
127
|
-
"mdast-util-math": "^3.0.0",
|
|
128
|
-
"micromark-extension-gfm": "^3.0.0",
|
|
129
|
-
"micromark-util-sanitize-uri": "^2.0.1",
|
|
130
|
-
"zustand": "~4.4.7",
|
|
131
|
-
"immer": "^10.1.1"
|
|
144
|
+
"typescript": "6.0.3",
|
|
145
|
+
"vitest": "^4.1.8",
|
|
146
|
+
"zustand": "~4.4.7"
|
|
132
147
|
},
|
|
133
148
|
"peerDependenciesMeta": {
|
|
134
149
|
"@deepseek-ai/dsh-api-remotes": {
|
|
@@ -155,7 +170,13 @@
|
|
|
155
170
|
"@deepseek-ai/dsh-client-locale": {
|
|
156
171
|
"optional": true
|
|
157
172
|
},
|
|
158
|
-
"@deepseek-ai/dsh-
|
|
173
|
+
"@deepseek-ai/dsh-client-ui-model-selection": {
|
|
174
|
+
"optional": true
|
|
175
|
+
},
|
|
176
|
+
"@deepseek-ai/dsh-client-ui-conversation": {
|
|
177
|
+
"optional": true
|
|
178
|
+
},
|
|
179
|
+
"@deepseek-ai/dsh-typert-registry": {
|
|
159
180
|
"optional": true
|
|
160
181
|
}
|
|
161
182
|
},
|
|
@@ -165,6 +186,7 @@
|
|
|
165
186
|
},
|
|
166
187
|
"keywords": [
|
|
167
188
|
"deepseek-harness",
|
|
189
|
+
"dsh-plugin",
|
|
168
190
|
"dsh",
|
|
169
191
|
"opencode",
|
|
170
192
|
"opencode-go",
|