dsh-packycode-api 1.2.8 → 1.2.9
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 +6 -0
- package/README.en.md +5 -5
- package/README.md +5 -5
- package/lib/client.js +16 -4
- package/lib/index.js +40 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.2.9
|
|
4
|
+
|
|
5
|
+
- **Remove all works again.** **Remove all** under **Accounts and keys** answered "读取 PackyCode 状态失败: PackyCode request failed" and kept every key. Emptying the ring wrote `activeId: undefined`, and DSH's credential store (`credentials-local`) accepts only plain JSON in a grant payload, so it refused the whole write. The same refusal hit removing the last conversation or image key on its own, and marking the only key unusable after its quota ran out or the gateway rejected it. That last case was only logged ("could not move past key …"), so a lone exhausted key was never shown as disabled. The ring now leaves out a field that has no value: an empty ring stores no `activeId`, and a disabled mark from a hand-edited record stores no empty reason.
|
|
6
|
+
- A credential-store failure now reads "PackyCode could not save the key change in DSH's credential store" instead of the generic "PackyCode request failed". A refused key change is labelled 更新 Key 失败 / "Could not update the keys" instead of being reported as a failed status read.
|
|
7
|
+
- Validation, 2026-10-16: 444 offline tests (7 new), both rebuilt bundles and the versioned tarball. The suite's in-memory credential store now refuses non-JSON payloads exactly as DSH 0.2.0-rc.2's `credentials-local` does, and four existing key-ring tests failed against it before the fix. The change is host-side key storage, not the catalog, the provider composition or failure classification, so no live gateway call was made. No DSH restart.
|
|
8
|
+
|
|
3
9
|
## 1.2.8
|
|
4
10
|
|
|
5
11
|
- **Diagnostics for request problems.** Settings → PackyCode gains a **Diagnostics** card (诊断信息). A user who hits "已达到输出 token 上限" or repeated failures picks the session (the 20 most recent top-level sessions, newest first, labelled by local start time, the workspace folder's base name and whether it is open), clicks **Generate diagnostics** and then **Copy**, and sends the text to the plugin author. Without a clipboard API the text is selected for a manual copy. The host builds the text from DSH's session history over two new RPC endpoints, `diagnostics/sessions` and `diagnostics/session`, in format `packycode-diagnostics/1`. It holds the plugin version; the session id, start time and live state; each stored key by position with its groups and reachable models; the logged request settings (provider, model, reasoning effort, `maxTokens`, and whether DSH's adapter supplied that ceiling); the steps that ended at the output limit; the latest steps' token usage and finish reasons; turn endings; retries and failed attempts with their codes; and the compaction count. Error messages are redacted and cut to 160 characters. Conversation text, reasoning, titles, tool arguments and results, paths, key labels and keys never enter it. An invalid session id or a runtime without session history is refused with its own message.
|
package/README.en.md
CHANGED
|
@@ -48,10 +48,10 @@ You need **DeepSeek Harness** and a **PackyCode (PackyAPI) API key**. For DSH se
|
|
|
48
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**:
|
|
49
49
|
|
|
50
50
|
```text
|
|
51
|
-
dsh-packycode-api@1.2.
|
|
51
|
+
dsh-packycode-api@1.2.9
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
Choose the **official** install source, then click **Install**. `1.2.
|
|
54
|
+
Choose the **official** install source, then click **Install**. `1.2.9` was the latest release when this was written; the [npm page](https://www.npmjs.com/package/dsh-packycode-api) shows the current one.
|
|
55
55
|
|
|
56
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**.
|
|
57
57
|
|
|
@@ -72,7 +72,7 @@ Choose a model from the `PackyCode` group. `deepseek-flash`, `gpt-6.1-sol`, `gpt
|
|
|
72
72
|
|
|
73
73
|
The **Plugins** page shows the installed state and version, and is also where you enable, disable, or uninstall.
|
|
74
74
|
|
|
75
|
-
**For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.2.
|
|
75
|
+
**For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.2.9`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
|
|
76
76
|
|
|
77
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.
|
|
78
78
|
|
|
@@ -213,7 +213,7 @@ Only GPT Responses requests keep `prompt_cache_key`; other Responses models omit
|
|
|
213
213
|
|
|
214
214
|
## Update and uninstall
|
|
215
215
|
|
|
216
|
-
**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 from the **Plugins** page works too, again with the version in the package name (for example `dsh-packycode-api@1.2.
|
|
216
|
+
**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 from the **Plugins** page works too, again with the version in the package name (for example `dsh-packycode-api@1.2.9`); without it you may get a version that is merely the newest one published at least 24 hours ago.
|
|
217
217
|
|
|
218
218
|
**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.
|
|
219
219
|
|
|
@@ -229,7 +229,7 @@ ls ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/node_modules
|
|
|
229
229
|
|
|
230
230
|
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.
|
|
231
231
|
|
|
232
|
-
Recovery: **uninstall** the plugin on the **Plugins** page, **install** it again with the version in the package name (for example `dsh-packycode-api@1.2.
|
|
232
|
+
Recovery: **uninstall** the plugin on the **Plugins** page, **install** it again with the version in the package name (for example `dsh-packycode-api@1.2.9`), 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.
|
|
233
233
|
|
|
234
234
|
**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:
|
|
235
235
|
|
package/README.md
CHANGED
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
打开桌面应用的**插件**页,点击**添加插件**,在**包名或地址**中填入**带版本号**的包名:
|
|
49
49
|
|
|
50
50
|
```text
|
|
51
|
-
dsh-packycode-api@1.2.
|
|
51
|
+
dsh-packycode-api@1.2.9
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
在**安装源**中选择**官方源**,然后点击**安装**。`1.2.
|
|
54
|
+
在**安装源**中选择**官方源**,然后点击**安装**。`1.2.9` 是写这份说明时的最新版,当前最新版本号以 [npm 页面](https://www.npmjs.com/package/dsh-packycode-api) 为准。
|
|
55
55
|
|
|
56
56
|
> **一定要带版本号。** 只填 `dsh-packycode-api` 时,安装前的提示显示的是 npm 上的最新版,但 DSH 自带的 pnpm 默认只安装发布满 24 小时的版本,实际装上的可能是好几个版本之前的旧版,而安装提示里看不出这一点。填写精确版本时,pnpm 会直接安装这个版本,并自动把它加入 profile 的 `minimumReleaseAgeExclude`。装好后可以在 **设置 → PackyCode → 插件版本** 核对「当前版本」。
|
|
57
57
|
|
|
@@ -72,7 +72,7 @@ dsh-packycode-api@1.2.8
|
|
|
72
72
|
|
|
73
73
|
桌面应用的**插件**页可以看到已安装状态与版本,也可以在那里启用、停用或卸载。
|
|
74
74
|
|
|
75
|
-
**仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.2.
|
|
75
|
+
**仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.2.9`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
|
|
76
76
|
|
|
77
77
|
本地开发要加 `link:` 前缀:`dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`。**不要直接写路径(或 `file:`)** —— 那样的安装会把整个仓库目录(连同 `node_modules`)复制进 profile,之后它会在 profile 内部挡住 DSH 自带的包,插件看起来像没装,见「常见问题」。已经那样装过的话,先卸载再按上面的方式重装。
|
|
78
78
|
|
|
@@ -213,7 +213,7 @@ Responses 请求只有 GPT 模型保留 `prompt_cache_key`,其他 Responses
|
|
|
213
213
|
|
|
214
214
|
## 更新与卸载
|
|
215
215
|
|
|
216
|
-
**更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装,同样要填写带版本号的包名(例如 `dsh-packycode-api@1.2.
|
|
216
|
+
**更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装,同样要填写带版本号的包名(例如 `dsh-packycode-api@1.2.9`),否则装上的可能是发布满 24 小时的旧版。
|
|
217
217
|
|
|
218
218
|
**从本地路径安装切回官方源时,必须先卸载。** 「更新」是 `pnpm add`,它只重写包目录里的文件,不会删除更早一次本地路径安装留在包目录内的 `node_modules`;那份旧依赖会继续挡住 DSH 自带的包,插件行加载失败且看不出原因。「卸载」执行的是 `pnpm remove`,会删掉整个包目录,重装才是干净的。用 `node scripts/install-check.mjs` 可以确认当前 profile 是否处于这个状态。
|
|
219
219
|
|
|
@@ -229,7 +229,7 @@ ls ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/node_modules
|
|
|
229
229
|
|
|
230
230
|
有输出就是残留:从 npm 安装的包不会自带 `node_modules`,这一份通常来自更早一次「本地路径」安装(`file:` 或直接写路径,而不是 `link:`)。它位于 profile 目录内部,而 DSH 解析插件导入时优先使用 profile 内的副本,所以插件拿到的仍是那份旧依赖 —— 例如 `@deepseek-ai/schemastery` 3.18.2 没有 `Schema.volatile()`,模块在导入阶段就抛错。导入失败时 Loader 不会为这一行创建 fiber,客户端 bundle 也不会被组合,于是模型路由、RPC 通道和设置页全都不会出现。
|
|
231
231
|
|
|
232
|
-
修复:到**插件**页**卸载**本插件,再用带版本号的包名重新**安装**(例如 `dsh-packycode-api@1.2.
|
|
232
|
+
修复:到**插件**页**卸载**本插件,再用带版本号的包名重新**安装**(例如 `dsh-packycode-api@1.2.9`),然后完全退出并重新打开桌面应用。卸载执行的是 `pnpm remove`,会删掉整个包目录;直接重装或点「更新」只重写文件,不会清掉这份残留。也可以手动删掉上面那个 `node_modules` 再重启。
|
|
233
233
|
|
|
234
234
|
**首次安装后,设置页每张卡片都显示 `transport failure for /packycode-api/…: HTTP 405`?** 实际装上的是 1.1.6 或更早的版本,通常是因为安装时只填了包名:安装提示显示的是最新版,pnpm 实际装的却是发布满 24 小时的旧版(见「安装插件」)。这些旧版要等 DSH 重启、重建它的 `connection` 服务之后,才能注册设置通道。所以首次安装后 `/packycode-api` 通道还不存在,请求落到静态页面,返回 405;模型路由和设置页本身照常加载。1.1.7 起首次安装不需要重启。先确认装上的版本:
|
|
235
235
|
|
package/lib/client.js
CHANGED
|
@@ -118,6 +118,7 @@ window.__ModuleLoader__.load({
|
|
|
118
118
|
add: "添加",
|
|
119
119
|
notWritable: "当前 profile 不允许写入设置,改动只在本次运行内生效。",
|
|
120
120
|
error: "读取 PackyCode 状态失败",
|
|
121
|
+
saveError: "更新 Key 失败",
|
|
121
122
|
groupsTitle: "分组",
|
|
122
123
|
groupsChecking: "正在读取分组…",
|
|
123
124
|
groupsUnknown: "分组未读到",
|
|
@@ -317,6 +318,7 @@ window.__ModuleLoader__.load({
|
|
|
317
318
|
add: "Add",
|
|
318
319
|
notWritable: "This profile does not allow settings writes; changes apply to this run only.",
|
|
319
320
|
error: "Could not read PackyCode status",
|
|
321
|
+
saveError: "Could not update the keys",
|
|
320
322
|
groupsTitle: "Groups",
|
|
321
323
|
groupsChecking: "Reading groups…",
|
|
322
324
|
groupsUnknown: "Groups not read",
|
|
@@ -2192,7 +2194,10 @@ window.__ModuleLoader__.load({
|
|
|
2192
2194
|
setStatus(nextStatus);
|
|
2193
2195
|
setBalance(nextBalance);
|
|
2194
2196
|
}).catch((failure) => {
|
|
2195
|
-
if (generation.current === current) setError(
|
|
2197
|
+
if (generation.current === current) setError({
|
|
2198
|
+
kind: "read",
|
|
2199
|
+
message: clearMessage(failure)
|
|
2200
|
+
});
|
|
2196
2201
|
}).finally(() => {
|
|
2197
2202
|
if (generation.current === current) setBusy(false);
|
|
2198
2203
|
});
|
|
@@ -2203,14 +2208,21 @@ window.__ModuleLoader__.load({
|
|
|
2203
2208
|
generation.current += 1;
|
|
2204
2209
|
};
|
|
2205
2210
|
}, [load]);
|
|
2211
|
+
/** A refused change says so; a balance read after a stored change is a read. */
|
|
2206
2212
|
const mutate = (endpoint, payload) => {
|
|
2207
2213
|
setBusy(true);
|
|
2208
2214
|
setError(void 0);
|
|
2209
2215
|
return call(endpoint, payload).then((nextStatus) => {
|
|
2210
2216
|
setStatus(nextStatus);
|
|
2211
2217
|
readGroups(false);
|
|
2212
|
-
return call("balance", { force: true })
|
|
2213
|
-
|
|
2218
|
+
return call("balance", { force: true }).then(setBalance, (failure) => setError({
|
|
2219
|
+
kind: "read",
|
|
2220
|
+
message: clearMessage(failure)
|
|
2221
|
+
}));
|
|
2222
|
+
}, (failure) => setError({
|
|
2223
|
+
kind: "save",
|
|
2224
|
+
message: clearMessage(failure)
|
|
2225
|
+
})).finally(() => setBusy(false));
|
|
2214
2226
|
};
|
|
2215
2227
|
const addKey = (event) => {
|
|
2216
2228
|
event.preventDefault();
|
|
@@ -2319,7 +2331,7 @@ window.__ModuleLoader__.load({
|
|
|
2319
2331
|
error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2320
2332
|
className: "pkc-error",
|
|
2321
2333
|
role: "alert",
|
|
2322
|
-
children: `${t("error")}: ${error}`
|
|
2334
|
+
children: `${t(error.kind === "save" ? "saveError" : "error")}: ${error.message}`
|
|
2323
2335
|
}),
|
|
2324
2336
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
2325
2337
|
className: "pkc-advanced",
|
package/lib/index.js
CHANGED
|
@@ -6351,28 +6351,48 @@ var PackyCodeKeyRing = class {
|
|
|
6351
6351
|
async #read() {
|
|
6352
6352
|
return normalizeState(await this.#credentials.readRecord(this.#recordKey));
|
|
6353
6353
|
}
|
|
6354
|
+
/**
|
|
6355
|
+
* Replace the record with what `mutate` decides. The store accepts plain
|
|
6356
|
+
* JSON only and refuses a payload holding `undefined`, so a field without a
|
|
6357
|
+
* value is left out: an emptied ring has no `activeId`, and a disabled mark
|
|
6358
|
+
* from a hand-edited record may have no reason. A store failure is reported
|
|
6359
|
+
* in the ring's own words, since the store's may quote the credential file.
|
|
6360
|
+
*/
|
|
6354
6361
|
async #write(mutate) {
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
key: candidate.key,
|
|
6367
|
-
addedAt: candidate.addedAt,
|
|
6368
|
-
...candidate.disabledAt === void 0 ? {} : {
|
|
6369
|
-
disabledAt: candidate.disabledAt,
|
|
6370
|
-
disabledReason: candidate.disabledReason
|
|
6371
|
-
}
|
|
6372
|
-
}))
|
|
6362
|
+
let refused = false;
|
|
6363
|
+
let next;
|
|
6364
|
+
try {
|
|
6365
|
+
next = await this.#credentials.modifyRecord(this.#recordKey, async (current) => {
|
|
6366
|
+
const state = normalizeState(current);
|
|
6367
|
+
let updated;
|
|
6368
|
+
try {
|
|
6369
|
+
updated = await mutate(state);
|
|
6370
|
+
} catch (error) {
|
|
6371
|
+
refused = true;
|
|
6372
|
+
throw error;
|
|
6373
6373
|
}
|
|
6374
|
-
|
|
6375
|
-
|
|
6374
|
+
if (updated === void 0) return current;
|
|
6375
|
+
return {
|
|
6376
|
+
kind: "grant",
|
|
6377
|
+
payload: {
|
|
6378
|
+
version: RECORD_VERSION,
|
|
6379
|
+
...updated.activeId === void 0 ? {} : { activeId: updated.activeId },
|
|
6380
|
+
keys: updated.keys.map((candidate) => ({
|
|
6381
|
+
id: candidate.id,
|
|
6382
|
+
label: candidate.label,
|
|
6383
|
+
key: candidate.key,
|
|
6384
|
+
addedAt: candidate.addedAt,
|
|
6385
|
+
...candidate.disabledAt === void 0 ? {} : { disabledAt: candidate.disabledAt },
|
|
6386
|
+
...candidate.disabledAt === void 0 || candidate.disabledReason === void 0 ? {} : { disabledReason: candidate.disabledReason }
|
|
6387
|
+
}))
|
|
6388
|
+
}
|
|
6389
|
+
};
|
|
6390
|
+
});
|
|
6391
|
+
} catch (error) {
|
|
6392
|
+
if (refused) throw error;
|
|
6393
|
+
throw new Error("PackyCode could not save the key change in DSH's credential store", { cause: error });
|
|
6394
|
+
}
|
|
6395
|
+
return normalizeState(next);
|
|
6376
6396
|
}
|
|
6377
6397
|
/** The keys as the browser may see them. */
|
|
6378
6398
|
async list() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-packycode-api",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"description": "Use PackyCode API keys in DeepSeek Harness with multi-protocol models, image generation and editing, separate key rings, and balance display",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|