dsh-packycode-api 1.2.10 → 1.3.0
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/CHANGELOG.md +20 -0
- package/README.en.md +36 -55
- package/README.md +35 -54
- package/SECURITY.md +6 -8
- package/lib/client.js +4 -212
- package/lib/index.js +1746 -5080
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
| **多 Key 按顺序使用** | 额度用尽或 Key 被拒绝时自动切到下一个可用 Key;失败的那一步由重试接手 |
|
|
30
30
|
| **按分组选 Key** | 每个 Key 后面列出它所在的 PackyCode 分组和能用的模型;当前 Key 的分组用不了所选模型(例如没有 cc 分组却选了 Claude)时,这一轮自动改用分组合适的 Key |
|
|
31
31
|
| **余额一眼可见** | 设置页列出每个 Key 的剩余、已用、额度、重置周期和用量条,并给出这些 Key 的合计;输入框右侧显示当前 Key 的剩余额度 |
|
|
32
|
-
| **Claude
|
|
32
|
+
| **Claude 插件内直连** | 三个 Claude 模型通过 HTTP Messages 调用,使用 DSH 的工具、权限和完整对话历史,无需本机 CLI |
|
|
33
33
|
| **网页搜索可走 PackyCode** | 可选:DSH 的 `web_search` 改用 PackyCode 搜索,后端在 DeepSeek 与 GPT 之间切换;可只对 PackyCode 模型生效 |
|
|
34
34
|
| **图片生成与编辑** | 独立图片 Key,支持 GPT Image 2 / 2.5 Flare / 2.5 Sunburst、型号与质量设置、参考图编辑和 PNG 原图保存;已通过网关生图与编辑实测 |
|
|
35
35
|
| **凭据不离开本机** | Key 只存在 DSH 凭据文件里。浏览器只能看到备注、状态和余额,拿不到 Key |
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
<img width="575" height="522" alt="截屏2026-10-15 10 34 49" src="https://github.com/user-attachments/assets/89cf89ca-fce3-427d-95cb-94fa2b05d6aa" />
|
|
39
39
|
<img width="272" height="425" alt="截屏2026-10-13 10 07 46" src="https://github.com/user-attachments/assets/040fc57a-2dd2-4195-9bbc-5fa3357d1eb1" />
|
|
40
40
|
|
|
41
|
-
|
|
42
41
|
## 安装
|
|
43
42
|
|
|
44
43
|
先准备好 **DeepSeek Harness** 和 **PackyCode(PackyAPI)的 API Key**。尚未安装 DSH,可查看 [DSH 官方说明](https://github.com/deepseek-ai/deepseek-harness#run)。还没有 API Key 的,可以通过[这个邀请链接](https://www.packyapi.ai/register?aff=Im3l)注册 PackyCode 申请。
|
|
@@ -48,10 +47,10 @@
|
|
|
48
47
|
打开桌面应用的**插件**页,点击**添加插件**,在**包名或地址**中填入**带版本号**的包名:
|
|
49
48
|
|
|
50
49
|
```text
|
|
51
|
-
dsh-packycode-api@1.
|
|
50
|
+
dsh-packycode-api@1.3.0
|
|
52
51
|
```
|
|
53
52
|
|
|
54
|
-
在**安装源**中选择**官方源**,然后点击**安装**。`1.
|
|
53
|
+
在**安装源**中选择**官方源**,然后点击**安装**。`1.3.0` 是写这份说明时的最新版,当前最新版本号以 [npm 页面](https://www.npmjs.com/package/dsh-packycode-api) 为准。
|
|
55
54
|
|
|
56
55
|
> **一定要带版本号。** 只填 `dsh-packycode-api` 时,安装前的提示显示的是 npm 上的最新版,但 DSH 自带的 pnpm 默认只安装发布满 24 小时的版本,实际装上的可能是好几个版本之前的旧版,而安装提示里看不出这一点。填写精确版本时,pnpm 会直接安装这个版本,并自动把它加入 profile 的 `minimumReleaseAgeExclude`。装好后可以在 **设置 → PackyCode → 插件版本** 核对「当前版本」。
|
|
57
56
|
|
|
@@ -65,14 +64,14 @@ dsh-packycode-api@1.2.10
|
|
|
65
64
|
|
|
66
65
|
### 3. 选择模型
|
|
67
66
|
|
|
68
|
-
回到对话,在模型选择器里选 `PackyCode`
|
|
67
|
+
回到对话,在模型选择器里选 `PackyCode` 分组下的模型。九个模型都通过插件内 HTTP 调用;Key 的分组必须覆盖所选模型。
|
|
69
68
|
|
|
70
69
|
<details>
|
|
71
70
|
<summary>检查安装 / 其它 profile / 本地目录</summary>
|
|
72
71
|
|
|
73
72
|
桌面应用的**插件**页可以看到已安装状态与版本,也可以在那里启用、停用或卸载。
|
|
74
73
|
|
|
75
|
-
**仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.
|
|
74
|
+
**仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.3.0`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
|
|
76
75
|
|
|
77
76
|
本地开发要加 `link:` 前缀:`dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`。**不要直接写路径(或 `file:`)** —— 那样的安装会把整个仓库目录(连同 `node_modules`)复制进 profile,之后它会在 profile 内部挡住 DSH 自带的包,插件看起来像没装,见「常见问题」。已经那样装过的话,先卸载再按上面的方式重装。
|
|
78
77
|
|
|
@@ -86,11 +85,11 @@ dsh-packycode-api@1.2.10
|
|
|
86
85
|
|
|
87
86
|
**换 Key。** Key 按添加顺序使用。点「切到此 Key」指定优先使用的 Key,下一轮就生效;「重命名」改备注(最多 60 字,不能为空);充值或更换后点「重新启用」。
|
|
88
87
|
|
|
89
|
-
**看分组。** 「账户与 Key」里每个 Key 下面列出它所在的 PackyCode 分组(鼠标悬停可看分组说明),以及能用哪些模型:✓ 可用、◐ 部分可用、✕ 不可用。分组由网关自己报出(对一个不存在的模型 id 的拒绝里会写明「已选分组」,不产生费用),再对照 PackyCode 公开的模型分组表。Claude
|
|
88
|
+
**看分组。** 「账户与 Key」里每个 Key 下面列出它所在的 PackyCode 分组(鼠标悬停可看分组说明),以及能用哪些模型:✓ 可用、◐ 部分可用、✕ 不可用。分组由网关自己报出(对一个不存在的模型 id 的拒绝里会写明「已选分组」,不产生费用),再对照 PackyCode 公开的模型分组表。Claude 的分组覆盖要按具体模型确认,不能假定 `cc-sale` 支持全部三个型号;GPT 需要 `codex` / `codex-sale`;DeepSeek 需要 `deepseek-officially` / `deepseek-sale`。
|
|
90
89
|
|
|
91
90
|
**看余额。** 「账户与 Key」顶部的合计是**已列出的这些 Key** 的剩余、已用与额度,不是 PackyCode 账号下全部令牌的账单。读失败的 Key 不计入合计,并会注明个数;某个 Key 这次读失败但之前读到过,会继续显示上次的余额并注明读取时间(输入框里显示为 `≈US$…`),重启 DSH 后才清空。输入框右侧只在选中 PackyCode 模型时显示当前 Key 的剩余额度。「刷新」会跳过约 60 秒的缓存。默认模型接口是 `https://cf.api.fan`,余额接口是 `https://www.packyapi.ai`,可在「高级:接口地址」里改。旧默认值 `https://www.packyapi.com` 在国内网络下 DNS 被污染、直连会 `fetch failed`,即使设置里保存的是它,插件也会先试 `.ai`。
|
|
92
91
|
|
|
93
|
-
**用 Claude。**
|
|
92
|
+
**用 Claude。** 直接选择三个 Claude 模型之一即可,无需安装 CLI。思考档位会发送给模型;对话历史、附件、工具调用、计划模式和权限均由 DSH 管理。
|
|
94
93
|
|
|
95
94
|
**网页搜索。** DSH 的 `web_search` 默认调用 DeepSeek 官方接口(用 `DEEPSEEK_API_KEY` 计费)。在 **设置 → PackyCode → 网页搜索** 里可以改走 PackyCode:
|
|
96
95
|
|
|
@@ -107,17 +106,7 @@ dsh-packycode-api@1.2.10
|
|
|
107
106
|
|
|
108
107
|
PackyCode 没有专用搜索接口:一次搜索就是一次带服务端搜索工具的模型调用,用这里的 Key 计费,额度用尽或 Key 被拒绝时同样切到下一个 Key。
|
|
109
108
|
|
|
110
|
-
**Claude
|
|
111
|
-
|
|
112
|
-
```text
|
|
113
|
-
Claude Code CLI → 本机临时 MCP web_search → 插件选定的 DeepSeek/GPT 后端
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
- **后端选择对 CLI 生效;路由选择只影响 DSH。** 即使选了「不接管」,CLI 搜索仍用这里选的后端,不转到 DSH 默认搜索。更改后端后下一次搜索即使用新选择。
|
|
117
|
-
- Claude 普通对话仍需要 Claude 分组;搜索需要存入插件的 Key 覆盖 DeepSeek 或 GPT 分组,可以是另一个 Key。搜索错误会返回给 CLI,不伪造成功、不自动切另一个后端。
|
|
118
|
-
- 只读、编辑模式单独自动允许这个只读 MCP 搜索工具,不增加 Shell 或文件写权限;用户/管理员的拒绝规则仍有效。CLI 的 `--allowedTools` 是自动批准列表,不是可用工具的排他列表,已有其他工具权限保持原样。
|
|
119
|
-
- 每轮最多 8 次搜索,最多同时 2 次;查询不超过 2000 字符,每次最多 8 个来源,整体搜索预算 60 秒。标题生成不启动 MCP 或进行搜索。
|
|
120
|
-
- 思考区会显示 `▸ 网页搜索:PackyCode DeepSeek(MCP,原生 WebSearch 已禁用)`(或 GPT)。临时服务只监听 `127.0.0.1`,配置中仅含本机一次性凭证,不含搜索 API Key;CLI 结束、取消、超时或插件卸载时关闭并清理,不修改用户现有 MCP 配置。
|
|
109
|
+
**Claude 的搜索。** Claude 对话使用 DSH 的 `web_search`,遵守上表的路由选择,搜索所用 Key 与其它原生模型遵循同一规则。
|
|
121
110
|
|
|
122
111
|
<details>
|
|
123
112
|
<summary>网页搜索是怎么接进 DSH 的</summary>
|
|
@@ -137,7 +126,7 @@ Claude Code CLI → 本机临时 MCP web_search → 插件选定的 DeepSeek/GPT
|
|
|
137
126
|
|
|
138
127
|
- **会切换并停用当前 Key:** 额度用尽(网关报额度、余额、insufficient quota 之类),或 Key 被拒绝(HTTP 401 / `无效的令牌`)。失败的那一步由 harness 重试,从而用上新 Key。
|
|
139
128
|
- **按分组改用,不停用:** 分组读数显示当前 Key 用不了这一轮的模型、而另一个 Key 能用时,这一轮直接用那个 Key(Claude 轮次会在思考区写明「当前 Key「A」的分组不能用 …,本轮改用 Key「B」」)。「使用中」的 Key 不变,其它模型照常用它。只在有证据时才改用:分组还没读到的 Key 照旧使用。
|
|
140
|
-
- **不会切换:** 限速(429);网关把上游渠道故障误报成 400(`当前令牌未覆盖供应商 …`);以及「只允许官方客户端」的 403
|
|
129
|
+
- **不会切换:** 限速(429);网关把上游渠道故障误报成 400(`当前令牌未覆盖供应商 …`);以及「只允许官方客户端」的 403。网关表示「客户端已授权,无需发送连通性测试消息」的 403 单独记为 `GATEWAY_TEST_MESSAGE`,直接说明请求被当作测试消息拒绝,不禁用 Key。仅 Haiku 工具上下文可按下方规则原样重发一次。
|
|
141
130
|
- 全部 Key 都停用时,请求失败并说明没有可用 Key,不会回退到别的凭据。
|
|
142
131
|
|
|
143
132
|
</details>
|
|
@@ -150,7 +139,7 @@ Claude Code CLI → 本机临时 MCP web_search → 插件选定的 DeepSeek/GPT
|
|
|
150
139
|
|
|
151
140
|
选择请求型号与质量后,可在 PackyCode 对话里点 **创建图片** 补充描述,或明确要求使用 `packycode_image_generate`。上传参考图后描述修改要求会调用 `/v1/images/edits`;新图调用 `/v1/images/generations`。图片型号独立于对话型号,其他插件的图片工具仍可并存。
|
|
152
141
|
|
|
153
|
-
|
|
142
|
+
Claude 与其它模型一样,通过 DSH 的 `packycode_image_generate` 工具生图、编辑图片并回传会话,使用独立的图片 Key、设置和余额缓存。旧版 CLI 会话已经保存的图片仍可查看,无需重新生成。
|
|
154
143
|
|
|
155
144
|
**详情里有图、主聊天却显示「图片无法预览」:** 图片结果会在主聊天单独展示,收起思维链或工具详情时仍可见,包括 PTC 嵌套调用。修复版重新打开历史对话也会用已保存的附件补出图片卡片,无需再次生图;模型回复里遗留的无效本机路径图片链接不影响这张卡片。
|
|
156
145
|
|
|
@@ -174,9 +163,9 @@ Claude Code CLI → 本机临时 MCP web_search → 插件选定的 DeepSeek/GPT
|
|
|
174
163
|
| `grok-4.7`(Grok 4.7) | HTTP,Responses,可带图;500k 上下文 | 不能关;`low` / `medium` / `high` / `xhigh` | 以设置页从网关读取的 Grok 分组覆盖为准 |
|
|
175
164
|
| `gemini-4-argon`(Gemini 4 Argon) | HTTP,Gemini 原生流式,可带图;1,048,576 上下文,65,536 输出 | 不能关;`low` / `medium` / `high` | `gemini-slb` |
|
|
176
165
|
| `gemini-3.8-flash`(Gemini 3.8 Flash) | HTTP,Gemini 原生流式,可带图;1,048,576 输入,65,536 输出 | 不能关;`low` / `medium` / `high` | `gemini-slb` |
|
|
177
|
-
| `claude-opus-5-5` |
|
|
166
|
+
| `claude-opus-5-5` | HTTP,Anthropic Messages,可带图和原生工具 | 不能关;`low` / `medium` / `high` / `xhigh` / `max` | 以设置页读取的 Claude 分组覆盖为准 |
|
|
178
167
|
| `claude-sonnet-5-5` | 同上 | 同上 | 同上 |
|
|
179
|
-
| `claude-haiku-5-5` |
|
|
168
|
+
| `claude-haiku-5-5` | 同上;Claude 会话标题固定走它 | 同上 | 同上 |
|
|
180
169
|
|
|
181
170
|
列表里看得到模型,不代表当前令牌分组一定放行。换分组时不要把对应分组一起去掉。
|
|
182
171
|
|
|
@@ -184,36 +173,34 @@ Claude Code CLI → 本机临时 MCP web_search → 插件选定的 DeepSeek/GPT
|
|
|
184
173
|
|
|
185
174
|
Gemini 的能力与限制来自 Google 官方模型页:[Gemini 4 Argon](https://ai.google.dev/gemini-api/docs/models/gemini-4-argon)、[Gemini 3.8 Flash](https://ai.google.dev/gemini-api/docs/models/gemini-3.8-flash)。两款模型统一使用 Gemini 原生协议,通过 `/v1beta/models/{model}:streamGenerateContent` 流式返回文字、思考和工具调用,图片仍由 DSH 附件服务读取。思考档位通过 `thinkingLevel` 传入。两者均使用单次流式输出上限,不执行超过 65,536 token 的自动续写。可用端点与分组以 [PackyAPI 实时模型目录](https://www.packyapi.com/api/pricing) 为准。
|
|
186
175
|
|
|
187
|
-
**
|
|
176
|
+
**Gemini 工具续聊的思维签名:** PackyCode 的 Gemini 原生通道在工具调用场景下不能正确处理思维签名,会返回 HTTP 400 `Invalid thought signature` / `Corrupted thought signature`,原样重发也无济于事(PackyCode 客服的答复)。因此插件对 Gemini 4 Argon 和 Gemini 3.8 Flash 不再回传模型返回的签名,而是按 [Google 文档](https://ai.google.dev/gemini-api/docs/thought-signatures) 在需要签名的位置填入跳过校验的值 `skip_thought_signature_validator`。协议、端点和模型都不变,DSH 的回放记录仍保留原始签名。Google 提示跳过签名可能削弱多步工具调用之间的推理连贯性。Flash 仍保留原有兜底:HTTP 400 签名拒绝且尚未输出任何流事件时,等待 1 秒原样重发一次。这类 400 不会被当作 Key 失效。
|
|
188
177
|
|
|
189
178
|
Grok 4.7 的上下文与推理档位来自 [官方文档](https://docs.x.ai/developers/grok-4-7)。官方没有单独限制文字输出长度;插件将输出上限设为上下文大小,并按每次请求的剩余上下文收紧。
|
|
190
179
|
|
|
191
180
|
Responses 请求只有 GPT 模型保留 `prompt_cache_key`,其他 Responses 模型默认省略。当前网关的 Grok 路由会将这个字段误报成 `Incorrect API key provided`。
|
|
192
181
|
|
|
193
182
|
<details>
|
|
194
|
-
<summary
|
|
195
|
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
-
|
|
203
|
-
-
|
|
204
|
-
-
|
|
205
|
-
-
|
|
206
|
-
-
|
|
207
|
-
-
|
|
208
|
-
-
|
|
209
|
-
- 另有 `claude_code` 工具:当前模型是 `gpt-6.1-sol`、`gpt-6-astra` 或 `deepseek-flash` 时,可以把一个任务委派给本机 Claude Code。请求的 `mode` 不会超过会话权限允许的上限;会话处于计划模式时,这个委派也只规划,并把计划正文交回父模型。
|
|
210
|
-
- 声明了模型不支持的推理档位会被 harness 在发请求前拒绝,不要随手改档位映射。
|
|
183
|
+
<summary>协议、分组与客户端兼容性</summary>
|
|
184
|
+
|
|
185
|
+
- 九个模型均在插件内通过 HTTP 调用。Claude 使用 `anthropic-messages`,base URL 不带 `/v1`;SDK 会拼出 `/v1/messages`。模型、协议、上下文和档位映射保持不变。
|
|
186
|
+
- Claude 请求带上实测通过的 CLI 兼容请求头、Bearer 认证、会话元数据和身份系统提示前缀,并保留原始 DSH 系统说明、工具 schema、附件及签名回放。兼容版本固定为 `2.1.295`,无需检测或启动本机 CLI。
|
|
187
|
+
- Bearer 只来自插件保存并按模型选中的 Key;不读取 CLI 登录状态、外部配置或环境 Key,不切换其它提供商。
|
|
188
|
+
- 这组兼容处理不代表服务端取消了分组的客户端限制。当前 Key 仍需覆盖 Claude;客户端政策拒绝会直接说明原因,不禁用 Key,也不自动改用 CLI。服务端规则变化可能使兼容处理失效,详见 [PackyCode 分组政策](https://docs.packyapi.ai/docs/token/)。
|
|
189
|
+
- Haiku 与 Sonnet 的工具请求都已出现「客户端异常」403 后相同请求成功的情况。插件只对这一特定响应等待 1 秒、原样重发一次;Haiku 另覆盖已捕获的「客户端已授权,无需发送测试消息」403,两种错误共用一次上限。再次拒绝仍会报错。Opus、纯文本请求、普通「只允许官方 CLI」拒绝、429 和已经开始的响应流不触发这次重发。原始失败保留在实测记录中;这不是网关内部判定已得到修复的证明。
|
|
190
|
+
- Claude 流收到 `message_stop` 后即可完成,不再等网关关闭 HTTP 连接;跨分片的 CRLF 换行保持完整。流内错误与取消仍会返回,未收到响应头的等待也不会被当作成功。
|
|
191
|
+
- DSH 的 bash/read/write/edit/glob/grep 在 HTTP 请求中使用已声明的 CLI 标准名称(如 `Bash`、`Read`),其它工具使用 MCP 命名;回到 DSH 时仅还原本次实际提供的工具名称,未知名称不会获得执行权限。工具参数、调用 id、结果和历史签名不变。思考展示采用 CLI 默认:Haiku 为 `omitted`,Sonnet / Opus 为 `updates`(附带相应 beta)。所选推理强度和输出上限不变,空思考块的签名仍完整回传;明确指定的显示模式优先。
|
|
192
|
+
- Claude 请求中的旧工作目录句式会在与当前会话元数据一致时转换为单独的 JSON 路径,避免把提示语的句号复制进路径。真实目录名中的点、Windows 盘符、UNC、空格和反斜杠保持不变;命令参数不会被自动修剪。命令工具优先使用当前目录或 `workdir`,Windows 的 PowerShell 工具保持其原有语法。
|
|
193
|
+
- 普通 Claude 对话保留完整 DSH 工具循环、权限及计划模式;网页搜索和生图使用宿主工具。会话标题改由 `claude-haiku-5-5` 通过 HTTP 生成;Astra 标题仍交给 Sol。
|
|
194
|
+
- 已移除旧 `claude_code` 委派工具、CLI 运行器、检测与安装界面、配置字段及本机 MCP 桥。旧配置中的 `claudeCliPath`、`claudeCliMode` 和 `claudeCliCwd` 不再生效;用户独立安装的 Claude Code 不受影响。
|
|
195
|
+
- Codex 的 Responses 请求仍需要 `prompt_cache_key`;插件补上缺失的会话标识,其它 Responses 模型省略该字段。
|
|
196
|
+
- 构建后可用 `node scripts/claude-check.mjs` 验证三个 Claude 模型的订单核算、工单归类、库存补货、只读库存查询工具回传、商品色卡标注和中文标题,并核对业务答案。`node scripts/claude-stability.mjs --start --hours 6 --key-label <备注名>` 开始有截止时间和请求上限的采样;定时执行同一脚本继续采样,用 `--status` 查看记录。业务场景版本和每轮构建分别记录;测试消息拒绝将对应检查记为失败,其余预定检查继续,真实凭据或额度错误仍会停止整个窗口。测试不改变已保存的凭据,也不启动 DSH。
|
|
197
|
+
- 连续对话可用 `node scripts/claude-conversation-check.mjs --model claude-haiku-5-5 --rounds 3 --key-label <备注名> --output .artifacts/claude-conversation.json`:同一插件适配器处理独立会话,每组保留六轮对话和完整工具历史,检查追问中的数值一致性、最终 JSON 和异常字符;遇到失败停止该批次并保留记录。单请求默认 65 秒、输出上限 2048 token;诊断可通过 `--timeout-ms`(5000–300000)和 `--max-tokens`(1024–128000)显式调整。`--capture-wire` 记录这组模拟业务的完整请求、非认证头和中断前的流事件,用于精确重放;不记录 Key。报告包含场景版本、适配器生命周期、所用上限、首响应和完整响应耗时。这些选项不修改插件的运行参数。
|
|
211
198
|
|
|
212
199
|
</details>
|
|
213
200
|
|
|
214
201
|
## 更新与卸载
|
|
215
202
|
|
|
216
|
-
**更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装,同样要填写带版本号的包名(例如 `dsh-packycode-api@1.
|
|
203
|
+
**更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装,同样要填写带版本号的包名(例如 `dsh-packycode-api@1.3.0`),否则装上的可能是发布满 24 小时的旧版。
|
|
217
204
|
|
|
218
205
|
**从本地路径安装切回官方源时,必须先卸载。** 「更新」是 `pnpm add`,它只重写包目录里的文件,不会删除更早一次本地路径安装留在包目录内的 `node_modules`;那份旧依赖会继续挡住 DSH 自带的包,插件行加载失败且看不出原因。「卸载」执行的是 `pnpm remove`,会删掉整个包目录,重装才是干净的。用 `node scripts/install-check.mjs` 可以确认当前 profile 是否处于这个状态。
|
|
219
206
|
|
|
@@ -229,7 +216,7 @@ ls ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/node_modules
|
|
|
229
216
|
|
|
230
217
|
有输出就是残留:从 npm 安装的包不会自带 `node_modules`,这一份通常来自更早一次「本地路径」安装(`file:` 或直接写路径,而不是 `link:`)。它位于 profile 目录内部,而 DSH 解析插件导入时优先使用 profile 内的副本,所以插件拿到的仍是那份旧依赖 —— 例如 `@deepseek-ai/schemastery` 3.18.2 没有 `Schema.volatile()`,模块在导入阶段就抛错。导入失败时 Loader 不会为这一行创建 fiber,客户端 bundle 也不会被组合,于是模型路由、RPC 通道和设置页全都不会出现。
|
|
231
218
|
|
|
232
|
-
修复:到**插件**页**卸载**本插件,再用带版本号的包名重新**安装**(例如 `dsh-packycode-api@1.
|
|
219
|
+
修复:到**插件**页**卸载**本插件,再用带版本号的包名重新**安装**(例如 `dsh-packycode-api@1.3.0`),然后完全退出并重新打开桌面应用。卸载执行的是 `pnpm remove`,会删掉整个包目录;直接重装或点「更新」只重写文件,不会清掉这份残留。也可以手动删掉上面那个 `node_modules` 再重启。
|
|
233
220
|
|
|
234
221
|
**首次安装后,设置页每张卡片都显示 `transport failure for /packycode-api/…: HTTP 405`?** 实际装上的是 1.1.6 或更早的版本,通常是因为安装时只填了包名:安装提示显示的是最新版,pnpm 实际装的却是发布满 24 小时的旧版(见「安装插件」)。这些旧版要等 DSH 重启、重建它的 `connection` 服务之后,才能注册设置通道。所以首次安装后 `/packycode-api` 通道还不存在,请求落到静态页面,返回 405;模型路由和设置页本身照常加载。1.1.7 起首次安装不需要重启。先确认装上的版本:
|
|
235
222
|
|
|
@@ -241,13 +228,13 @@ grep '"version"' ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/package.
|
|
|
241
228
|
|
|
242
229
|
**某个模型不可用,但 Key 是有效的?** 看「账户与 Key」里这个 Key 的分组和 ✓ / ✕:分组不覆盖这个模型时,换一个分组合适的 Key,或在 PackyCode 控制台给 Key 加上对应分组。存了分组合适的 Key 时,插件会自动用它跑这个模型。分组拒绝不会停用 Key。
|
|
243
230
|
|
|
244
|
-
**Claude
|
|
231
|
+
**Claude 报「只接受官方 Claude Code CLI」或「客户端存在异常」?** 这是网关的客户端政策拒绝,不等于 Key 失效。先在「账户与 Key」和 PackyCode 模型广场确认所选模型的分组覆盖;确认覆盖后仍被拒绝,可用诊断信息定位。插件不会因此禁用 Key、切换提供商或启动 CLI。
|
|
245
232
|
|
|
246
233
|
**余额对不上账号账单?** 设置页合计的是这里列出的 Key,不含同账号下没添加到本插件的其它令牌。个别 Key 读失败时会单独注明,不会被算成 0。
|
|
247
234
|
|
|
248
235
|
**余额显示 `读取失败: https://www.packyapi.com: fetch failed`?** 这是 1.0.4 及更早版本的默认余额接口在国内网络下被 DNS 污染,开了代理才能连上,所以有时正常、有时失败。新版本默认改用 `https://www.packyapi.ai`。模型列表是插件内置的,不需要向 PackyCode 查询,不受影响。
|
|
249
236
|
|
|
250
|
-
**选了 Claude 模型一直显示「深度求索中」?**
|
|
237
|
+
**选了 Claude 模型一直显示「深度求索中」?** 查看 DSH 的错误或诊断信息。429/503 表示网关排队或限流,按宿主重试策略处理;客户端政策拒绝会直接说明原因。普通模型对话不会启动本机 CLI。
|
|
251
238
|
|
|
252
239
|
**限速之后 Key 被停用了?** 不该发生。429 不会切换 Key。额度用尽或 401 才会停用;充值后点「重新启用」。
|
|
253
240
|
|
|
@@ -255,13 +242,13 @@ grep '"version"' ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/package.
|
|
|
255
242
|
|
|
256
243
|
**网页搜索报「no stored API key's group covers …」?** 所选搜索后端的模型不在你的令牌分组里(或网关暂时把它路由到了别的供应商)。在 **设置 → PackyCode → 网页搜索** 换一个后端,或添加分组覆盖它的 Key。
|
|
257
244
|
|
|
258
|
-
|
|
245
|
+
**以前安装的 Claude Code 还需要吗?** 本插件已经移除 CLI 运行、安装和委派功能,Claude 模型直接通过 HTTP 调用。独立使用 Claude Code 的用户可继续保留它;本插件不会改动其安装或配置。
|
|
259
246
|
|
|
260
247
|
**回答被截断(「已达到输出 token 上限」)、请求反复失败,怎么反馈?** 打开 **设置 → PackyCode → 诊断信息**,选出问题的会话(最近 20 个,按时间倒序,标着所在文件夹名),点「生成诊断信息」再点「复制」,把内容贴到 [Issue](https://github.com/BaronCyrus/dsh-packycode-api/issues) 或发给插件作者。内容只有设置和数字:插件版本、会话 id 与创建时间、每个 Key 的序号与分组(不含备注名和 Key 本身)、每次请求用的模型、推理档位和输出上限、最近若干步的 token 用量与结束原因,以及重试和失败的错误码(错误信息已脱敏并截短)。不含对话内容、文件路径和 Key。复制不可用时,文本会被全选,按 ⌘C 或 Ctrl+C 即可。
|
|
261
248
|
|
|
262
249
|
## 安全边界
|
|
263
250
|
|
|
264
|
-
本项目是社区插件,与 DeepSeek、PackyCode 无隶属或背书关系。模型请求会发到你配置的 PackyCode 接口;凭据不返回浏览器,不代表推理在本地完成。Claude
|
|
251
|
+
本项目是社区插件,与 DeepSeek、PackyCode 无隶属或背书关系。模型请求会发到你配置的 PackyCode 接口;凭据不返回浏览器,不代表推理在本地完成。Claude 也通过插件内的 HTTP 路由调用。
|
|
265
252
|
|
|
266
253
|
Key 存在本机 DSH 凭据文件(`~/.dsh/.credentials.yaml`,权限由 DSH 设为仅所有者可读),不进设置文档、日志或对话记录。余额请求只在宿主侧发出,带超时并禁止重定向。
|
|
267
254
|
|
|
@@ -278,13 +265,7 @@ pnpm run check
|
|
|
278
265
|
|
|
279
266
|
`pnpm run check` 会跑全部测试、重新构建,并在 `.artifacts/` 打出 tarball。`lib/` 是已提交的构建产物,改 `src/` 后用 `pnpm run build` 生成,不要手改。
|
|
280
267
|
|
|
281
|
-
真机网关用 `node scripts/live-check.mjs` 验证:它通过插件注册的同一条路由,读余额和分组、让每个 HTTP 模型回答一次、演练 Key 轮换和失败分类,只打印 Key 的末 4 位。加 `--with-
|
|
282
|
-
|
|
283
|
-
Claude CLI 的 MCP 接口验证用 `node scripts/cli-search-check.mjs`:运行真实 CLI,普通 Claude 响应和搜索数据默认由本地测试服务模拟,不消费额度;会检查三种权限模式、原生搜索禁用和临时资源清理。加 `--live --backend deepseek` 或 `--live --backend gpt` 会让只读模式的那一次搜索走真实后端(其它两种模式仍模拟)。这不等于验证了真实 Claude 上游对话或运行中的 DSH 集成。
|
|
284
|
-
|
|
285
|
-
图片 MCP 验证用 `node scripts/cli-image-check.mjs`:真实官方 CLI 依次生图、用生成结果编辑,并经 DSH 消息组装器验证持久化图片;默认 Claude 和图片网关响应均在本地模拟,同时检查只读/编辑/完全权限、计划模式、标题和临时配置清理。加 `--live` 会用已保存的独立图片 Key 向真实图片网关发出一次 Sunburst `low` 生图与一次编辑,结果写入 `.artifacts/`;Claude 回复仍由本地模拟网关提供。加 `--with-claude` 则连 Claude 也走真实网关,默认 Haiku,另消费对话额度;两者都不启动或重启 DSH,也不等于验证了运行中桌面会话。
|
|
286
|
-
|
|
287
|
-
计划模式另用 `node scripts/cli-plan-check.mjs` 验证:真实 CLI 对接本地模拟网关,检查 stdio 计划提交、并发计划归属、本轮文件回退、旧计划隔离、实际拒绝次数上限和清理;不读取真实凭据、不消费额度、不启动 DSH。
|
|
268
|
+
真机网关用 `node scripts/live-check.mjs` 验证:它通过插件注册的同一条路由,读余额和分组、让每个 HTTP 模型回答一次、演练 Key 轮换和失败分类,只打印 Key 的末 4 位。加 `--with-search` 会每个搜索后端各搜一次;默认运行只消耗少量额度。
|
|
288
269
|
|
|
289
270
|
排查「装了却看不到插件」用 `node scripts/install-check.mjs`:它只读当前 profile,列出被包内残留 `node_modules` 挡住的宿主包(含版本)和对应的修复步骤,发现问题时以退出码 1 结束;`--profile <name>`、`--home <dir>` 可指定其它 profile,`--json` 输出结构化结果。
|
|
290
271
|
|
package/SECURITY.md
CHANGED
|
@@ -11,16 +11,14 @@
|
|
|
11
11
|
## Network
|
|
12
12
|
|
|
13
13
|
- Balance requests carry a timeout (`AbortSignal.timeout`) and `redirect: 'error'`, and go only to the configured hosts plus the PackyAPI fallback host.
|
|
14
|
-
- Model traffic goes to the configured model host through the
|
|
14
|
+
- Model traffic goes to the configured model host through the plugin's pi-ai adapter. Protocol-specific compatibility headers are applied host-side; credentials remain scoped to the selected plugin key.
|
|
15
15
|
|
|
16
|
-
## Claude
|
|
16
|
+
## Native Claude requests
|
|
17
17
|
|
|
18
|
-
-
|
|
19
|
-
- The
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
- The local capability and owner-only files reduce accidental exposure; they do **not** isolate the service from a compromised process or customization running as the same OS user. Do not run the delegated CLI in an untrusted workspace with hostile hooks/MCP configuration.
|
|
23
|
-
- Startup cancellation also revokes an already-bound listener while filesystem setup is pending. Completed/failed/abandoned invocations and plugin unload close the server and clean up only their own temporary config directory.
|
|
18
|
+
- Claude uses the plugin's HTTP Messages route. The plugin has no Claude CLI runner, installer, delegation tool or local MCP bridge. Existing standalone Claude Code installations and configuration are untouched.
|
|
19
|
+
- The compatibility headers and session metadata do not load a CLI login or external configuration. Bearer authentication uses only the plugin's selected conversation key; images keep their separate credential record.
|
|
20
|
+
- DSH owns tool execution, permissions, plan mode, attachments and history. Wire tool aliases are restored only for tools offered on that request; unknown aliases are not decoded into host tools. Saved images from older CLI-backed sessions remain readable without executing their old tools.
|
|
21
|
+
- Captured client-policy refusals do not disable keys or switch providers. The specific pre-stream anomalies covered by the native transport may replay the exact bytes and credential once; ordinary policy refusals, HTTP 429 and accepted streams are excluded. Cancellation aborts the replay.
|
|
24
22
|
|
|
25
23
|
## Reporting
|
|
26
24
|
|
package/lib/client.js
CHANGED
|
@@ -144,29 +144,6 @@ window.__ModuleLoader__.load({
|
|
|
144
144
|
composerUnread: "余额读取失败",
|
|
145
145
|
composerStale: "上次读取于 {time},本次读取失败",
|
|
146
146
|
quotaReadAt: "更新于 {time}",
|
|
147
|
-
cliTitle: "Claude Code CLI",
|
|
148
|
-
cliChecking: "正在检测本机的 Claude Code CLI…",
|
|
149
|
-
cliInstalled: "已安装",
|
|
150
|
-
cliVersion: "版本",
|
|
151
|
-
cliPath: "位置",
|
|
152
|
-
cliRecheck: "重新检测",
|
|
153
|
-
cliMissing: "未检测到 Claude Code CLI",
|
|
154
|
-
cliMissingHint: "不安装将无法正常使用 Claude 模型(claude-opus-5-5、claude-sonnet-5-5、claude-haiku-5-5):PackyCode 只把 Claude 模型提供给官方 Claude Code CLI,插件需要调用本机的 CLI 来运行它。其它模型不受影响。",
|
|
155
|
-
cliConfiguredMissing: "设置里指定的 CLI 路径不存在:{path}",
|
|
156
|
-
cliBroken: "找到了 CLI,但无法运行",
|
|
157
|
-
cliInstall: "安装 Claude Code CLI",
|
|
158
|
-
cliReinstall: "重新安装",
|
|
159
|
-
cliInstalling: "正在安装…(通常需要一两分钟,请勿关闭 DSH)",
|
|
160
|
-
cliInstallCommand: "将在本机执行:{command}(需要 Node.js 18 或更高版本)",
|
|
161
|
-
cliInstallSucceeded: "安装完成。",
|
|
162
|
-
cliInstallFailed: "安装失败",
|
|
163
|
-
cliNpmMissing: "没有找到 npm。请先从 https://nodejs.org 安装 Node.js(18 或更高版本),然后再点安装。",
|
|
164
|
-
cliPermission: "npm 没有权限写入全局目录。请在终端执行 sudo {command},或把 npm 的全局目录改到用户目录后重试。",
|
|
165
|
-
cliPermissionWindows: "npm 没有权限写入全局目录。请以管理员身份打开终端执行 {command},然后点「重新检测」。",
|
|
166
|
-
cliNetwork: "下载失败,请检查网络或 npm 镜像设置后重试。",
|
|
167
|
-
cliTimeout: "安装超时,请检查网络后重试。",
|
|
168
|
-
cliNotFoundAfterInstall: "npm 显示安装完成,但仍找不到 claude 命令。请在终端执行 claude --version 确认,然后点「重新检测」。",
|
|
169
|
-
cliWindowsNote: "Windows 上 Claude Code 还需要 Git for Windows(https://git-scm.com/downloads/win)。",
|
|
170
147
|
versionTitle: "插件版本",
|
|
171
148
|
versionCurrent: "当前版本",
|
|
172
149
|
versionLatest: "最新版本",
|
|
@@ -202,8 +179,7 @@ window.__ModuleLoader__.load({
|
|
|
202
179
|
diagError: "生成诊断信息失败",
|
|
203
180
|
searchTitle: "网页搜索",
|
|
204
181
|
searchScope: "DSH 全局设置",
|
|
205
|
-
searchIntro: "DSH 的 web_search
|
|
206
|
-
searchCliHint: "Claude CLI 始终通过 MCP 使用这里的搜索后端,原生 WebSearch 已禁用。下面的路由选项只控制 DSH 全局搜索,不影响 CLI。",
|
|
182
|
+
searchIntro: "DSH 的 web_search 可使用这里选择的 DeepSeek/GPT 后端,Claude 与其它模型遵循相同的路由设置。每次搜索是独立的模型调用,用插件保存的 Key 计费。",
|
|
207
183
|
searchChecking: "正在读取搜索设置…",
|
|
208
184
|
searchLoadFailed: "搜索设置读取或保存失败",
|
|
209
185
|
searchModeTitle: "DSH 路由",
|
|
@@ -223,7 +199,7 @@ window.__ModuleLoader__.load({
|
|
|
223
199
|
searchApplyFailed: "写入搜索补丁失败:{error}",
|
|
224
200
|
searchForeign: "检测到 {names} 订阅插件:它们接管的模型仍按各自的搜索设置,其余请求才会到达这里的选择。",
|
|
225
201
|
searchOverridden: "基础搜索现在是 {base},不是 PackyCode:可能还在热加载,或被其他插件的补丁覆盖。",
|
|
226
|
-
searchUnavailable: "当前运行环境没有 DSH
|
|
202
|
+
searchUnavailable: "当前运行环境没有 DSH 网页搜索服务,搜索路由暂不生效。",
|
|
227
203
|
searchNotWritable: "当前 profile 不允许写入设置。",
|
|
228
204
|
searchUnknown: "未知"
|
|
229
205
|
};
|
|
@@ -336,29 +312,6 @@ window.__ModuleLoader__.load({
|
|
|
336
312
|
composerUnread: "Balance unavailable",
|
|
337
313
|
composerStale: "Last read at {time}; this read failed",
|
|
338
314
|
quotaReadAt: "Updated at {time}",
|
|
339
|
-
cliTitle: "Claude Code CLI",
|
|
340
|
-
cliChecking: "Checking this device for the Claude Code CLI…",
|
|
341
|
-
cliInstalled: "Installed",
|
|
342
|
-
cliVersion: "Version",
|
|
343
|
-
cliPath: "Location",
|
|
344
|
-
cliRecheck: "Check again",
|
|
345
|
-
cliMissing: "Claude Code CLI not found",
|
|
346
|
-
cliMissingHint: "Without it the Claude models (claude-opus-5-5, claude-sonnet-5-5, claude-haiku-5-5) cannot work: PackyCode serves Claude models only to the official Claude Code CLI, so the plugin runs the CLI on this device. Other models are unaffected.",
|
|
347
|
-
cliConfiguredMissing: "The CLI path set in settings does not exist: {path}",
|
|
348
|
-
cliBroken: "The CLI was found but could not run",
|
|
349
|
-
cliInstall: "Install Claude Code CLI",
|
|
350
|
-
cliReinstall: "Reinstall",
|
|
351
|
-
cliInstalling: "Installing… (usually a minute or two; keep DSH open)",
|
|
352
|
-
cliInstallCommand: "Runs on this device: {command} (requires Node.js 18 or later)",
|
|
353
|
-
cliInstallSucceeded: "Installed.",
|
|
354
|
-
cliInstallFailed: "Install failed",
|
|
355
|
-
cliNpmMissing: "npm was not found. Install Node.js 18 or later from https://nodejs.org, then click Install again.",
|
|
356
|
-
cliPermission: "npm cannot write its global directory. Run sudo {command} in a terminal, or point npm’s global prefix at a folder you own, then retry.",
|
|
357
|
-
cliPermissionWindows: "npm cannot write its global directory. Open a terminal as administrator, run {command}, then click Check again.",
|
|
358
|
-
cliNetwork: "The download failed. Check your network or npm registry settings and retry.",
|
|
359
|
-
cliTimeout: "The install timed out. Check your network and retry.",
|
|
360
|
-
cliNotFoundAfterInstall: "npm reported success, but the claude command still cannot be found. Run claude --version in a terminal, then click Check again.",
|
|
361
|
-
cliWindowsNote: "On Windows, Claude Code also needs Git for Windows (https://git-scm.com/downloads/win).",
|
|
362
315
|
versionTitle: "Plugin version",
|
|
363
316
|
versionCurrent: "Current version",
|
|
364
317
|
versionLatest: "Latest version",
|
|
@@ -394,8 +347,7 @@ window.__ModuleLoader__.load({
|
|
|
394
347
|
diagError: "Could not generate diagnostics",
|
|
395
348
|
searchTitle: "Web search",
|
|
396
349
|
searchScope: "DSH-wide setting",
|
|
397
|
-
searchIntro: "DSH’s web_search
|
|
398
|
-
searchCliHint: "Claude CLI always uses this backend through MCP; native WebSearch is disabled. The routing options below only control DSH-wide search, not CLI search.",
|
|
350
|
+
searchIntro: "DSH’s web_search can use the DeepSeek/GPT backend selected here. Claude follows the same routing settings as other models. Each search is a separate model call billed to the plugin-stored keys.",
|
|
399
351
|
searchChecking: "Reading the search preference…",
|
|
400
352
|
searchLoadFailed: "Could not read or save the search preference",
|
|
401
353
|
searchModeTitle: "DSH routing",
|
|
@@ -415,7 +367,7 @@ window.__ModuleLoader__.load({
|
|
|
415
367
|
searchApplyFailed: "Could not write the search patch: {error}",
|
|
416
368
|
searchForeign: "{names} subscription plugin detected: the models it routes keep its own search choice; only the other requests reach the choice made here.",
|
|
417
369
|
searchOverridden: "The base search is {base}, not PackyCode: the reload may still be running, or another plugin’s patch overrides it.",
|
|
418
|
-
searchUnavailable: "This runtime has no DSH web search service;
|
|
370
|
+
searchUnavailable: "This runtime has no DSH web search service; search routing has no effect.",
|
|
419
371
|
searchNotWritable: "This profile does not allow settings writes.",
|
|
420
372
|
searchUnknown: "unknown"
|
|
421
373
|
};
|
|
@@ -1936,7 +1888,6 @@ window.__ModuleLoader__.load({
|
|
|
1936
1888
|
const REFRESH_MS = 6e4;
|
|
1937
1889
|
/** PackyCode registration through the author's invite link, offered only until a key is stored. */
|
|
1938
1890
|
const INVITE_URL = "https://www.packyapi.ai/register?aff=Im3l";
|
|
1939
|
-
const INSTALL_POLL_MS = 2e3;
|
|
1940
1891
|
/** How long after a search change the panel re-reads what DSH applied (the patch hot-reloads). */
|
|
1941
1892
|
const SEARCH_SETTLE_MS = 1500;
|
|
1942
1893
|
const OWN_SEARCH_IDS = {
|
|
@@ -2521,10 +2472,6 @@ window.__ModuleLoader__.load({
|
|
|
2521
2472
|
className: "pkc-note",
|
|
2522
2473
|
children: t("searchIntro")
|
|
2523
2474
|
}),
|
|
2524
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2525
|
-
className: "pkc-note",
|
|
2526
|
-
children: t("searchCliHint")
|
|
2527
|
-
}),
|
|
2528
2475
|
state === void 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2529
2476
|
className: "pkc-note",
|
|
2530
2477
|
role: "status",
|
|
@@ -2629,157 +2576,6 @@ window.__ModuleLoader__.load({
|
|
|
2629
2576
|
]
|
|
2630
2577
|
});
|
|
2631
2578
|
}
|
|
2632
|
-
const INSTALL_FAILURES = {
|
|
2633
|
-
"npm-missing": () => "cliNpmMissing",
|
|
2634
|
-
permission: (cli) => cli.platform === "win32" ? "cliPermissionWindows" : "cliPermission",
|
|
2635
|
-
network: () => "cliNetwork",
|
|
2636
|
-
timeout: () => "cliTimeout",
|
|
2637
|
-
"not-found-after-install": () => "cliNotFoundAfterInstall"
|
|
2638
|
-
};
|
|
2639
|
-
/** The sentence explaining a failed install, by the code the host classified. */
|
|
2640
|
-
function installFailure(cli, t) {
|
|
2641
|
-
const key = INSTALL_FAILURES[cli.install?.code]?.(cli);
|
|
2642
|
-
return key === void 0 ? void 0 : fill(t(key), { command: cli.command ?? "" });
|
|
2643
|
-
}
|
|
2644
|
-
/**
|
|
2645
|
-
* Whether this device has the Claude Code CLI, which version, and — when it
|
|
2646
|
-
* has none — a button that installs it with npm.
|
|
2647
|
-
*/
|
|
2648
|
-
function ClaudeCliCard({ call, t }) {
|
|
2649
|
-
const [cli, setCli] = react.useState();
|
|
2650
|
-
const [checking, setChecking] = react.useState(false);
|
|
2651
|
-
const [error, setError] = react.useState();
|
|
2652
|
-
const check = react.useCallback((force = false) => {
|
|
2653
|
-
setChecking(true);
|
|
2654
|
-
setError(void 0);
|
|
2655
|
-
return call("claude-cli/status", { force }).then(setCli).catch((failure) => setError(clearMessage(failure))).finally(() => setChecking(false));
|
|
2656
|
-
}, [call]);
|
|
2657
|
-
react.useEffect(() => {
|
|
2658
|
-
check(false);
|
|
2659
|
-
}, [check]);
|
|
2660
|
-
const running = cli?.install?.state === "running";
|
|
2661
|
-
react.useEffect(() => {
|
|
2662
|
-
if (!running) return void 0;
|
|
2663
|
-
let live = true;
|
|
2664
|
-
const timer = window.setInterval(() => {
|
|
2665
|
-
call("claude-cli/status").then((value) => {
|
|
2666
|
-
if (live) setCli(value);
|
|
2667
|
-
}).catch(() => void 0);
|
|
2668
|
-
}, INSTALL_POLL_MS);
|
|
2669
|
-
return () => {
|
|
2670
|
-
live = false;
|
|
2671
|
-
window.clearInterval(timer);
|
|
2672
|
-
};
|
|
2673
|
-
}, [call, running]);
|
|
2674
|
-
const install = () => {
|
|
2675
|
-
setError(void 0);
|
|
2676
|
-
call("claude-cli/install").then(setCli).catch((failure) => setError(clearMessage(failure)));
|
|
2677
|
-
};
|
|
2678
|
-
const usable = cli?.installed === true && cli.version !== void 0;
|
|
2679
|
-
const failed = cli?.install?.state === "failed";
|
|
2680
|
-
const failure = cli === void 0 ? void 0 : installFailure(cli, t);
|
|
2681
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Card, {
|
|
2682
|
-
title: t("cliTitle"),
|
|
2683
|
-
aside: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
2684
|
-
disabled: checking || running,
|
|
2685
|
-
onClick: () => check(true),
|
|
2686
|
-
children: checking ? t("refreshing") : t("cliRecheck")
|
|
2687
|
-
}),
|
|
2688
|
-
children: [
|
|
2689
|
-
cli === void 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2690
|
-
className: "pkc-note",
|
|
2691
|
-
children: t("cliChecking")
|
|
2692
|
-
}),
|
|
2693
|
-
usable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2694
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2695
|
-
className: "pkc-status",
|
|
2696
|
-
children: [
|
|
2697
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2698
|
-
className: "pkc-dot",
|
|
2699
|
-
"data-tone": "success"
|
|
2700
|
-
}),
|
|
2701
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("cliInstalled") }),
|
|
2702
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: `${t("cliVersion")} ${cli.version}` })
|
|
2703
|
-
]
|
|
2704
|
-
}),
|
|
2705
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2706
|
-
className: "pkc-meta",
|
|
2707
|
-
children: [
|
|
2708
|
-
t("cliPath"),
|
|
2709
|
-
" ",
|
|
2710
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2711
|
-
className: "pkc-mono",
|
|
2712
|
-
children: cli.path
|
|
2713
|
-
})
|
|
2714
|
-
]
|
|
2715
|
-
}),
|
|
2716
|
-
cli.install?.state === "succeeded" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2717
|
-
className: "pkc-note",
|
|
2718
|
-
children: t("cliInstallSucceeded")
|
|
2719
|
-
})
|
|
2720
|
-
] }),
|
|
2721
|
-
cli !== void 0 && !usable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2722
|
-
className: "pkc-callout",
|
|
2723
|
-
children: [
|
|
2724
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2725
|
-
className: "pkc-status",
|
|
2726
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2727
|
-
className: "pkc-dot",
|
|
2728
|
-
"data-tone": cli.installed ? "danger" : "warn"
|
|
2729
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("b", { children: cli.installed ? t("cliBroken") : t("cliMissing") })]
|
|
2730
|
-
}),
|
|
2731
|
-
cli.installed && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2732
|
-
className: "pkc-meta",
|
|
2733
|
-
children: [
|
|
2734
|
-
t("cliPath"),
|
|
2735
|
-
" ",
|
|
2736
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2737
|
-
className: "pkc-mono",
|
|
2738
|
-
children: cli.path
|
|
2739
|
-
})
|
|
2740
|
-
]
|
|
2741
|
-
}), cli.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
2742
|
-
className: "pkc-detail",
|
|
2743
|
-
children: cli.error
|
|
2744
|
-
})] }),
|
|
2745
|
-
cli.configuredPath !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2746
|
-
className: "pkc-note",
|
|
2747
|
-
children: fill(t("cliConfiguredMissing"), { path: cli.configuredPath })
|
|
2748
|
-
}),
|
|
2749
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2750
|
-
className: "pkc-note",
|
|
2751
|
-
children: t("cliMissingHint")
|
|
2752
|
-
}),
|
|
2753
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2754
|
-
className: "pkc-split",
|
|
2755
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
2756
|
-
variant: "primary",
|
|
2757
|
-
size: "md",
|
|
2758
|
-
disabled: running || checking,
|
|
2759
|
-
onClick: install,
|
|
2760
|
-
children: running ? t("cliInstalling") : cli.installed ? t("cliReinstall") : t("cliInstall")
|
|
2761
|
-
})
|
|
2762
|
-
}),
|
|
2763
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
2764
|
-
className: "pkc-note",
|
|
2765
|
-
children: [fill(t("cliInstallCommand"), { command: cli.command ?? "" }), cli.platform === "win32" && ` ${t("cliWindowsNote")}`]
|
|
2766
|
-
})
|
|
2767
|
-
]
|
|
2768
|
-
}),
|
|
2769
|
-
failed && !usable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2770
|
-
className: "pkc-error",
|
|
2771
|
-
children: failure === void 0 ? t("cliInstallFailed") : `${t("cliInstallFailed")} · ${failure}`
|
|
2772
|
-
}), cli.install.detail !== void 0 && cli.install.detail !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
2773
|
-
className: "pkc-detail",
|
|
2774
|
-
children: cli.install.detail
|
|
2775
|
-
})] }),
|
|
2776
|
-
error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2777
|
-
className: "pkc-error",
|
|
2778
|
-
children: `${t("error")}: ${error}`
|
|
2779
|
-
})
|
|
2780
|
-
]
|
|
2781
|
-
});
|
|
2782
|
-
}
|
|
2783
2579
|
function VersionCard({ call, t }) {
|
|
2784
2580
|
const [info, setInfo] = react.useState();
|
|
2785
2581
|
const [loading, setLoading] = react.useState(true);
|
|
@@ -2938,10 +2734,6 @@ window.__ModuleLoader__.load({
|
|
|
2938
2734
|
call,
|
|
2939
2735
|
t
|
|
2940
2736
|
}),
|
|
2941
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClaudeCliCard, {
|
|
2942
|
-
call,
|
|
2943
|
-
t
|
|
2944
|
-
}),
|
|
2945
2737
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(VersionCard, {
|
|
2946
2738
|
call,
|
|
2947
2739
|
t
|