dsh-packycode-api 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.en.md +18 -4
- package/README.md +18 -4
- package/SECURITY.md +9 -0
- package/lib/client.js +12 -6
- package/lib/index.js +1104 -153
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.2
|
|
4
|
+
|
|
5
|
+
- **Claude CLI follows DSH plan mode.** While the current session's plan mode is on (including a selection that applies on this step but is not logged yet), a Claude model turn and the `claude_code` tool run the local CLI with `--permission-mode plan`. That wins over the session permission preset and over an explicit `claudeCliMode` pin. The CLI may explore read-only; other permission prompts are denied, and after eight denials the run stops instead of hanging. `ExitPlanMode` is never allowed inside the CLI process. A submitted plan becomes the assistant's `exit_plan_mode` tool call, so DSH's existing review approves it and the next step implements. The delegation tool returns the plan text for the parent model to submit. Session titles stay read-only. A host without the plan-mode service behaves as before.
|
|
6
|
+
|
|
7
|
+
## 1.1.1
|
|
8
|
+
|
|
9
|
+
- **Claude CLI search through MCP.** CLI-backed Claude turns and the `claude_code` delegation tool now get a temporary, authenticated, loopback HTTP MCP `web_search` tool calling the plugin's selected DeepSeek/GPT backend. Native CLI `WebSearch` is explicitly denied in every permission mode: it makes a separate Claude server-tool request that PackyCode can refuse even when ordinary turns work. The official CLI/system identity is preserved; no vendor headers or identities are forged. Backend selection applies to CLI searches even when DSH routing is set to Off/Do not take over; the DSH routing mode remains independent, and headless profiles need no `web` service. MCP callbacks capture their originating session ID before losing agent context and always call the direct PackyCode provider, never an auto-router fallback.
|
|
10
|
+
- **Bridge boundaries.** Each run has a collision-resistant server/tool name, an independent random capability, and an owner-only temporary MCP config; search API keys stay in the host key ring, not MCP config, argv or results. Only the exact search tool is added to read-only/edit auto-approvals; shell/file privileges, existing MCP configuration, and user/managed deny rules remain unchanged. No `--strict-mcp-config` or wildcard MCP approval. Queries are bounded at 2000 characters, bodies at 16 KiB, sources at 8, concurrency at 2, calls at 8 per run, and each logical search at 60 seconds including retries/key resolution. Tool failures are explicit, sanitized errors, with no automatic backend/native-search fallback. Results are marked as untrusted external content.
|
|
11
|
+
- **Lifetime and redaction fixes.** MCP capability is revoked immediately on cancellation, including while binding/writing config; late filesystem resources remain owned until cleanup completes. Normal/error exits, spawn/stdin failures, startup watchdog, timeout, early iterator close, and plugin unload clean up. Fixed pre-existing runner races where cancellation during credential/binary setup could still spawn a child and returning at the first labeled-key yield left a child running. Streaming now checks nonzero process exits even after a successful-looking result. Redaction handles JSON-escaped keys and credentials/capabilities fragmented across text/thinking deltas. Title generation allocates no MCP server/search grant.
|
|
12
|
+
- The settings card explains CLI backend selection versus DSH routing. Added `scripts/cli-search-check.mjs`: real official CLI + a local mocked Claude gateway verifies actual MCP transport/permissions and absence of native search in all modes; `--live --backend deepseek|gpt` performs one real search through that backend. The mock gateway is a test fixture only, never a replacement for DSH or the production gateway.
|
|
13
|
+
- Validation: complete suite on Node 24 and Node 22.20.0; real CLI 2.1.39 and 2.1.295 both called the built bridge in read-only/edit/full modes, with official identity retained and no Claude native-search child call. Real DeepSeek and GPT searches via the bridge returned 10 and 20 sources; one initial GPT backend attempt failed explicitly, and a later attempt succeeded. Ordinary HTTP models, key rotation/failure classification and secret-free RPC projections passed the live check. Claude main-model responses in the MCP test were mocked (the available stored key has no Claude group); actual Claude upstream/desktop DSH integration is not claimed from these checks.
|
|
14
|
+
|
|
3
15
|
## 1.1.0
|
|
4
16
|
|
|
5
17
|
- **Keys are chosen by their groups.** A colleague's Claude turns kept failing with "PackyCode 的上游拒绝了这次 Claude Code CLI 请求……请更新 CLI" because the active key had no Claude Code group; PackyCode answers such a key with the same "only the official Claude Code CLI" wording as a real client fault. The plugin now reads each key's groups and routes by them:
|
package/README.en.md
CHANGED
|
@@ -44,7 +44,7 @@ Open the desktop application's **Plugins** page, click **Add plugin**, and enter
|
|
|
44
44
|
dsh-packycode-api
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
Choose the **official** install source, then click **Install**. To pin a version, enter `dsh-packycode-api@1.1.
|
|
47
|
+
Choose the **official** install source, then click **Install**. To pin a version, enter `dsh-packycode-api@1.1.2`.
|
|
48
48
|
|
|
49
49
|
Then **manually restart the desktop application**. Refreshing the page does not reload the plugin inside the Host process.
|
|
50
50
|
|
|
@@ -63,7 +63,7 @@ Choose a model from the `PackyCode` group. `deepseek-flash`, `gpt-6.1-sol`, and
|
|
|
63
63
|
|
|
64
64
|
The **Plugins** page shows the installed state and version, and is also where you enable, disable, or uninstall.
|
|
65
65
|
|
|
66
|
-
**For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.1.
|
|
66
|
+
**For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.1.2`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
|
|
67
67
|
|
|
68
68
|
A local checkout can be linked with `dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`.
|
|
69
69
|
|
|
@@ -96,6 +96,18 @@ A profile without a browser can still use the model route. It just has no settin
|
|
|
96
96
|
|
|
97
97
|
PackyCode has no dedicated search endpoint: one search is one model call with a server-side search tool, billed to the keys stored here. An exhausted or rejected key rotates exactly as on the model route.
|
|
98
98
|
|
|
99
|
+
**Claude CLI search.** Both CLI-backed Claude models and the `claude_code` delegation tool use a temporary MCP search tool calling the DeepSeek/GPT backend selected above. Native `WebSearch` is disabled: it sends an additional Claude server-tool subrequest that PackyCode's Claude upstream may reject as an unofficial client even when ordinary turns work.
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
Claude Code CLI → temporary local MCP web_search → selected PackyCode DeepSeek/GPT backend
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- **Backend selection applies to CLI; routing selection only applies to DSH.** Even with Off/Do not take over selected, CLI searches use the selected backend, not DSH's default. A backend change applies to the next search.
|
|
106
|
+
- Ordinary Claude requests still need a Claude-group key. Search needs a plugin-stored key covering DeepSeek or GPT; it can be another key. Failures are returned to the CLI, with no invented success or automatic switch to another backend.
|
|
107
|
+
- Read-only/edit modes auto-approve only this specific read-only MCP search tool, without adding shell or file-write privileges. User/managed denials still apply. CLI `--allowedTools` is an additive auto-approval list, not an exclusive tool whitelist; existing other permissions are preserved.
|
|
108
|
+
- At most 8 searches per invocation, 2 concurrently, 2000 characters per query and 8 sources per result, with a 60-second end-to-end search deadline. Title generation allocates no MCP server or search grant.
|
|
109
|
+
- Reasoning reports `▸ 网页搜索:PackyCode DeepSeek(MCP,原生 WebSearch 已禁用)` (or GPT). The temporary server binds only `127.0.0.1`; its private config contains an independent one-run capability, never a search API key. CLI completion/cancellation/timeout/plugin unload revokes it and removes the private config, leaving existing user MCP configurations untouched.
|
|
110
|
+
|
|
99
111
|
<details>
|
|
100
112
|
<summary>How web search is wired into DSH</summary>
|
|
101
113
|
|
|
@@ -141,14 +153,14 @@ A model in the list does not mean the current token group allows it. When changi
|
|
|
141
153
|
- 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.
|
|
142
154
|
- 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.
|
|
143
155
|
- 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.
|
|
144
|
-
- 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.
|
|
156
|
+
- 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`. DSH plan mode wins over that mapping and over the pin: the CLI runs with `--permission-mode plan`, and `ExitPlanMode` submits the plan to DSH's review instead of editing in the same process. The previous mode returns after approval or `/plan off`. Session titles stay out of plan mode. An empty `claudeCliPath` is looked up automatically; an empty `claudeCliCwd` uses the session workspace.
|
|
145
157
|
- 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.
|
|
146
158
|
- The reasoning block opens with `▸ 启动 Claude Code CLI…` and then shows the CLI's version and model once it is up. When the gateway throttles or is busy (429, 503 `账号并发排队已满` / per-account wait queue full, and similar), the CLI retries up to 10 times on its own; each retry now shows as `↻ 网关返回 HTTP 503,CLI 自动重试 n/10` instead of looking hung. When the retries run out, the turn says PackyCode's Claude upstream is busy, not that the key is bad. A CLI that prints nothing for 2 minutes after starting is stopped and reported.
|
|
147
159
|
- The conversation and its images reach the CLI over stdin (`--input-format stream-json`), not argv: a Windows command line is length-limited and cannot carry an image. Images in the conversation are sent to Claude as images, at the HTTP route's request size (at most 2048×2048, about 1 MiB each; at most 20 images and 20 MiB per turn, dropping the oldest first). An image left out is named with its read-only local copy, which the CLI can open with Read.
|
|
148
160
|
- Every run carries `--append-system-prompt` (the delegation note). In `-p` mode the official CLI introduces itself as "You are Claude Code, Anthropic's official CLI for Claude …" when it has appended instructions and as "You are a Claude agent, built on Anthropic's Claude Agent SDK." when it has none; the latter was refused upstream as not coming from the official CLI (403 `only accepts requests from the official Claude Code CLI`). That is the official CLI's own behavior; the plugin does not rewrite its system prompt.
|
|
149
161
|
- 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.
|
|
150
162
|
- While the session model is `gpt-6-astra`, titles are generated with `gpt-6.1-sol` (same Codex group); the turns themselves stay on Astra. Other models title their own sessions.
|
|
151
|
-
- The `claude_code` tool can delegate one task to the local CLI while the session model is `gpt-6.1-sol`, `gpt-6-astra`, or `deepseek-flash`. The requested `mode` cannot exceed what the session preset allows.
|
|
163
|
+
- The `claude_code` tool can delegate one task to the local CLI while the session model is `gpt-6.1-sol`, `gpt-6-astra`, or `deepseek-flash`. The requested `mode` cannot exceed what the session preset allows. While the session is in plan mode the delegation plans too, and returns the plan text to the parent model.
|
|
152
164
|
- An effort level the model does not support is rejected before the request is sent. Do not edit a model's effort map casually.
|
|
153
165
|
|
|
154
166
|
</details>
|
|
@@ -200,6 +212,8 @@ pnpm run check
|
|
|
200
212
|
|
|
201
213
|
`node scripts/live-check.mjs` checks the live gateway through the same route the plugin registers: balance and groups, one answer per HTTP model, a rotation rehearsal, and the failure classification, printing only the key's last four characters. `--with-cli` also runs the three Claude models through the local Claude Code CLI, and `--with-search` runs one search per backend; the default run spends a small amount of quota.
|
|
202
214
|
|
|
215
|
+
`node scripts/cli-search-check.mjs` runs the real CLI against a local test gateway and MCP bridge; Claude responses and search data are mocked by default, with no quota consumed. It checks all three permission modes, native-search exclusion and temporary-resource cleanup. `--live --backend deepseek` or `--live --backend gpt` sends the read-only mode's one search to the real backend (edit/full remain mocked). This does not verify actual Claude upstream turns or a running DSH integration.
|
|
216
|
+
|
|
203
217
|
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.
|
|
204
218
|
|
|
205
219
|
## License
|
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
dsh-packycode-api
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
在**安装源**中选择**官方源**,然后点击**安装**。需要固定版本时填入 `dsh-packycode-api@1.1.
|
|
51
|
+
在**安装源**中选择**官方源**,然后点击**安装**。需要固定版本时填入 `dsh-packycode-api@1.1.2`。
|
|
52
52
|
|
|
53
53
|
完成后**手动重启桌面应用**。仅刷新页面不会重新加载 Host 里的插件。
|
|
54
54
|
|
|
@@ -67,7 +67,7 @@ dsh-packycode-api
|
|
|
67
67
|
|
|
68
68
|
桌面应用的**插件**页可以看到已安装状态与版本,也可以在那里启用、停用或卸载。
|
|
69
69
|
|
|
70
|
-
**仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.1.
|
|
70
|
+
**仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.1.2`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
|
|
71
71
|
|
|
72
72
|
本地开发可以用绝对路径:`dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`。
|
|
73
73
|
|
|
@@ -100,6 +100,18 @@ dsh-packycode-api
|
|
|
100
100
|
|
|
101
101
|
PackyCode 没有专用搜索接口:一次搜索就是一次带服务端搜索工具的模型调用,用这里的 Key 计费,额度用尽或 Key 被拒绝时同样切到下一个 Key。
|
|
102
102
|
|
|
103
|
+
**Claude CLI 的搜索。** Claude 模型和 `claude_code` 委派工具都通过临时 MCP 搜索工具使用上表选定的 DeepSeek/GPT 后端,原生 `WebSearch` 被禁用。原因是原生搜索会额外发一个 Claude 服务端搜索子请求,PackyCode 的 Claude 上游可能把它拒为「不是官方 CLI」,即使普通对话能正常工作。新的调用链是:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
Claude Code CLI → 本机临时 MCP web_search → 插件选定的 DeepSeek/GPT 后端
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **后端选择对 CLI 生效;路由选择只影响 DSH。** 即使选了「不接管」,CLI 搜索仍用这里选的后端,不转到 DSH 默认搜索。更改后端后下一次搜索即使用新选择。
|
|
110
|
+
- Claude 普通对话仍需要 Claude 分组;搜索需要存入插件的 Key 覆盖 DeepSeek 或 GPT 分组,可以是另一个 Key。搜索错误会返回给 CLI,不伪造成功、不自动切另一个后端。
|
|
111
|
+
- 只读、编辑模式单独自动允许这个只读 MCP 搜索工具,不增加 Shell 或文件写权限;用户/管理员的拒绝规则仍有效。CLI 的 `--allowedTools` 是自动批准列表,不是可用工具的排他列表,已有其他工具权限保持原样。
|
|
112
|
+
- 每轮最多 8 次搜索,最多同时 2 次;查询不超过 2000 字符,每次最多 8 个来源,整体搜索预算 60 秒。标题生成不启动 MCP 或进行搜索。
|
|
113
|
+
- 思考区会显示 `▸ 网页搜索:PackyCode DeepSeek(MCP,原生 WebSearch 已禁用)`(或 GPT)。临时服务只监听 `127.0.0.1`,配置中仅含本机一次性凭证,不含搜索 API Key;CLI 结束、取消、超时或插件卸载时关闭并清理,不修改用户现有 MCP 配置。
|
|
114
|
+
|
|
103
115
|
<details>
|
|
104
116
|
<summary>网页搜索是怎么接进 DSH 的</summary>
|
|
105
117
|
|
|
@@ -145,14 +157,14 @@ PackyCode 没有专用搜索接口:一次搜索就是一次带服务端搜索
|
|
|
145
157
|
- `cc`(Claude Code 专用)只接受官方 Claude CLI。用普通 API 客户端调 Claude 会 403:`This API endpoint is only accessible via the official Claude CLI`。本插件因此调用本机 `claude`,而不是改去 `cc-sale`,也不是伪造客户端身份。令牌如果没有开放给官方 CLI 的分组,这三个模型仍然不可用。
|
|
146
158
|
- 选了 Claude 模型但本机没有 CLI 时,这一回合会直接说明未安装,并指向设置页的安装按钮。
|
|
147
159
|
- CLI 使用插件配置的地址和当前 Key(`ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN`),以及独立配置目录 `~/.dsh/packycode-claude-cli`。不隔离的话,`~/.claude/settings.json` 里的 `env` 会盖掉插件 Key。
|
|
148
|
-
- CLI 权限默认跟随当前会话:`read-only` → 只读,`workspace-write` → 可编辑,`danger-full-access` 且不再审批 → `full`。CLI 不能向 DSH 弹审批,所以只要会话还要审批,就不会给它 `full`。也可把设置项 `claudeCliMode` 固定成 `read-only` / `edit` / `full
|
|
160
|
+
- CLI 权限默认跟随当前会话:`read-only` → 只读,`workspace-write` → 可编辑,`danger-full-access` 且不再审批 → `full`。CLI 不能向 DSH 弹审批,所以只要会话还要审批,就不会给它 `full`。也可把设置项 `claudeCliMode` 固定成 `read-only` / `edit` / `full`。DSH 计划模式优先于该映射和这个固定档:CLI 以 `--permission-mode plan` 只读探索,调用 `ExitPlanMode` 后把计划交给 DSH 审阅,批准或 `/plan off` 之后才恢复原来的档位。会话标题不进入计划模式。`claudeCliPath` 留空则自动查找;`claudeCliCwd` 留空则用当前会话工作区。
|
|
149
161
|
- 思考过程和工具调用(`▸ Bash`、`▸ Read`,失败时带 `✗`)会出现在这一回合的思考区。它们是进度,不是 DSH 的工具调用。CLI 自己的工具不受 DSH 沙箱约束。
|
|
150
162
|
- 思考区第一行是「▸ 启动 Claude Code CLI…」,CLI 起来后显示版本和模型。网关限流或繁忙(429、503 `账号并发排队已满` 等)时,CLI 会自己重试最多 10 次,每次重试都会显示成 `↻ 网关返回 HTTP 503,CLI 自动重试 n/10`,不再像卡住。重试用完仍失败时,会说明是 PackyCode 的 Claude 上游繁忙,不是 Key 的问题。CLI 启动后 2 分钟内没有任何输出会被停止并报告原因。
|
|
151
163
|
- 对话记录和图片通过 stdin 交给 CLI(`--input-format stream-json`),不走命令行参数:Windows 命令行长度有上限,而且命令行带不了图片。对话里的图片会以图片形式发给 Claude(与 HTTP 路由相同的压缩规格:每张不超过 2048×2048、约 1 MiB;一回合最多 20 张、合计 20 MiB,超出时先舍弃最早的)。没随消息发出的图片会写明本机只读副本的路径,CLI 需要时可以用 Read 读取。
|
|
152
164
|
- 每次运行都带 `--append-system-prompt`(委派说明)。在 `-p` 模式下,官方 CLI 有追加说明时会以 "You are Claude Code, Anthropic's official CLI for Claude …" 自我介绍,没有时是 "You are a Claude agent, built on Anthropic's Claude Agent SDK.";后者曾被上游当成非官方 CLI 拒绝(403 `only accepts requests from the official Claude Code CLI`)。这是官方 CLI 自己的行为,插件没有改写它的系统提示词。
|
|
153
165
|
- 会话跑在 Claude 模型上时,生成标题改用 `claude-haiku-5-5`,只读、临时目录,避免为起标题跑一整轮 Opus。
|
|
154
166
|
- 会话跑在 `gpt-6-astra` 上时,标题改由 `gpt-6.1-sol` 生成(同一个 Codex 分组);对话本身仍然用 Astra。其它模型的标题由会话模型自己生成。
|
|
155
|
-
- 另有 `claude_code` 工具:当前模型是 `gpt-6.1-sol`、`gpt-6-astra` 或 `deepseek-flash` 时,可以把一个任务委派给本机 Claude Code。请求的 `mode`
|
|
167
|
+
- 另有 `claude_code` 工具:当前模型是 `gpt-6.1-sol`、`gpt-6-astra` 或 `deepseek-flash` 时,可以把一个任务委派给本机 Claude Code。请求的 `mode` 不会超过会话权限允许的上限;会话处于计划模式时,这个委派也只规划,并把计划正文交回父模型。
|
|
156
168
|
- 声明了模型不支持的推理档位会被 harness 在发请求前拒绝,不要随手改档位映射。
|
|
157
169
|
|
|
158
170
|
</details>
|
|
@@ -204,6 +216,8 @@ pnpm run check
|
|
|
204
216
|
|
|
205
217
|
真机网关用 `node scripts/live-check.mjs` 验证:它通过插件注册的同一条路由,读余额和分组、让每个 HTTP 模型回答一次、演练 Key 轮换和失败分类,只打印 Key 的末 4 位。加 `--with-cli` 会用本机 Claude Code CLI 跑三个 Claude 模型,加 `--with-search` 会每个搜索后端各搜一次;默认运行只消耗少量额度。
|
|
206
218
|
|
|
219
|
+
Claude CLI 的 MCP 接口验证用 `node scripts/cli-search-check.mjs`:运行真实 CLI,普通 Claude 响应和搜索数据默认由本地测试服务模拟,不消费额度;会检查三种权限模式、原生搜索禁用和临时资源清理。加 `--live --backend deepseek` 或 `--live --backend gpt` 会让只读模式的那一次搜索走真实后端(其它两种模式仍模拟)。这不等于验证了真实 Claude 上游对话或运行中的 DSH 集成。
|
|
220
|
+
|
|
207
221
|
使用 Agent 修改或发布时,先读 [AGENTS.md](AGENTS.md)。发布由推送 `v*` 标签触发 [Publish workflow](.github/workflows/publish.yml),不要在本机执行 `npm publish`。
|
|
208
222
|
|
|
209
223
|
## License
|
package/SECURITY.md
CHANGED
|
@@ -13,6 +13,15 @@
|
|
|
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
14
|
- Model traffic goes to the configured model host through the host's own pi-ai adapter, with the harness attribution headers, exactly like a configured provider route.
|
|
15
15
|
|
|
16
|
+
## Claude CLI MCP search bridge
|
|
17
|
+
|
|
18
|
+
- Each CLI invocation owns a temporary HTTP MCP server bound exclusively to `127.0.0.1` on a random port. Every method requires an independent cryptographically random capability; Host/Origin validation rejects rebinding and cross-origin browser requests. No CORS access is granted.
|
|
19
|
+
- The owner-only temporary MCP config (private directory, file mode 0600 on POSIX) contains only this local capability. The search API keys remain in the host's key ring and are never placed in MCP configuration, argv, schemas, tool results or raw diagnostics. Result/CLI redaction handles escaped keys and secrets split across text deltas.
|
|
20
|
+
- The endpoint offers only bounded `web_search`; models cannot supply backend, API host, credentials, session IDs, shell commands or arbitrary fetch requests. Input size, query size, concurrency, search count, output size and an end-to-end timeout are bounded. Run stop and tool cancellation abort the provider.
|
|
21
|
+
- Native CLI WebSearch is denied even in full mode. Read-only/edit modes add only the exact MCP search tool to their auto-approval lists. Existing MCP/settings and user/managed deny rules remain effective; `--allowedTools` is not an exclusive whitelist. Hooks, other trusted MCP servers and full-permission commands remain part of the CLI's existing trust boundary.
|
|
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.
|
|
24
|
+
|
|
16
25
|
## Reporting
|
|
17
26
|
|
|
18
27
|
Report a security issue through the repository's GitHub issues rather than a public discussion of a live credential. Never paste a key, token, or credential-store value into an issue, a log, or a chat.
|
package/lib/client.js
CHANGED
|
@@ -135,10 +135,11 @@ window.__ModuleLoader__.load({
|
|
|
135
135
|
versionLater: "稍后",
|
|
136
136
|
searchTitle: "网页搜索",
|
|
137
137
|
searchScope: "DSH 全局设置",
|
|
138
|
-
searchIntro: "
|
|
138
|
+
searchIntro: "DSH 的 web_search 和 Claude CLI 的 MCP 搜索可使用这里选择的 DeepSeek/GPT 后端。每次搜索是独立的模型调用,用插件保存的 Key 计费。",
|
|
139
|
+
searchCliHint: "Claude CLI 始终通过 MCP 使用这里的搜索后端,原生 WebSearch 已禁用。下面的路由选项只控制 DSH 全局搜索,不影响 CLI。",
|
|
139
140
|
searchChecking: "正在读取搜索设置…",
|
|
140
141
|
searchLoadFailed: "搜索设置读取或保存失败",
|
|
141
|
-
searchModeTitle: "
|
|
142
|
+
searchModeTitle: "DSH 路由",
|
|
142
143
|
searchModeDefault: "不接管",
|
|
143
144
|
searchModeDefaultHint: "不改动 DSH 的搜索路由(默认)。切回此项会移除本插件写入 profile 的搜索补丁。",
|
|
144
145
|
searchModeAuto: "按模型",
|
|
@@ -155,7 +156,7 @@ window.__ModuleLoader__.load({
|
|
|
155
156
|
searchApplyFailed: "写入搜索补丁失败:{error}",
|
|
156
157
|
searchForeign: "检测到 {names} 订阅插件:它们接管的模型仍按各自的搜索设置,其余请求才会到达这里的选择。",
|
|
157
158
|
searchOverridden: "基础搜索现在是 {base},不是 PackyCode:可能还在热加载,或被其他插件的补丁覆盖。",
|
|
158
|
-
searchUnavailable: "当前运行环境没有 DSH
|
|
159
|
+
searchUnavailable: "当前运行环境没有 DSH 网页搜索服务,全局路由暂不生效;Claude CLI 的 MCP 搜索不受影响。",
|
|
159
160
|
searchNotWritable: "当前 profile 不允许写入设置。",
|
|
160
161
|
searchUnknown: "未知"
|
|
161
162
|
};
|
|
@@ -259,10 +260,11 @@ window.__ModuleLoader__.load({
|
|
|
259
260
|
versionLater: "Later",
|
|
260
261
|
searchTitle: "Web search",
|
|
261
262
|
searchScope: "DSH-wide setting",
|
|
262
|
-
searchIntro: "
|
|
263
|
+
searchIntro: "DSH’s web_search and Claude CLI’s MCP search can use the DeepSeek/GPT backend selected here. Each search is a separate model call billed to the plugin-stored keys.",
|
|
264
|
+
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.",
|
|
263
265
|
searchChecking: "Reading the search preference…",
|
|
264
266
|
searchLoadFailed: "Could not read or save the search preference",
|
|
265
|
-
searchModeTitle: "
|
|
267
|
+
searchModeTitle: "DSH routing",
|
|
266
268
|
searchModeDefault: "Off",
|
|
267
269
|
searchModeDefaultHint: "Leave DSH search routing untouched (the default). Switching back here removes the search patch this plugin wrote into the profile.",
|
|
268
270
|
searchModeAuto: "By model",
|
|
@@ -279,7 +281,7 @@ window.__ModuleLoader__.load({
|
|
|
279
281
|
searchApplyFailed: "Could not write the search patch: {error}",
|
|
280
282
|
searchForeign: "{names} subscription plugin detected: the models it routes keep its own search choice; only the other requests reach the choice made here.",
|
|
281
283
|
searchOverridden: "The base search is {base}, not PackyCode: the reload may still be running, or another plugin’s patch overrides it.",
|
|
282
|
-
searchUnavailable: "This runtime has no DSH web search service;
|
|
284
|
+
searchUnavailable: "This runtime has no DSH web search service; global routing has no effect. Claude CLI’s MCP search is unaffected.",
|
|
283
285
|
searchNotWritable: "This profile does not allow settings writes.",
|
|
284
286
|
searchUnknown: "unknown"
|
|
285
287
|
};
|
|
@@ -1062,6 +1064,10 @@ window.__ModuleLoader__.load({
|
|
|
1062
1064
|
className: "pkc-note",
|
|
1063
1065
|
children: t("searchIntro")
|
|
1064
1066
|
}),
|
|
1067
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1068
|
+
className: "pkc-note",
|
|
1069
|
+
children: t("searchCliHint")
|
|
1070
|
+
}),
|
|
1065
1071
|
state === void 0 && error === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1066
1072
|
className: "pkc-note",
|
|
1067
1073
|
role: "status",
|