dsh-packycode-api 1.3.6 → 1.3.8

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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.3.8
4
+
5
+ - **DSH's official 自动审查 can review with jev-latest or DeepSeek Flash.** DSH ships an experimental "自动授权审查" plugin (`@deepseek-ai/dsh-experimental-auto-review`, row `auto-review`, off by default). Switched on, it adds 自动审查 to the composer's permission menu and reviews every tool call of a session in that mode with one hand-built `llm.stream` request on the session's own model. The plugin now listens on DSH's `llm/stream` waterfall, which every model request passes. It recognizes that request by its fixed `REVIEW_POLICY` system prompt and four-section message, and answers it with the reviewer chosen under Settings → PackyCode → 自动审查 (`autoReviewModel`: `jev-latest` by default, `deepseek-flash`, or `session` to leave it alone). What is reviewed, the policy, asking the user, final denials in children, and refusing a call whose review failed all stay the official plugin's. Every other request goes on untouched. The plugin registers no permission preset and no tool gate of its own.
6
+ - **DeepSeek Flash gets the official request itself**, re-addressed to `packycode/deepseek-flash`; the official reviewer reads its answer.
7
+ - **jev-latest answers through System One.** Jev cannot write the official JSON answer, so the four sections become its state together with the official policy text, bounded to about 24K characters for its 32K-token per-question limit (Chinese measured one token per character; the user's instructions are kept first). Two questions are asked: the risk (`high` / `medium` / `low`, worded as the official policy and with the conservative option first, because Jev leans to the first choice) and whether the user asked for exactly this action (a `noul` told to judge by effect). A call is allowed when P(low) + P(medium) × P(asked) ≥ 0.6 and P(high) < 0.2. The decision goes back as the official answer, a text block holding `{"risk","decision"}` with a Chinese `reason` naming jev-latest on a denial. A failed review ends the stream with an error, which the official reviewer turns into a refused call. `jev-latest` was answered by `jev-1.14.0`.
8
+ - **jev-latest joins the catalog as a classifier, not a chat model.** PackyCode lists it as the `systemone` endpoint (`POST /v1/systemone`) in the `typesafe-officially` group ("jev官方渠道"). DSH's pi-ai adapter only serves chat models, so `PACKYCODE_CLASSIFIER_MODELS` keeps it out of the picker, and the plugin calls it host-side with its own keys. Its group coverage is read like the chat models', and each key's reach line in Settings shows Jev. A review tries the keys in ring order, keys whose groups reach Jev first. An exhausted or rejected key moves aside as on the model route, a key outside the group is passed over, and one gateway 5xx or 429 is resent after 0.5 s.
9
+ - **Settings → PackyCode → 自动审查** shows whether DSH's plugin is on (and how to switch it on), the reviewer choice, the reviews the plugin answered since start (allowed / denied / failed) and the last one, and a warning when no stored key's groups reach the chosen reviewer. DSH's own copy under the menu entry still says the same model reviews; the card says which one does. Every review the plugin answers logs one line (`packycode-api: auto review allowed bash (jev-1.14.0, low risk, 352 ms)`), without arguments.
10
+ - The web search's key ordering moves to `key-chooser.js` so the reviewer shares it. `scripts/live-check.mjs` sends the official request about one ordinary call and one exfiltration to each reviewer and reads the answers with the official parser (vendored, with the official policy text, in `tests/fixtures/official-auto-review.mjs`).
11
+ - Validation, 2026-10-22: 510 offline tests (new: recognizing the official request and passing every other request through; reading its four sections; Jev's bounded state with the official policy, its decision rule and denial reasons; answers and failures read by the official reviewer's own parser; key order, coverage, quota rotation, the transient resend and cancellation; the listener's three choices, the re-addressed Flash request reaching the adapter on its second trip, the counts, status and preference; the `llm/stream` registration; the settings card), both rebuilt bundles and the versioned tarball. One full run failed two hot-install registration tests on their 5-second fixture timeout while the machine was loaded (load average 4.5); they pass alone and in the next full run. Live with a key in `typesafe-officially` and `deepseek-officially`: the official request for 37 scenarios (the 0.2.1-rc.2 policy text and message format, read back by its parser) matched all 35 with a definite answer for both reviewers; jev-latest took a median 0.35 s, DeepSeek Flash 2.3 s. End to end in a scratch DSH 0.2.1-rc.2 headless profile with `@deepseek-ai/dsh-experimental-auto-review` switched on, a session in 自动审查 on `gpt-6.1-sol`, and a request to force-push: with `jev-latest` Jev answered the review (no reasoning, `jev-latest 判定为中风险操作…`); with `deepseek-flash` the request reached `packycode/deepseek-flash`, which gave its own reason; with `session` `gpt-6.1-sol` reviewed it. Each time DSH asked for approval with its own `Auto review denied tool "bash": …` and, without an approval channel, refused the push. `scripts/live-check.mjs` passed every HTTP model, the rotation, the classification and the RPC projections, read the key as reaching `jev-latest`, and both reviewers allowed `pnpm test` and denied an upload of `~/.ssh/id_rsa`. Not yet checked in the desktop app.
12
+
13
+ ## 1.3.7
14
+
15
+ - **The CLI card also offers the update when a newer Claude Code is out.** Until now **Update Claude Code CLI** only appeared for a CLI older than 2.1.259. The plugin now reads the newest release on the host, from `https://registry.npmjs.org/@anthropic-ai/claude-code/latest` (npm's `latest` and the native installer's `latest` channel named the same 2.1.303 when checked), with a 10-second timeout and redirects refused, at most once every 30 minutes, again after 2 minutes when it got no answer, and at once when **Check again** is clicked. A CLI that works but is behind gets a note naming the new version, the same button and the command it runs; the installed version keeps working, so it is not marked too old. Without an answer from npm no update is offered. The update itself is unchanged: `claude update` for the native installer, npm with `--allow-scripts` for an npm install. Its outcome is now judged for a CLI that already worked: a run that changed nothing while a newer version exists fails with the installer's own output (for example Homebrew's `brew upgrade claude-code`) instead of reading as "updated", a failed command that changed nothing reports that failure, and a clean run with the newest release unknown says the version is unchanged.
16
+ - Validation, 2026-10-19: 467 offline tests (new: the newest-release reader's URL, timeout, refused redirects, cache, forced re-read and silent failures; `updateAvailable` for a CLI behind, at, or without a newest release; an update from behind to latest; a clean run that left the CLI behind, a failed run that changed nothing, and a no-op run; the card's note, button, progress and outcomes), both rebuilt bundles and the versioned tarball. Live, the built manager read this device's native CLI as 2.1.295 and npm's latest as 2.1.303 and offered the update (887 ms for both reads). In a scratch HOME and npm prefix, an npm install of 2.1.295 was offered the update with the npm command, and the built `update()` took it to 2.1.303 in 36 s, after which no update was offered; the device's own CLI stayed untouched. The native `claude update` path was not run again; it is unchanged from 1.3.5. The card was checked through the client tests, not in DeepSeek Harness.
17
+ - **GPT web search works again.** With the GPT backend, every search failed with "PackyCode search returned no web_search_call". The search did run: PackyCode's Codex channel answers a non-streaming `/v1/responses` request with `status: completed`, `tool_usage.web_search.num_requests: 1` and about 16K input tokens, but an empty `output`. Streamed, the same request carries the preamble, each `web_search_call` and the cited answer as `response.output_item.done` events, then ends on a `response.completed` whose `output` is empty as well. The GPT backend now streams (`stream: true`) and rebuilds the output from those events in `output_index` order; a final event that does carry output is used as it is, and a channel that answers with one JSON body is read as before. Sources and the summary come from the same items as before. A body with no output at all now says the gateway did not pass the result on, instead of claiming the model ran no search.
18
+ - **A full upstream is resent inside the search.** The channel relays OpenAI's "Temporary capacity limit. Please try again in 2s." (`rate_limit_exceeded`) and its `server_error` inside the 200 stream, before any output, so the gateway cannot resend them itself. The search resends on the same key after the pause the message names (1 s when it names none; a pause over 5 s is reported instead), at most twice, as the official Codex client resends them. Quota and key wording are never resent, and no key is moved aside for this. When it persists, the error names the model and suggests the DeepSeek backend. Any other failure relayed in the stream is reported at once as "failed upstream", not as HTTP 200.
19
+ - **Every GPT search sends a `prompt_cache_key`.** The Codex group answers a Responses request without one with a 403 ("请使用标准 Codex 客户端"; 3 of 3 live, while 3 of 3 with one were accepted). DSH's searches already carried the session id or the plugin's fallback id; a caller that names no session, such as `scripts/live-check.mjs --with-search`, now gets one id per provider, as the model route does.
20
+ - Validation, 2026-10-21: 480 offline tests (new: the empty-output message; the stream reader rebuilding the output in index order, keeping a final event's own output, surviving CRLF, bare CR and chunks split mid-line and mid-character, turning `error` / `response.failed` into the body error and refusing a stream without a final event; which upstream errors are resent and after which pause; a GPT search that streams, always sends a cache key, resends a capacity refusal on the same key without blaming it, reports a persisting one after three attempts and any other one at once; cancellation during the pause and mid-stream), both rebuilt bundles and the versioned tarball. Against a local server, a stream that stalls ends at the request timeout as "no answer within", and a cancel ends it as `WEB_ABORTED`. Live with a key in `codex`: non-streaming `gpt-6.1-sol` searches returned `completed` with an empty `output` 3 of 3 times, and the streams checked for it ended on an empty final `output` with every item in `response.output_item.done`. 28 live GPT searches parsed through the rebuild; through the built provider they returned 13–20 sources and a 1.0–1.8K-character summary in 14.6–29.9 s (one more ran past the test script's own 30 s cancel; DSH's desktop presets give `web_search` 60 s). `node scripts/live-check.mjs --with-search` passed every HTTP model, the rotation and the classification; DeepSeek search returned 10 sources in 6.0 s, and GPT search met the upstream capacity limit on all three attempts and reported it with the new message. The capacity limit is upstream: `gpt-6.1-sol`, `gpt-5.6-sol` and `gpt-6-astra` searches each met it about once in five, plain requests never. One existing CLI test that aborts after 300 ms failed in two full runs while the machine was heavily loaded (it also fails on its own at the unchanged HEAD); the final full run passed all 480.
21
+
3
22
  ## 1.3.6
4
23
 
5
24
  - **DeepSeek Flash runs over Responses.** `deepseek-flash` moves from `openai-completions` to `openai-responses`; the base URL stays `https://cf.api.fan/v1`, so requests now go to `/v1/responses` instead of `/v1/chat/completions`. PackyCode's `/api/pricing` lists `openai-response` among the model's endpoints, for the same groups (`deepseek-officially`, `deepseek-sale`). The effort levels are unchanged (`off`, `low`, `high`, `max`), and so is `thinkingLevelMap`: `off` now sends `reasoning.effort: "none"`, which the gateway answers with no reasoning item and zero reasoning tokens. The Chat Completions dialect (`thinkingFormat: 'deepseek'`, `max_tokens`, reasoning content on assistant messages) is gone with it; reasoning comes back as `reasoning_text` items, which pi-ai streams as thinking and sends back with the turn's tool calls. Like Grok, DeepSeek omits `prompt_cache_key`: the gateway accepts the field, but its prefix cache already hits without it. Image input is sent as `input_image`. The 384,000-token output ceiling stays under the gateway's Responses limit of 393,216. No catalog model uses Chat Completions any more, so the provider no longer registers that API; the group probe still uses `/v1/chat/completions`, which needs no model. A session that ran on Chat Completions continues over Responses: pi-ai sends its earlier thinking as text and keeps its tool calls.
package/README.en.md CHANGED
@@ -32,6 +32,7 @@ The `PackyCode` model group ships with the plugin. No YAML edits and no separate
32
32
  | **Claude route by group** | The `cc` group only serves the official client, so Claude requests on `cc` keys go through this device's Claude Code CLI; `cc-sale`, `cc-expensive`, `claude-officially` and other groups use the plugin's HTTP route. Either way DSH runs the tools and permissions, and plan mode, attachments and the full history behave the same |
33
33
  | **Web search through PackyCode** | Optional: DSH's `web_search` searches through PackyCode, with a DeepSeek or GPT backend, for every request or for PackyCode models only |
34
34
  | **Image generation and editing** | Separate image keys, GPT Image 2 / 2.5 Flare / 2.5 Sunburst, model and quality settings, reference edits and original PNG storage; generation and editing verified against the gateway |
35
+ | **Auto review on your model** | With DSH's built-in “Auto authorization review” switched on, the permission menu's Auto review can review each tool call with jev-latest or DeepSeek Flash; the rules and outcomes stay the official ones |
35
36
  | **Credentials stay on the machine** | Keys live in the DSH credential file. The browser receives labels, state, and balances only |
36
37
 
37
38
  <img width="774" height="455" alt="截屏2026-10-15 10 34 28" src="https://github.com/user-attachments/assets/c5eaa535-dd1e-4e2f-be9f-c181404d4dd6" />
@@ -47,10 +48,10 @@ You need **DeepSeek Harness** and a **PackyCode (PackyAPI) API key**. For DSH se
47
48
  Open the desktop application's **Plugins** page, click **Add plugin**, and enter the package name **with a version** as the **package name or address**:
48
49
 
49
50
  ```text
50
- dsh-packycode-api@1.3.6
51
+ dsh-packycode-api@1.3.8
51
52
  ```
52
53
 
53
- Choose the **official** install source, then click **Install**. `1.3.6` was the latest release when this was written; the [npm page](https://www.npmjs.com/package/dsh-packycode-api) shows the current one.
54
+ Choose the **official** install source, then click **Install**. `1.3.8` was the latest release when this was written; the [npm page](https://www.npmjs.com/package/dsh-packycode-api) shows the current one.
54
55
 
55
56
  > **Always include the version.** With a bare `dsh-packycode-api`, the install prompt shows the newest version on npm, but DSH's bundled pnpm by default installs only versions published at least 24 hours ago, so you can end up several releases behind with no sign of it in the prompt. With an exact version, pnpm installs that version and adds it to the profile's `minimumReleaseAgeExclude` itself. Afterwards, check **Current version** under **Settings → PackyCode → Plugin version**.
56
57
 
@@ -71,7 +72,7 @@ Choose a model from the `PackyCode` group. All ten models use the plugin’s HTT
71
72
 
72
73
  The **Plugins** page shows the installed state and version, and is also where you enable, disable, or uninstall.
73
74
 
74
- **For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.3.6`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
75
+ **For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.3.8`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
75
76
 
76
77
  For a local checkout, keep the `link:` prefix: `dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`. **Do not pass a bare path or `file:`** — that install copies the whole checkout, `node_modules` included, into the profile, where it then shadows the packages the DSH installation itself provides and the plugin looks uninstalled; see the FAQ. If you already installed that way, uninstall first and reinstall as above.
77
78
 
@@ -89,7 +90,7 @@ A profile without a browser can still use the model route. It just has no settin
89
90
 
90
91
  **Read the balance.** Each key under **Accounts and keys** shows its own remaining, used, and limit (limit = remaining + used); an unlimited key shows **No quota limit**. Keys are not added up into a total. An API key can read only its own quota, not the PackyCode account's balance, so check the account balance in the PackyCode console. A key that could not be read says why on its own row; a key whose read failed this time but succeeded before keeps showing its last balance with the time it was read (the composer shows it as `≈US$…`) until DSH restarts. 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.ai`; both can be changed under **Advanced: endpoints**. The old default, `https://www.packyapi.com`, is DNS-poisoned on mainland networks and answers `fetch failed` without a proxy; even when settings still name it, `.ai` is tried first.
91
92
 
92
- **Use Claude.** Select any Claude model. When the key is in the `cc` group, the plugin sends the request with this device's official Claude Code CLI, so install it first under **Settings → PackyCode → Claude Code CLI** (or run `npm install -g @anthropic-ai/claude-code --allow-scripts=@anthropic-ai/claude-code`), and click **Update Claude Code CLI** there when it is too old; keys in `cc-sale`, `cc-expensive`, `claude-officially` and other groups use the plugin's HTTP route and need no CLI. Under **Accounts and keys**, every key that reaches Claude is marked “Claude via official CLI” or “Claude via HTTP”; the groups alone decide the route, and it cannot be switched by hand. On both routes DSH executes every tool under its own permissions, and plan mode, questions, todos, subagents, attachments, reasoning effort and history behave as for any other model. See “Claude Code CLI route” below.
93
+ **Use Claude.** Select any Claude model. When the key is in the `cc` group, the plugin sends the request with this device's official Claude Code CLI, so install it first under **Settings → PackyCode → Claude Code CLI** (or run `npm install -g @anthropic-ai/claude-code --allow-scripts=@anthropic-ai/claude-code`), and click **Update Claude Code CLI** there when it is too old or a newer version is out; keys in `cc-sale`, `cc-expensive`, `claude-officially` and other groups use the plugin's HTTP route and need no CLI. Under **Accounts and keys**, every key that reaches Claude is marked “Claude via official CLI” or “Claude via HTTP”; the groups alone decide the route, and it cannot be switched by hand. On both routes DSH executes every tool under its own permissions, and plan mode, questions, todos, subagents, attachments, reasoning effort and history behave as for any other model. See “Claude Code CLI route” below.
93
94
 
94
95
  **Web search.** DSH's `web_search` calls DeepSeek's official API by default (billed to `DEEPSEEK_API_KEY`). **Settings → PackyCode → Web search** can route it through PackyCode instead:
95
96
 
@@ -139,7 +140,7 @@ PackyCode's `cc` group (“claude code专用”) only serves the official Claude
139
140
  - **DSH's prompt and history, unchanged.** DSH's system prompt is appended to the CLI's own; the history (text, images, signed thinking, tool calls and results) is written as a CLI transcript and resumed; the reasoning effort is passed as `--effort`.
140
141
  - **One long-lived process per conversation.** A DSH session keeps one CLI process per model: tool results and the next user turn continue it, so requests keep one cacheable prefix. After compaction, a plan-mode switch or a key change, a new process is resumed from DSH's full history; session titles and compaction use one-shot processes. A process idle for 20 minutes stops; at most 8 stay alive.
141
142
  - **Isolated from your own Claude Code.** It runs with its own config home, `~/.dsh/packycode-claude-cli`, and never reads `~/.claude` settings, CLAUDE.md, MCP configuration or logins; only the key stored in the plugin is passed to the child. Auto-update, telemetry, auto-compaction, auto-memory and model fallback are off, and retries are left to DSH's retry policy, which rotates keys.
142
- - **An outdated CLI is one click away from current.** The plugin needs Claude Code 2.1.259 or later (the first release with the `--permission-prompts` option it passes). An older CLI is stopped before the request with an explanation, and the CLI card marks it too old and offers **Update Claude Code CLI**: an install from the official installer (`~/.local/bin/claude`) runs `claude update`; an npm global install runs `npm install -g @anthropic-ai/claude-code@latest --allow-scripts=@anthropic-ai/claude-code`, because npm 12 skips install scripts by default and `claude update` does not allow them on an npm install, which leaves a CLI that cannot run. Your Claude Code is only updated when you click that button.
143
+ - **An outdated CLI is one click away from current.** The plugin needs Claude Code 2.1.259 or later (the first release with the `--permission-prompts` option it passes). An older CLI is stopped before the request with an explanation, and the CLI card marks it too old and offers **Update Claude Code CLI**: an install from the official installer (`~/.local/bin/claude`) runs `claude update`; an npm global install runs `npm install -g @anthropic-ai/claude-code@latest --allow-scripts=@anthropic-ai/claude-code`, because npm 12 skips install scripts by default and `claude update` does not allow them on an npm install, which leaves a CLI that cannot run. When the CLI works but is not the latest release, the card names the new version and offers the same button: the plugin reads `latest` of `@anthropic-ai/claude-code` from npm on this device (the same version as the native installer's `latest` channel), at most once every 30 minutes, and again when you click Check again; without an answer it offers nothing. Your Claude Code is only updated when you click that button.
143
144
  - **Failures say why.** A missing CLI, an outdated CLI, and a request from the official CLI that the gateway still refuses each get their own explanation; nothing switches to another route or provider, and no key is disabled.
144
145
 
145
146
  Known differences: starting a process takes about 0.3–1 s; when a process is resumed in the middle of a tool turn, the CLI adds “Continue from where you left off.” after the tool results, as the official client does. Requires Claude Code 2.1.259 or later (tested with 2.1.295 and 2.1.303). On Windows, Claude Code also needs Git for Windows.
@@ -166,6 +167,53 @@ After adding the image key, `node scripts/image-check.mjs --all --edit` checks a
166
167
 
167
168
  Live checks on 2026-10-15 passed generation and editing at `low` on all three engines. Sunburst also passed both operations at `xhigh` and `max`, with matching quality values in the responses. All 10 requests succeeded without retries and returned 1024×1024 PNGs; visual inspection confirmed the requested color edits with composition preserved. Generate/edit times were about 43/48 seconds at xhigh and 84/91 seconds at max. These are built-client gateway checks; no desktop conversation was created to verify the full chat flow in this run. See the [protocol research and gateway results](docs/research/image-api.md) for scope and evidence.
168
169
 
170
+ ### Auto review
171
+
172
+ DSH ships an experimental plugin, “Auto authorization review”, switched off by default. Switched on, it adds **Auto review** (marked EXP) to the permission menu under the composer (Read only / Workspace write / Full access). In a session set to Auto review, a model reviews every tool call first:
173
+
174
+ - A call it allows runs at once, without a sandbox.
175
+ - A call it denies asks for your approval; in a subagent it is refused outright.
176
+ - When the review itself fails, the call does not run.
177
+
178
+ By default DSH reviews with the conversation's own model. This plugin leaves the review logic alone and only swaps the reviewer model. Choose it under **Settings → PackyCode → Auto review**:
179
+
180
+ | Reviewer | Notes | Group needed |
181
+ | --- | --- | --- |
182
+ | jev-latest (default) | TypeSafe's decision classifier: about 0.4 s per review, billed by input only; a denial names only the risk level | `typesafe-officially` |
183
+ | DeepSeek Flash | About 2 s per review, and a denial says why | `deepseek-officially` / `deepseek-sale` |
184
+ | Conversation model | Leave the review alone, as DSH does by default | — |
185
+
186
+ Steps:
187
+
188
+ 1. Switch on “Auto authorization review” on DSH's Plugins page in the sidebar.
189
+ 2. Pick Auto review in the composer's permission menu and confirm the risk notice.
190
+ 3. Choose the reviewer under Settings → PackyCode → Auto review.
191
+
192
+ The card shows whether DSH's plugin is on, how many reviews this plugin answered (allowed / denied / failed), and the last one. It warns when no key reaches the chosen reviewer.
193
+
194
+ <details>
195
+ <summary>How the review is taken over</summary>
196
+
197
+ - DSH's reviewer sends one model request per review:
198
+ - its fixed `REVIEW_POLICY` as the system prompt;
199
+ - four JSON sections as the user message: ENVIRONMENT, PROJECT_INSTRUCTIONS, FILTERED_HISTORY, PENDING_ACTION;
200
+ - and it expects one `{"risk","decision","reason"?}` object back.
201
+ - Every model request passes DSH's `llm/stream` waterfall. The plugin recognizes only this request there; conversation turns and everything else go on untouched.
202
+ - **DeepSeek Flash** gets the same request, re-addressed to the PackyCode route; DSH still reads its answer.
203
+ - **jev-latest** cannot write that object. The plugin passes the four sections and the official policy text to System One as the state and asks two questions: the risk, and whether you explicitly asked for this action.
204
+ - It allows a call when the probability of "low risk, or medium risk you asked for" is at least 0.6 and that of high risk is below 0.2.
205
+ - A denial says that jev-latest judged the call medium or high risk.
206
+ - jev-latest has a small context, so a long history is cut starting from the oldest entries; your instructions are kept first.
207
+ - What is reviewed, the rules, and what an allow or a denial does all stay DSH's. DSH refuses a call whose review failed (for example, no key reaches jev-latest), and the plugin keeps that.
208
+ - Measured on 37 scenarios with the official request format and the official parser: both reviewers matched all 35 scenarios that have a clear answer.
209
+ - jev-latest's median was 0.35 s, DeepSeek Flash's 2.3 s.
210
+ - If a later DSH changes the review request:
211
+ - a request the plugin no longer recognizes goes on untouched, reviewed by the conversation model;
212
+ - a format jev-latest cannot read fails that review, which shows in the card's counts.
213
+ - The description under Auto review in the menu says the same model reviews; that is DSH's text. With jev-latest or DeepSeek Flash chosen, that model reviews.
214
+
215
+ </details>
216
+
169
217
  ## Models and groups
170
218
 
171
219
  | Model | How it runs | Effort | Token group |
@@ -183,6 +231,8 @@ Live checks on 2026-10-15 passed generation and editing at `low` on all three en
183
231
 
184
232
  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.
185
233
 
234
+ `jev-latest` (TypeSafe Jev) is not in the model picker: it is a decision model that answers classification questions and cannot hold a conversation, so it only serves [Auto review](#auto-review). The plugin calls `/v1/systemone` host-side; it needs a key in the `typesafe-officially` group, and each key's Jev entry under Accounts and keys shows whether it can.
235
+
186
236
  All ten models in the current catalog declare text and image input. DeepSeek Flash follows the [official vision guide](https://api-docs.deepseek.com/guides/vision/); images are read through DSH's attachment service and sent with the Responses request.
187
237
 
188
238
  Gemini capabilities and limits follow Google's model pages: [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). Both models use the native Gemini protocol through `/v1beta/models/{model}:streamGenerateContent`, streaming text, thinking and tool calls; images are read through DSH's attachment service. Thinking levels are sent with `thinkingLevel`. Both routes use the single-stream output limit without automatic continuation beyond 65,536 tokens. Available endpoints and groups follow the [PackyAPI live model catalog](https://www.packyapi.com/api/pricing).
@@ -216,9 +266,9 @@ DeepSeek Flash uses the gateway's Responses endpoint (`/api/pricing` lists `open
216
266
 
217
267
  ## Update and uninstall
218
268
 
219
- > **Upgrading from 1.3.2 or earlier:** install `dsh-packycode-api@1.3.6` on the Plugins page instead of clicking **Update plugin** in the old settings card. The old button bypasses pnpm's release-age policy: if the version it installs is less than 24 hours old, the profile refuses every other plugin install until that version is 24 hours old. After the install and a restart, the button is the fixed one, and later updates can use it.
269
+ > **Upgrading from 1.3.2 or earlier:** install `dsh-packycode-api@1.3.8` on the Plugins page instead of clicking **Update plugin** in the old settings card. The old button bypasses pnpm's release-age policy: if the version it installs is less than 24 hours old, the profile refuses every other plugin install until that version is 24 hours old. After the install and a restart, the button is the fixed one, and later updates can use it.
220
270
 
221
- **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. The install keeps pnpm's release-age policy instead of overriding it: by default pnpm installs the version at once and records it in the profile's `minimumReleaseAgeExclude`; under a stricter pnpm policy the button says when the update can run. 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 from the **Plugins** page works too, again with the version in the package name (for example `dsh-packycode-api@1.3.6`); without it you may get a version that is merely the newest one published at least 24 hours ago.
271
+ **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. The install keeps pnpm's release-age policy instead of overriding it: by default pnpm installs the version at once and records it in the profile's `minimumReleaseAgeExclude`; under a stricter pnpm policy the button says when the update can run. 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 from the **Plugins** page works too, again with the version in the package name (for example `dsh-packycode-api@1.3.8`); without it you may get a version that is merely the newest one published at least 24 hours ago.
222
272
 
223
273
  **Coming back from a local-path install, uninstall first.** An update is a `pnpm add`: it rewrites the files inside the package directory and leaves a `node_modules` that an earlier local-path install left there. That older tree keeps shadowing the packages the DSH installation provides, so the plugin row fails to load with no visible reason. **Uninstall** runs `pnpm remove`, which deletes the package directory outright — only a reinstall after that is clean. `node scripts/install-check.mjs` reports whether a profile is in that state.
224
274
 
@@ -234,7 +284,7 @@ ls ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/node_modules
234
284
 
235
285
  Output means a leftover tree: a registry install ships no `node_modules`, so this one usually comes from an earlier local-path install (`file:`, or a bare path instead of `link:`). It sits inside the profile directory, and DSH resolves a plugin's imports from inside the profile first, so the plugin gets those old copies — for example `@deepseek-ai/schemastery` 3.18.2, which has no `Schema.volatile()`, so the module throws while it is imported. When an import fails the Loader creates no fiber for that row and no client bundle is composed either, so the model route, the RPC channel, and the settings panel all stay absent.
236
286
 
237
- Recovery: **uninstall** the plugin on the **Plugins** page, **install** it again with the version in the package name (for example `dsh-packycode-api@1.3.6`), then quit and reopen the desktop application. Uninstall runs `pnpm remove` and deletes the whole package directory; reinstalling or clicking **Update** only rewrites files and keeps the leftover tree. Deleting that `node_modules` by hand and restarting works too.
287
+ Recovery: **uninstall** the plugin on the **Plugins** page, **install** it again with the version in the package name (for example `dsh-packycode-api@1.3.8`), then quit and reopen the desktop application. Uninstall runs `pnpm remove` and deletes the whole package directory; reinstalling or clicking **Update** only rewrites files and keeps the leftover tree. Deleting that `node_modules` by hand and restarting works too.
238
288
 
239
289
  **Right after a first install, every card in Settings shows `transport failure for /packycode-api/…: HTTP 405`?** The installed version is 1.1.6 or earlier, usually because only the bare package name was entered: the install prompt shows the newest version, but pnpm installs the newest one published at least 24 hours ago (see **Install the plugin**). Those older versions can register their settings channel only after DSH restarts and rebuilds its `connection` service. So right after a first install `/packycode-api` does not exist yet, requests fall through to the static page, and it answers 405; the model route and the settings panel itself load normally. From 1.1.7 on, a first install needs no restart. Check which version was installed:
240
290
 
package/README.md CHANGED
@@ -32,6 +32,7 @@
32
32
  | **Claude 按分组选通道** | `cc` 分组只接受官方客户端,这些 Key 的 Claude 请求由本机 Claude Code CLI 发出;`cc-sale`、`cc-expensive`、`claude-officially` 等分组走插件内 HTTP。两条通道都由 DSH 执行工具、审批权限,计划模式、附件和完整对话历史完全一致 |
33
33
  | **网页搜索可走 PackyCode** | 可选:DSH 的 `web_search` 改用 PackyCode 搜索,后端在 DeepSeek 与 GPT 之间切换;可只对 PackyCode 模型生效 |
34
34
  | **图片生成与编辑** | 独立图片 Key,支持 GPT Image 2 / 2.5 Flare / 2.5 Sunburst、型号与质量设置、参考图编辑和 PNG 原图保存;已通过网关生图与编辑实测 |
35
+ | **自动审查可换模型** | 开启 DSH 自带的「自动授权审查」后,权限菜单里的「自动审查」可改用 jev-latest 或 DeepSeek Flash 审查每次工具调用,审查规则和处理方式保持官方原样 |
35
36
  | **凭据不离开本机** | Key 只存在 DSH 凭据文件里。浏览器只能看到备注、状态和余额,拿不到 Key |
36
37
 
37
38
  <img width="774" height="455" alt="截屏2026-10-15 10 34 28" src="https://github.com/user-attachments/assets/060c4192-00ea-40e6-9b85-bbec605b5c31" />
@@ -47,10 +48,10 @@
47
48
  打开桌面应用的**插件**页,点击**添加插件**,在**包名或地址**中填入**带版本号**的包名:
48
49
 
49
50
  ```text
50
- dsh-packycode-api@1.3.6
51
+ dsh-packycode-api@1.3.8
51
52
  ```
52
53
 
53
- 在**安装源**中选择**官方源**,然后点击**安装**。`1.3.6` 是写这份说明时的最新版,当前最新版本号以 [npm 页面](https://www.npmjs.com/package/dsh-packycode-api) 为准。
54
+ 在**安装源**中选择**官方源**,然后点击**安装**。`1.3.8` 是写这份说明时的最新版,当前最新版本号以 [npm 页面](https://www.npmjs.com/package/dsh-packycode-api) 为准。
54
55
 
55
56
  > **一定要带版本号。** 只填 `dsh-packycode-api` 时,安装前的提示显示的是 npm 上的最新版,但 DSH 自带的 pnpm 默认只安装发布满 24 小时的版本,实际装上的可能是好几个版本之前的旧版,而安装提示里看不出这一点。填写精确版本时,pnpm 会直接安装这个版本,并自动把它加入 profile 的 `minimumReleaseAgeExclude`。装好后可以在 **设置 → PackyCode → 插件版本** 核对「当前版本」。
56
57
 
@@ -71,7 +72,7 @@ dsh-packycode-api@1.3.6
71
72
 
72
73
  桌面应用的**插件**页可以看到已安装状态与版本,也可以在那里启用、停用或卸载。
73
74
 
74
- **仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.3.6`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
75
+ **仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.3.8`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
75
76
 
76
77
  本地开发要加 `link:` 前缀:`dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`。**不要直接写路径(或 `file:`)** —— 那样的安装会把整个仓库目录(连同 `node_modules`)复制进 profile,之后它会在 profile 内部挡住 DSH 自带的包,插件看起来像没装,见「常见问题」。已经那样装过的话,先卸载再按上面的方式重装。
77
78
 
@@ -89,7 +90,7 @@ dsh-packycode-api@1.3.6
89
90
 
90
91
  **看余额。** 「账户与 Key」里每个 Key 显示它自己的剩余、已用与额度(额度 = 剩余 + 已用),不限额的 Key 显示「不限额度」;多个 Key 不相加成合计。API Key 只能读到自己的额度,读不到 PackyCode 账号的总余额,账号余额请到 PackyCode 控制台查看。读失败的 Key 会在它那一行注明原因;某个 Key 这次读失败但之前读到过,会继续显示上次的余额并注明读取时间(输入框里显示为 `≈US$…`),重启 DSH 后才清空。输入框右侧只在选中 PackyCode 模型时显示当前 Key 的剩余额度。「刷新」会跳过约 60 秒的缓存。默认模型接口是 `https://cf.api.fan`,余额接口是 `https://www.packyapi.ai`,可在「高级:接口地址」里改。旧默认值 `https://www.packyapi.com` 在国内网络下 DNS 被污染、直连会 `fetch failed`,即使设置里保存的是它,插件也会先试 `.ai`。
91
92
 
92
- **用 Claude。** 直接选择三个 Claude 模型之一。Key 在 `cc` 分组时,插件用本机的官方 Claude Code CLI 发出请求,需要先在 **设置 → PackyCode → Claude Code CLI** 一键安装(或自行 `npm install -g @anthropic-ai/claude-code --allow-scripts=@anthropic-ai/claude-code`),版本过低时在同一处点「更新 Claude Code CLI」;`cc-sale`、`cc-expensive`、`claude-officially` 等分组直接走插件内 HTTP,不需要 CLI。「账户与 Key」里每个能用 Claude 的 Key 会标出「Claude 经官方 CLI」或「Claude 经 HTTP」,通道只由分组决定,不能手动切换。无论哪条通道,工具都由 DSH 执行并按 DSH 的权限审批,计划模式、提问、待办、子代理、附件、思考档位和历史都和其它模型一样。详见下方「Claude Code CLI 通道」。
93
+ **用 Claude。** 直接选择三个 Claude 模型之一。Key 在 `cc` 分组时,插件用本机的官方 Claude Code CLI 发出请求,需要先在 **设置 → PackyCode → Claude Code CLI** 一键安装(或自行 `npm install -g @anthropic-ai/claude-code --allow-scripts=@anthropic-ai/claude-code`),版本过低或有新版本时在同一处点「更新 Claude Code CLI」;`cc-sale`、`cc-expensive`、`claude-officially` 等分组直接走插件内 HTTP,不需要 CLI。「账户与 Key」里每个能用 Claude 的 Key 会标出「Claude 经官方 CLI」或「Claude 经 HTTP」,通道只由分组决定,不能手动切换。无论哪条通道,工具都由 DSH 执行并按 DSH 的权限审批,计划模式、提问、待办、子代理、附件、思考档位和历史都和其它模型一样。详见下方「Claude Code CLI 通道」。
93
94
 
94
95
  **网页搜索。** DSH 的 `web_search` 默认调用 DeepSeek 官方接口(用 `DEEPSEEK_API_KEY` 计费)。在 **设置 → PackyCode → 网页搜索** 里可以改走 PackyCode:
95
96
 
@@ -139,7 +140,7 @@ PackyCode 的 `cc` 分组(「claude code专用」)只接受官方 Claude Cod
139
140
  - **提示与历史保持 DSH 原样。** DSH 的系统提示追加在 CLI 官方提示之后;历史(文字、图片、带签名的思考、工具调用与结果)由插件写成 CLI 的会话记录后续接,思考档位以 `--effort` 传入。
140
141
  - **一个会话一个常驻进程。** 同一个 DSH 会话、同一模型复用一个 CLI 进程:工具结果和下一轮消息直接续接,请求前缀不变,网关缓存照常命中。历史被压缩、切换计划模式或换 Key 时,用 DSH 的完整历史恢复一个新进程;会话标题和压缩用一次性进程。空闲 20 分钟的进程自动结束,最多同时保留 8 个。
141
142
  - **与你自己的 Claude Code 隔离。** 使用独立配置目录 `~/.dsh/packycode-claude-cli`,不读取 `~/.claude` 的设置、CLAUDE.md、MCP 配置和登录状态;只把插件保存的 Key 交给子进程。自动更新、遥测、自动压缩、自动记忆和模型回退都关闭,失败重试交还给 DSH 的重试策略(会按 Key 轮换)。
142
- - **版本过低一键更新。** 插件需要 Claude Code 2.1.259 或更新版本(插件传入的 `--permission-prompts` 从这一版开始提供)。更旧的 CLI 在请求发出前就被拦下并说明原因,CLI 卡片标出「版本过低」并提供「更新 Claude Code CLI」:官方安装器(`~/.local/bin/claude`)装的执行 `claude update`;npm 全局安装的执行 `npm install -g @anthropic-ai/claude-code@latest --allow-scripts=@anthropic-ai/claude-code`,因为 npm 12 默认不运行安装脚本,而 `claude update` 在 npm 安装上不会放行脚本,会留下一个无法运行的 CLI。只有点这个按钮时才会更新你的 Claude Code。
143
+ - **版本过低一键更新。** 插件需要 Claude Code 2.1.259 或更新版本(插件传入的 `--permission-prompts` 从这一版开始提供)。更旧的 CLI 在请求发出前就被拦下并说明原因,CLI 卡片标出「版本过低」并提供「更新 Claude Code CLI」:官方安装器(`~/.local/bin/claude`)装的执行 `claude update`;npm 全局安装的执行 `npm install -g @anthropic-ai/claude-code@latest --allow-scripts=@anthropic-ai/claude-code`,因为 npm 12 默认不运行安装脚本,而 `claude update` 在 npm 安装上不会放行脚本,会留下一个无法运行的 CLI。CLI 能用但不是最新版时,卡片也会提示新版本并提供同一个按钮:插件在本机读取 npm 上 `@anthropic-ai/claude-code` 的 `latest`(与官方安装器的 `latest` 通道是同一版本),30 分钟内最多读一次,点「重新检测」立即重读;读不到时不提示。只有点这个按钮时才会更新你的 Claude Code。
143
144
  - **出错会说清原因。** 未安装 CLI、CLI 版本过旧、官方 CLI 发出的请求仍被网关拒绝,分别给出说明和下一步,不会改走其它通道或提供商,也不会停用 Key。
144
145
 
145
146
  已知差异:新进程启动约 0.3–1 秒;在一轮工具调用中途恢复进程时,CLI 会按官方行为在工具结果后附上一句 “Continue from where you left off.”。需要 Claude Code 2.1.259 或更新版本(实测 2.1.295 与 2.1.303)。Windows 上 Claude Code 还需要 Git for Windows。
@@ -166,6 +167,53 @@ Claude 与其它模型一样,通过 DSH 的 `packycode_image_generate` 工具
166
167
 
167
168
  2026-10-15 实测:三个型号均通过 `low` 生图与编辑;Sunburst 额外通过 `xhigh`、`max` 生图与编辑,两档响应的 quality 均与请求一致。合计 10 次成功请求,无重试,全部返回 1024×1024 PNG;编辑正确改色并保留构图。xhigh 生成/编辑约 43/48 秒,max 约 84/91 秒。这是已构建图片 client 的网关验证;本轮未新建 DSH 对话验证完整聊天流程。完整范围和记录见[协议核查与网关实测](docs/research/image-api.md)。
168
169
 
170
+ ### 自动审查
171
+
172
+ DSH 自带一个实验性插件「自动授权审查」,默认关闭。开启后,输入框下方的权限菜单(「仅可查看 / 工作区内修改 / 完全权限」)会多出一项 **自动审查**(带 EXP 标记)。选了自动审查的会话里,每次工具调用前都先由模型审查:
173
+
174
+ - 放行的直接执行,不使用沙箱。
175
+ - 拒绝的改为请你批准;在子代理里则直接拒绝。
176
+ - 审查本身失败时,这次调用不执行。
177
+
178
+ 官方默认用当前对话的模型审查。本插件不改官方的审查逻辑,只替换审查模型。在 **设置 → PackyCode → 自动审查** 里选:
179
+
180
+ | 审查模型 | 说明 | 需要的分组 |
181
+ | --- | --- | --- |
182
+ | jev-latest(默认) | TypeSafe 的决策分类模型,一次约 0.4 秒,只按输入计费;拒绝时只给出风险等级 | `typesafe-officially` |
183
+ | DeepSeek Flash | 一次约 2 秒,拒绝时写明原因 | `deepseek-officially` / `deepseek-sale` |
184
+ | 跟随对话模型 | 不接管,按官方默认审查 | — |
185
+
186
+ 使用步骤:
187
+
188
+ 1. 在 DSH 左侧「插件」页开启「自动授权审查」。
189
+ 2. 在输入框的权限菜单里选「自动审查」,确认风险提示。
190
+ 3. 在「设置 → PackyCode → 自动审查」选审查模型。
191
+
192
+ 卡片会显示:官方插件是否已开启、本插件处理过多少次审查(放行 / 拒绝 / 失败)和最近一次结果。如果没有 Key 能调用所选模型,卡片会提示。
193
+
194
+ <details>
195
+ <summary>怎么接管的</summary>
196
+
197
+ - 官方审查器每次审查发出一个模型请求:
198
+ - 系统提示是它固定的 `REVIEW_POLICY`;
199
+ - 用户消息是四段 JSON:ENVIRONMENT、PROJECT_INSTRUCTIONS、FILTERED_HISTORY、PENDING_ACTION;
200
+ - 要求返回一个 `{"risk","decision","reason"?}` 对象。
201
+ - 所有模型请求都经过 DSH 的 `llm/stream` 流水线。本插件在这里只认这一种请求,对话等其它请求原样放过。
202
+ - **DeepSeek Flash**:同一个请求原样改发到 PackyCode 线路,结果仍由官方解析。
203
+ - **jev-latest**:它写不出 JSON。插件把四段内容和官方规则原文作为 System One 的 state,问两个问题:风险等级,以及你是否明确要求过这个操作。
204
+ - 放行条件:「低风险,或中风险且你要求过」的概率不低于 0.6,且高风险概率低于 0.2。
205
+ - 拒绝时,理由里写明是 jev-latest 判定的中风险或高风险。
206
+ - jev-latest 上下文较小,过长的历史会从最旧的开始截掉,你的指令优先保留。
207
+ - 看什么、按什么规则判、放行或拒绝后怎么处理,都由官方插件决定。官方对审查失败(例如 Key 调不了 jev-latest)的处理是拒绝这次调用,本插件不改变这一点。
208
+ - 实测方式:37 个场景,用官方的请求格式和官方解析器。其中 35 个有明确答案,两个模型都全部符合预期。
209
+ - jev-latest 中位 0.35 秒,DeepSeek Flash 中位 2.3 秒。
210
+ - 如果以后 DSH 改了审查请求的格式:
211
+ - 认不出这个请求时,原样放过,由对话模型审查;
212
+ - jev-latest 读不懂新格式时,这次审查失败,卡片计数里会看到。
213
+ - 菜单里「自动审查」的说明写的是「由同一模型审查」,那是 DSH 的文字。选了 jev-latest 或 DeepSeek Flash 时,实际由所选模型审查。
214
+
215
+ </details>
216
+
169
217
  ## 模型与分组
170
218
 
171
219
  | 模型 | 怎么调用 | 推理档位 | 适合的令牌分组 |
@@ -183,6 +231,8 @@ Claude 与其它模型一样,通过 DSH 的 `packycode_image_generate` 工具
183
231
 
184
232
  列表里看得到模型,不代表当前令牌分组一定放行。换分组时不要把对应分组一起去掉。
185
233
 
234
+ `jev-latest`(TypeSafe Jev)不在模型选择器里:它是只回答分类问题的决策模型,不能对话,只用于[自动审查](#自动审查)。插件在宿主侧直接调用 `/v1/systemone`,需要 Key 在 `typesafe-officially` 分组;「账户与 Key」里每个 Key 的「Jev」一项会显示能否使用。
235
+
186
236
  当前目录中的 10 个模型都声明了文字和图像输入。DeepSeek Flash 的识图能力按 [官方图像理解文档](https://api-docs.deepseek.com/zh-cn/guides/vision/) 配置;图片通过 DSH 附件服务读取,再随 Responses 请求发送。
187
237
 
188
238
  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) 为准。
@@ -216,9 +266,9 @@ DeepSeek Flash 走网关的 Responses 接口(`/api/pricing` 列出 `openai-res
216
266
 
217
267
  ## 更新与卸载
218
268
 
219
- > **从 1.3.2 或更早版本升级:** 请在插件页填写 `dsh-packycode-api@1.3.6` 安装,不要点旧版设置页里的「更新插件」。旧按钮安装时会绕过 pnpm 的发布冷却期:装到的版本如果发布还不满 24 小时,这个 profile 在它满 24 小时之前就装不了其他插件。装好并重启后,按钮就换成了修好的版本,以后直接点即可。
269
+ > **从 1.3.2 或更早版本升级:** 请在插件页填写 `dsh-packycode-api@1.3.8` 安装,不要点旧版设置页里的「更新插件」。旧按钮安装时会绕过 pnpm 的发布冷却期:装到的版本如果发布还不满 24 小时,这个 profile 在它满 24 小时之前就装不了其他插件。装好并重启后,按钮就换成了修好的版本,以后直接点即可。
220
270
 
221
- **更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。安装遵守 pnpm 的发布冷却策略,不会绕过它:默认情况下 pnpm 会直接装上这个版本,并把它记进 profile 的 `minimumReleaseAgeExclude`;如果你给 pnpm 配了更严格的策略,按钮会提示什么时候可以更新。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装,同样要填写带版本号的包名(例如 `dsh-packycode-api@1.3.6`),否则装上的可能是发布满 24 小时的旧版。
271
+ **更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。安装遵守 pnpm 的发布冷却策略,不会绕过它:默认情况下 pnpm 会直接装上这个版本,并把它记进 profile 的 `minimumReleaseAgeExclude`;如果你给 pnpm 配了更严格的策略,按钮会提示什么时候可以更新。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装,同样要填写带版本号的包名(例如 `dsh-packycode-api@1.3.8`),否则装上的可能是发布满 24 小时的旧版。
222
272
 
223
273
  **从本地路径安装切回官方源时,必须先卸载。** 「更新」是 `pnpm add`,它只重写包目录里的文件,不会删除更早一次本地路径安装留在包目录内的 `node_modules`;那份旧依赖会继续挡住 DSH 自带的包,插件行加载失败且看不出原因。「卸载」执行的是 `pnpm remove`,会删掉整个包目录,重装才是干净的。用 `node scripts/install-check.mjs` 可以确认当前 profile 是否处于这个状态。
224
274
 
@@ -234,7 +284,7 @@ ls ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/node_modules
234
284
 
235
285
  有输出就是残留:从 npm 安装的包不会自带 `node_modules`,这一份通常来自更早一次「本地路径」安装(`file:` 或直接写路径,而不是 `link:`)。它位于 profile 目录内部,而 DSH 解析插件导入时优先使用 profile 内的副本,所以插件拿到的仍是那份旧依赖 —— 例如 `@deepseek-ai/schemastery` 3.18.2 没有 `Schema.volatile()`,模块在导入阶段就抛错。导入失败时 Loader 不会为这一行创建 fiber,客户端 bundle 也不会被组合,于是模型路由、RPC 通道和设置页全都不会出现。
236
286
 
237
- 修复:到**插件**页**卸载**本插件,再用带版本号的包名重新**安装**(例如 `dsh-packycode-api@1.3.6`),然后完全退出并重新打开桌面应用。卸载执行的是 `pnpm remove`,会删掉整个包目录;直接重装或点「更新」只重写文件,不会清掉这份残留。也可以手动删掉上面那个 `node_modules` 再重启。
287
+ 修复:到**插件**页**卸载**本插件,再用带版本号的包名重新**安装**(例如 `dsh-packycode-api@1.3.8`),然后完全退出并重新打开桌面应用。卸载执行的是 `pnpm remove`,会删掉整个包目录;直接重装或点「更新」只重写文件,不会清掉这份残留。也可以手动删掉上面那个 `node_modules` 再重启。
238
288
 
239
289
  **首次安装后,设置页每张卡片都显示 `transport failure for /packycode-api/…: HTTP 405`?** 实际装上的是 1.1.6 或更早的版本,通常是因为安装时只填了包名:安装提示显示的是最新版,pnpm 实际装的却是发布满 24 小时的旧版(见「安装插件」)。这些旧版要等 DSH 重启、重建它的 `connection` 服务之后,才能注册设置通道。所以首次安装后 `/packycode-api` 通道还不存在,请求落到静态页面,返回 405;模型路由和设置页本身照常加载。1.1.7 起首次安装不需要重启。先确认装上的版本:
240
290