dsh-packycode-api 1.0.1 → 1.0.4

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/AGENTS.md CHANGED
@@ -46,4 +46,52 @@ Live gateway behavior is verified with `node scripts/live-check.mjs` after a bui
46
46
 
47
47
  ## Release authorization
48
48
 
49
- `npm publish`, Git tags, GitHub Releases, and version publication are externally visible and partially irreversible. Execute them only when the user explicitly asks and confirms the version. Never reuse or move a published version or tag; publish a new patch version instead.
49
+ `npm publish`, Git tags, GitHub Releases, and version publication are externally visible and partially irreversible. Execute them only when the user explicitly asks to publish or release and confirms the target version. A request to modify, test, or commit alone is not release authorization.
50
+
51
+ Never reuse, move, delete, or overwrite a published npm version or Git tag. If a published version needs a correction, create a new patch version.
52
+
53
+ ## Release checklist
54
+
55
+ 1. Synchronize and confirm a clean base:
56
+
57
+ ```sh
58
+ git fetch origin --tags --prune
59
+ git status --short --branch
60
+ git log --oneline HEAD..origin/main
61
+ ```
62
+
63
+ Fast-forward clean remote changes before editing. Never discard remote changes.
64
+
65
+ 2. Confirm the requested SemVer is unused:
66
+
67
+ ```sh
68
+ npm view dsh-packycode-api@<version> version --json
69
+ git ls-remote --exit-code --tags origin refs/tags/v<version>
70
+ ```
71
+
72
+ For an unused npm version, `npm view` normally returns `E404`. An existing npm version or Git tag requires choosing a new version.
73
+
74
+ 3. Update all release metadata together: `package.json` version, `CHANGELOG.md`, and any version pinned in `README.md` / `README.en.md`.
75
+
76
+ 4. Validate and inspect the exact release artifact:
77
+
78
+ ```sh
79
+ pnpm install --frozen-lockfile
80
+ pnpm run check
81
+ npm publish .artifacts/dsh-packycode-api-<version>.tgz --access public --dry-run --json
82
+ ```
83
+
84
+ 5. Commit the release and push `main` without force. [`.github/workflows/publish.yml`](.github/workflows/publish.yml) must already be on the commit that will be tagged. Do not push the tag in this step.
85
+
86
+ 6. Confirm the package has a GitHub Actions trusted publisher before pushing the tag: repository `BaronCyrus/dsh-packycode-api`, workflow filename `publish.yml`, environment empty. Never request that a token, password, or one-time code be pasted into chat.
87
+
88
+ 7. Create the annotated tag and push it. That push publishes with GitHub OIDC. Do not run `npm publish` locally for a release. A local publish cannot attach provenance. Do not set `NODE_AUTH_TOKEN` or a setup-node `registry-url` in the publish workflow; npm treats either as token auth and skips OIDC.
89
+
90
+ ```sh
91
+ git tag -a v<version> -m "dsh-packycode-api v<version>"
92
+ git push origin v<version>
93
+ ```
94
+
95
+ `workflow_dispatch` on the same workflow only prints the OIDC identity npm will match. It does not publish.
96
+
97
+ 8. Confirm the publish workflow succeeded for that tag before declaring the release public. On an OIDC `package not found` error, fix the trusted publisher and re-run the same workflow. Do not move the tag. If the tagged tree itself must change, publish a new patch version.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.4
4
+
5
+ - Settings can check for and install a newer npm release. **Update plugin** installs the exact published version into the owning profile with the host's bundled pnpm, then reads `package.json` back before reporting success. A `link:` checkout is left alone. The desktop app still needs a full restart afterwards.
6
+ - The update runs with `minimumReleaseAge=0`, so neither a fresh release of this plugin nor a fresh release of a sibling plugin already in the profile lockfile blocks it. The README FAQ explains the `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION` that a Plugins-page install can still hit.
7
+
8
+ ## 1.0.3
9
+
10
+ - The Claude CLI timeout test holds the event loop open. The runner unrefs its timer and the test stub is not a real process, so Node 22's test runner cancelled the still-pending test and stopped the publish workflow. Plugin behavior is unchanged. `1.0.2` was tagged but not published.
11
+
12
+ ## 1.0.2
13
+
14
+ - The plugin card and both READMEs show the PackyCode mascot. The package declares a top-level `icon` and ships a 512×512 transparent lossless WebP, under DSH's 256 KiB icon limit. The original README PNG is unchanged.
15
+ - Keys can be renamed from the settings panel (`keys/rename`, up to 60 characters, empty names refused). Before, a label was fixed at add time, so keys stored under a duplicate default name could only be fixed by removing and re-adding them.
16
+ - The account-balance rows now show the key's own name instead of the PackyCode token name, so a rename shows up in both lists; the token name moves to the row's detail line when it differs.
17
+
3
18
  ## 1.0.1
4
19
 
5
20
  - The balance card no longer shows PackyCode's account-level billing line (`PackyCode 账号(含同账号其它用量):剩余 … · 已用 … · 额度 …`). It counts every token on the account, including usage from keys not stored here, so it could read as a large negative remaining beside the per-key totals. The headline figures — the sum of the listed keys — are unchanged.
package/README.en.md ADDED
@@ -0,0 +1,161 @@
1
+ <div align="center">
2
+
3
+ <img src="docs/assets/dsh-packycode-mascot.png" width="220" height="220" alt="DSH PackyCode API mascot">
4
+
5
+ # DSH PackyCode API
6
+
7
+ [简体中文](README.md) · **English**
8
+
9
+ **Pick models, rotate keys, and read balances in DSH with a PackyCode API key.**
10
+
11
+ The `PackyCode` model group ships with the plugin. No YAML edits and no separate provider setup.
12
+
13
+ [![CI](https://github.com/BaronCyrus/dsh-packycode-api/actions/workflows/ci.yml/badge.svg)](https://github.com/BaronCyrus/dsh-packycode-api/actions/workflows/ci.yml)
14
+ [![npm](https://img.shields.io/npm/v/dsh-packycode-api?logo=npm&label=npm)](https://www.npmjs.com/package/dsh-packycode-api)
15
+ [![Total npm downloads](https://img.shields.io/npm/dt/dsh-packycode-api?logo=npm&label=total%20downloads)](https://www.npmjs.com/package/dsh-packycode-api)
16
+ [![MIT](https://img.shields.io/badge/license-MIT-111111.svg)](LICENSE)
17
+ [![Star](https://img.shields.io/github/stars/BaronCyrus/dsh-packycode-api?style=flat&logo=github&label=Star)](https://github.com/BaronCyrus/dsh-packycode-api/stargazers)
18
+
19
+ [Features](#features) · [Install](#install) · [Daily use](#daily-use) · [Models and groups](#models-and-groups) · [Update and uninstall](#update-and-uninstall)
20
+
21
+ </div>
22
+
23
+ ## Features
24
+
25
+ | Capability | What it does |
26
+ | --- | --- |
27
+ | **Built-in model route** | Adds a `PackyCode` group to the model picker. No provider configuration and no `cordis.patch.yml` edits |
28
+ | **Keys used in order** | An exhausted or rejected key is disabled and the next usable key takes over; the failed step is retried on that key |
29
+ | **Visible balance** | Settings lists each key's remaining, used, limit, and reset period, plus a total of those keys. The composer shows the active key's remaining balance |
30
+ | **Claude through the local CLI** | `claude-opus-5-5`, `claude-sonnet-5-5`, and `claude-haiku-5-5` run the official Claude Code CLI on this device. Settings can detect it and install it |
31
+ | **Credentials stay on the machine** | Keys live in the DSH credential file. The browser receives labels, state, and balances only |
32
+
33
+ ## Install
34
+
35
+ You need **DeepSeek Harness** and a **PackyCode (PackyAPI) API key**. For DSH setup, see the [official instructions](https://github.com/deepseek-ai/deepseek-harness#run).
36
+
37
+ ### 1. Install the plugin
38
+
39
+ Open the desktop application's **Plugins** page, click **Add plugin**, and enter this as the **package name or address**:
40
+
41
+ ```text
42
+ dsh-packycode-api
43
+ ```
44
+
45
+ Choose the **official** install source, then click **Install**. To pin a version, enter `dsh-packycode-api@1.0.4`.
46
+
47
+ Then **manually restart the desktop application**. Refreshing the page does not reload the plugin inside the Host process.
48
+
49
+ ### 2. Add a key
50
+
51
+ Open **Settings → PackyCode**. Paste the API key under **Add a key**. A label is optional and only distinguishes keys. Click **Add**.
52
+
53
+ > Do not paste a key into a public issue, chat, or screenshot. The plugin does not read `PACKY_CODE_API_KEY` from the environment, and it does not silently switch to another provider when a request fails.
54
+
55
+ ### 3. Select a model
56
+
57
+ Choose a model from the `PackyCode` group. `deepseek-flash` and `gpt-6.1-sol` work once a key is stored. The three Claude models also need the Claude Code CLI on this device; see below.
58
+
59
+ <details>
60
+ <summary>Verify the install / other profiles / a local checkout</summary>
61
+
62
+ The **Plugins** page shows the installed state and version, and is also where you enable, disable, or uninstall.
63
+
64
+ **For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.0.4`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
65
+
66
+ A local checkout can be linked with `dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`.
67
+
68
+ A profile without a browser can still use the model route. It just has no settings panel and no composer balance.
69
+
70
+ </details>
71
+
72
+ ## Daily use
73
+
74
+ **Switch keys.** Keys are used in the order they were added. **Use this key** selects one; **Rename** changes its label (at most 60 characters, empty names are refused); **Re-enable** puts a disabled key back after a top-up or replacement.
75
+
76
+ **Read the balance.** The settings total is the remaining, used, and limit of **the keys listed here**, not the bill for every token on the PackyCode account. A key that could not be read is left out of the total and counted in a note. The composer shows the active key's remaining balance only while a PackyCode model is selected. **Refresh** bypasses the roughly 60-second cache. The default model host is `https://cf.api.fan` and the balance host is `https://www.packyapi.com`; both can be changed under **Advanced: endpoints**.
77
+
78
+ **Use Claude.** The **Claude Code CLI** card at the top of Settings checks this device. If the CLI is missing, **Install Claude Code CLI** runs `npm install -g @anthropic-ai/claude-code` (Node.js 18+). No DSH restart is required after that install. Windows also needs [Git for Windows](https://git-scm.com/downloads/win).
79
+
80
+ <details>
81
+ <summary>When a key is rotated</summary>
82
+
83
+ - **Rotates and disables the current key:** the gateway reports exhausted quota, or it rejects the key (HTTP 401 / invalid token). The harness retries the failed step, which is what actually sends it on the next key.
84
+ - **Does not rotate:** rate limits (429); a 400 that this gateway uses for a dead upstream channel; and a 403 that means the group accepts only the vendor's official client. That last case is explained directly instead of being shown as an invalid API key.
85
+ - When every stored key is disabled, the request fails and says so. There is no fallback credential.
86
+
87
+ </details>
88
+
89
+ ## Models and groups
90
+
91
+ | Model | How it runs | Effort | Token group |
92
+ | --- | --- | --- | --- |
93
+ | `deepseek-flash` | HTTP, chat/completions | Can be off; `low` / `high` / `max` | `deepseek-officially`, `deepseek-sale` |
94
+ | `gpt-6.1-sol` | HTTP, Responses, images allowed | Cannot be off; `low` / `medium` / `high` / `xhigh` / `max` | `codex`, `codex-sale` |
95
+ | `claude-opus-5-5` | Local Claude Code CLI | The picker offers the same levels; the CLI chooses the actual effort | A group the official CLI is allowed to use; see below |
96
+ | `claude-sonnet-5-5` | Same | Same | Same |
97
+ | `claude-haiku-5-5` | Same; session titles always use this model | Same | Same |
98
+
99
+ A model in the list does not mean the current token group allows it. When changing groups, do not drop the group that serves the model you still want.
100
+
101
+ <details>
102
+ <summary>Protocol, group, and CLI constraints</summary>
103
+
104
+ - OpenAI / Codex traffic must use the Responses protocol. `gpt-6.1-sol` is pinned to `openai-responses` at `https://cf.api.fan/v1`. Do not put `/responses` in the base URL.
105
+ - Codex-group Responses requests must include `prompt_cache_key` or the gateway returns 403. The harness supplies the session id; the plugin adds a fallback when a caller does not.
106
+ - The Anthropic base URL has no `/v1` (the client appends `/v1/messages`). The three Claude models declare the Messages protocol in the catalog, but their requests are made by the local CLI.
107
+ - The `cc` group accepts only the official Claude CLI. A normal API client gets `403 This API endpoint is only accessible via the official Claude CLI`. This plugin runs the local `claude` binary for that group instead of switching the token to `cc-sale` or pretending to be the official client. If the token has no group the official CLI may use, the three Claude models still will not run.
108
+ - Selecting a Claude model when the CLI is missing fails that turn with an install hint. It does not surface as a missing binary name alone.
109
+ - The CLI receives this plugin's endpoint and current key (`ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN`) and an isolated config directory, `~/.dsh/packycode-claude-cli`. Without that isolation, `env` in `~/.claude/settings.json` would override the plugin key.
110
+ - CLI permission follows the session by default: `read-only` stays read-only, `workspace-write` may edit, and `danger-full-access` with approval disabled may use `full`. The CLI cannot ask the DSH user for approval, so a session that still asks never gets `full`. `claudeCliMode` can pin `read-only`, `edit`, or `full`. An empty `claudeCliPath` is looked up automatically; an empty `claudeCliCwd` uses the session workspace.
111
+ - Thinking and tool activity (`▸ Bash`, `▸ Read`, and `✗` on failure) appear in that turn's reasoning block. They are progress, not DSH tool calls. The CLI's own tools are outside the DSH sandbox.
112
+ - While the session model is a Claude model, titles are generated with `claude-haiku-5-5`, read-only, in a temporary directory, instead of a full Opus turn.
113
+ - The `claude_code` tool can delegate one task to the local CLI while the session model is `gpt-6.1-sol` or `deepseek-flash`. The requested `mode` cannot exceed what the session preset allows.
114
+ - An effort level the model does not support is rejected before the request is sent. Do not edit a model's effort map casually.
115
+
116
+ </details>
117
+
118
+ ## Update and uninstall
119
+
120
+ **Update:** open **Settings → PackyCode** and, when a newer version is listed, click **Update plugin**. It installs that exact version into the owning profile with DSH's bundled pnpm and reads `package.json` back before reporting success. A local `link:` checkout does not get the button. Then quit and reopen the desktop application. A page refresh does not reload the Host. Reinstalling `dsh-packycode-api` from the **Plugins** page does the same job.
121
+
122
+ **Uninstall:** remove this plugin on the **Plugins** page, then restart the desktop application. Uninstalling does not remove other plugins, the profile, or the token in the PackyCode console.
123
+
124
+ ## FAQ
125
+
126
+ **One model fails, but the key is valid?** Check whether the token group covers that model. The `cc` group does not serve Claude to a normal API client; this plugin's Claude models need the local CLI. A group refusal does not disable the key or rotate to the next one.
127
+
128
+ **The balance does not match the account bill?** Settings totals only the keys stored here, not other tokens on the same PackyCode account. A key that failed to read is noted separately and is not treated as zero.
129
+
130
+ **A rate limit disabled the key?** It should not. HTTP 429 does not rotate. Exhausted quota or HTTP 401 does; after a top-up, click **Re-enable**.
131
+
132
+ **Installing from the Plugins page fails with `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`?** pnpm refuses packages published less than 24 hours ago and checks the whole profile lockfile. The package it names is often another plugin that was just updated, not this one. Retry once it is 24 hours old, or add the reported `name@version` under `minimumReleaseAgeExclude` in the profile's `pnpm-workspace.yaml`. Once this plugin is installed, **Update plugin** in Settings is not subject to that check.
133
+
134
+ **The CLI is installed, but Claude still fails?** A host launched from Finder or the Start menu usually has a shorter `PATH` than a terminal. The plugin also checks the official install location, common package-manager directories, and `npm prefix -g`. If it still cannot find the binary, set `claudeCliPath` or click **Check again**. After a Host change or a reinstall, quit and reopen the desktop application.
135
+
136
+ ## Security and scope
137
+
138
+ This is a community plugin, not affiliated with or endorsed by DeepSeek or PackyCode. Model requests go to the PackyCode host you configured. Keeping credentials out of browser responses does not mean inference is local. Claude models also start the official CLI on this device.
139
+
140
+ Keys stay in the local DSH credential file (`~/.dsh/.credentials.yaml`, owner-only as enforced by DSH). They are not written into settings, logs, or the transcript. Balance requests run only on the host, with a timeout and redirects refused.
141
+
142
+ Use [Issues](https://github.com/BaronCyrus/dsh-packycode-api/issues) for ordinary bugs. Never include a key, token, or credential-file contents. See [SECURITY.md](SECURITY.md).
143
+
144
+ ## Local development
145
+
146
+ ```sh
147
+ git clone https://github.com/BaronCyrus/dsh-packycode-api.git
148
+ cd dsh-packycode-api
149
+ pnpm install --frozen-lockfile
150
+ pnpm run check
151
+ ```
152
+
153
+ `pnpm run check` runs every test, rebuilds, and writes a tarball under `.artifacts/`. `lib/` is a committed build; regenerate it with `pnpm run build` after editing `src/`, and do not hand-edit it.
154
+
155
+ `node scripts/live-check.mjs` checks the live gateway. It reads a key already stored on this machine and spends a small amount of quota.
156
+
157
+ Read [AGENTS.md](AGENTS.md) before agent-assisted changes or a release. Publishing is the [Publish workflow](.github/workflows/publish.yml), triggered by pushing a `v*` tag. Do not run `npm publish` locally.
158
+
159
+ ## License
160
+
161
+ [MIT](LICENSE)
package/README.md CHANGED
@@ -1,101 +1,161 @@
1
- # dsh-packycode-api
1
+ <div align="center">
2
2
 
3
- DeepSeek Harness 的 PackyCode(PackyAPI)插件:**填一个 API Key 就能用**,插件自带模型路由,不需要你改任何 YAML。
3
+ <img src="docs/assets/dsh-packycode-mascot.png" width="220" height="220" alt="DSH PackyCode API 吉祥物">
4
4
 
5
- - **自带路由与模型目录**:安装后模型选择器里直接出现 `PackyCode` 分组,不需要配置 provider。
6
- - **多个 Key 按顺序使用**:某个 Key 额度用尽或被网关拒绝时,自动切到下一个可用 Key,本轮请求由重试接手,不需要你手动改配置。
7
- - **看得到余额**:设置页列出每个 Key 的剩余额度、已用量、重置周期与状态;对话输入框右侧常驻显示当前 Key 的剩余额度。
8
- - **三种协议各就各位**:`deepseek-flash`(chat/completions)、`gpt-6.1-sol`(Responses)、`claude-opus-5-5`(Anthropic Messages),每个模型的档位按厂商官方文档声明。
5
+ # DSH PackyCode API
6
+
7
+ **简体中文** · [English](README.en.md)
8
+
9
+ **用 PackyCode 的 API Key,在 DSH 里选模型、轮换 Key、看余额。**
10
+
11
+ 安装后自带 `PackyCode` 模型分组,不用改 YAML,也不用另配 provider。
12
+
13
+ [![CI](https://github.com/BaronCyrus/dsh-packycode-api/actions/workflows/ci.yml/badge.svg)](https://github.com/BaronCyrus/dsh-packycode-api/actions/workflows/ci.yml)
14
+ [![npm](https://img.shields.io/npm/v/dsh-packycode-api?logo=npm&label=npm)](https://www.npmjs.com/package/dsh-packycode-api)
15
+ [![npm 总下载量](https://img.shields.io/npm/dt/dsh-packycode-api?logo=npm&label=%E6%80%BB%E4%B8%8B%E8%BD%BD%E9%87%8F)](https://www.npmjs.com/package/dsh-packycode-api)
16
+ [![MIT](https://img.shields.io/badge/license-MIT-111111.svg)](LICENSE)
17
+ [![Star](https://img.shields.io/github/stars/BaronCyrus/dsh-packycode-api?style=flat&logo=github&label=Star)](https://github.com/BaronCyrus/dsh-packycode-api/stargazers)
18
+
19
+ [功能](#功能) · [安装](#安装) · [日常使用](#日常使用) · [模型与分组](#模型与分组) · [更新与卸载](#更新与卸载)
20
+
21
+ </div>
22
+
23
+ ## 功能
24
+
25
+ | 能力 | 使用体验 |
26
+ | --- | --- |
27
+ | **自带模型路由** | 安装后模型选择器出现 `PackyCode` 分组,不需要配置 provider,也不用改 `cordis.patch.yml` |
28
+ | **多 Key 按顺序使用** | 额度用尽或 Key 被拒绝时自动切到下一个可用 Key;失败的那一步由重试接手 |
29
+ | **余额一眼可见** | 设置页列出每个 Key 的剩余、已用、额度和重置周期,并给出这些 Key 的合计;输入框右侧显示当前 Key 的剩余额度 |
30
+ | **Claude 走本机 CLI** | `claude-opus-5-5`、`claude-sonnet-5-5`、`claude-haiku-5-5` 由本机官方 Claude Code CLI 执行;设置页可以检测并一键安装 |
31
+ | **凭据不离开本机** | Key 只存在 DSH 凭据文件里。浏览器只能看到备注、状态和余额,拿不到 Key |
9
32
 
10
33
  ## 安装
11
34
 
12
- ```sh
13
- dsh plugin --profile <profile> add dsh-packycode-api
35
+ 先准备好 **DeepSeek Harness** 和 **PackyCode(PackyAPI)的 API Key**。尚未安装 DSH,可查看 [DSH 官方说明](https://github.com/deepseek-ai/deepseek-harness#run)。
36
+
37
+ ### 1. 安装插件
38
+
39
+ 打开桌面应用的**插件**页,点击**添加插件**,在**包名或地址**中填入:
40
+
41
+ ```text
42
+ dsh-packycode-api
14
43
  ```
15
44
 
16
- 安装后重启 DSH。插件通过自带的 `cordis.patch.yml` 注册自己,profile 的 `dsh.profile.bundles` 会自动包含它。模型路由本身不依赖浏览器:没有 `connection` 服务的 profile(例如 headless)也能用,只是看不到设置面板与输入框额度。
45
+ 在**安装源**中选择**官方源**,然后点击**安装**。需要固定版本时填入 `dsh-packycode-api@1.0.4`。
17
46
 
18
- ## 使用
47
+ 完成后**手动重启桌面应用**。仅刷新页面不会重新加载 Host 里的插件。
19
48
 
20
- 1. 打开 **设置 → PackyCode**。
21
- 2. 在「添加 Key」里粘贴 PackyCode 的 API Key(可填备注,便于区分多个 Key),点「添加」。
22
- 3. 回到对话,在模型选择器里选 `PackyCode` 分组下的模型,例如 `claude-opus-5-5`。
49
+ ### 2. 添加 Key
23
50
 
24
- 余额会在设置页与输入框右侧显示;「刷新」会强制重新读取(默认 60 秒缓存)。
51
+ 打开 **设置 → PackyCode**,在「添加 Key」里粘贴 API Key。备注可选,用来区分多个 Key。点「添加」。
25
52
 
26
- ## 多 Key 轮换
53
+ > 不要把 Key 粘贴到公开 Issue、聊天记录或截图里。插件不会读取环境变量 `PACKY_CODE_API_KEY`,也不会在失败时偷偷改用别的 provider。
27
54
 
28
- - Key 按添加顺序排列,插件只使用「当前 Key」;点击「切到此 Key」可以手动指定。
29
- - 同一个 Key 出现**额度用尽**(网关会报 `额度/余额/insufficient quota` 之类)或**被拒绝**(HTTP 401 / `无效的令牌`)时,插件会把该 Key 标记为「已停用」并自动切到下一个可用 Key;本轮失败的那一步由 harness 的重试重新执行,从而真正用上新 Key。
30
- - 限速(429)不会切换 Key——那是瞬时问题,由重试吸收即可。
31
- - 网关把上游渠道故障误报成 400(`当前令牌未覆盖供应商 …`)时也不会切换 Key,插件把它当作可重试的瞬时故障。
32
- - Key 充值或更换后,点「重新启用」即可让它重新参与。
55
+ ### 3. 选择模型
33
56
 
34
- ## 余额从哪里来
57
+ 回到对话,在模型选择器里选 `PackyCode` 分组下的模型。`deepseek-flash` 和 `gpt-6.1-sol` 添加 Key 后即可用。三个 Claude 模型还需要本机装有 Claude Code CLI,见下文。
35
58
 
36
- | 数据 | 接口 | 说明 |
37
- | --- | --- | --- |
38
- | 每个 Key 的额度 | `GET {余额接口}/api/usage/token/` | `total_available` / `quota_limit` / `quota_reset_period`;`quota_limit = -1` 表示无周期上限,`unlimited_quota = true` 表示不限额度 |
39
- | 账号额度 | `GET {模型接口}/v1/dashboard/billing/subscription` 与 `/usage` | `hard_limit_usd` 与 `total_usage`,剩余即两者之差 |
59
+ <details>
60
+ <summary>检查安装 / 其它 profile / 本地目录</summary>
40
61
 
41
- 额度单位按 new-api 约定换算:`500000 quota = 1 USD`。默认模型接口是 `https://cf.api.fan`,余额接口是 `https://www.packyapi.com`(`cf.api.fan` 不提供 `/api/*` 系列,插件会自动回退到另一个 host)。两者都可以在设置页「高级」里改。
62
+ 桌面应用的**插件**页可以看到已安装状态与版本,也可以在那里启用、停用或卸载。
42
63
 
43
- ## PackyCode 官方的注意事项(插件已内置)
64
+ **仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.0.4`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
44
65
 
45
- - **OpenAI / Codex 系模型必须走 Responses 协议**,用 chat/completions 会协议不匹配、流式提前中断 —— `gpt-6.1-sol` 已固定为 `openai-responses`。
46
- - **OpenAI / Codex 的 base_url 要带 `/v1`**,且不要把 `/responses` 这类端点路径写进根地址(客户端自己拼)。插件里是 `https://cf.api.fan/v1`。
47
- - **Anthropic 的 base_url 不能带 `/v1`**(客户端自己拼 `/v1/messages`)—— `claude-opus-5-5` 用的是 `https://cf.api.fan`。
48
- - Codex 分组的 Responses 请求**必须带 `prompt_cache_key`**(否则 403 反代校验)。harness 会带上会话 id;插件在调用方没给 session id 时补一个兜底值。
49
- - 各模型的推理档位按厂商文档声明:`deepseek-flash` = `off/low/high/max`,`gpt-6.1-sol` 与 `claude-opus-5-5` = `low/medium/high/xhigh/max`(后两者无法关闭推理)。请求里声明了模型不支持的档位会被 harness 在发请求前拒绝,所以档位不要随手改。
50
- - **分组决定"能不能用 API 调用"**(PackyCode 控制台里给令牌选的分组):
51
- - `cc`(claude code 专用)**只接受官方 Claude CLI**,用 API 调 Claude 会 403 `This API endpoint is only accessible via the official Claude CLI`。要让本插件调 Claude,请选 `cc-sale` 或 `claude-officially`。
52
- - `codex` / `codex-sale` 要求标准 Codex 客户端形态(插件已内置 `prompt_cache_key` 等必要条件),对应用 `gpt-6.1-sol`。
53
- - `deepseek-officially` / `deepseek-sale` 对应用 `deepseek-flash`。
54
- - 换分组时别把这三个分组一起去掉,否则对应模型会失效。
55
- - 插件识别这类"只允许官方客户端"的拒绝:**不重试、不切换也不停用 Key**,并直接给出中文说明(而不是让你看到"API Key 无效")。
66
+ 本地开发可以用绝对路径:`dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`。
56
67
 
57
- ## Claude 模型走本机 Claude Code CLI
68
+ 没有浏览器的 profile 也能走模型路由,只是看不到设置页和输入框额度。
58
69
 
59
- PackyCode 的 `cc` 分组只把 Claude 模型提供给**官方 Claude CLI**,API 客户端会被 403 挡住。所以插件的 `claude-opus-5-5`、`claude-sonnet-5-5`、`claude-haiku-5-5` **不是**普通的 HTTP 模型:**在模型选择器里选中它,底层就由本机真正的 `claude` 二进制执行**(其余模型照旧走 pi-ai / HTTP)。
70
+ </details>
60
71
 
61
- - **检测与一键安装**:**设置 → PackyCode** 顶部的「Claude Code CLI」卡片会检测本机是否装了 CLI,并显示版本号(`claude --version`)与位置。没装时会提示「不安装将无法正常使用 Claude Opus 模型」,并给出「安装 Claude Code CLI」按钮:macOS 与 Windows 统一执行 `npm install -g @anthropic-ai/claude-code`(需要 Node.js 18+),安装期间卡片每 2 秒刷新一次,装好后不用重启 DSH 就能用。
62
- - 查找顺序:设置项 `claudeCliPath` → 官方安装器位置(`~/.local/bin/claude`,Windows 为 `%USERPROFILE%\.local\bin\claude.exe`)→ npm / Homebrew / Volta / nvm 的常见位置(Windows 为 `%APPDATA%\npm\claude.cmd`)→ `PATH` → `npm prefix -g` 给出的全局目录(从 Finder / 开始菜单启动的 DSH 拿到的 `PATH` 往往比终端短,所以要问 npm)。
63
- - Windows 上 npm 装出来的是 `claude.cmd` 启动器。插件**不经过** `cmd.exe` 启动它,而是读出启动器指向的程序(`node …\cli.js` 或包内的 `.exe`)直接运行,所以提示词不会被 `cmd.exe` 解析。只有 `npm install` 本身经 `cmd.exe` 运行,它的参数都是固定的。Windows 上 Claude Code 另外需要 Git for Windows。
64
- - 常见失败会给出对应提示:找不到 npm(先装 Node.js)、全局目录没有写权限(`EACCES`/`EPERM`,提示用 `sudo` 或管理员终端)、网络错误、超时;同时显示 npm 输出的最后几行。
65
- - 没装 CLI 时选了 Claude 模型,该回合会直接报「Claude Code CLI is not installed on this device…」,并提示去设置页安装。
66
- - **凭据**:子进程用**插件配置的 baseURL 与当前 Key**(`ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN`),并使用独立的 `CLAUDE_CONFIG_DIR`(`~/.dsh/packycode-claude-cli`)。隔离是必须的:`~/.claude/settings.json` 里的 `env` 会覆盖进程环境,不隔离就等于用你 CLI 自己配置里的 token,插件 Key 完全不生效。
67
- - **设置项**:
68
- - `claudeCliPath` — CLI 路径,空则按上面「查找顺序」自动查找。
69
- - `claudeCliMode` — 默认 `auto`:**跟随当前会话的 DSH 权限预设**,不需要额外配置。`read-only` 预设 → `read-only`(Read/Grep/Glob);`workspace-write` 预设 → `edit`(另加 Edit/Write);`danger-full-access` 且审批为 `never` → `full`(`--dangerously-skip-permissions`,含 shell 命令)。CLI 无法向 DSH 用户发起审批,所以只要会话还需要审批,就不会给它 `full`。也可以显式填 `read-only` / `edit` / `full` 固定下来。
70
- - `claudeCliCwd` — 工作目录,空则用**当前会话的工作区**(取不到时退回进程目录)。
71
- - **语义**:一个 CLI 回合 = 一次委派。CLI 用**它自己的**工具与权限系统完成任务并给出最终答案;它无法调用 harness 的工具,所以插件**不会**把工具清单转发给它;系统提示也用 CLI 自己的(只把最近的对话作为上下文,过长按尾部截断)。因此对 `claude-opus-5-5` 而言:DSH 的沙箱/审批不约束子进程内部动作。
72
- - **实时输出**:CLI 的思考过程与每一次工具调用(`▸ Bash · git status`、`▸ Read · …`,失败时追加 `✗ …`)会实时出现在该回合的「思考」区,回答正文实时流式输出。它们只是进度展示,不是 DSH 的工具调用,也不会带进下一回合的委派提示。
73
- - **用量**:上下文占用与缓存命中取自 CLI 本回合**最后一次**请求(未缓存输入 / 缓存读 / 缓存写),输出 token 为整回合合计。CLI 几乎全部输入都命中缓存,所以缓存命中率通常很高。
74
- - **会话标题**:会话跑在 Claude 模型上时,生成标题固定改用 `claude-haiku-5-5`,只读、在临时目录下运行(不加载项目记忆),只把标题请求本身作为提示词,不再为起个标题跑一整轮 Opus 委派。
75
- - **代价**:每次数秒到数十秒,按 PackyCode 计费(实测单次约 **$0.19**,因 CLI 自带大量系统提示与工具说明)。
76
- - 另有 `claude_code` **工具**:当会话由 `gpt-6.1-sol` / `deepseek-flash` 驱动时,可以让模型显式把某个任务委派给 Claude Code(参数含 `prompt` / `mode` / `model` / `cwd`),与上面共用同一个 runner。模型请求的 `mode` 不会超过会话权限预设允许的上限。
72
+ ## 日常使用
77
73
 
78
- ## 安全
74
+ **换 Key。** Key 按添加顺序使用。点「切到此 Key」可以指定当前 Key;「重命名」改备注(最多 60 字,不能为空);充值或更换后点「重新启用」。
79
75
 
80
- - API Key 只存在本机 DSH 凭据文件(`~/.dsh/.credentials.yaml`,权限 0600),由 DSH 的 credential record 管理;不会写进设置文档、日志或对话记录。
81
- - 浏览器只能拿到 Key 的**备注、状态和余额**,拿不到 Key 本身。
82
- - 余额请求只在宿主侧发出,带超时并禁止重定向。
83
- - 插件**不会**回退到环境变量里的 `PACKY_CODE_API_KEY`,也不会回退到其它 provider:只用你显式添加的 Key。
76
+ **看余额。** 设置页的合计是**已列出的这些 Key** 的剩余、已用与额度,不是 PackyCode 账号下全部令牌的账单。读失败的 Key 不计入合计,并会注明个数。输入框右侧只在选中 PackyCode 模型时显示当前 Key 的剩余额度。「刷新」会跳过约 60 秒的缓存。默认模型接口是 `https://cf.api.fan`,余额接口是 `https://www.packyapi.com`,可在「高级:接口地址」里改。
84
77
 
85
- ## 开发与验证
78
+ **用 Claude。** 设置页顶部的「Claude Code CLI」卡片会检测本机 CLI。没装时点「安装 Claude Code CLI」,本机执行 `npm install -g @anthropic-ai/claude-code`(需要 Node.js 18+)。装好后不用重启 DSH。Windows 上另外需要 [Git for Windows](https://git-scm.com/downloads/win)。
86
79
 
87
- ```sh
88
- pnpm install
89
- pnpm run check # 全部测试 + 构建 + 打包
90
- node scripts/live-check.mjs # 真机验证(需要本机已存 PackyCode Key,会消耗少量额度)
91
- ```
80
+ <details>
81
+ <summary>什么时候会自动切换 Key</summary>
82
+
83
+ - **会切换并停用当前 Key:** 额度用尽(网关报额度、余额、insufficient quota 之类),或 Key 被拒绝(HTTP 401 / `无效的令牌`)。失败的那一步由 harness 重试,从而用上新 Key。
84
+ - **不会切换:** 限速(429);网关把上游渠道故障误报成 400(`当前令牌未覆盖供应商 …`);以及「只允许官方客户端」的 403。后一种会直接说明原因,而不是显示成 API Key 无效。
85
+ - 全部 Key 都停用时,请求失败并说明没有可用 Key,不会回退到别的凭据。
86
+
87
+ </details>
88
+
89
+ ## 模型与分组
90
+
91
+ | 模型 | 怎么调用 | 推理档位 | 适合的令牌分组 |
92
+ | --- | --- | --- | --- |
93
+ | `deepseek-flash` | HTTP,chat/completions | 可关;`low` / `high` / `max` | `deepseek-officially`、`deepseek-sale` |
94
+ | `gpt-6.1-sol` | HTTP,Responses,可带图 | 不能关;`low` / `medium` / `high` / `xhigh` / `max` | `codex`、`codex-sale` |
95
+ | `claude-opus-5-5` | 本机 Claude Code CLI | 选择器档位同上,实际档位由 CLI 决定 | 要能给官方 CLI 用的分组,见下 |
96
+ | `claude-sonnet-5-5` | 同上 | 同上 | 同上 |
97
+ | `claude-haiku-5-5` | 同上;会话标题也固定走它 | 同上 | 同上 |
98
+
99
+ 列表里看得到模型,不代表当前令牌分组一定放行。换分组时不要把对应分组一起去掉。
92
100
 
93
- `scripts/live-check.mjs` 会读取本机已存的 Key,验证:余额读取、三个模型各跑通一次(三种协议各一条)、以及「无效 Key + 真 Key」的轮换演练,并报告 harness 侧的失败分类。
101
+ <details>
102
+ <summary>协议、分组和 CLI 的具体约束</summary>
94
103
 
95
- 本地迭代时可以把插件 link 进 profile:
104
+ - OpenAI / Codex 必须走 Responses。`gpt-6.1-sol` 已固定为 `openai-responses`,base URL 是 `https://cf.api.fan/v1`,不要把 `/responses` 写进根地址。
105
+ - Codex 分组的 Responses 请求必须带 `prompt_cache_key`,否则 403。harness 会带会话 id;没有会话 id 时插件补一个兜底值。
106
+ - Anthropic 的 base URL 不带 `/v1`(客户端自己拼 `/v1/messages`)。三个 Claude 模型虽然目录里声明了 Messages 协议,实际请求由本机 CLI 发出。
107
+ - `cc`(Claude Code 专用)只接受官方 Claude CLI。用普通 API 客户端调 Claude 会 403:`This API endpoint is only accessible via the official Claude CLI`。本插件因此调用本机 `claude`,而不是改去 `cc-sale`,也不是伪造客户端身份。令牌如果没有开放给官方 CLI 的分组,这三个模型仍然不可用。
108
+ - 选了 Claude 模型但本机没有 CLI 时,这一回合会直接说明未安装,并指向设置页的安装按钮。
109
+ - CLI 使用插件配置的地址和当前 Key(`ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN`),以及独立配置目录 `~/.dsh/packycode-claude-cli`。不隔离的话,`~/.claude/settings.json` 里的 `env` 会盖掉插件 Key。
110
+ - CLI 权限默认跟随当前会话:`read-only` → 只读,`workspace-write` → 可编辑,`danger-full-access` 且不再审批 → `full`。CLI 不能向 DSH 弹审批,所以只要会话还要审批,就不会给它 `full`。也可把设置项 `claudeCliMode` 固定成 `read-only` / `edit` / `full`。`claudeCliPath` 留空则自动查找;`claudeCliCwd` 留空则用当前会话工作区。
111
+ - 思考过程和工具调用(`▸ Bash`、`▸ Read`,失败时带 `✗`)会出现在这一回合的思考区。它们是进度,不是 DSH 的工具调用。CLI 自己的工具不受 DSH 沙箱约束。
112
+ - 会话跑在 Claude 模型上时,生成标题改用 `claude-haiku-5-5`,只读、临时目录,避免为起标题跑一整轮 Opus。
113
+ - 另有 `claude_code` 工具:当前模型是 `gpt-6.1-sol` 或 `deepseek-flash` 时,可以把一个任务委派给本机 Claude Code。请求的 `mode` 不会超过会话权限允许的上限。
114
+ - 声明了模型不支持的推理档位会被 harness 在发请求前拒绝,不要随手改档位映射。
115
+
116
+ </details>
117
+
118
+ ## 更新与卸载
119
+
120
+ **更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装 `dsh-packycode-api`。
121
+
122
+ **卸载:** 在**插件**页卸载本插件,然后重启桌面应用。卸载不会删除其它插件、整个 profile,也不会撤销 PackyCode 控制台里的令牌。
123
+
124
+ ## 常见问题
125
+
126
+ **某个模型不可用,但 Key 是有效的?** 先看令牌分组是否覆盖这个模型。`cc` 分组不会把 Claude 交给普通 API 客户端;本插件的 Claude 模型要靠本机 CLI。分组拒绝不会停用 Key,也不会切到下一个 Key。
127
+
128
+ **余额对不上账号账单?** 设置页合计的是这里列出的 Key,不含同账号下没添加到本插件的其它令牌。个别 Key 读失败时会单独注明,不会被算成 0。
129
+
130
+ **限速之后 Key 被停用了?** 不该发生。429 不会切换 Key。额度用尽或 401 才会停用;充值后点「重新启用」。
131
+
132
+ **插件页安装报 `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION`?** pnpm 默认拒绝发布不满 24 小时的包,并且会检查 profile 里的整个 lockfile。报错里点名的往往是另一个刚更新过的插件,不是本插件。等它发布满 24 小时再重试,或把报错里的 `包名@版本` 加到 profile 目录 `pnpm-workspace.yaml` 的 `minimumReleaseAgeExclude` 下。已安装本插件后,设置页的「更新插件」不受这个限制。
133
+
134
+ **装了 CLI 还是不能用 Claude?** 从 Finder 或开始菜单启动时,`PATH` 往往比终端短。插件会再查官方安装位置、常见包管理器目录和 `npm prefix -g`。仍找不到就在设置里填 `claudeCliPath`,或点「重新检测」。改的是 Host 或重新安装了插件时,要完全退出并重启桌面应用。
135
+
136
+ ## 安全边界
137
+
138
+ 本项目是社区插件,与 DeepSeek、PackyCode 无隶属或背书关系。模型请求会发到你配置的 PackyCode 接口;凭据不返回浏览器,不代表推理在本地完成。Claude 模型还会在本机启动官方 CLI。
139
+
140
+ Key 存在本机 DSH 凭据文件(`~/.dsh/.credentials.yaml`,权限由 DSH 设为仅所有者可读),不进设置文档、日志或对话记录。余额请求只在宿主侧发出,带超时并禁止重定向。
141
+
142
+ 普通问题请提交 [Issue](https://github.com/BaronCyrus/dsh-packycode-api/issues)。不要附带 Key、令牌或凭据文件内容。更多说明见 [SECURITY.md](SECURITY.md)。
143
+
144
+ ## 本地开发
96
145
 
97
146
  ```sh
98
- dsh plugin --profile <profile> add link:/path/to/dsh-packycode-api
147
+ git clone https://github.com/BaronCyrus/dsh-packycode-api.git
148
+ cd dsh-packycode-api
149
+ pnpm install --frozen-lockfile
150
+ pnpm run check
99
151
  ```
100
152
 
101
- 改了 Host 代码必须重启 DSH 才会生效;只改客户端代码刷新浏览器即可。
153
+ `pnpm run check` 会跑全部测试、重新构建,并在 `.artifacts/` 打出 tarball。`lib/` 是已提交的构建产物,改 `src/` 后用 `pnpm run build` 生成,不要手改。
154
+
155
+ 真机网关用 `node scripts/live-check.mjs` 验证。它会读本机已保存的 Key,并消耗少量额度。
156
+
157
+ 使用 Agent 修改或发布时,先读 [AGENTS.md](AGENTS.md)。发布由推送 `v*` 标签触发 [Publish workflow](.github/workflows/publish.yml),不要在本机执行 `npm publish`。
158
+
159
+ ## License
160
+
161
+ [MIT](LICENSE)
Binary file