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/SECURITY.md CHANGED
@@ -15,18 +15,18 @@
15
15
 
16
16
  ## Claude requests
17
17
 
18
- - Claude requests use one of two transports, chosen by the request key's PackyCode groups (or the user's pin): keys in `cc` send them through this device's official Claude Code CLI; every other key uses the plugin's HTTP Messages route. Both carry the same payload; neither has any fallback to the other, to another provider, or to another credential.
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 on both routes. 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.
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 transport
23
+ ## The Claude Code CLI route
24
24
 
25
- - The CLI is a transport, not an agent: it runs with all of its own tools disabled (`--tools ""`), so it cannot read, write or execute anything itself. The tools it can see are the ones DSH offered for that request, served by an MCP bridge; every call is answered with the result DSH produced after running the tool under its own permissions and sandbox.
26
- - The bridge is a per-process Streamable HTTP server bound to `127.0.0.1` on a random port. It requires a random 256-bit capability on every request, rejects foreign `Host` and `Origin` headers, and closes with its process. The capability lives only in an owner-only (`0600`) config file inside an owner-only run directory under the CLI home; it never appears in a command line.
27
- - The CLI runs with an isolated config home (`~/.dsh/packycode-claude-cli`), `--setting-sources ""`, `--strict-mcp-config`, `--disable-slash-commands`, `--no-session-persistence`, and CLAUDE.md, auto-memory, auto-update, telemetry and non-essential traffic 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.
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. The DSH system prompt and the conversation transcript the CLI resumes are written to that owner-only run directory and removed when the process ends; directories left by a crashed host are removed after a day.
29
- - The CLI's own retries, model fallback, refusal fallback and compaction are disabled: one DSH step is one API request, and retries follow DSH's policy. Processes are stopped on cancellation, after 20 idle minutes, beyond eight live conversations, and when the plugin unloads.
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 请求由本机 Claude Code CLI 发出。",
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 客户端,这些 Key 的 Claude 请求由本机的 Claude Code CLI 发出;cc-sale、cc-expensive、claude-officially 等分组继续走插件内置的 HTTP 通道。通道由 Key 所在的分组决定。两种通道都由 DSH 执行工具、审批权限、计划模式、附件和历史,体验一致,CLI 只负责把请求发给 PackyCode。",
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 requests are sent by this device's Claude Code CLI.",
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 requests on cc keys go through this device's Claude Code CLI; cc-sale, cc-expensive, claude-officially and other groups keep the built-in HTTP route. The key's groups decide the route. Either way DSH runs the tools, permissions, plan mode, attachments and history the same; the CLI only carries the request to PackyCode.",
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 === "cli" ? fill(t("keyClaudeCliHint"), { groups: (route.groups ?? []).join(" / ") || "cc" }) : t("keyClaudeHttpHint");
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",