Commit Graph
274 Commits
Author SHA1 Message Date
Menghuan1918 93ad87dfe7 fix(sidechat): stamp the seed with fork markers so the child inherits no pending inbox
sidechat.start passed `seed` without `meta.isSeeded: true` +
`inheritedEventCount`, so dsh-session treated the whole seed as the
child's OWN events and the child's Inbox constructor replayed the
parent's `agent/inbox/spliced` history — inheriting whatever input sat
UNCLAIMED in the parent at the click moment:

- next-turn: a queued follow-up behind a still-running turn;
- next-step (the reported long-context case, parent queue empty): a
  tool-result context / steering spliced between step boundaries.

The first side prompt then claimed [phantom, boundary, question] — the
stale parent message was sent to the model BEFORE the boundary and
logged as a user/message. The fix passes the exact marker pair the
host's own session.fork uses (api-session-controller); ownEvents() now
stops at the end-seed boundary and the inherited inbox replays empty.

Regression tests run the REAL Session.create + Inbox in both
directions (old shape inherits the phantom, marked shape stays empty);
routes tests pin the two create options. Verified: pnpm typecheck /
test (5 pre-existing unrelated UI-spec failures on main unchanged) /
build.
2026-09-06 00:59:03 +08:00
Menghuan1918 e39ea92ade feat(files): tree rename (inline) + delete (confirmed) + submenu visual tether
资源管理器补全:文件树右键菜单新增「重命名」(行内编辑:预填+全选、
Enter/失焦提交、Esc 取消、IME 组合键守卫)与「删除」(Modal 确认,文件/
目录文案区分,永久删除——宿主无回收站)。根行(工作区根)不提供两项,
服务端 fs.rename/fs.remove 双保险拒绝;目标已存在 409;link-aware——
symlink 行只改/删链接本身(lstat 判定),fence 校验对解析后目标进行。

落定收尾:pruneTree 清旧前缀缓存 + 收起 stale expanded + 单层重载父目录;
tab 调解走 service(rename→updateTab 改路径改标题、delete→closeTab 关
受影响 tab,覆盖两侧分栏/底栏/浮动窗口,经 tree-mutations.ts)。

二级菜单视觉关系(layout.css,仍限 data-dsh-sidebar-submenu 作用域):
父行在子菜单打开期间保持高亮(宿主已渲染 aria-expanded="true"),
卡片间距 10px→4px(悬停走廊同步收窄),翻转规则一并 4px。

i18n 新增 7 key × 20 语言文件(locales.spec 的 key-set-parity 门禁)。
测试:fs-operations 追加 12 例(rename/remove 全失败面);新增
file-tree-rename-delete.spec.tsx 8 例(菜单可见性/重命名流/删除流/错误条);
menu-flip.spec.tsx 契约扩展覆盖 tether 规则。设计文档
docs/plans/2026-09-04-file-tree-rename-delete-design.md。
2026-09-04 22:08:02 +08:00
Menghuan1918 76b57508f4 fix(ui): compact context menus + viewport-clamped submenu flip
减重:全部右键菜单(FileTree 行菜单 / TabBar tab 菜单 / GitLens 文件与
历史菜单 / FreeWindow 标题菜单)与「+」菜单切到宿主 Menu 原语的 compact
密度(26px 行高 / 12px 字 / 164px 卡片),图标随槽位 16→14,「打开方式」
子菜单图钉 20→16,还原工具型右键菜单的趁手感。

越界:宿主子菜单纯 CSS 定位(从父行向上、向右生长)不受视口钳制——树顶
部右键时「打开方式 ▸」子菜单伸出视口上沿,窄面板(280–400px)时伸出右
沿。新增 menu-flip.ts:菜单打开期间在 <body> 发布 data-dsh-sidebar-submenu
="down|left" 方向 token(y < vh/2 → down;x + 400 > vw → left),layout.css
据此翻转子菜单生长方向与 ::before 悬停桥;属性存续期即作用域,宿主自有
菜单不受影响。刻意不做 max-height 滚动钳制——overflow 裁剪会切断悬停桥。

测试:menu-flip.spec.tsx(token 纯函数 + hook 生命周期 + CSS 契约跨文件
一致性);tab-bar / file-tree 两个 spec 追加翻转向量断言;mount.e2e 追加
compact 行高(≤30px)布局级证据。设计偏差记录同步至
docs/plans/2026-08-22-open-with-menu-design.md。
2026-09-04 20:28:35 +08:00
Menghuan1918 dc33087ce1 feat(client): 删除 rc.7 宿主的 __DSH_MODULES__ 回退路径
peer 基线已是 ^0.1.2-rc.1(全部 dsh-* peer),最后提供
window.__DSH_MODULES__ 页面全局的宿主是 0.1.0-rc.7,远低于下限,
装不上本插件——回退在受支持宿主上不可达。受支持宿主上 apply() 在
任何懒加载发生前调 setChunkModuleSystem(ctx.modules),moduleSystem()
前两跳(注入变量 + 插件全局 __dshSidebarModuleSystem__)必中。

回退的唯一活消费者是 vitest fixture:installModuleSystem() 原先经
rc.7 全局投递 fake 模块系统,现改为与生产同路径的 setChunkModuleSystem
注入;无任何专测回退分支的用例,全部断言保持不变。

- chunk-loader.ts: 删 moduleSystem() 第三跳,同步头注 /
  ChunkModuleSystem 接口注中的回退描述
- index.tsx: 删「falls back to the rc.7 global」注释
- README v0.14.0 changelog 与 docs/plans 设计文档中的提及属历史
  存档(描述 PR #232 当时的迁移),保留不改

验证:lint / typecheck / build / vitest 119 文件 1243 用例全绿;
真机挂载 lane(钉版 @deepseek-ai/dsh@0.1.2-rc.1 CLI)mount.e2e
全内置 tab sweep(含终端 / editor 懒加载 chunk)通过;lib/*.js
产物中无 __DSH_MODULES__ 残留。
2026-09-03 20:29:59 +08:00
Menghuan1918 8820efd6bf fix(tests): 补回 add-plugin-modal.spec 缺失的 builtinTabPlugins import
#535(i18n catalog names)给 tests/add-plugin-modal.spec.tsx 新增
sentinelEntry 行时漏了 import;#535 自身 CI run 被 cancel,#536 带病
合入,main HEAD 7b5c7dd 的 typecheck/test 双红(本地 stash 复现一致:
TS2304 / ReferenceError: builtinTabPlugins is not defined,CI run
33754439466 failure)。补上与 plugin-list.spec.ts 同源的 import。

与本 PR 主题无关,仅为本流验证门(typecheck/test 全绿)所需的最小
main 修复,独立成 commit 便于 review 剔除。
2026-09-03 20:29:50 +08:00
Atlas Zeng 7b5c7ddcc4 Merge pull request #536 from omdsh-dev/feat/eslint
feat(lint): 引入 ESLint flat config 并接入 CI 与 Makefile
2026-09-03 20:18:10 +08:00
Atlas Zeng f8bb3013ff Merge pull request #535 from omdsh-dev/feat/i18n-catalog-names
feat(i18n): 目录项与 shell 预设文案词典化,兜底错误条改皮肤令牌链
2026-09-03 20:18:05 +08:00
Menghuan1918 5a1e75e46b fix(lint): 清零存量 lint 告警并接入 CI / Makefile 门禁
存量清理(首跑 141 errors / 21 warnings → 0 / 0):
- 删除孤儿 disable:SideChatView / Sidebar / selection-popup 三处 exhaustive-deps 豁免与 chunk-artifact 的 no-new-func 豁免(多行理由注释把 disable-next-line 顶离了实报行;selection-popup 改为提取 popupOpen 标志真修复)
- 死代码:未用导入(Sidebar×7、TextEditor、SideCardSection、config、fs-operations 及 6 个 spec)、sidechat-core 死累加器 total、chunk-loader.spec 死助手 registry、sidechat-seed-validation 死助手 toolResultMessage
- 真实小修:agent-opens 三处 throw 补 cause;lazy-chunk any → ComponentType<P>(P extends object);service.ts claimed 初值改定值赋值;chunk-loader task / spec 内 etag / pendingLoad / snapshot 改 const;terminal-links 去掉字符类内多余转义;SubagentView catalogs 空兜底 useMemo 稳定标识;editor-host.spec 组件提出大写 FakeViewer(rules-of-hooks);pty-helpers.spec 内联 require 提升为静态导入;panel-host-css 注释里的零宽空格改为可见写法
- 依赖数组豁免(均带理由):granular scope 字段(EditorHost / PdfView / ChangesTab / GitLens×2)、job.status 粒度(SubagentView×2)、清理期读 ref、mount-only 注册等;ctx(挂载期恒定)直接入 deps(Sidebar×3)、TextEditor previewScroll 补 scope(幂等)
- 刻意控制字符正则(conversation-draft / markdown-images)与宿主槽位 any 签名(context-types)以带理由豁免保留

接入:
- Makefile:lint 目标(typecheck 旁),check 聚合补 lint 保持「对齐 CI」语义
- ci.yml ci / ci-windows 两 job 与 release.yml 在 Typecheck 后加 Lint 步骤(release 注释同步顺序)
2026-09-03 20:00:08 +08:00
Menghuan1918 040b182b1c refactor(theme): One Dark/Light 语法色板单源化
新增 src/client/one-dark-palette.ts,作为 one-dark / one-light 两套语法
色系的唯一来源:TerminalView 的 ANSI 16 与 cm-themes 的 CodeMirror 高亮
规则改为从色板常量组装各自的映射(ANSI 槽位 / lezer tag 到色相的映射
仍留在各消费方——两边的角色映射本就不同)。

行为不变的纯重构:每个 hex/rgba 迁移前后逐字节一致(旧新片段在桩
tags 下求值深度比对相等;产物 hex 清单无删除、非色板 hex 计数零变化)。
TerminalView 的 token 兜底色与 cm-themes 的 selection/activeLine rgba
与语法色系无关,保留原处未合并。

chunk 边界:色板为纯常量,被 terminal / editor 两个懒 chunk 各自内联
(每 chunk 约 200B 字面量),不引入跨 chunk import;核心 bundle
(client.js / client-registry.js)对该模块零引用(grep 产物验证)。
tests/one-dark-palette.spec.ts 钉住色板字面量防意外漂移。
2026-09-03 19:59:00 +08:00
Menghuan1918 fa301da29e feat(i18n): localize plugin catalog names and shell preset desc
Catalog entry names (15 tab + 4 viewer) and the dsh-desktop shell preset
desc were raw hardcoded zh strings rendered straight into the add-plugin
modals and the title-bar scheme dropdown. Mirror the existing desc
pattern exactly: PluginEntry.name / ShellPreset.desc widen to the
i18n-friendly string-or-() =>-string union, the catalogs carry lazy
t('pluginXxxName') / t('presetDshDesktopDesc') lookups, and the
add-plugin modal (render, search filter, aria-labels) plus the scheme
SelectMenu resolve them like every other copy. The plain-string arm of
the union stays as the raw-name fallback, and t() itself never yields
empty text (missing keys render the key), so a dict gap can never blank
a name.

20 new dictionary keys added to zh/en (locales.ts), ja (locales-ja.ts),
and all 18 third-language dictionaries — tests/locales.spec.ts enforces
key-set equality against zh for every shipped dict (precedent: 9cc642b),
so the 'leave other locales-* untouched' shortcut would fail the hard
parity gate; real translations are provided instead.

Spec follow-ups (behavior change: names/descs now render through t()):
- plugin-list.spec.ts: name non-empty assertion resolves the union.
- add-plugin-modal.spec.tsx: sentinel/office name assertions resolve
  from the catalog (en locale in tests) instead of pinning zh literals.
- shell-presets.spec.ts: desc non-empty assertion resolves the union.
2026-09-03 19:59:00 +08:00
Menghuan1918 fbfd59bd1b feat: adapt to DSH 0.1.2-rc.1 and bump to v0.18.0 (stable)
Graduate from the alpha track to the stable channel:

- Baseline: CI mount pin, dsh.plugin.json engines floor, and every
  @deepseek-ai/* peer floor / devDependencies pin move to 0.1.2-rc.1
  (published on the `next` dist-tag). alpha.5 -> rc.1 is a pure version
  bump in the harness (all package.json "version" lines, zero source
  delta), so no code adaptation; every host contract was re-verified
  unchanged and the real-host mount smoke passes.
- dsh-client-locale resumed publishing; its trailing-pin exception is
  gone — peers and devDeps align at 0.1.2-rc.1 (pnpm peers check clean).
- Version: fold the unpublished v0.18.1-alpha.0 / v0.19.0-alpha.0 bumps
  into the v0.18.0 stable release; SIDEBAR_SERVICE_VERSION follows
  package.json (asserted by tests/service.spec.ts).
- Docs: README/README_EN badges + channel notes + a full "since v0.17.1"
  changelog entry (the two folded alpha numbers are annotated), AGENTS.md
  §2/§3 baseline wording, external-plugin-guide version line, and the
  e2e-host-protocol header's re-verified list gains 0.1.2-rc.1.
2026-09-03 17:32:04 +08:00
Menghuan1918 0831505854 test(lib-guards): lib 产物缺失时 chunk-artifact / manifest-consistency 跳过而非 ENOENT
fresh clone 未 build 直接 pnpm test 时,两 spec 的 readFileSync 会
ENOENT 崩溃(此前靠 package.json prepare 钩子隐式兜底)。改为文件级
describe.skipIf 守卫:缺产物时整套显示为 skipped 并 console 提示先
pnpm build(exit 0);产物存在时行为与之前完全一致(本仓 prepare 钩
子产出 lib 后两 spec 照常执行,已验证 9 passed 非 skipped)。
2026-09-03 12:04:41 +08:00
Menghuan1918 936df662b0 test(specs): 收敛 28 个组件 spec 的渲染样板到共享 test-utils
- 7 个 spec 的本地 mount()(createRoot + act 容器循环)替换为
  renderRoot():sidechat-view、subagent-jobs-view、subagent-live-polling、
  lazy-chunk、side-card-section-rows(本地 mount 删除,调用点改名);
  editor-refresh、markdown-manual-refresh(EditorHost 包装 mount 改为
  委托 renderRoot,调用点不动)
- 24 个 spec 的内联 IS_REACT_ACT_ENVIRONMENT 赋值替换为 setupReactAct()
  (subagent-jobs-view / subagent-live-polling / lazy-chunk 原本未设
  flag,保持原样不引入)

全部为语义相同的样板替换:迁移后全量 118 files / 1241 passed +
9 skipped,与迁移前一致。
2026-09-03 12:04:35 +08:00
Menghuan1918 a627a4c84d test(utils): 新建共享 React 测试工具 setupReactAct / renderRoot
收敛组件 spec 两类样板的最小共享面:IS_REACT_ACT_ENVIRONMENT 幂等设置
(vitest 按文件隔离 global,逐 spec 调用与原内联语句语义一致)与
createRoot + act 的分离容器渲染循环。刻意不做查询 DSL / 自动清理 /
新依赖。
2026-09-03 12:04:24 +08:00
Atlas Zeng ad392ceea4 Merge pull request #522 from wang-kaopu/fix/517-client-ssh-open
fix(editor): open SSH remote editor links on the client
2026-09-03 10:54:34 +08:00
Menghuan1918 24db20a796 test: make five suites Windows-runner clean
First ci-windows run exposed four platform assumptions in the fixtures:

- smoke: the scratch repo inherited the runner's system-wide
  core.autocrlf=true (Git for Windows default), so every index restore
  smudged LF to CRLF and broke the byte-exact assertions — pin
  core.autocrlf=false in the fixture (eol policy is not what these
  destructive-op tests are about).
- git / git-worktree: Windows TEMP is the 8.3 short form
  (C:\Users\RUNNER~1\...) while git reports long paths, and
  realpathSync does not expand 8.3 aliases — switch the canonicalizer
  to realpathSync.native (libuv resolves via GetFinalPathNameByHandle,
  which does); same trick as the existing macOS /var workaround.
- bundle-route: the ETag memo revalidates on stat (mtime+size) and
  Windows updates file timestamps lazily, so the equal-size rewrite
  still looked unchanged — change the length too.
- market-manifest: GNU tar (Git Bash) reads the drive-letter colon of
  absolute Windows paths as a remote-host spec — run it from the pack
  dir with the bare tarball name instead.
2026-09-03 10:42:56 +08:00
Atlas Zeng c78c6dcf25 Merge pull request #503 from jackie-cqz/fix/windows-custom-shell-resolution
fix(terminal): resolve Windows custom shell executables
2026-09-03 10:42:45 +08:00
Atlas Zeng c9a960884f Merge pull request #461 from Guochaoo/fix/markdown-preview-toc-and-code-header
fix(markdown): preview TOC dismiss-on-outside-click, popover z-index, code-block banner stickiness
2026-09-03 10:42:20 +08:00
Kunping Wang ed2ccc829e fix(editor): 在客户端打开 SSH 远程编辑器链接 2026-09-03 10:32:34 +08:00
Ch3n4y 94ffac0224 fix(editor): keep file basename in @-reference links
The explorer @ button appended plain text (@folder/file.ts), which DSH's
composer only decorates as a folder ref (@folder/) — the file name stayed
outside the link. Insert FILE references through DSH's own structured
insert-reference event instead, minting one chip for the whole reference
(displayed as @basename, serialized as the full @path). Directories keep the
plain @dir/ mention so folder completion still works.
2026-09-03 10:00:13 +08:00
jackie-cqz 74993839e7 fix(terminal): resolve Windows custom shell executables (#487) 2026-09-03 09:58:42 +08:00
Guochao a2a26901e6 fix(markdown): preview TOC dismiss-on-outside-click, popover z-index, code-block banner stickiness
Three preview (render) bugs where DSH's chat-optimized markdown primitives
leak into the file-preview scroll world:

- CodeBlock banner: DSH's bannerWrap is position:sticky (top:0, z-index:6) so a
  block keeps its copy action reachable inside a per-message scroll container.
  In the preview every fence shares one .editorMd scroll container, so the
  banner pins to the viewport top until the whole block scrolls past and reads
  as a floating header. Neutralize stickiness for non-mermaid fences in the
  preview (mermaid chrome replaces the banner and is excluded via
  data-mermaid-processed).

- TOC popover z-index: .tocBar was z-index:3, below the code banner's 6, so the
  outline panel painted beneath a sticky fence header. Raise the bar to 7.

- TOC dismissal: only the toggle re-click closed the popover. Add a document
  pointerdown listener that closes on an outside press (blank preview space),
  exempting the button and panel so the toggle still flips.

Adds md-toc unit coverage for outside-click dismiss and toggle-preserving
behavior; records the deviations in the TOC design doc.
2026-09-03 09:56:31 +08:00
chendefine 96650fa189 fix(shell): keep an overflow:hidden fallback beneath clip + guard the cascade
shift fix) — but as a BARE declaration. Engines without clip support
(Safari < 16, older Chromium) drop an unsupported declaration at parse
time, which leaves the host `overflow: visible`: no clipping at all,
and the historical "collapsed panels extend the document's scrollable
area, whole page draggable" regression returns on those engines.

Declare `overflow: hidden` BEFORE `overflow: clip`: clip-aware engines
apply the later clip (identical behavior to #453), while old engines
fall back to hidden and keep clipping (with its pre-clip
scrollability — the same state they had before #453, strictly better
than visible). The cascade order is the contract.

Also extends the rule comment (the fix guards the whole
scroll-into-view class — focus moving into off-viewport regions,
nested iframes/workbenches claiming focus while loading — not just the
reveal case) and adds tests/panel-host-css.spec.ts guarding the
cascade (hidden first, clip last), the fixed viewport layer, and that
the degraded rule never reintroduces overflow. Contract documented in
the integration guide §12 (root anchor bullet).
2026-09-02 23:51:13 +08:00
Atlas Zeng 5337ef77dd Merge pull request #398 from SparkElf/fix/desktop-sidebar-layout-mode
fix: preserve desktop shell layout with side card
2026-09-02 23:44:15 +08:00
Atlas Zeng a446192008 Merge pull request #373 from Jstn-1g/fix/162-narrow-auto-activation
fix: avoid forcing mobile drawer on auto-activation
2026-09-02 23:44:06 +08:00
Atlas Zeng f61c161494 Merge pull request #455 from wang-kaopu/fix/issue-399-wsl-paths
fix: resolve Linux absolute paths in WSL workspaces
2026-09-02 23:43:58 +08:00
Atlas Zeng 0607517134 Merge pull request #394 from Beverly621/fix/markdown-frontmatter-preview
fix(editor): hide YAML frontmatter in Markdown preview(在 Markdown 预览中隐藏 YAML Front Matter)
2026-09-02 23:43:49 +08:00
laoyh e12927e8a9 fix: preserve desktop shell layout with side card 2026-09-02 23:37:40 +08:00
Justin Skowyra 2d2e8534a5 fix: keep restored mobile drawer closed 2026-09-02 23:26:04 +08:00
Justin Skowyra 41da8cb101 docs: align responsive auto-activation contract 2026-09-02 23:26:04 +08:00
Justin Skowyra d6c587e577 fix: avoid forcing mobile drawer on auto-activation 2026-09-02 23:26:04 +08:00
Kunping Wang 180b16de1b fix: 修复 WSL 会话 Linux 路径解析 (#399) 2026-09-02 23:20:17 +08:00
Beverly621 e31130adb8 fix(editor): hide YAML frontmatter in Markdown preview 2026-09-02 23:15:19 +08:00
Cyancat 26d37c1a8f fix(client): intercept the alpha chat file-open funnel (remote.session.openWorkspacePath)
0.1.2-alpha 宿主删除了 ctx.workspaces.openPath,聊天文件点击全部改走
remote 命名空间,旧拦截成为死代码(点击穿透到 xdg-open)。改为在
ctx.inject(['remote.session']) 内以 defineProperty 遮蔽该方法(accessor
属性,赋值无效),接管时返回 RemoteResult 成功包络。语义不变,

设计:docs/plans/2026-08-31-openpath-intercept-alpha-design.md
2026-09-02 23:13:57 +08:00
Atlas Zeng 02b2310335 Merge pull request #456 from wang-kaopu/fix/issue-403-sidebar-locate-performance
perf(sidebar): reduce repeated center-column DOM queries
2026-09-02 23:11:10 +08:00
Atlas Zeng 3b5e255882 Merge pull request #385 from TaurusWood/fix/free-window-restored-id-collision
fix(state): seed restored free-window ids
2026-09-02 23:10:46 +08:00
Atlas Zeng ded3cf13b0 Merge pull request #454 from wang-kaopu/fix/issue-440-old-git-worktree
fix(git): support worktree listing on older Git versions
2026-09-02 23:10:37 +08:00
Atlas Zeng fc666eee47 Merge pull request #366 from GeekRicardo/fix/terminal-font-monospace-fallback
fix(terminal): 自定义字体解析失败时兜底到等宽,避免掉进比例字体毁掉网格
2026-09-02 23:10:30 +08:00
Atlas Zeng 2a8187431d Merge pull request #509 from Awesome-AI-Pedia/fix/438-reference-button-tail
fix(explorer): pin reference affordance to row tail
2026-09-02 23:09:41 +08:00
Atlas Zeng ffbd9d7882 Merge pull request #427 from eg-bole/fix/selection-popup-dismiss-cursor-insert
fix(editor/conversation): selection popup dismissal + caret-anchored draft insert (#425)
2026-09-02 23:09:15 +08:00
Atlas Zeng 5815ad0f09 Merge pull request #428 from Jstn-1g/fix/426-safe-pty-resize
fix(terminal): contain transient resize failures
2026-09-02 23:08:52 +08:00
Atlas Zeng 4f0d66dbc5 Merge pull request #516 from omdsh-dev/feat/dsh-0.1.2-alpha.5
feat: adapt to DSH 0.1.2-alpha.5 and bump to v0.19.0-alpha.0
2026-09-02 21:50:41 +08:00
Menghuan1918 a78dd57b23 feat: adapt to DSH 0.1.2-alpha.5 and bump to v0.19.0-alpha.0
- pins: CI mount-gate CLI, dsh.plugin.json engines floor, and the
  @deepseek-ai/* peer floor / devDependencies baseline move to
  0.1.2-alpha.5 (dsh-client-locale trails at 0.1.2-alpha.3 — no such
  release upstream; ^0.1.2-alpha.3 already accepts the alpha.5 runtime)
- code: migrate the alpha.4 Session.events removal to snapshotEvents()
  (sidechat transcript live reads, fork inheritance, jobs.output replay,
  subagent activity) and drop the seedLength meta field the host removed
  from CreateAgentOptions.meta
- gates: pnpm peers check clean, typecheck + 1137 unit tests green,
  real-host mount smoke 14/14 on npm-published 0.1.2-alpha.5
2026-09-02 21:43:34 +08:00
Atlas Zeng efc328a8c1 Merge pull request #489 from omdsh-dev/feat/sidebar-perf
perf: 侧边栏性能优化(核心包 -45%)+ 修复底栏拖拽引发的原生左栏突变
2026-09-02 21:33:49 +08:00
yangkun 75a888df14 fix(explorer): pin reference affordance to row tail 2026-09-02 10:55:03 +08:00
yangkun ac02598150 fix: preserve Windows explorer reveal selection 2026-09-02 10:27:43 +08:00
Menghuan1918 e06ce8cef1 test: fix the perf lane's resource typing for typecheck
getEntriesByType widens to PerformanceEntry; transferSize/
decodedBodySize live on PerformanceResourceTiming (the e2e specs sit
outside tsconfig.build.json, so the bundler never saw this).
2026-09-01 16:07:33 +08:00
Menghuan1918 cf542d6318 perf: tag the center column instead of a :has() selector; stop re-stringifying the editor doc per keystroke
The bottom-push rule anchored on #root :has(> [data-slot=conversation]):
a :has() match cache invalidates on every #root subtree mutation, and
the streaming chat mutates that subtree constantly — every layout-push
frame (the bottom drag writes --dsh-sidebar-height per frame) paid a
whole-document selector re-evaluation. The shell's locator (which
already holds the measured column node for the ResizeObserver) now
tags it with [data-dsh-center-col]; the rule evaluates once per node.
The tag retargets with the ref on boot swap / HMR node replacement and
is removed on unmount; the drag lane pins exactly-one-tagged-node and
its identity as the conversation slot wrapper's parent. The dead
[data-pane] branch (renamed away in alpha hosts) is gone.

TextEditor: the CodeMirror updateListener re-stringified the WHOLE
document into React state on every keystroke (O(docLength) per key,
re-rendering the shell per key). The listener now only flips the dirty
flag; the preview's draft is snapshotted from the live view when
entering preview (or on a content swap), and save() already reads the
live document.
2026-09-01 16:01:34 +08:00
Menghuan1918 c7d58c9b25 perf: move the 19 non-zh/en dictionaries into a lazy locale chunk
The core client bundle statically imported every third-language
dictionary (ja/de/fr/…/zh-HK/MO/TW, ~640KB of source — roughly half
the bundle's weight) for a code path most sessions never enter: the
sidebar's own t() only consults zh/en plus the better-locale override
store, and the dicts' ONLY consumer is that store's register() call.

They now ride the existing lazy-chunk machinery as lib/client-locale.js
(fetched from /sidebar/bundle only when better-locale is actually
installed; a generation counter keeps the async registration moot when
the integration effect re-runs or disposes mid-flight). Until the chunk
lands, t() keeps the zh/en chain; the store's own revision bump on
register re-renders the chrome once the dicts arrive.

Core client.js: 1.46MB → 822KB (-44%). The chunk-boundary key-set
check moves to the existing runtime test (every shipped dict stays
key-set-equal to zh).
2026-09-01 16:01:34 +08:00
Menghuan1918 b7af498427 perf: stabilize renders (transcript row reuse, tree Sets, shared + options, batched drags)
SideChat transcript: every 2s poll rebuilt ALL row objects, so every
row (markdown parse + DOMPurify included) re-rendered even when the
log had not changed. transcriptRows now takes the previous poll's
rows and re-adopts the position-aligned rows whose content is
identical (reuseRows) — only the changed tail rebuilds. The view
feeds the memoized array back through a ref; unit tests pin the
identity contract (unchanged rows keep object identity, changed rows
and everything past the change rebuild, tool-result landings never
re-adopt).

FileTree: expanded/revealed membership was an includes() scan per
rendered row (O(rows × expanded) per render on deep trees); one Set
per render keeps it O(1) per row.

Shell: buildNewTabOptions was inlined in the two Workbench JSX
sites — two fresh arrays per render (drag state, resizes) re-rendered
every LeafView's + affordance. One shared memo now.

DiffPane resize / TerminalView ResizeObserver: pointer and resize
streams fired a setState / glyph-measuring fit() per event; both ride
per-frame batching now (frame-batcher in the core, a local rAF gate
in the lazy terminal chunk). SessionLens sizes each row's content
with a Blob (a UTF-8 encode of the whole edit) — that moved from
per-row-per-render into one memoized pass per changed fold.
2026-09-01 16:01:34 +08:00