Files
apes-sidebar/package.json
T
Menghuan1918 98a446bbfc fix(sidebar): 点击展开时文件树整体重建(两处根因)+ v0.24.1
用户报告:「点击展开的时候,文件树会频繁整体刷新,看起来非常难受」。

根因 1(主):src/client/native/index.ts 的 sync() 把 files 接管项当成多余注册。
它按 KIND 记账、永远不在 wanted 里,于是每次 sync 都被 dispose + 重建;而
disposeSubscriptions 同时订阅了 service 与 store,**任何会话状态写入**(展开/收起、
切 tab、拖底部工作台、选中…)都会跑一遍 sync。替换 slot 注册 = 宿主换 slot entry →
插件 tab body 被 unmount/remount → 文件树丢失层缓存、滚动位置与目录 watcher,并重新
fs.trees([root, ...expanded]) 重列整棵可见树。机械证明(临时插桩,已回退):
  [probe-sync] enter live=[editor,git,subagent,sidechat,diff,files]
  [probe-registerSlots] slot inject ran for dsh-better-sidebar:files
  [probe-body] unmount tab3 kind=files
  [probe-body] mount tab3 kind=files
修法:wantsFiles 提前,删除循环里对 files 接管项 skip(禁用 editor 时仍照旧释放)。

根因 2(次):FileTree.tsx 的 retryDir 先把该层缓存删掉再请求,行被「Loading…」
占位替换后重建——目录有外部写入(构建 / 格式化 / 模型跑 bash)时整层闪空。
修法:复用既有 force 路径 loadLevels([dir], { force: true }),保留旧行直到新答案到达
(与 refreshTick 的强制刷新路径行为一致)。

判别性证据(回退任一修复即红)
- tests/native-surface.spec.ts:三次 store 写入不得产生任何注册/注销 → 回退后
  registered 6 → 12、disposed 全是 dsh-better-sidebar:files
- tests/file-tree-batch-load.spec.tsx:重列期间旧行仍在屏 → 回退后层被删空
- 新增真实宿主 lane tests/e2e/zz-expand-refresh.e2e.ts(quiescence 判据,无固定 sleep;
  zz- 前缀保证它最后跑,因为它会自建 workspace + session):A1 展开只请求被展开那一层、
  A2 tab body 存活(不重开 watch socket)、A3 屏上行数不归零;回退修复 1 后退出码 1
  (Error: expanding a folder must ask for that folder, not the whole visible set)

修复后实测(40 子项目录,同一探针/机器/工作区)
| 阶段 | fs.trees payload | 新开 ws | DOM +/- | 被删行 | body 替换 | 层内最小行数 |
| 展开 big | [big](原 [root, big]) | 0(原 1) | +41/-1 | 0(原 45) | 0(原是) | 40(原 40) |
| 外部写入 big | [big] | 0 | +1/-0(原 +41/-40) | 0 | 0 | 40(原 0) |
| 展开 bravo | [bravo] | 0 | +2/-1 | 0(原 45) | 0(原是) | 41 |

证伪记录:新建 fs.watch(dir,{persistent:false}) 在 macOS 上无改动时 0 事件(Node 微
探针两遍 + 8 轮真实时序 + 浏览器侧从未收到 {dir} 陈旧帧)→ src/fs-watch.ts 与
use-dir-watch.ts 一行未改。

验证:pnpm typecheck / lint / test(136 文件 1486 通过 9 跳过,基线 1484 + 新增 2)/ build
全绿;DSH_CMD='npx -y --package @deepseek-ai/dsh@0.2.0-rc.1 dsh' pnpm test:mount = 8/8。
版本 0.24.0 → 0.24.1(package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION /
README×2 / CHANGELOG×2 同步)。
2026-09-28 22:33:30 +08:00

232 lines
7.7 KiB
JSON

{
"name": "dsh-better-sidebar",
"version": "0.24.1",
"description": "Better Sidebar for DSH — file tree, editor, changes, tasks and side chat in one column, separate for every conversation. Also exposes a service other plugins use to register sidebar tabs and file viewers.",
"type": "module",
"repository": {
"type": "git",
"url": "https://github.com/omdsh-dev/DSH-better-sidebar"
},
"publishConfig": {
"access": "public"
},
"main": "lib/index.js",
"types": "lib/types/index.d.ts",
"exports": {
".": {
"types": "./lib/types/index.d.ts",
"default": "./lib/index.js"
},
"./invariant": {
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./client": {
"types": "./lib/types/client/index.d.ts",
"default": "./lib/client.js"
},
"./client/service": {
"types": "./lib/types/client/service.d.ts",
"default": "./lib/client.js"
},
"./client/api": {
"types": "./lib/types/client/service.d.ts",
"default": "./lib/client.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json",
"./locale/*.json": "./locale/*.json"
},
"engines": {
"node": ">=20"
},
"packageManager": "pnpm@11.8.0",
"dsh": {
"bundle": {
"patch": "./cordis.patch.yml"
},
"client": {
"inject": [
"@deepseek-ai/dsh-client-locale",
"@deepseek-ai/dsh-client-ui-slots",
"@deepseek-ai/dsh-client-ui-conversation",
"@deepseek-ai/dsh-client-ui-sidebar-right",
"@deepseek-ai/dsh-client-modules"
],
"platform": "web"
},
"manifestVersion": 1
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/client.js",
"lib/client-registry.js",
"lib/client-editor.js",
"lib/client-locale.js",
"lib/client-mermaid.js",
"lib/types/**/*.d.ts",
"src",
"scripts/install.sh",
"scripts/install.ps1",
"cordis.patch.yml",
"README.md",
"README_EN.md",
"LICENSE",
"icon.svg",
"locale/*.json"
],
"scripts": {
"build": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\" && tsc -p tsconfig.build.json && tsdown",
"prepublishOnly": "pnpm build",
"typecheck": "tsc --noEmit",
"bundle": "tsdown",
"watch": "tsdown --watch",
"prepare": "tsdown",
"test": "vitest run",
"test:windows": "vitest run --maxWorkers=1",
"test:mount": "bash scripts/e2e-mount.sh",
"test:mount:aggregate": "bash scripts/e2e-aggregate-mount.sh",
"clean": "node -e \"require('node:fs').rmSync('lib',{recursive:true,force:true})\"",
"check:consumer-types": "bash scripts/check-consumer-types.sh",
"lint": "eslint ."
},
"license": "MIT",
"peerDependencies": {
"@deepseek-ai/cordis": "^4.0.4",
"@deepseek-ai/dsh-agent": "^0.2.0-rc.1",
"@deepseek-ai/dsh-client-locale": "^0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-conversation": "^0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-primitives": "^0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-settings": "^0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-sidebar-right": "^0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-slots": "^0.2.0-rc.1",
"@deepseek-ai/dsh-host-webserver": "^0.2.0-rc.1",
"@deepseek-ai/dsh-invariants": "^0.2.0-rc.1",
"@deepseek-ai/dsh-llm": "^0.2.0-rc.1",
"@deepseek-ai/dsh-session": "^0.2.0-rc.1",
"@deepseek-ai/dsh-settings": "^0.2.0-rc.1",
"@deepseek-ai/dsh-subagent": "^0.2.0-rc.1",
"@deepseek-ai/dsh-tools": "^0.2.0-rc.1",
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"peerDependenciesMeta": {
"@huanlin/dsh-plugin-better-locale": {
"optional": true
},
"@deepseek-ai/dsh-client-ui-sidebar-right": {
"optional": true
}
},
"dependencies": {
"@codemirror/commands": "^6.10.4",
"@codemirror/lang-cpp": "^6.0.3",
"@codemirror/lang-css": "^6.3.1",
"@codemirror/lang-go": "^6.0.1",
"@codemirror/lang-html": "^6.4.12",
"@codemirror/lang-java": "^6.0.2",
"@codemirror/lang-javascript": "^6.2.5",
"@codemirror/lang-json": "^6.0.2",
"@codemirror/lang-markdown": "^6.5.2",
"@codemirror/lang-php": "^6.0.2",
"@codemirror/lang-python": "^6.2.1",
"@codemirror/lang-rust": "^6.0.2",
"@codemirror/lang-sql": "^6.10.0",
"@codemirror/lang-vue": "^0.1.3",
"@codemirror/lang-xml": "^6.1.0",
"@codemirror/lang-yaml": "^6.1.3",
"@codemirror/language": "^6.12.4",
"@codemirror/legacy-modes": "^6.5.3",
"@codemirror/search": "^6.7.1",
"@codemirror/state": "^6.7.1",
"@codemirror/view": "^6.43.8",
"@deepseek-ai/schemastery": "^3.18.4",
"@lezer/highlight": "^1.2.3",
"clsx": "^2.1.1",
"dompurify": "^3.4.14",
"mermaid": "^11.16.1",
"react-icons": "5.7.0",
"rxjs": "^7.8.2",
"ws": "^8.18.0",
"yaml": "^2.9.1"
},
"devDependencies": {
"@cordisjs/plugin-loader": "^1.0.0-rc.5",
"@deepseek-ai/cordis": "4.0.4",
"@deepseek-ai/cordis-plugin-group": "1.0.4",
"@deepseek-ai/cordis-plugin-include": "1.0.9",
"@deepseek-ai/dsh-agent": "0.2.0-rc.1",
"@deepseek-ai/dsh-agent-loop": "0.2.0-rc.1",
"@deepseek-ai/dsh-attachment": "0.2.0-rc.1",
"@deepseek-ai/dsh-client-locale": "0.2.0-rc.1",
"@deepseek-ai/dsh-client-store": "0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-sidebar-right": "0.2.0-rc.1",
"@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1",
"@deepseek-ai/dsh-host-webserver": "0.2.0-rc.1",
"@deepseek-ai/dsh-invariants": "0.2.0-rc.1",
"@deepseek-ai/dsh-llm": "0.2.0-rc.1",
"@deepseek-ai/dsh-ptc-runtime": "0.2.0-rc.1",
"@deepseek-ai/dsh-sandbox": "0.2.0-rc.1",
"@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.1",
"@deepseek-ai/dsh-scope": "0.2.0-rc.1",
"@deepseek-ai/dsh-session": "0.2.0-rc.1",
"@deepseek-ai/dsh-session-persistence": "0.2.0-rc.1",
"@deepseek-ai/dsh-session-projection": "0.2.0-rc.1",
"@deepseek-ai/dsh-settings": "0.2.0-rc.1",
"@deepseek-ai/dsh-subagent": "0.2.0-rc.1",
"@deepseek-ai/dsh-system-prompt": "0.2.0-rc.1",
"@deepseek-ai/dsh-tools": "0.2.0-rc.1",
"@deepseek-ai/dsh-user-approval": "0.2.0-rc.1",
"@deepseek-ai/dsh-util-code-language": "0.2.0-rc.1",
"@deepseek-ai/dsh-util-time": "0.2.0-rc.1",
"@deepseek-ai/dsh-util-workspace-path": "0.2.0-rc.1",
"@eslint/js": "^10.0.1",
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
"@playwright/test": "^1.62.1",
"@shikijs/langs": "^4.3.1",
"@types/mdast": "^4.0.4",
"@types/node": "^24.0.0",
"@types/react": "~18.3.1",
"@types/react-dom": "~18.3.1",
"@types/ws": "^8.5.10",
"anser": "^2.3.5",
"cordis": "^4.0.0-rc.8",
"diff": "^9.0.0",
"eslint": "^10.9.1",
"eslint-plugin-react-hooks": "^7.1.1",
"globals": "^17.12.0",
"immer": "^10.1.1",
"jsdom": "^29.1.1",
"katex": "^0.16.47",
"lightningcss": "^1.32.0",
"mdast-util-from-markdown": "^2.0.3",
"mdast-util-gfm": "^3.1.0",
"mdast-util-math": "^3.0.0",
"micromark-core-commonmark": "^2.0.3",
"micromark-extension-gfm": "^3.0.0",
"micromark-extension-math": "^3.1.0",
"micromark-factory-space": "^2.0.1",
"micromark-util-character": "^2.1.1",
"micromark-util-classify-character": "^2.0.1",
"micromark-util-sanitize-uri": "^2.0.1",
"micromark-util-symbol": "^2.0.1",
"micromark-util-types": "^2.0.2",
"react": "^18.2.0",
"react-dom": "18.2.0",
"shiki": "^4.3.1",
"simple-icons": "^16.32.0",
"tsdown": "^0.22.2",
"typescript": "^5.6.0",
"typescript-eslint": "^8.69.0",
"unrun": "^0.2.39",
"vitest": "^4.1.8",
"zustand": "~4.4.7"
},
"icon": "./icon.svg"
}