From de99fd4cfb13445c145c18ee4f5ba651d6666fb9 Mon Sep 17 00:00:00 2001 From: Menghuan1918 Date: Mon, 21 Sep 2026 21:00:09 +0800 Subject: [PATCH] docs: record the 0.1.6-alpha.2 adaptation and resync the user docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the per-version adaptation record (docs/plans/2026-09-21-…-adaptation.md), rewrites AGENTS.md §3 for the new baseline (the two silent contract breaks, the terminal/browser handoff, the new official plugin-manager surface, the three ui-primitives breaks, the widened primitives bare-import set), and updates both READMEs and the integration guide for the v0.20.0 feature set. Also retires the support text the terminal deletion made false: the install flow is one step again (no build-script approval), the FAQ's two node-pty rows collapse into one pointing at DSH's own terminal, the platform note no longer promises prebuilt native binaries (there are no native deps left), and the installers drop the -Repair mode and their allowBuilds writes along with pnpm-workspace.yaml's now-empty allowBuilds block. Removes the dead browserNoSandboxWarning locale key (its setting went with the plugin's browser) and tightens theme.spec's capsule guard so a literal colour fails it. The e2e resolver now refuses a PATH that is not on the baseline line: this machine's PATH is 0.1.6-alpha.1, and running the mount lane against it fails at 'the bundle was not registered' with a zero exit from the CLI — a misleading dead end worth one explicit error instead. --- AGENTS.md | 36 +++-- README.md | 61 ++++---- README_EN.md | 61 ++++---- docs/external-plugin-guide.md | 42 +++--- ...2026-09-21-dsh-0.1.6-alpha.2-adaptation.md | 130 ++++++++++++++++++ pnpm-workspace.yaml | 3 - scripts/e2e-aggregate-mount.sh | 2 +- scripts/e2e-common.sh | 32 +++-- scripts/install.ps1 | 55 +------- scripts/install.sh | 56 ++------ scripts/package-registry.mjs | 2 +- src/client/locales-ar.ts | 1 - src/client/locales-de.ts | 1 - src/client/locales-fr.ts | 1 - src/client/locales-hi.ts | 1 - src/client/locales-id.ts | 1 - src/client/locales-it.ts | 1 - src/client/locales-ja.ts | 1 - src/client/locales-ko.ts | 1 - src/client/locales-nl.ts | 1 - src/client/locales-pl.ts | 1 - src/client/locales-pt.ts | 1 - src/client/locales-ru.ts | 1 - src/client/locales-sv.ts | 1 - src/client/locales-th.ts | 1 - src/client/locales-tr.ts | 1 - src/client/locales-vi.ts | 1 - src/client/locales-zh-HK.ts | 1 - src/client/locales-zh-MO.ts | 1 - src/client/locales-zh-TW.ts | 1 - src/client/locales.ts | 2 - tests/theme.spec.ts | 28 ++-- 32 files changed, 308 insertions(+), 221 deletions(-) create mode 100644 docs/plans/2026-09-21-dsh-0.1.6-alpha.2-adaptation.md diff --git a/AGENTS.md b/AGENTS.md index 41474b5..0b0e634 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,17 +17,35 @@ ## 2. CI 挂载冒烟(`plugin-mount` job / `pnpm test:mount`) -「npm 打包 → 真实挂载 → 无头渲染」门禁(证明打包产物在真实 DSH 挂载后不 crash):`pnpm build && pnpm pack` 产 tarball → `scripts/e2e-mount.sh` 装进全新 scratch profile(`dsh plugin --profile web add `)并启动真实 `dsh web`(keyless,`--port 0`)→ `tests/e2e/mount.e2e.ts`(Playwright)断言 `[data-dsh-better-sidebar]` 挂载、无错误条/pageerror/console 错误,展开 DSH 原生右侧栏后经其 guide 页逐个打开插件 tab 类型(含终端懒加载 chunk),再经插件文件树(原生 `files` kind 接管)打开 seed 文件强制加载 editor chunk(`client-editor.js`),并跑 mermaid / README 预览与 sidechat 宿主路由烟测。 +「npm 打包 → 真实挂载 → 无头渲染」门禁(证明打包产物在真实 DSH 挂载后不 crash):`pnpm build && pnpm pack` 产 tarball → `scripts/e2e-mount.sh` 装进全新 scratch profile(`dsh plugin --profile web add `)并启动真实 `dsh web`(keyless,`--port 0`)→ `tests/e2e/mount.e2e.ts`(Playwright)断言 `[data-dsh-better-sidebar]` 挂载、无错误条/pageerror/console 错误,展开 DSH 原生右侧栏后经其 guide 页逐个打开本插件贡献的 tab 类型**以及宿主自己的终端 / 浏览器条目**(后者在宿主装了对应包时必须恰好 1 条——多于 1 条即意味着插件又在遮蔽宿主),再经插件文件树(原生 `files` kind 接管)打开 seed 文件强制加载 editor chunk(`client-editor.js`),并跑 mermaid / README 预览与 sidechat 宿主路由烟测。 -本地:`pnpm build && pnpm pack && pnpm exec playwright install chromium && pnpm test:mount`。CI 钉 `@deepseek-ai/dsh@0.1.5-rc.2`(npm `next`;`latest` 仍是 rc.1;peer 下限 `^0.1.5-rc.1`)。该步骤用 `NODE_OPTIONS=--max-old-space-size=4096`:钉版自身的传递依赖是浮动 `^` 范围,上游分阶段发布预发布版时(rc.2 于 2026-09-10 的 14:43–14:57 逐包上线)npm 会组出混合 peer 图,3062 条 ERESOLVE 后 OOM(exit 134);另一个失败模式是对未发布兄弟包 ETARGET,靠「钉一个已完整发布的版本」修掉。**不要加 `--legacy-peer-deps`**:它跳过的正是全局安装必须提供的 peer,`@deepseek-ai/dsh-app-boot` 在 boot 时 require 的 `@deepseek-ai/cordis-plugin-group` 是 peer 而非 dependency,加了它 CLI 直接 `ERR_MODULE_NOT_FOUND`(实测过一次,见 rc.2 计划 C 节)。`ci-windows` 的 `Test` 跑 `pnpm test:windows`(`--maxWorkers=2`)而非 `pnpm test`——多个 spec 真起进程(`agent-pty` / `pty-deps` / `pty-helpers` / `install-powershell` / `smoke`),2 核 runner 上并行起 ConPTY / 冷启 `powershell.exe` 是超时与 worker 静默死亡的放大器;`vitest.config.ts` 的全局 `testTimeout: 15_000`(默认 5000 在 Windows 上对真起进程的用例太低,三个不同文件先后翻车)是配套的一半。e2e spec 命名 `*.e2e.ts` + vitest `exclude` 双保险;**改 `exclude` 必须保留默认排除项**(exclude 整体替换默认值)。 +本地:`pnpm build && pnpm pack && pnpm exec playwright install chromium && pnpm test:mount`(`DSH_CMD` 未设时 `scripts/e2e-common.sh` 回退的 npx 钉版是 `DSH_NPX_SPEC`,默认 `@deepseek-ai/dsh@0.1.6-alpha.2`——**不钉就会解析 `latest`,而 `latest` 仍是插件已不支持的 0.1.5 线**)。CI 钉 `@deepseek-ai/dsh@0.1.6-alpha.2`(npm `alpha`;`latest` 仍是 0.1.5-rc.2;peer 下限 `^0.1.6-alpha.2`)。该步骤用 `NODE_OPTIONS=--max-old-space-size=4096`:钉版自身的传递依赖是浮动 `^` 范围,上游分阶段发布预发布版时(rc.2 于 2026-09-10 的 14:43–14:57 逐包上线)npm 会组出混合 peer 图,3062 条 ERESOLVE 后 OOM(exit 134);另一个失败模式是对未发布兄弟包 ETARGET,靠「钉一个已完整发布的版本」修掉。**不要加 `--legacy-peer-deps`**:它跳过的正是全局安装必须提供的 peer,`@deepseek-ai/dsh-app-boot` 在 boot 时 require 的 `@deepseek-ai/cordis-plugin-group` 是 peer 而非 dependency,加了它 CLI 直接 `ERR_MODULE_NOT_FOUND`(实测过一次,见 rc.2 计划 C 节)。`ci-windows` 的 `Test` 跑 `pnpm test:windows`(`--maxWorkers=1`)而非 `pnpm test`——多个 spec 真起进程(`smoke` / `install-powershell` / `git`;终端删除后 `agent-pty` / `pty-deps` / `pty-helpers` 已不在),2 核 runner 上并行起 ConPTY / 冷启 `powershell.exe` 是超时与 worker 静默死亡的放大器;`vitest.config.ts` 的全局 `testTimeout: 15_000`(默认 5000 在 Windows 上对真起进程的用例太低,三个不同文件先后翻车)是配套的一半。e2e spec 命名 `*.e2e.ts` + vitest `exclude` 双保险;**改 `exclude` 必须保留默认排除项**(exclude 整体替换默认值)。 --- -## 3. DSH 0.1.5 适配要点(0.1.5-rc.1+ 基线) +## 3. DSH 0.1.6-alpha.2 适配要点(0.1.6-alpha.2+ 基线) -**v0.19.0(正式版,npm `latest`)起仅支持 DSH 0.1.5-rc.1+**(peer 下限 `^0.1.5-rc.1`,CI 钉 `@deepseek-ai/dsh@0.1.5-rc.2`)。**v0.19.1 把钉版推进到 rc.2 而 peer 下限不动**:rc.1 → rc.2 的 delta 里没有任何触及本插件的面(零 `packages/api|host|session|agent` 变更,真正的代码改动只有消息反馈弹窗、产物卡片 CSS、`CodeFileIcon` 的 SVG 数据拆分),`^0.1.5-rc.1` 天然容纳 rc.2,rc.1 用户无需升级即可用新版插件。0.1.5-alpha.2 用户停留在 **v0.19.0-alpha.1**(npm `alpha`)——rc 线的 delta 都很小,插件不再对 alpha 线做运行时兼容;0.1.2-rc.1 稳定线用户继续用 **v0.18.1**——0.1.5 的会话事件模型与文件打开漏斗都变了,插件不再对 0.1.2 做运行时兼容。发版:release.yml 按版本号是否含 `-` 自动选 `alpha`/`latest` dist-tag(0.19.1 无后缀 → `latest`;npm `alpha` 标签仍指向 `0.19.0-alpha.1`)。 +**v0.20.0(正式版,npm `latest`)起仅支持 DSH 0.1.6-alpha.2+**(peer 下限 `^0.1.6-alpha.2`,CI 钉 `@deepseek-ai/dsh@0.1.6-alpha.2`)。**下限必须动**:semver 的预发布规则要求比较子与候选版本同 `[major,minor,patch]` 元组,`^0.1.5-rc.1` 在数学上**永远容纳不下任何 `0.1.6-*` 预发布版**(实测:`0.1.6-alpha.2` 对 `^0.1.5-rc.1` / `^0.1.5-rc.2` / 裸 `*` 全部 false),而 `^0.1.6-alpha.2` 天然容纳 0.1.6 的 alpha/rc 全线。**支持线取舍**:0.1.5-rc.* 用户停留在 **v0.19.1**——rc.2 → alpha.2 有真实破坏(`SidebarRightGuideEntry.id` 必填、`conversation.chat.turnTail` chain→list),按本仓库先例(v0.19.0 抬到 0.1.5-rc.1 时直接桥掉 0.1.2 线)不写运行时兼容层;0.1.5-alpha.2 及更早同样停留在旧版。发版:release.yml 按版本号是否含 `-` 自动选 `alpha`/`latest` dist-tag(0.20.0 无后缀 → `latest`)。 -宿主契约(均经真机挂载冒烟 14/14 验证): +**本版新增的两条硬契约(两者都是静默失败,已在 v0.20.0 修好并加测试守护)**: + +1. **`SidebarRightGuideEntry.id` 必填且同一 provider 内唯一**(`tab-registry.ts`):缺 `id` 时两个条目在 `undefined` 上相撞,`SidebarRightTabRegistry.register` 抛 `duplicate guide entry id`。抛点在本插件 `ctx.inject(['sidebarRightTabs'], cb)` 的**回调体内**,异常被 cordis 吞掉——症状是整个原生承载面**静默空掉**(指南无条目、`openTab` 全拒),没有任何其它提示。`src/client/native/index.ts` 的两个 guide 条目各自带 `id`(descriptor id / `files`),`tests/native-surface.spec.ts` 断言「每个 guide 条目都有非空且互不重复的 id」。同处还加了 `reportFailure` 上报口:任何 descriptor 注册失败走 `index.tsx` 的可见诊断条,且单个失败不再带走其余注册。 +2. **`conversation.chat.turnTail` 由 `chain` 改为 `list`**(`ui-chat/src/client/contract/slots.ts`):list 槽要求 `options.id`,传 `select` 直接抛 `list slot "…" requires options.id`。**语义变了**:chain 的 `select` 让一个条目**替换**内置产物行,list 只能**追加**——上游是有意为之(「An additive list lets both plugins contribute without either knowing the other's data or rendering」),所以插件再注册一行只会与内置的产物卡**重复**。插件的轮尾接管(`intercept.tsx` / `produced-files.ts`)因此整体删除,产物行交回宿主;它开文件走宿主 `openFile` → 本插件的 editor,行为不变。**副作用(已接受)**:失去 F5 式「在侧边栏文件树里揭示该文件」的入口(树内右键「在文件夹中显示」仍在)。 + +**本版新增的让位(宿主内置了插件原有的两个面)**: + +3. **终端**:`@deepseek-ai/dsh-client-ui-sidebar-terminal`(+ `dsh-api-terminal-controller`)是宿主自己的右列终端类型。插件侧整个 PTY 栈(`pty-manager` / `agent-pty` / `pty-deps` / `tools.ts` / `TerminalView` / 终端字体与链接 / 跨会话固定终端 / xterm chunk)已删除,`node-pty` 依赖、`pnpm-workspace.yaml` 的 `allowBuilds`、安装脚本的 `-Repair` 模式随之移除。**模型侧代价**:插件原有的 8 个 `terminal_*` 工具(默认关)是模型唯一的**跨调用持久**终端,而上游等价物 `@deepseek-ai/dsh-tool-terminal` **未被任何 shipped bundle 默认挂载**——删除后模型只剩一次性 `bash` / `pwsh`。这是「不维护第二套 PTY」的既定代价,README 给出自行启用的指引。 +4. **浏览器**:`@deepseek-ai/dsh-client-ui-sidebar-browser` 是宿主自己的 `browser` kind,且 `ui-chat` 已内置把正文里的 http(s) 链接委派给它(`ctx.sidebarRight.openTab('browser', { params: { url } })`)。插件删掉 `BrowserView` / `browser.ts` / `browser-probe.ts` 与自己的 `browser` tab 类型;**保留** DOM 层链接接管(宿主不做按协议分流,https 默认交系统浏览器是本插件唯一还能提供的能力)与已发布的 `urlTarget` 机制,接管目标改为**宿主的 browser kind**(`window.open` 兜底,宿主没装该包时不至于点了没反应)。宿主的 `browser` kind 不进插件注册表,所以 `browserNoSandbox` / `browserAllowedLoopback` 两个只配置插件自家 iframe 的设置项随 `browser.probe` 宿主路由一并删除。 + +**本版还需知道的**: + +5. **原生右列布局现在会持久化**(`localStorage` `dsh.sidebar-right.v1.`,zod 校验,tab 体渲染前恢复):§3.10 里「原生布局只在内存,不做持久化」的旧说法对 0.1.6 起**已失效**。同时新增 `ctx.sidebarRight.openTabs` / `tabsIn(sessionId)` / `registerCloseHandler(kind, handler)`(class 上而不在 `ISidebarRight` 接口里)、`SidebarRightTabDefinition.multiple`、`SidebarRightPlacement.preferNewPane`、keyed 槽 `sidebar.right.tab.guide.entry`。插件只用到 `multiple` 与既有面。 +6. **`dsh.profile.patchReload` 已从 manifest 删除且零代码读取**(静默失效):HMR 现在是 `packages/boot/hmr` 的一行。本仓库未使用它。 +7. **`dsh.plugin.json` 从来不是 DSH 契约**:任何 DSH 版本都没有读它的代码(tag `dsh-v0.1.5-rc.2` / `dsh-v0.1.6-alpha.2` 全树 grep 均 0 命中)。DSH 真正读的是 `package.json` 的 `dsh.bundle.patch` + `dsh.client`(`platform`/`inject`/`immediately`/`external`)+ `exports["./client"]`。`dsh.plugin.json` 只服务第三方 registry(社区市场)通道,`lib/client-registry.js` 同理;`tests/manifest-consistency.spec.ts` 守护的是这条通道的形状,不是 DSH 契约。0.1.6 新增的官方管控面是 `packages/boot/plugin-manager`(`ctx.pluginManager` + `plugin_manager` 工具,需 `danger-full-access`)与 Web 的 Plugins 页——**两者都会零额外声明地接管任何已声明 `dsh.bundle.patch` 的包**,本插件无需适配。 +8. **`@deepseek-ai/dsh-client-ui-primitives` 仍不声明 `dependencies`,且裸 import 的集合又变大了**:0.1.6-alpha.2 的 bundle 额外裸 import `diff` 与 `simple-icons`(前者此前只由传递依赖满足,后者是新引入的 3 万余品牌图标集,`lib/index.js` 里具名 import 32 个)。两者已提升进 devDependencies;`@deepseek-ai/dsh-code-runtime` 则**整包消失**(`packages/code-runtime` 已删,npm 上停在 0.1.5-alpha.2),devDependencies 同步移除。 +9. **`ui-primitives` 本版的三处破坏**(已适配):`IconSendOutline16` 不再导出(只剩 `IconSendOutline14`);`TerminalBlockLabels` 新增必填的 `noExitCode`;`ConnectionIndicator` 删掉 `reconnectLabel`(断线标签现在**自身**命名重试动作,跟随宿主文案)。 + +宿主契约(0.1.5 线起沿用,均经真机挂载冒烟验证): 1. **一次性 token 鉴权**:就绪行 `dsh web: http://127.0.0.1:/?token=<43字符>`(导航换签名 cookie,干净 URL 401)。`e2e-mount.sh` 的 URL grep 必须延伸到空白(`[^ ]*`,在 `/` 截断丢 token);e2e 统一走 `tests/e2e/host.ts`(token 必选:`parseLaunchUrl` 对裸 origin 直接抛错),带 stamps 导航走 `gotoPage()`(先 addCookies 再直达——token 换 cookie 的 303 会丢弃同 URL 其它 query 参数)。插件 `/sidebar/*` 路由不受影响,同源 fetch 照旧。 2. **Remote gateway 斜杠 RPC(唯一方言)**:`POST /api/workspace/create`,payload 恰为 `{args: {...}}`,**args 按控制器 TS 参数名包装**(`workspace/create`、`session/create` → `{args:{request:{...}}}`;`session/list` 参数名 `_request` **不可省略**——`{}` 也被拒 `args fields do not match the descriptor`);envelope `method` 与路径一致,点分路径 404。请求由 `tests/e2e/host-protocol.ts` 的 `rpcAttempt` 构造、`tests/e2e-host-protocol.spec.ts` 锁定;要调新方法先在真机验参数名再进 `RPC_ARGS_KEY`。 @@ -38,7 +56,7 @@ 7. **`@deepseek-ai/dsh-client-runtime` 包已消亡**(继任 seed 是裸名 `dsh-client-store`,无 `/client` 子路径):peerDependencies、devDependencies、`dsh.client.inject`、chunk externals 白名单(`src/client/chunk-loader.ts` / `tsdown.config.ts` / `tests/chunk-loader.spec.ts` / `tests/manifest-consistency.spec.ts` 四处同步)均已无该条目。 8. **e2e scratch profile 的 `minimumReleaseAgeExclude` 含 `'@deepseek-ai/*'`**(`scripts/e2e-mount.sh` / `e2e-aggregate-mount.sh`,与仓库根 `pnpm-workspace.yaml` 同策):alpha 版本常在发布后 24h 内跑 lane,pnpm 11 的 `minimumReleaseAge` 默认会拒装新鲜包。 9. **插件开发树的 dsh-* 传递 peer 需提升为 devDependencies**(alpha.3 首见):`dsh-subagent` 等 npm 包把 `dsh-attachment` 等 dsh-* 姊妹包全部声明为 peerDependencies(由宿主 bundle 树统一提供,宿主侧无此问题),插件仓库若只直接依赖其中一部分,其余 peer 在 pnpm 下会解析到树上残留的旧版——如 `dsh-attachment@0.1.1-rc.1` 缺 `admitPromptContent` 导出、`dsh-subagent` 产物 import 它时测试加载即崩。因此 devDependencies 需涵盖 dev 树实际触达的全部 peer(attachment / code-runtime / scope / session-projection / system-prompt / user-approval / util-time 七个即为此提升,与直接依赖同款精确钉版);`@deepseek-ai/cordis` peer 自 alpha.3 起要求 `^4.0.2`(上游全线 peer 已升)。适配新 alpha 版本时先跑 `pnpm peers check`,把新失配的传递 peer 一并提升进 devDependencies。例外:**`dsh-client-locale` 的 peer/devDep 允许落后于基线**(alpha.5 时上游停在 0.1.2-alpha.3 未发新版)——peer 下限 `^0.1.2-alpha.3` 天然容纳同 tuple 的 alpha.5 运行时,此时保持旧钉版并在 `pnpm-workspace.yaml` 注明,待上游发版再追平;rc.1 起上游恢复发版,该包回到与 DSH 同 tuple(0.1.2-rc.1 → 0.1.5-rc.1,peer 下限 `^0.1.5-rc.1`),该例外消除。**alpha.2 起还有一类:上游包自身的 `dependencies` 丢失**——`@deepseek-ai/dsh-client-ui-primitives@0.1.5-alpha.2` 的 manifest 不再声明任何 `dependencies`(alpha.1 声明了 19 个),但 `lib/*.js` 仍裸 import `anser` / `shiki` / `@shikijs/langs/*` / `mdast-util-*` / `micromark-*` / `katex`。宿主由预构建前端 bundle 满足,独立安装的 dev/test 树不会——vitest 一碰 primitives 就 `Cannot find package 'anser'`。此时把 alpha.1 声明的同一组版本提升进 devDependencies(`clsx` 已在 dependencies 无需重复)。**rc.1 复查:`@deepseek-ai/dsh-client-ui-primitives@0.1.5-rc.1` 仍不声明任何 `dependencies`,bundle 仍裸 import 同一组包**(rc.2 同:只把 `CodeFileIcon` 的 SVG 数据拆进了新文件,无 `dependencies`)——这组提升不得回退,`pnpm peers check` / 单测一旦报 `Cannot find package 'anser'` 即是有人回退了。 -10. **右侧栏是 DSH 原生栏,插件只提供 tab 类型**:聊天里一切文件打开(工具行 / 产物行 / 正文提及 / 行内代码路径)统一走 `ctx.sidebarRight.openResource(fileAddressFor(sessionId, cwd, path))`(`packages/client/ui-chat/src/client/apply.ts` 是唯一调用点),`remote.session.openWorkspacePath` 在 0.1.5 客户端已无调用者,插件的 openpath 拦截随之删除。插件的每个 `TabDescriptor` 注册成原生 tab 类型(`kind = descriptor.id`,`extension` 带)+ 原生 tab 体(`sidebar.right.pane.tab` keyed 槽,key = `dsh-better-sidebar:`);`editor` 类型同时认领 `dsh-resource://file/**`(压过内置 `text` 的 `fallback`),并接管内置 `files` 页面 kind(`openTab('files')` 打开插件文件树,注销即复位)。`ctx.sidebarRight.openTab/openResource/close` 只对**在屏会话**写入;跨会话用具体类上的 `openTabIn/openResourceIn/closeIn`(不在 `ISidebarRight` 接口里,需结构化探测),目标会话未挂载时排队到上屏重放(`src/client/native/surface.ts`)。原生 tab 的插件侧状态(合成 `SidebarTab`、树展开集合、实例编号)在 `src/client/native/tab-adapter.tsx`;原生布局只在内存,不做持久化。**注册必须等服务、不能等槽声明**:原生栏先声明 `sidebar.right.pane.tab` 再 `provide('sidebarRightTabs')`,真机 profile(web,0.1.5-alpha.1)上槽声明回调里 `ctx.get('sidebarRightTabs')` 仍是 undefined(实测 3 秒后才出现),按槽触发注册会静默什么都不注册且永不重试——用 `ctx.inject(['sidebarRightTabs'], cb)` 驱动类型注册(`tests/native-surface.spec.ts` 以「槽先触发、服务后到达」的顺序守护),槽声明只用来挂 tab 体。指南 §0 列了全部行为差异。**alpha.2 起(v0.19.0-alpha.1)**:指南条目一度改成「图标+标题」胶囊、`TabDescriptor.description` 随之下线,新建标签页的默认页改为从注册表选(恰好 1 个指南条目 → 直接开它,0 或 ≥2 → 开指南),`revealIfOpened` 对「页面」在同一 pane 内强制去重。原生 tab 体宿主 `.paneBody` 是**有确定高度的块级滚动容器**(非 flex 容器),native 适配层因此给每个 tab 体包一层 `height:100%` 的列 flex 宿主(`sidebar.module.css` 的 `.nativeTabHost`),tab 组件根继续用 `flex:1`/`height:100%`——否则根盒塌成内容高度,sidechat 的输入框就贴不到面板底。全局面板(根级 `main` keyed 槽 + `sidebar.panellist` + `ctx.layout.selectPanel/beginNavigation`、`rightbar` 改根级并新增 `rightbar.session`)插件**不接入**,只做兼容。底部工作台的中心列锚点改认 `[data-slot="main.conversation"]`(并跳过 `display: contents` 祖先,同时保留 alpha.1 的 `[data-slot="conversation"]`);文件地址语法跟随 alpha.2(`fileAddressFor` 一律 session 作用域、绝对路径保留前导 `/`、`parseFileAddress` 前缀解析并去 `?`/`#`)。**rc.1 起(v0.19.0)**:`SidebarRightGuideEntry.description` 回归(可选),插件恢复 `TabDescriptor.description`(六个内置类型各声明一条说明,`guideDesc*` 词条回到 20 份词典),但**宿主的原生指南只在列出的条目 ≤ 4 条时渲染说明**(上游 `MAX_DESCRIBED_ENTRIES = 4`;更长的列表是整列丢弃,不是截断)——插件默认贡献 6 个 guide 条目(文件 / 文件变动 / 任务管理 / 侧边对话 / 终端 / 浏览器),所以**默认组合下说明不渲染**,只有读者在插件设置页关掉足够多 tab 类型、把 guide 压到 ≤ 4 条时才出现;插件**不恢复**旧的 `nativeGuideDesc` 通用兜底句(宿主自己没有兜底,通用句是噪音),没声明说明的 descriptor 就不发 `description` 字段;条目缺 `icon` 时由宿主补方块占位。 +10. **右侧栏是 DSH 原生栏,插件只提供 tab 类型**:聊天里一切文件打开(工具行 / 产物行 / 正文提及 / 行内代码路径)统一走 `ctx.sidebarRight.openResource(fileAddressFor(sessionId, cwd, path))`(`packages/client/ui-chat/src/client/apply.ts` 是唯一调用点),`remote.session.openWorkspacePath` 在 0.1.5 客户端已无调用者,插件的 openpath 拦截随之删除。插件的每个 `TabDescriptor` 注册成原生 tab 类型(`kind = descriptor.id`,`extension` 带)+ 原生 tab 体(`sidebar.right.pane.tab` keyed 槽,key = `dsh-better-sidebar:`);`editor` 类型同时认领 `dsh-resource://file/**`(压过内置 `text` 的 `fallback`),并接管内置 `files` 页面 kind(`openTab('files')` 打开插件文件树,注销即复位)。`ctx.sidebarRight.openTab/openResource/close` 只对**在屏会话**写入;跨会话用具体类上的 `openTabIn/openResourceIn/closeIn`(不在 `ISidebarRight` 接口里,需结构化探测),目标会话未挂载时排队到上屏重放(`src/client/native/surface.ts`)。原生 tab 的插件侧状态(合成 `SidebarTab`、树展开集合、实例编号)在 `src/client/native/tab-adapter.tsx`;**原生布局在 0.1.5 线只在内存,0.1.6 起由宿主持久化**(见上方第 5 条)。**注册必须等服务、不能等槽声明**:原生栏先声明 `sidebar.right.pane.tab` 再 `provide('sidebarRightTabs')`,真机 profile(web,0.1.5-alpha.1)上槽声明回调里 `ctx.get('sidebarRightTabs')` 仍是 undefined(实测 3 秒后才出现),按槽触发注册会静默什么都不注册且永不重试——用 `ctx.inject(['sidebarRightTabs'], cb)` 驱动类型注册(`tests/native-surface.spec.ts` 以「槽先触发、服务后到达」的顺序守护),槽声明只用来挂 tab 体。指南 §0 列了全部行为差异。**alpha.2 起(v0.19.0-alpha.1)**:指南条目一度改成「图标+标题」胶囊、`TabDescriptor.description` 随之下线,新建标签页的默认页改为从注册表选(恰好 1 个指南条目 → 直接开它,0 或 ≥2 → 开指南),`revealIfOpened` 对「页面」在同一 pane 内强制去重。**0.1.6-alpha.2 起**:`SidebarRightGuideEntry.id` 必填且同 provider 内唯一(见 §3 第 1 条——缺它会静默清空整个承载面);同 provider 的 guide 条目是**追加**关系,`chain` 那种「替换宿主条目」的语义只存在于 `conversation.chat.turnTail` 且已被上游改成 `list`(§3 第 2 条)。原生 tab 体宿主 `.paneBody` 是**有确定高度的块级滚动容器**(非 flex 容器),native 适配层因此给每个 tab 体包一层 `height:100%` 的列 flex 宿主(`sidebar.module.css` 的 `.nativeTabHost`),tab 组件根继续用 `flex:1`/`height:100%`——否则根盒塌成内容高度,sidechat 的输入框就贴不到面板底。全局面板(根级 `main` keyed 槽 + `sidebar.panellist` + `ctx.layout.selectPanel/beginNavigation`、`rightbar` 改根级并新增 `rightbar.session`)插件**不接入**,只做兼容。底部工作台的中心列锚点改认 `[data-slot="main.conversation"]`(并跳过 `display: contents` 祖先,同时保留 alpha.1 的 `[data-slot="conversation"]`);文件地址语法跟随 alpha.2(`fileAddressFor` 一律 session 作用域、绝对路径保留前导 `/`、`parseFileAddress` 前缀解析并去 `?`/`#`)。**rc.1 起(v0.19.0)**:`SidebarRightGuideEntry.description` 回归(可选),插件恢复 `TabDescriptor.description`,但**宿主的原生指南只在列出的条目 ≤ 4 条时渲染说明**(上游 `MAX_DESCRIBED_ENTRIES = 4`;更长的列表是整列丢弃,不是截断)——插件默认贡献 4 个 guide 条目(文件 / 文件变动 / 任务管理 / 侧边对话;终端与浏览器在 0.20.0 交还宿主),**与宿主自己的终端 / 浏览器条目合计后仍可能超过 4 条**,此时说明不渲染,只有读者在插件设置页关掉足够多 tab 类型把总数压到 ≤ 4 条时才出现;插件**不恢复**旧的 `nativeGuideDesc` 通用兜底句(宿主自己没有兜底,通用句是噪音),没声明说明的 descriptor 就不发 `description` 字段;条目缺 `icon` 时由宿主补方块占位。 11. **自定义种子必须带 fork 标记对(`meta.isSeeded: true` + `inheritedEventCount`)**:dsh-session 契约「只给 seed 不标 isSeeded,种子算重放历史而非继承前缀」——缺标记时 `Session.ownEvents()` 含整个种子,子会话的 inbox 折(`inboxProjectionDefinition`,0.1.5 起 `@deepseek-ai/dsh-agent` 只导出 `Inbox` 接口,实现是该投影)重放种子里的 `agent/inbox/spliced`,**继承父会话切割时刻未领取的 inbox 输入**(排队用户消息 next-turn、长回合中工具结果上下文/steering next-step——后者即「上下文很长时侧边对话先把之前的 User msg 发出去」的根因,幽灵消息排在 boundary 之前最先发给模型)。宿主 `session.fork`(api-session-controller)的调用即规范形态;回归由 `tests/sidechat-seed-validation.spec.ts`(真实 `Session.create` + 对 `ownEvents()` 跑 inbox 折)守护。0.1.5 复评:无更优雅的 sidechat 宿主 API(`ContinuableStartSpec` 仍无 seed 字段),`AgentRegistry.create` 接缝补齐标记即为规范用法;`Session.create` 的 header `version` 必须用 `SESSION_FORMAT_VERSION`(0.1.5 是 `3` 字面量类型),勿钉 `0`。 --- @@ -57,13 +75,13 @@ ## 5. 开发规则速查 - **构建纯度门**:client bundle 禁止 value-import `@dsh-external/*` 或非白名单 `@deepseek-ai/*`(`tsdown.config.ts` 拦截);`import type {}` 被擦除不触发——类型可共享,运行时符号不行;跨插件交互走 `ctx.betterSidebar` 方法调用。 -- **懒加载 chunk**:重依赖(xterm/CodeMirror/mermaid)在独立 bundle(`lib/client-.js`),经 `/sidebar/bundle` 按需下发、`globalThis.__dshChunks__` 物化(`src/client/chunk-loader.ts`),**核心 bundle 禁止静态 import `src/client/chunks/*`**。 +- **懒加载 chunk**:重依赖(CodeMirror / mermaid / 19 份第三语言词典)在独立 bundle(`lib/client-.js`,0.20.0 起只剩 `editor` / `mermaid` / `locale`),经 `/sidebar/bundle` 按需下发、`globalThis.__dshChunks__` 物化(`src/client/chunk-loader.ts`),**核心 bundle 禁止静态 import `src/client/chunks/*`**。chunk 名在 8 处镜像(`tsdown.config.ts` / `src/bundle-route.ts` / `src/client/chunk-loader.ts` / `package.json.files` / `scripts/package-registry.mjs` / `tests/{bundle-route,chunk-loader,chunk-artifact,manifest-consistency}.spec.ts`)——删一个 chunk 必须同步全部。 - **i18n**:词典在 `betterSidebar` 命名空间,跟随 DSH `ctx.locale`;**新增 zh key 必须同步 `src/client/locales-ja.ts` 的 ja 翻译**(否则 ja 下回退 en)。渲染 `MarkdownText` 必须经 `markdownTextProps()`(§3 第 3 条)。 - **皮肤契约**:视觉值只消费 `--dsw-alias-*` / `--dsw-font-*` / `--ds-*` 令牌,无硬编码颜色,**插件没有任何豁免面**——文件/文件夹图标是 DSH 官方 `FileTypeIcon` 的图形(宿主自己的调色板),插件画的每个 glyph(含内置 tab 彩色图标)颜色都来自令牌;`tests/theme.spec.ts` 同时守护「图标模块零颜色字面量」「样式表每条 `color` 解析到令牌」「没有图标数据被做成 chunk」。契约全文与 titleBar 四方案模型见[指南 §12](docs/external-plugin-guide.md),改动必须同步该节与 `tests/theme.spec.ts`。 - **契约反向引用**:皮肤契约被 `src/client/shell-presets.ts`、`tests/e2e/mount.e2e.ts` 的注释以「指南 §12」引用——调整指南章节结构时同步检查这两处。 - **接入 API 即文档**:`src/client/service.ts` 与 `src/client/builtins/` 的任何行为变更,必须同步 [docs/external-plugin-guide.md](docs/external-plugin-guide.md)(唯一权威接入文档,不再双份维护)。 - **文件/文件夹图标**:回退链是「具体 `names`/`exts` 注册 → catch-all(`exts: []`)→ 宿主 `FileTypeIcon`」。插件**不持有**扩展名表、图标数据或图标 chunk(#429 的 563 条数据与 `fileIconTheme` 开关在 rc.2 适配时删除,因为宿主已导出官方图形)。**语义雷区**:宿主分类器覆盖任意路径,所以注册 `exts: []` 会接管所有未具体命中的行——只想补几个类型的插件必须用 `exts`/`names`。 -- **内置 tab 图标**:六个内置类型与 diff 视图的 glyph 集中在 `src/client/builtins/tab-icons.tsx`(颜色在 `tab-icons.module.css`,全部 `--dsw-alias-*`),三处消费面自动同步:底部工作台 tab 条、原生指南胶囊、原生 tab 芯片。**原生芯片的图标是插件自己画的**——宿主的 `SidebarRightTabDefinition` 没有 icon 字段,但 `sidebar.right.pane.tab.title` 槽就是芯片内容(`NativeTabTitle` 渲染 `[glyph][title]`,glyph `aria-hidden` 以免改可访问名)。 +- **内置 tab 图标**:五个内置类型(文件 / 文件变动 / 任务管理 / 侧边对话 / diff)的 glyph 集中在 `src/client/builtins/tab-icons.tsx`(颜色在 `tab-icons.module.css`,全部 `--dsw-alias-*`),三处消费面自动同步:底部工作台 tab 条、原生指南胶囊、原生 tab 芯片。**原生芯片的图标是插件自己画的**——宿主的 `SidebarRightTabDefinition` 没有 icon 字段,但 `sidebar.right.pane.tab.title` 槽就是芯片内容(`NativeTabTitle` 渲染 `[glyph][title]`,glyph `aria-hidden` 以免改可访问名)。 --- @@ -71,4 +89,4 @@ - **接入 API 全参考**:[docs/external-plugin-guide.md](docs/external-plugin-guide.md)(消费插件开发者向;§0 原生栏承载面 / §4 Tab API / §5 FileViewer API / §7 服务方法 / §10 平台陷阱 / §11 已移除的自由窗口 / §12 皮肤契约 / §15 真实案例)。 - **设计文档**:[docs/plans/](docs/plans/)(30+ 份逐特性设计,含实施偏差记录)。 -- **关键测试守护**:`tests/service.spec.ts` / `builtins.spec.ts`(注册表与内置清单:7 tab + 6 viewer)/ `market-manifest.spec.ts`(市场约束)/ `e2e-host-protocol.spec.ts`(RPC 双协议)/ `native-surface.spec.ts`(原生右侧栏承载面)/ `theme.spec.ts`(皮肤契约)/ `plugin-list.spec.ts`(推荐插件目录)/ `fs-search.spec.ts`(host 文件名搜索)。 +- **关键测试守护**:`tests/service.spec.ts` / `builtins.spec.ts`(注册表与内置清单:**5 tab + 6 viewer**——终端与浏览器已交还宿主)/ `market-manifest.spec.ts`(市场约束,含 `pnpm pack` 后的产物面)/ `manifest-consistency.spec.ts`(registry 通道形状)/ `e2e-host-protocol.spec.ts`(RPC 双协议)/ `native-surface.spec.ts`(原生右侧栏承载面,含 guide 条目 id 唯一性)/ `theme.spec.ts`(皮肤契约,含空白面板胶囊几何)/ `plugin-list.spec.ts`(推荐插件目录)/ `fs-search.spec.ts`(host 文件名搜索)。 diff --git a/README.md b/README.md index 4db739e..000a323 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # dsh-better-sidebar > [!IMPORTANT] -> **已适配 DSH 原生侧边栏 API**(v0.19.0 起,DSH `0.1.5-rc.1+`):右列就是 DSH 自己的右侧栏——插件的每个 tab 类型与 tab 体通过 `ctx.sidebarRightTabs` / `ctx.sidebarRight` 注册与打开,聊天里的文件打开统一走 `ctx.sidebarRight.openResource('dsh-resource://file/…')`,插件**不再自绘右侧面板**(旧的浮窗能力同步移除)。自绘的底部工作台与开放给其他插件的 `ctx.betterSidebar` 服务保持不变,接入方式见[插件接入指南](docs/external-plugin-guide.md)。 +> **已适配 DSH 原生侧边栏 API**(v0.19.0 起):右列就是 DSH 自己的右侧栏——插件的每个 tab 类型与 tab 体通过 `ctx.sidebarRightTabs` / `ctx.sidebarRight` 注册与打开,聊天里的文件打开统一走 `ctx.sidebarRight.openResource('dsh-resource://file/…')`,插件**不再自绘右侧面板**(旧的浮窗能力同步移除)。自绘的底部工作台与开放给其他插件的 `ctx.betterSidebar` 服务保持不变,接入方式见[插件接入指南](docs/external-plugin-guide.md)。 +> +> **v0.20.0 起宿主支持下限是 DSH `0.1.6-alpha.2`**:DSH 该版本内置了自己的右侧栏**终端**与**浏览器**,因此插件**删掉了自研终端**(xterm + node-pty 整套)并把**浏览器视图让给内置**,只保留按协议分流的链接接管。0.1.5-rc.* 及更早用户请停留在 **v0.19.1**。
@@ -12,9 +14,9 @@ GitHub stars License: MIT dshfind

- 支持的 DSH 版本(v0.19.1 正式版):0.1.5-rc.1+(已在 0.1.5-rc.2 上验证) + 支持的 DSH 版本(v0.20.0 正式版):0.1.6-alpha.2+ 插件生态:GitHub topic dsh-better-sidebar

- 文件管理 编辑预览 内嵌浏览器 真实终端 文件变动 后台任务 侧边对话 插件接入

+ 文件管理 编辑预览 内置浏览器 文件变动 后台任务 侧边对话 插件接入

右侧栏 + 底部面板双工作台,并把 ctx.betterSidebar 服务开放给所有插件——
通过 registerTab / registerFileViewer 注册新的侧边栏页面与文件预览器。
@@ -44,17 +46,16 @@ ## ✨ 功能一览 - **🗂️ 文件工作台**:资源管理器(懒加载目录树;软链接按目标类型展示——目录软链接可展开、失效链接标红;文件树与文件 tab 按扩展名显示图标——markdown / 图片 / PDF / 代码 / 配置 / 压缩包等各有 glyph,插件可经 `registerFileIcon` 注册自定义图标与目录图标)+ CodeMirror 编辑器;图片 / Markdown(含 Mermaid 图表,strict 安全渲染 + 点击放大;README 级内嵌 HTML——徽章墙 / `
` 折叠 / 表格内联标签经 DOMPurify 消毒真实渲染;浮动目录大纲一键跳转)/ HTML / PDF -- **🌐 内嵌浏览器**:多开网页 tab,后退 / 前进 / 刷新;内容运行在沙箱 iframe;外链默认按协议分流——HTTP 在侧边栏打开、HTTPS 走系统浏览器(设置页可分别调整) -- **💻 真实终端**:xterm.js + node-pty 真实 shell,断线重连回放;可选为模型注入 `terminal_*` 工具 +- **🌐 内置浏览器 + 链接分流**:网页 tab 由 **DSH 内置**的 `ui-sidebar-browser` 提供(多开 / 后退前进刷新 / 沙箱 iframe);插件保留聊天与界面里的**外链接管**——HTTP 在侧边栏打开、HTTPS 走系统浏览器(设置页可分别调整),这是宿主自身不提供的按协议分流 +- **💻 终端(DSH 内置)**:右侧栏终端由 **DSH 内置**的 `ui-sidebar-terminal` 提供(shell 选择 / 重命名 / 断线重连 / 刷新后恢复 / 主题跟随)。插件不再自带 xterm + node-pty 实现 - **📂 模型侧边栏打开(可选)**:全局设置开启后注入 `sidebar_open` 工具——模型可主动在侧边栏打开文件 / 文件夹(树以该目录为根)/ HTTP(S) 网页 - **🌿 文件变动**:Git 视角(真 diff / 历史 / 暂存·提交·还原 / worktree·子仓库选择)与本轮文件视角(模型读 / 写 / 编辑实时追踪,按文件分组、按类型筛选)**双视角合一**;统一 diff 渲染(改蓝配对 + 行内字符级高亮 + 语法着色(含 mjs/cjs/mts/cts、CSS/SCSS/Less、HTML/XML/SVG/Vue、GraphQL、JSONC/JSON5)+ 上下文折叠),底部可拖拽预览面板,可一键展开为独立 diff tab(落进工作台的 diff 分栏);`.md` 操作(读 / 写 / 编辑)预览头部可切换**阅读模式**——经共享 MarkdownText 渲染 GFM 表格 / 任务列表 / 删除线 / 脚注 / 数学公式,本地图片自动改写为 `/sidebar/file` 媒体路由;含 ```mermaid 围栏时走编辑器同款懒加载 mermaid 渲染器(图可点击缩放 / 平移);**敏感内容脱敏**——凭据形态路径整文件遮罩、普通文件按内容形态遮值(api_key: / Bearer / sk- / AKIA / ghp_ / PEM 等,字段名保留),默认开启、预览面板一键开关(localStorage 记忆),仅影响显示、不改会话数据。已知边界:mermaid 无引号节点标签含被遮密钥时,图回退源码(规避:标签加引号);`.html` 操作(读 / 写 / 编辑)预览头部可切换**渲染模式**——复用编辑器同款 `/sidebar/html` 路由 iframe,相对资源(./style.css、img/x.png)同路由解析,分段读取也渲染完整文档,恒定沙箱(opaque origin + CSP 头,无逃生门);`.pdf` 操作(读 / 写 / 编辑)同样可切换**渲染模式**——复用编辑器同款 PDF 预览(媒体路由字节流 + 显式 Blob,浏览器原生查看器内嵌,附下载入口) - **🧩 后台任务页**:subagent 拓扑 + 后台任务(退出码 / 实时输出 / 强制终止) - **💬 侧边对话(beta)**:Codex 风格的侧边线程——继承主会话完整上下文(含进行中的回合与工具调用)独立运行,不进入主会话;线程内可持续追问,一键「保存为新会话」提升为顶层会话 -- **🖥️ 原生右侧栏 + 底部工作台**:右列交给 DSH 0.1.5 的原生右侧栏——插件把每个 tab 类型注册成原生 tab(文件打开走 `dsh-resource://file/**`,并接管内置「文件」页 / 文件树),插件自己只保留底部工作台(分栏 / 终端 / 随会话持久化),开合按钮挂在会话头右侧 -- **📌 固定终端**:右键终端 Tab 可「固定到工作区 / 固定到全局」——固定后切换会话不消失,在 TabBar 内联呈现(跨会话虚拟 Tab,点击就地激活,PTY 按 home 会话 id+tab 直连宿主 PTY,无需切回宿主会话);Agent 终端被 reconcile 移除时豁免保留 +- **🖥️ 原生右侧栏 + 底部工作台**:右列交给 DSH 原生右侧栏——插件把每个 tab 类型注册成原生 tab(文件打开走 `dsh-resource://file/**`,并接管内置「文件」页 / 文件树),插件自己只保留底部工作台(分栏 / 随会话持久化),开合按钮挂在会话头右侧 - **🔁 会话隔离**:布局 / Tab / 面板按会话持久化,陈旧状态自动净化 - **⚙️ 声明式设置**:设置页「侧边卡片」逐项独立开关,二级设置经齿轮弹窗 -- **⚡ 按需加载**:启动只拉 ~325KB 核心,终端 / 编辑器 / Mermaid 图表等重依赖用到才按需拉取([设计文档](docs/plans/2026-08-12-lazy-chunks-design.md)) +- **⚡ 按需加载**:启动只拉 ~325KB 核心,编辑器 / Mermaid 图表 / 第三语言词典等重依赖用到才按需拉取([设计文档](docs/plans/2026-08-12-lazy-chunks-design.md)) - **🌏 多语言**:界面文案跟随 DSH 语言(zh / en)实时切换;安装 `@huanlin/dsh-plugin-better-locale` 后支持日语(ja)等第三语言覆盖(见下方「🌏 第三语言覆盖」) > 🔌 **核心理念**:服务优先——内置的 8 tab + 6 viewer 与第三方插件通过同一套 `ctx.betterSidebar` API 注册,能力完全对等;官方不再内置、可由生态提供的功能,交由生态插件实现(已有 **28+ 生态插件**,见下方「🌐 插件生态」)。接入文档见「🔌 服务化扩展」与 [外部插件接入指南](./docs/external-plugin-guide.md)。 @@ -64,30 +65,28 @@ **前置**:已装好 DSH(`dsh web` 能正常运行),Node.js ≥ 20、pnpm ≥ 10。 **支持的 DSH 版本**: -支持的 DSH 版本(v0.19.1 正式版):0.1.5-rc.1+(已在 0.1.5-rc.2 上验证) +支持的 DSH 版本(v0.20.0 正式版):0.1.6-alpha.2+ -> 📌 **正式版**:`v0.19.0` 起适配 DSH **0.1.5-rc.1+**(npm dist-tag `latest`;`v0.19.1` 已在 **0.1.5-rc.2** 上完成真机挂载验证,rc.1 用户无需升级即可用本版——peer 下限仍是 `^0.1.5-rc.1`)。仍停在 DSH 0.1.5-alpha.2 的用户请固定安装 `dsh-better-sidebar@0.19.0-alpha.1`;0.1.2-rc.1 稳定线用户继续用 `dsh-better-sidebar@0.18.x`;DSH ≤ 0.1.1-rc.2 请用 `dsh-better-sidebar@0.17.1`。 +> 📌 **正式版**:`v0.20.0` 起适配 DSH **0.1.6-alpha.2+**(npm dist-tag `latest`;peer 下限 `^0.1.6-alpha.2`)。**下限必须动**:semver 的预发布规则让 `^0.1.5-rc.1` 在数学上永远匹配不到任何 `0.1.6` 预发布版。仍停在 DSH 0.1.5-rc.*(含 npm `latest` 的 0.1.5-rc.2)的用户请固定安装 **`dsh-better-sidebar@0.19.1`**——0.1.6 有两个真实破坏契约,本版不写运行时兼容层;DSH 0.1.5-alpha.2 及更早同样请用旧版(`0.19.0-alpha.1` / `0.18.x` / `0.17.1`)。 ```sh -dsh plugin --profile web add dsh-better-sidebar@latest # 首次会因 pnpm 11 拦截 node-pty 构建脚本而失败(依赖已写入) -cd ~/.dsh/profiles/web && pnpm approve-builds --all # 放行构建脚本(自动重跑安装) -dsh plugin --profile web add dsh-better-sidebar@latest # 重跑即成功 +dsh plugin --profile web add dsh-better-sidebar@latest ``` +> v0.20.0 起插件不再依赖任何需要构建脚本的包(`node-pty` 已随自研终端删除),所以安装**一步到位**,不再需要 `pnpm approve-builds` 那轮重跑。DSH 0.1.6 也自带 Web 侧的 **Plugins 页面**(`ui-plugin-manager`)与 `plugin_manager` 工具,装完后可以直接在那里启停。 + 装完**硬刷新浏览器**(Cmd/Ctrl+Shift+R)即可看到侧边栏(DSH 对 client 改动热加载,无需重启;仅 host 半更新时需要重启)。 **方式二:让 DSH 自己装**——把下面这段提示词发给任意一个 DSH 会话: ```text 帮我安装 dsh-better-sidebar 插件(DSH 侧边栏工作台),步骤: -1. 执行 dsh plugin --profile web add dsh-better-sidebar@latest(首次会被 pnpm 11 拦截 node-pty 构建脚本而失败,属正常) -2. 在 ~/.dsh/profiles/web 下执行 pnpm approve-builds --all(放行构建脚本,会自动重跑安装) -3. 再次执行 dsh plugin --profile web add dsh-better-sidebar@latest -4. 完成后提醒我硬刷新浏览器(Cmd/Ctrl+Shift+R) +1. 执行 dsh plugin --profile web add dsh-better-sidebar@latest(v0.20.0 起一步到位,无需构建脚本放行) +2. 完成后提醒我硬刷新浏览器(Cmd/Ctrl+Shift+R) 遇到报错先查 https://github.com/omdsh-dev/DSH-better-sidebar README 的常见问题表。 ``` -**方式三:一键脚本**——克隆本仓库后执行 `bash scripts/install.sh`(macOS / Linux / Windows Git Bash;Windows 原生环境用 `install.ps1`;`-h` 查看参数),自动完成 add → 放行构建脚本 → 重跑安装。 +**方式三:一键脚本**——克隆本仓库后执行 `bash scripts/install.sh`(macOS / Linux / Windows Git Bash;Windows 原生环境用 `install.ps1`;`-h` 查看参数),自动完成安装 + bundle 注册(含幂等清理旧的手动挂载行)。
更新 @@ -105,12 +104,11 @@ dsh plugin --profile web add dsh-better-sidebar@latest | 现象 | 原因与解决 | |---|---| -| 报 `Ignored build scripts` | pnpm 11 拦截构建脚本。在 profile 目录(`~/.dsh/profiles/web`)跑 `pnpm approve-builds --all`。 | +| 报 `Ignored build scripts` | pnpm 11 拦截了某个传递依赖的构建脚本。在 profile 目录(`~/.dsh/profiles/web`)跑 `pnpm approve-builds` 按提示放行——v0.20.0 起本插件自身不再有构建脚本依赖。 | | 报 `minimum release age` / 版本不足 24h | 装的版本发布不足 24 小时。等 24h 或重跑一次(pnpm 会自动补 `minimumReleaseAgeExclude`)。 | | 报「找不到 profile 目录」 | 先跑一次 `dsh web`,让它初始化 `~/.dsh/profiles/web`。 | | 页面出现**两个侧边栏** | 双挂载。旧的手动挂载行:`~/.dsh/profiles/web/cordis.patch.yml` 还留着 `- insert: ... better-sidebar ...`,删掉那段(同 id 重复挂载 loader 会直接报 `duplicate loader entry id`)。聚合包(如 `@linxin666/dsh-web-ui-all`)以**不同 id** 挂载本包时,0.13.x 起插件自身 bundle patch 会自动退让(检测到已有启用中的同包名挂载就不挂自己),无需手动处理;若仍双挂载,先确认聚合包的 bundle 顺序在 `dsh-better-sidebar` 之前。 | -| Windows 下终端无法使用 | `node-pty` 依赖预编译二进制;若当前 Node 版本没有对应产物,需装编译工具链(VS Build Tools)。主流 Node 版本一般已有预编译。 | -| 终端提示「node-pty 加载失败」 | `node-pty` 安装缺失/损坏(如 pnpm 拦截了构建脚本)。终端横幅会给出修复命令:复制到 DSH 所在环境的终端/cmd 执行(在 `~/.dsh/profiles/web` 下 `pnpm approve-builds --all && pnpm rebuild node-pty`),完成后重启 DSH 并点重试。插件与 DSH 核心使用同一 `node-pty@^1.1.0`,修复后两者同步恢复。 | +| 终端无法使用 / 提示 shell 启动失败 | 终端与 `node-pty` 现在都由 **DSH 自身的 `ui-sidebar-terminal`** 提供(本插件 v0.20.0 起不再自带)。遇到问题请查 DSH 侧文档;若报错提到构建脚本,见上一行。 | | 提示 `dsh: command not found` | 先安装 DSH;或直接用 `npx -y --package @deepseek-ai/dsh dsh plugin --profile web add dsh-better-sidebar@latest`。 |
@@ -166,8 +164,8 @@ dsh registry enable dsh-external/dsh-better-sidebar |---|---| | **🗂️ 文件工作台:资源管理器**
支持两种格式的资源管理器:内嵌在文件预览中 / 独立显示文件树。懒加载目录树、软链接按目标类型展示(目录软链接可展开、失效链接标红)、全局文件名搜索、上传文件/文件夹与拖放上传、右键菜单(在新 Tab 打开 / 在侧边打开 / 复制路径)、悬浮 `@文件` 一键引用进输入框。
文件资源管理器
| **📝 Markdown · 图片 · PDF 内联预览**
Markdown 预览支持 **Mermaid 图表**(`securityLevel: 'strict'` 安全渲染 + 二次清洗;点击图表弹窗放大、滚轮缩放、拖拽平移)、**README 级内嵌 HTML**(徽章墙 `
`、`
` 折叠块内嵌 markdown、表格单元格内联标签——DOMPurify 白名单消毒真实渲染,`