dsh-packycode-api 1.3.8 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +53 -0
- package/README.en.md +29 -27
- package/README.md +29 -27
- package/SECURITY.md +8 -8
- package/lib/client.js +35 -5
- package/lib/index.js +4581 -3375
- package/package.json +1 -1
package/SECURITY.md
CHANGED
|
@@ -15,18 +15,18 @@
|
|
|
15
15
|
|
|
16
16
|
## Claude requests
|
|
17
17
|
|
|
18
|
-
- Claude requests use one of two
|
|
18
|
+
- Claude requests use one of two routes, chosen only by the request key's PackyCode groups: on keys in `cc`, and on a key whose groups are not read yet, this device's official Claude Code CLI carries out the session as the agent; every other key uses the plugin's HTTP Messages route with DSH's own agent. A turn that starts on the CLI finishes there. Neither route has any fallback to the other after a failure, to another provider, or to another credential.
|
|
19
19
|
- The HTTP route's compatibility headers and session metadata do not load a CLI login or external configuration. Bearer authentication uses only the plugin's selected conversation key; images keep their separate credential record.
|
|
20
|
-
- DSH owns tool execution, permissions, plan mode, attachments and history
|
|
20
|
+
- On the HTTP route DSH owns tool execution, permissions, plan mode, attachments and history. Wire tool aliases are restored only for tools offered on that request; unknown aliases are not decoded into host tools. Saved images from older CLI-backed sessions remain readable without executing their old tools.
|
|
21
21
|
- Captured client-policy refusals do not disable keys or switch providers or transports. The specific pre-stream anomalies covered by the HTTP route may replay the exact bytes and credential once; ordinary policy refusals, HTTP 429 and accepted streams are excluded. Cancellation aborts the replay.
|
|
22
22
|
|
|
23
|
-
## The Claude Code CLI
|
|
23
|
+
## The Claude Code CLI route
|
|
24
24
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
- The CLI runs with an isolated config home (`~/.dsh/packycode-claude-cli`), `--setting-sources
|
|
28
|
-
- The request key reaches the child only as `ANTHROPIC_AUTH_TOKEN` in its environment, with the endpoint as `ANTHROPIC_BASE_URL`; it is never written to a file, an argument, a transcript or a log.
|
|
29
|
-
- The CLI's own retries
|
|
25
|
+
- Claude Code is the agent: it runs with its own system prompt and its own tools, so it reads, writes and executes on this device itself, with the user's privileges and outside DSH's sandbox. The plugin never adds DSH's prompt or tools to it, and of DSH's messages it passes on only the user's own (DSH's runtime context, skill catalog, `AGENTS.md` and notices stay in DSH).
|
|
26
|
+
- Every permission prompt it sends (`--permission-prompt-tool stdio`) is answered by DSH: the call appears as a `claude_code` tool card, and DSH's approval — the user, or Auto review under the `auto` preset — decides it under the session's permission preset. The CLI's permission mode follows that preset: plan mode is `plan`, `workspace-write` is `acceptEdits`, `read-only` and `auto` are `default`, and only `danger-full-access` (approval `never`) is `bypassPermissions`, which asks nothing. A refusal is passed back with its reason and the call does not run. Calls the CLI allows by itself (reads, read-only commands) run without a prompt and are shown afterwards. Prompts about calls DSH never showed (a subagent's) go to DSH's approval without a card. Plans go to DSH's plan review and questions to DSH's question UI; the plugin never answers a prompt on its own.
|
|
27
|
+
- The CLI runs with an isolated config home (`~/.dsh/packycode-claude-cli`), `--setting-sources user` (only that home's settings: never `~/.claude` or a project's `.claude/settings.json` and hooks) and `--strict-mcp-config` with no servers (never a project's `.mcp.json`), so a repository cannot point the CLI at another endpoint or run hooks with the key. Auto-memory, background tasks, auto-update, telemetry and non-essential traffic are disabled. Inherited `ANTHROPIC_*`, `CLAUDE_*`, `MCP_*`, `DISABLE_*` and `ENABLE_*` variables are removed, so the user's own Claude Code login, API key, base URL, model and settings never reach it. A project's `CLAUDE.md` is read as Claude Code always reads it.
|
|
28
|
+
- The request key reaches the child only as `ANTHROPIC_AUTH_TOKEN` in its environment, with the endpoint as `ANTHROPIC_BASE_URL`; it is never written to a file, an argument, a transcript or a log. Claude Code keeps its own session records and plan files in the CLI home's `projects/dsh-packycode` and `plans` directories; when a session is rebuilt from DSH's history, the plugin writes that transcript there as an owner-only (`0600`) file. `dsh-sessions.json` maps DSH sessions to Claude Code sessions by ids and response fingerprints only.
|
|
29
|
+
- The CLI's own retries and model and refusal fallbacks are disabled: one DSH step is one API request, and retries follow DSH's policy. Turns Claude Code would start on its own (scheduled prompts) are interrupted, because DSH could not show them. Processes are stopped on cancellation, after 20 idle minutes, beyond eight live conversations, and when the plugin unloads.
|
|
30
30
|
- Installing the CLI from the settings panel runs `npm install -g @anthropic-ai/claude-code` with constant arguments; on Windows the npm launcher is resolved to the program it forwards to, so no shell parses user text.
|
|
31
31
|
|
|
32
32
|
## Reporting
|
package/lib/client.js
CHANGED
|
@@ -124,10 +124,11 @@ window.__ModuleLoader__.load({
|
|
|
124
124
|
groupsStale: "分组为上次读取的结果",
|
|
125
125
|
keyClaudeCli: "Claude 经官方 CLI",
|
|
126
126
|
keyClaudeHttp: "Claude 经 HTTP",
|
|
127
|
-
keyClaudeCliHint: "分组 {groups} 只接受官方 Claude Code 客户端,这个 Key 的 Claude
|
|
127
|
+
keyClaudeCliHint: "分组 {groups} 只接受官方 Claude Code 客户端,这个 Key 的 Claude 会话由本机 Claude Code CLI 直接完成。",
|
|
128
128
|
keyClaudeHttpHint: "这个 Key 的 Claude 请求走插件内置的 HTTP 通道。",
|
|
129
|
+
keyClaudeCliUnreadHint: "还没读到这个 Key 的分组,Claude 会话先交给本机 Claude Code CLI;读到分组后按分组选通道。",
|
|
129
130
|
cliTitle: "Claude Code CLI",
|
|
130
|
-
cliIntro: "cc 分组只接受官方 Claude Code
|
|
131
|
+
cliIntro: "cc 分组只接受官方 Claude Code 客户端,所以这些 Key 的 Claude 会话由本机的 Claude Code CLI 直接完成:它用自己的系统提示词和工具,自己读写文件、执行命令。DSH 把每次工具调用显示成卡片;Claude Code 请求授权时,按当前权限预设由你或自动审查决定,计划和提问也交给 DSH 审阅。命令不经过 DSH 的沙箱,DSH 自己的工具(子代理、todo、生图等)在这些会话里不可用。cc-sale、cc-expensive、claude-officially 等分组继续走插件内置的 HTTP 通道,通道由 Key 所在的分组决定。",
|
|
131
132
|
cliProcesses: "运行中的 CLI 会话 {live} 个 · 已启动 {opened} 次 · 续接 {continued} 次",
|
|
132
133
|
cliChecking: "正在检测本机的 Claude Code CLI…",
|
|
133
134
|
cliInstalled: "已安装",
|
|
@@ -194,6 +195,10 @@ window.__ModuleLoader__.load({
|
|
|
194
195
|
versionUpdate: "更新插件",
|
|
195
196
|
versionUpdating: "正在更新…",
|
|
196
197
|
versionUpdateFailed: "更新失败,请重试,或在插件页重新安装。",
|
|
198
|
+
versionUpdateSyncing: "v{version} 刚发布不久,安装源还没有同步到这个版本。请过几分钟再更新;国内镜像可能要等更久。",
|
|
199
|
+
versionUpdateSyncingFrom: "v{version} 刚发布不久,安装源 {registry} 还没有同步到这个版本。请过几分钟再更新;国内镜像可能要等更久。",
|
|
200
|
+
versionUpdateUnreachable: "连不上安装源,没能下载 v{version}。请检查网络或代理后重试。",
|
|
201
|
+
versionUpdateUnreachableFrom: "连不上安装源 {registry},没能下载 v{version}。请检查网络或代理后重试。",
|
|
197
202
|
versionCooling: "v{version} 发布不久,DSH 的 pnpm 要等新版本过了发布冷却期才会安装,请稍后再更新。",
|
|
198
203
|
versionCoolingUntil: "v{version} 发布不久,DSH 的 pnpm 要等新版本过了发布冷却期才会安装,{time} 之后可以更新。",
|
|
199
204
|
versionUpdated: "已更新到 v{version}。",
|
|
@@ -360,10 +365,11 @@ window.__ModuleLoader__.load({
|
|
|
360
365
|
groupsStale: "groups from the last read",
|
|
361
366
|
keyClaudeCli: "Claude via official CLI",
|
|
362
367
|
keyClaudeHttp: "Claude via HTTP",
|
|
363
|
-
keyClaudeCliHint: "Group {groups} only serves the official Claude Code client, so this key's Claude
|
|
368
|
+
keyClaudeCliHint: "Group {groups} only serves the official Claude Code client, so this key's Claude sessions are carried out by this device's Claude Code CLI.",
|
|
364
369
|
keyClaudeHttpHint: "This key's Claude requests use the plugin's built-in HTTP route.",
|
|
370
|
+
keyClaudeCliUnreadHint: "This key's groups are not read yet, so its Claude sessions go to this device's Claude Code CLI until they are.",
|
|
365
371
|
cliTitle: "Claude Code CLI",
|
|
366
|
-
cliIntro: "The cc group only serves the official Claude Code client, so Claude
|
|
372
|
+
cliIntro: "The cc group only serves the official Claude Code client, so Claude sessions on cc keys are carried out by this device's Claude Code CLI itself, with its own system prompt and tools: it reads and writes files and runs commands. DSH shows each tool call as a card; when Claude Code asks for permission, you or Auto review decide under the session's permission preset, and plans and questions come to DSH for review. Commands run outside DSH's sandbox, and DSH's own tools (subagents, todos, image generation and so on) are not available in these sessions. cc-sale, cc-expensive, claude-officially and other groups keep the built-in HTTP route; the key's groups decide the route.",
|
|
367
373
|
cliProcesses: "{live} CLI session(s) running · started {opened} · continued {continued}",
|
|
368
374
|
cliChecking: "Checking this device for the Claude Code CLI…",
|
|
369
375
|
cliInstalled: "Installed",
|
|
@@ -422,6 +428,10 @@ window.__ModuleLoader__.load({
|
|
|
422
428
|
versionUpdate: "Update plugin",
|
|
423
429
|
versionUpdating: "Updating…",
|
|
424
430
|
versionUpdateFailed: "The update failed. Try again, or reinstall from the Plugins page.",
|
|
431
|
+
versionUpdateSyncing: "v{version} was published only recently and the install source has not synced it yet. Update again in a few minutes; a regional mirror can take longer.",
|
|
432
|
+
versionUpdateSyncingFrom: "v{version} was published only recently and the install source {registry} has not synced it yet. Update again in a few minutes; a regional mirror can take longer.",
|
|
433
|
+
versionUpdateUnreachable: "Could not reach the install source to download v{version}. Check the network or proxy, then try again.",
|
|
434
|
+
versionUpdateUnreachableFrom: "Could not reach the install source {registry} to download v{version}. Check the network or proxy, then try again.",
|
|
425
435
|
versionCooling: "v{version} was published recently. DSH’s pnpm installs a new version only after its release cooldown; update again later.",
|
|
426
436
|
versionCoolingUntil: "v{version} was published recently. DSH’s pnpm installs a new version only after its release cooldown; update after {time}.",
|
|
427
437
|
versionUpdated: "Updated to v{version}.",
|
|
@@ -2082,7 +2092,7 @@ window.__ModuleLoader__.load({
|
|
|
2082
2092
|
function ClaudeRoute({ group, t }) {
|
|
2083
2093
|
const route = group.claudeTransport;
|
|
2084
2094
|
if (route === void 0 || !CLAUDE_MODELS.some((id) => group.coverage?.[id] === true)) return null;
|
|
2085
|
-
const hint = route.transport
|
|
2095
|
+
const hint = route.transport !== "cli" ? t("keyClaudeHttpHint") : route.reason === "unknown" ? t("keyClaudeCliUnreadHint") : fill(t("keyClaudeCliHint"), { groups: (route.groups ?? []).join(" / ") || "cc" });
|
|
2086
2096
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2087
2097
|
className: "pkc-groups",
|
|
2088
2098
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -3036,6 +3046,11 @@ window.__ModuleLoader__.load({
|
|
|
3036
3046
|
return new Date(ms).toISOString().slice(0, 16).replace("T", " ");
|
|
3037
3047
|
}
|
|
3038
3048
|
}
|
|
3049
|
+
/** Copy for an update pnpm could not fetch: the source still syncing, or unreachable; with and without its host. */
|
|
3050
|
+
const UPDATE_BLOCKED = {
|
|
3051
|
+
syncing: ["versionUpdateSyncing", "versionUpdateSyncingFrom"],
|
|
3052
|
+
unreachable: ["versionUpdateUnreachable", "versionUpdateUnreachableFrom"]
|
|
3053
|
+
};
|
|
3039
3054
|
function VersionCard({ call, t }) {
|
|
3040
3055
|
const [info, setInfo] = react.useState();
|
|
3041
3056
|
const [loading, setLoading] = react.useState(true);
|
|
@@ -3044,6 +3059,8 @@ window.__ModuleLoader__.load({
|
|
|
3044
3059
|
const [updateFailed, setUpdateFailed] = react.useState(false);
|
|
3045
3060
|
/** A version pnpm still holds back under the profile's release-age policy. */
|
|
3046
3061
|
const [pending, setPending] = react.useState();
|
|
3062
|
+
/** A version pnpm could not fetch: its install source still syncing, or unreachable. */
|
|
3063
|
+
const [blocked, setBlocked] = react.useState();
|
|
3047
3064
|
const [updated, setUpdated] = react.useState();
|
|
3048
3065
|
const [restartHint, setRestartHint] = react.useState(false);
|
|
3049
3066
|
const generation = react.useRef(0);
|
|
@@ -3069,11 +3086,16 @@ window.__ModuleLoader__.load({
|
|
|
3069
3086
|
setUpdating(true);
|
|
3070
3087
|
setUpdateFailed(false);
|
|
3071
3088
|
setPending(void 0);
|
|
3089
|
+
setBlocked(void 0);
|
|
3072
3090
|
call("plugin/update").then((value) => {
|
|
3073
3091
|
if (value?.pending === true) {
|
|
3074
3092
|
setPending(value);
|
|
3075
3093
|
return;
|
|
3076
3094
|
}
|
|
3095
|
+
if (UPDATE_BLOCKED[value?.failed] !== void 0) {
|
|
3096
|
+
setBlocked(value);
|
|
3097
|
+
return;
|
|
3098
|
+
}
|
|
3077
3099
|
setUpdated(value);
|
|
3078
3100
|
setRestartHint(false);
|
|
3079
3101
|
}).catch(() => setUpdateFailed(true)).finally(() => setUpdating(false));
|
|
@@ -3135,6 +3157,14 @@ window.__ModuleLoader__.load({
|
|
|
3135
3157
|
role: "alert",
|
|
3136
3158
|
children: t("versionUpdateFailed")
|
|
3137
3159
|
}),
|
|
3160
|
+
blocked !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3161
|
+
className: blocked.failed === "syncing" ? "pkc-note" : "pkc-error",
|
|
3162
|
+
role: blocked.failed === "syncing" ? "status" : "alert",
|
|
3163
|
+
children: fill(t(UPDATE_BLOCKED[blocked.failed][typeof blocked.registry === "string" ? 1 : 0]), {
|
|
3164
|
+
version: blocked.version,
|
|
3165
|
+
registry: blocked.registry
|
|
3166
|
+
})
|
|
3167
|
+
}),
|
|
3138
3168
|
pending !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3139
3169
|
className: "pkc-note",
|
|
3140
3170
|
role: "status",
|