Commit Graph
105 Commits
Author SHA1 Message Date
Menghuan1918 8025b83a45 feat(file-icons): 目录保留扩展名注册 + 全局默认兜底 + 编辑器文件 tab 对应
- registerFileIcon 保留 'folder'/'folder-open' 特殊扩展名:目录行(含根行)
  图标可注册,匹配保留值不认领真实 .folder 文件
- 新增权威解析器 fileIcon(path,size)(具体注册 → 内置 glyph → catch-all
  全局默认 → VscFile,逐工厂崩溃隔离)与 folderIcon(path,open,size);
  matchFileIcon 收窄为仅具体扩展名匹配
- 编辑器文件 tab(非 meta.dir)与文件树行显示同一 fileIcon 图标
- 同步 external-plugin-guide §7(保留值/回退链/三例注册)与 README
  (功能一览、v0.19.0-alpha.0 发布注记、服务化扩展章节)
- tests/file-icons.spec.tsx 重写为 17 用例(链序/保留值/目录/崩溃回退)
2026-09-08 21:11:32 +08:00
Menghuan1918 05773e0f2a feat(file-icons): 文件树按扩展名区分图标 + 对外 registerFileIcon API
- 新增内置扩展名→glyph 映射(md/媒体/pdf/json/代码/配置/数据库/压缩包,
  单色 currentColor 遵循皮肤契约,未知扩展回退 VscFile)
- ctx.betterSidebar 新增 registerFileIcon/getFileIcons/matchFileIcon
  (priority 降序,同优先级 catch-all 垫底),features 增加 'fileIcons'
- FileTree 文件行消费注册表:注册图标优先(可为彩色 ReactNode,
  工厂抛错回退内置),注册/注销即时生效
- 同步 docs/external-plugin-guide.md §7 与 tests/file-icons.spec.ts
2026-09-08 21:11:32 +08:00
Menghuan1918 364a48df98 chore(release): 0.18.1
- package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION → 0.18.1(三者锁步由
  tests/service.spec.ts 与 tests/manifest-consistency.spec.ts 断言)
- README / README_EN:新增 v0.18.1 条目并同步三处徽章版本号——自 v0.18.0 起的
  11 个 PR:#499 变更面板预览增强(md 阅读模式 / html·pdf 渲染 / 密钥脱敏)、
  #550 文件树重命名与删除、#535 目录名词典化、#562 侧边对话种子补 fork 标记、
  #569 markdown 本地图片改写、#576 git 折叠上下文按需展开(含 git.show 路由
  rev:path 修正),以及 #524/#526/#527/#534/#536/#540/#541/#542 的内部收敛
- docs/external-plugin-guide.md:当前版本行 → v0.18.1
- DSH 基线不变(peer ^0.1.2-rc.1,CI 钉 0.1.2-rc.1),无运行时行为改动

验证:make check(typecheck → lint → build → test → check:consumer-types)全绿,
124 test files / 1319 passed, 9 skipped
2026-09-08 16:16:16 +08:00
haruhi 5bf7dfe3c4 fix(git): git.show 路由改用仓库相对路径,修复折叠展开空白
- src/index.ts: git.show 的 path 不再经 resolveGitPath 转绝对路径——rev:path 语法只认仓库相对路径(diff 输出剥 a// b/ 前缀的形态),绝对路径恒 fatal 返 null,折叠展开渲染空行;透传后暴露面与 git.diff/git.log 一致(仅本仓库版本树)
- src/client/changes/DiffPane.tsx / src/client/DiffTab.tsx: 两侧内容皆空时抛错走「上下文未加载」降级,不再静默空白展开

背景:真机 link 测试发现展开后 marker 消失但零行渲染——git.show 路由此前无真实调用方,resolveGitPath 的工作区语义与 rev:path 树寻址不匹配的缝隙首次暴露。
设计 docs/plans/2026-09-07-git-fold-expand-design.md 实施偏差第 8 条同提交。
2026-09-08 00:04:25 +08:00
haruhi 6b02285742 docs(diff): git 折叠行按需真实展开设计文档
- 新增 docs/plans/2026-09-07-git-fold-expand-design.md:bug 证据链、切片算法、两 lens 取数映射与边缘 case 清单
- §8 仓库规范补「风格对齐」条款;文末补实施偏差记录 7 条

背景:changes 的 git lens 折叠行显示「点击展开」却无交互(-U3 裁剪使 gap fold 无行文本),文档定稿按需拉取两侧内容真实展开的修复方案。
2026-09-07 23:51:05 +08:00
Menghuan1918 9302d02cf5 refactor(changes): bring the PDF render toggle in line with the pane conventions
Escape the .pdf extension in the op-target regex (the unescaped /.pdf$/
matched any path ending in pdf) and fold the copy-pasted toggle button
into PaneToggle; record the sixth deliverable in the design doc.
2026-09-06 23:48:25 +08:00
Menghuan1918 0c3d1d6e32 docs(changes): design doc for the op-preview enhancements
Records the five features shipped on this PR (md reading mode incl.
mermaid, highlight expansion, secret redaction, html render mode), their
deliberate boundaries (redaction heuristics, saved-file render
semantics), and the 2026-09-06 standards pass.
2026-09-06 23:46:46 +08:00
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 f59ffd0741 docs(plans): 全方位代码防腐审查报告与 backlog(2026-09-03) 2026-09-03 21:21:22 +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
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 5dbbde61ce docs(open-with): 同步 SSH 链接客户端打开后的注释与设计偏差记录 2026-09-03 10:50:26 +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
Menghuan1918 4742aa1b9c docs(guide): sync onReferenceFile(path, isDir) signature 2026-09-03 10:02:27 +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
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
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 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
Menghuan1918 8a01e5d881 docs: record the perf optimization's before/after measurements
The comparison table (3-run medians on the same machine against a real
0.1.2-alpha.2 host): mount latency 377→273ms (-28%), the host's
aggregated client bundle ships 203KB less over the wire (-14%,
matching the 19 dictionaries' gzip weight) and 640KB less decoded
(their source weight), boot settings.get 4→2, the bottom-drag width
leak 504px→0. Frame pacing was already at 8/10ms p50/p95 — the drag
fix removed the host-layout snap, not a frame drop. Structural wins
that don't show in a single sweep (git spawns per poll tick, fold
passes per poll, transcript row re-renders, per-keystroke doc
stringification) are listed with their per-event arithmetic.
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 f024fbf092 fix(changes): 会话事件改走宿主 changes.ops 路由 + diff 展开二级设置 + 视觉迭代
CI 修复(plugin-mount 的 ctx.sessions.get TypeError ×1003):
- 客户端 runtime 无事件日志面——badge/SessionLens 原在客户端直读
  ctx.sessions.get(id).events / ctx.on('session/event'),全部不可达。
- 新增宿主路由 changes.ops:live 会话日志优先,冷会话回放
  sessionPersistence.inspect;afterSeq 增量(缺省游标含 seq 0,
  显式游标为 seq > afterSeq,同 sidechat.events 约定),窗口上限
  4000 与客户端累加器一致。
- ChangesTab 轮询(mount 一拉 + visible 2.5s 增量)折入 ops,写
  模块级 opCounts 缓存供 badge 同步读取;SessionLens 改纯展示。

diff 展开二级设置(changesDiffFloat,默认浮窗):
- prefs 四处接线 + git tab settings select(浮窗/面板,图标选项卡)
- 预览面板「展开为 diff tab」按设置落点:浮窗居中弹出或源 pane
  下方 split;i18n 全 21 词典同步。

视觉迭代(真机挂载截图审查后调整):
- Session 视角:kind 徽章为左轨,大小+相对时间右对齐元列;失败
  操作行红色内嵌条;文件组头降为三级标签并加组间距。
- Git 视角:untracked '?' 徽章与新增同绿色;stage 按钮改 plus 图标。
- diff 折叠行:可展开折叠带 › 箭头 + 次级对比度,静态 gap 不再
  显示 pointer/hover;预览头路径改尾部截断(RTL 技巧,保文件名)。

验证:typecheck ✓ / vitest 1123 ✓ / pnpm test:mount(钉 alpha.2 CLI)
14/14 ✓;真机挂载截图(badge=5、双视角、浮窗展开)0 console error。
2026-08-31 17:52:59 +08:00
Menghuan1918 24a3813c63 feat!: 合并 Git 面板与文件追踪为统一「文件变动」tab(双视角 + 统一 diff 栈)
在 PR #471(file-trace)基础上的演进:

- 合并 tab:git tab(id 保留,兼容持久化布局)升级为「文件变动」双视角
  tab——Git 视角(原 GitView 全部能力:staged/unstaged/提交/历史/worktree·
  子仓库选择/右键菜单/确认弹窗)+ 本轮文件视角(原 file-trace:会话事件
  日志实时折叠的模型读写编辑记录,按文件分组、新增类型筛选 chips、相对
  时间);file-trace tab 移除(未随任何版本发布)。
- 统一 diff 组件:新 src/client/diff/ 模块(rows.ts 引擎 + DiffRows/
  DiffFiles 渲染器 + highlight.ts 语法着色)——git diff 与会话操作 diff
  共用一套渲染:mod 改写配对(del-run/add-run 对半标蓝)、行内字符级
  高亮(修复了旧实现旧侧失配不高亮的问题,改为行对象身份键)、上下文
  hunk 折叠、git hunk 间未输出区间按行号范围生成不可展开折叠、语法着色
  色相落位 diff 三色空档、+n −m 统计 chips、行底色 tint;DiffTab 改用
  该栈(git diff tab 从此也有高亮)。
- 交互:两视角共用底部可拖拽预览面板(点击文件/提交/操作即预览,不再
  直接开 diff tab;面板可刷新、可键盘/拖拽调高、git 目标可一键展开为
  独立 diff tab);视角选择与面板高度持久化在 tab.meta;git 行 XY 徽章
  按状态字母着色;选中行高亮。
- i18n:fileTrace* 十键重命名为 changes* 前缀,git 键值更新为「文件
  变动」,新增 7 键(视角/筛选/面板操作),全部 21 个词典同步。
- 结构:src/client/changes/(ChangesTab/GitLens/SessionLens/DiffPane/
  ops)+ src/client/diff/;GitView/DiffView/filetrace/ 删除;git 样式
  从 sidebar.module.css 迁至 changes.module.css。
- 测试:builtins 8→7(git tab 承接 badge pin)、diff-rows(unified
  转换/mod 配对/间隙折叠/统计)、changes-tab(壳交互 jsdom)、
  diff-files-collapse(原 DiffView 折叠行为钉住)、changes-ops(原
  filetrace 数据层)、git-view-worktree 迁移至 GitLens;全量 1122 通过。
- 文档:README ×2 功能矩阵合并、external-plugin-guide §4.4 与内置清单
  7 tab、mount e2e 菜单标题同步。
2026-08-31 01:31:22 +08:00
lhh010 9255040489 Merge origin/main into feat/file-trace-tab: resolve external-plugin-guide version line (keep 8-tab count, adopt v0.18.0-alpha.0 alpha-track wording) 2026-08-31 00:21:10 +08:00
Menghuan1918 07eebbbad0 feat!: move to the alpha track — DSH 0.1.2-alpha.x only (v0.18.0-alpha.0)
DSH itself is still on its 0.1.2-alpha line (npm `alpha` dist-tag), so the
plugin mirrors it: v0.18.0-alpha.0 publishes under the npm `alpha`
dist-tag and supports DSH 0.1.2-alpha.x only. Stable-DSH (0.1.0-rc.8 ~
0.1.1-rc.2) users stay on v0.17.1 (npm `latest`). Verified end-to-end
against a real 0.1.2-alpha.2 host: full vitest suite, typecheck,
build/pack, consumer type surface, and the headless mount smoke 14/14
(the prerelease version also passes `dsh plugin add file:`).

- peer floor raised `^0.1.0-rc.8` -> `^0.1.2-alpha.2` (the mount install
  no longer warns: the old floor could not semver-match a prerelease
  host); dsh.plugin.json engines.dsh `>=0.1.2-alpha.2`.
- Dropped the pre-alpha compatibility layer:
  - e2e host RPC collapsed from the dot/slash dual dialect to slash-only
    (rpcAttempt; the 404-probe negotiation and its cache are gone), and
    parseLaunchUrl now requires the ?token= launch URL;
  - MarkdownText labels collapsed to the nested single shape (the cast
    became unnecessary against the alpha.2 declarations);
  - the defunct `@deepseek-ai/dsh-client-runtime` row is gone from the
    chunk externals allowlist (chunk-loader / tsdown / two specs) and
    from dsh.client.inject.
- market-manifest guard now allows an exact prerelease version (alpha
  cuts are not the market's verified `latest` target); release.yml picks
  the npm dist-tag from the version (prerelease -> `alpha`, else
  `latest`) so an alpha can never hijack `latest`.
- Docs retargeted: AGENTS.md §2/§3, README/README_EN badges + v0.18.0
  -alpha.0 section + install note (`dsh-better-sidebar@alpha`), guide.
2026-08-30 23:42:16 +08:00
Menghuan1918 f9e00bb0d0 feat: adapt to DSH 0.1.2-alpha.2 (npm-published) and bump to v0.17.2
DSH 0.1.2-alpha.2 is on npm under the `alpha` dist-tag, so the CI mount
pin and the @deepseek-ai/* devDependencies baseline move up from
0.1.1-rc.1/rc.2 (the dead dsh-client-runtime devDep goes away with
them). Verified end-to-end against a real 0.1.2-alpha.2 host: full
vitest suite (1106), typecheck, build/pack, consumer type surface, and
the headless mount smoke 14/14 — the token URL, slash RPC and
MarkdownText labels contracts are unchanged from alpha.1.

- dsh-settings dropped the runtime `settingsNamespace` export:
  namespaces are validated at compile time (SettingsNamespaceInput), so
  the host passes the 'dsh-better-sidebar' constant directly and the
  fake settings service in smoke.spec casts to the branded type.
- dsh-subagent bumped SUBAGENT_DESCRIPTOR_VERSION 2 -> 3: the version is
  stamped by the host package; the sidechat seed assertion now follows
  the constant instead of pinning a literal.
- Restored SessionEvent.ignorable and the RemoteError wrapping were
  verified to have no impact on this plugin.
- e2e scratch profiles (e2e-mount.sh / e2e-aggregate-mount.sh) add
  '@deepseek-ai/*' to minimumReleaseAgeExclude (mirroring the repo
  root): alpha releases are often <24h old when the lane runs, which
  pnpm 11's default minimumReleaseAge would refuse to install.
- vitest excludes .worktrees/** — local task worktrees carried stale
  code against the shared node_modules and broke on the devDeps bump.
- Version lockstep 0.17.2 (package.json, dsh.plugin.json,
  SIDEBAR_SERVICE_VERSION, README/AGENTS/guide docs).
2026-08-30 22:38:09 +08:00
Menghuan1918 28447ca2e8 fix(sidechat): read the transcript through the plugin's own events route
DSH 0.1.2-alpha.1 removed the client `ctx.connection.api` face (Remote
gateway migration), so every Side Chat transcript poll (`sessions.history`)
threw TypeError into the view's catch and was swallowed — the tab rendered
an empty transcript forever, silently (no console error, so the mount lane
never caught it). The successor APIs are not a drop-in either:
session/follow|page reject plain session addresses for origin:'subagent'
logs (agent-busy fence) and paging cannot read past the current cursor.

Move the transcript to the plugin's own wire — one transport for every
DSH generation:

- new `sidechat.events` route: live threads read the in-memory
  `agent.session.events`; cold threads read `sessionPersistence.inspect`
  (both seams exist since 0.1.0-rc.8; alpha.1's inspect returns the
  expanded logical log, never the packed chunk-row encoding). The
  inherited seed is cut host-side (`threadOwnLogEvents`), polls ride an
  `afterSeq` delta, and the response is tail-capped at 8000 events (the
  old client walk ceiling).
- SideChatView.fetchThread is single-path; collectOwnEvents (the client
  walk) is gone, and so are the ctx.connection mirror and inject entry
  (no consumer left).
- transcriptRows keeps re-cutting at session/end-seed as defense in
  depth.

Verification:
- unit: sidechat.events route (seed cut, afterSeq delta + never
  resurrecting the seed, cap, cold/live sources, 404/503/bad-request),
  full suite 1104 passed; typecheck and build (purity gate) green.
- mount e2e vs a real dsh-v0.1.2-alpha.1 source build: 14/14, including
  the Side Chat tab sweep polling sidechat.events (performance resource
  assertion) and live + post-dispose (persisted) route reads.
- mount e2e vs PATH dsh 0.1.0-rc.8: 14/14 (no regression).
2026-08-30 22:25:45 +08:00
lhh010 02d3936b92 feat: 新增第 8 个内置 tab「文件追踪」——移植 dsh-file-trace 插件
- 数据层:直接折叠会话事件日志(tool/call + tool/result 对)提取文件操作,
  与仓库「读事件日志而非动注册表」的取向一致;含错误文本捕获与
  running 态实时更新(ctx.on('session/event'),不可见时暂停、恢复时追平)
- 视图:操作列表 + 底部可拖拽 diff 面板;行级 diff(删红/增绿/改蓝)+
  行内字符级高亮;读取视图带真实行号;失败操作统一展示真实错误文本
- 语法着色:轻量分词器(关键字/字符串/数字/类型/函数/注释/预处理),
  色相经 color-mix 落在 diff 三色之间的空档;跨行块注释状态按行序推导
- 单实例 tab,+ 菜单 order 55,角标显示操作数;设置页可整体关闭
  (与独立维护的 dsh-file-trace 插件共存)
- i18n:10 个新 key 同步全部 21 个词典;builtins 测试 7→8;
  README/指南内置清单同步
2026-08-30 20:59:50 +08:00
Menghuan1918 a9353ce627 feat: workspace fence toggle (workspaceFence pref + one-click off in error surfaces)
- New persisted built-in pref workspaceFence (default true) under the
  files card's secondary settings modal; host reads it per request via
  the settings seam (fenceEnabledOf — absent/malformed stays ON).
- ensureWorkspacePath/ensureWorkspaceWritePath gain a fence param:
  disarmed skips the containment assert but keeps realpath resolution;
  wired through fs.tree/fs.read/fs.write, the media + html routes, and
  the upload path (writeWorkspaceUpload fence input).
- Editor load failures and file-tree level errors show the localized
  reason plus a one-click global off (FenceErrorNotice) that flips the
  pref, adopts it into the store, and auto-retries the failed operation
  (reloadSeq / retryDir) — the raw wire text is never shown.
- GitView's two client-side pre-checks (hidden open action + no-op
  defense) respect the pref; store threaded through TreePanel/FileTree.
- i18n: 4 new keys across all 21 dictionaries; tests: fence-off route
  coverage, prefs parsing, schema default, editor toggles list;
  docs: guide §8/§8.1 + plans/2026-08-29 design record.
2026-08-29 15:49:19 +08:00
Menghuan1918 9bfe5ccb66 docs(guide): promote external-plugin-guide to the single canonical integration doc
Absorb the consumer-facing API reference previously duplicated in
AGENTS.md and refresh stale content to v0.17.1:

- TabDescriptor: full SettingRow shape (select/multi, v0.13.0+),
  urlTarget, richer dedupeKey/available/createTab semantics
- built-in tab table: replace stale explorer-based list with current
  editor/sidechat/pinned-terminal reality
- service: features list completed (urlTarget/settingSelect/
  floatWindows), OpenTabSeed meta null/undefined semantics, openFile
  path-derived-id caveat
- settings: full built-in prefs key list, select rows
- new sections: float windows (§11) and the token-driven skinning
  contract (§12, moved from AGENTS.md §8)
- traps: aionui right-panel mutex, i18n/better-locale, lazy chunks
- minimal example: drop removed @deepseek-ai/dsh-client-runtime peer
- references: 9-viewer typo fixed, plugins catalog / fs-search /
  markdown-html / agent-opens entries added
- fix duplicated §11 heading; sections now run §1-§15
2026-08-28 21:42:26 +08:00
HuanLinOTO e7c4578791 feat: inline pinned tabs in TabBar (replaces PinnedRail)
M4 rewrite per user feedback: pinned terminals should display in the
Tabs bar itself, not a separate rail. Clicking activates in-place
(cross-session terminal rendering), no session jump.

Changes:
- Delete PinnedRail.tsx + tests/pinned-rail.spec.tsx
- pinned.ts: add createPinnedVirtualTab (virtual id = pinned:<sess>:<id>,
  meta.__pinnedHome = { sessionId, cwd, tabId }), injectPinnedIntoTree
  (appends virtual tabs to first leaf, overrides active), isPinnedVirtualId,
  parsePinnedVirtualId, isPinnedVirtualTab, getPinnedHomeScope
- tab-content-memo.ts: add effectiveTabId to memo key — TabContent passes
  the original tab id (not the virtual id) to the descriptor component so
  TerminalView's WS URL resolves to the home PTY
- Sidebar.tsx: augmented tree (injectPinnedIntoTree), activePinnedTabId
  state, wrappedActions (intercept virtual ids for activate/close/unpin/
  drag/float), renderTab passes home scope + effectiveTabId for pinned tabs,
  pinnedRevision replaces railRevision
- TabBar.tsx: pinned virtual tabs non-draggable, pin icon prefix, stripped
  context menu (Unpin/Close only, no float/close-others/left/right)
- sidebar.module.css: remove rail styles, add .pinnedTab (italic + tertiary)
- Docs: README/README_EN/AGENTS.md/design doc updated for inline approach

157/157 client-side tests pass; typecheck + build clean
2026-08-26 21:40:32 +08:00
HuanLinOTO acf639471d feat: pinned terminal i18n + docs + v0.17.0 bump
M5 of pinned terminals (v0.17.0):
- README/README_EN: feature list adds pinned terminals
- AGENTS.md §3.4: terminal row documents pin capability
- Design doc: implementation deviations (M3 disconnect signal convergence,
  M4 railRevision state for reduceFor non-notify)
- package.json + dsh.plugin.json: 0.16.1 → 0.17.0
- i18n: 12 new keys synced across all 19 language dictionaries (done in M2)
- All client-side tests green (149/149); typecheck + build pass
2026-08-26 18:44:46 +08:00
HuanLinOTO d052bd7fb2 docs: pinned terminal design + implementation plan 2026-08-26 18:21:43 +08:00
HuanLinOTO 15e90d936e merge: 合入最新 main(#353 agent-open-tools / #360 markdown-html-toc 等),解决 PR 合并性
# Conflicts:
#	src/client/EditorHost.tsx
#	tests/prefs.spec.ts
2026-08-24 16:41:02 +08:00
Menghuan1918 8e0ef7a175 merge: 合入 main(PR #353 agent-open-tools),AGENTS.md 参考实现清单两条例目并存 2026-08-24 13:58:58 +08:00
Menghuan1918 7f634866bf feat(editor): Markdown 预览内嵌 HTML 安全渲染 + 目录大纲(TOC)
宿主 MarkdownText 出于聊天安全把 raw HTML 按字面文本渲染,预览 GitHub
风格 README(徽章墙 div、details 折叠块内嵌 markdown、表格单元格内联
标签、video/picture)时全是源码文本。本次在不动渲染器的前提下:

- markdown-html.ts(纯函数):fence 感知切分器把文档切成 markdown/html
  段(CommonMark type-6 块级标签名单 + 注释段 + 空行终止);段内标签
  tokenizer 归约 open/close/html parts;全文档引用定义收集(每段追加
  保持 [text][id] 跨段语义)
- MarkdownHtml.tsx:DOMPurify 白名单消毒(显式禁 script/iframe/form
  等;a 强制 _blank+noopener;本地媒体 src 经 /sidebar/file 重写);
  MarkdownDocument 帧栈状态机让 <details> 跨段嵌套内部 markdown;
  MarkdownSegment 内联替换(MutationObserver 幂等 pass,把表格单元格
  等处标签文本消毒还原为元素,纯散文不误伤)
- md-toc.tsx:零高度 sticky 浮动目录按钮(≥3 标题)+ 弹出大纲,跳转
  平滑滚动 + 自动展开折叠 details + 高亮闪现。关键修复:子组件读父
  ref 在 React layout 阶段恒为 null(子先于父),改为经自身 bar ref
  的 parentElement 定位容器(jsdom 单测传预填 ref 掩盖了该 bug,仅
  真实挂载 e2e 抓到)
- 纯 markdown 文档走原单次解析路径零变化(现有 mermaid e2e 守卫一字
  不动);新增 readme-style.md 种子 + 探针(消毒渲染/嵌套/内联/TOC
  全链路);19 语言词典新增 toc 键;dompurify 提升为直接依赖(与
  mermaid 传递依赖去重单版本)

设计文档 docs/plans/2026-08-24-markdown-html-toc-design.md
2026-08-24 12:05:14 +08:00
HuanLinOTO 867de61aca merge #215: editor preview refresh trio (Max-Null) 2026-08-24 01:34:24 +08:00
HuanLinOTO abe9c4fc46 merge #190: terminal Nerd Font icon fallback (ShelbyTang) 2026-08-24 01:34:10 +08:00
HuanLinOTO 53f3a2c246 merge #182: trust-fence Origin hostname compare for Edge 151 (MXY) 2026-08-24 01:34:06 +08:00
Menghuan1918 68640101e1 feat: sidebar_open tool gates model-driven sidebar opens behind a global setting
New global Side card setting `agentOpenTools` (default off, 常规 group):
when enabled, one `sidebar_open` tool is injected into the model so it can
actively open a local file, a local folder (tree rooted there), or an
HTTP(S) page in the calling session's sidebar.

- host: AgentOpenRegistry + registerOpenTool (src/agent-opens.ts); the tool
  classifies http(s) URLs / stat-driven file/folder paths, refuses other
  schemes, resolves relative paths against the session cwd, and reports
  target-tab-disabled instead of silently no-oping. Gated like
  agentTerminalTools (register/drain on settings watch).
- delivery: /sidebar/ws/agent-opens push (consume-on-send queue, replay on
  attach); the tool result reports `delivered` so queued opens for
  non-active sessions are honest.
- client: Sidebar subscribes and routes pushes to editor (file), folder
  window (meta.dir, tree rooted at the folder — EditorHost), or browser
  (URL) tabs; settings row in 常规 + 20 locale dictionaries.
- tests: agent-opens registry/tool spec, smoke gating + WS route list,
  prefs/plugin-shape defaults, editor-host folder window, side-card rows.
- docs: design doc, AGENTS.md key lists + reference, README feature bullets.
2026-08-24 01:19:43 +08:00
Atlas Zeng 36a4119253 Merge pull request #354 from omdsh-dev/feat/free-window
feat(ui): 自由窗口——tab 拖出侧边栏成为可移动/缩放/置顶的浮动窗口 (v0.16.0)
2026-08-24 01:12:37 +08:00
Menghuan1918 d15645bf23 feat(ui): 文件二级页面间距规整(8px 网格)+ 浮窗默认尺寸改手机竖屏比例
- 文件页 chrome 行统一:路径行与树搜索行同为 41px 高(路径输入框改
  border-box 28px 总高)、gap 统一 6px、内边距统一 6px 8px
- 树体侧距 6→8px 对齐 chrome 行;markdown 预览 10/14→12/16(与错误
  文案块一致);CodeMirror scroller 新增同款 12/16 内边距(预览/编辑
  切换文字位置不跳);截断横幅 12→8px
- 浮窗默认尺寸 480×360 → 390×780(1:2 手机竖屏比例),创建时先按
  视口减 24px 钳制再居中,矮视口得到更矮的窗而非溢出
- 测试/文档同步:state/free-window 预期重算(含 clampMove 回推的
  y=24 语义)、e2e 断言宽度上界、AGENTS §7.5 与设计文档
2026-08-24 00:59:27 +08:00
Menghuan1918 f17a1b30ac feat(ui): 自由窗口——tab 拖出侧边栏成为可移动/缩放/置顶的浮动窗口 (v0.16.0)
- 拖出:标签栏 tab 拖到主会话列(HTML5 DnD 检测 + 虚线提示浮层)或右键菜单
  「移动到自由窗口」(右/底面板共用 TabBar),tab 从 pane 移动进 SidebarState.floats
- 窗口(FreeWindow,渲染于 [data-dsh-panel-host] z-42):头部 pointer 拖动
  (rAF 直写 + 松手提交)、拖到 pane 高亮停靠(center 合并)、SE 角缩放、
  点击置顶、头部右键(回到侧边栏/关闭)、X = closeTab 走正常生命周期
- 服务语义:openTab dedupe/id 聚焦浮动 tab = 置顶窗口(不展开面板);
  closeTab/activateTab 兼顾 floats;agent 终端 reconcile 覆盖浮窗;
  features 单调新增 'floatWindows',版本 0.16.0
- 持久化:floats 随会话 localStorage,sanitizeState 宽容校验 + 几何钳制,
  uid 播种覆盖 float 前缀;i18n 三键 19 语言同步
- 关键修复(e2e 发现):portal 覆盖层(头部 Menu)的合成事件沿 React 树
  冒泡回拖拽表面,劫持菜单行点击——拖拽起点加 DOM 同源守卫(jsdom 不复现)
- e2e-mount.sh:缺省 tarball 改取 mtime 最新(旧字典序选择会把冒烟挂到
  过期产物);新增 tests/e2e/float-window.e2e.ts 双用例
2026-08-23 23:44:18 +08:00
HuanLinOTO 751fb954a2 fix: address Copilot review (9 comments)
#1 GitView: hide/disable 'open in editor' for external linked worktrees
   (path outside session workspace is rejected by the fence); add
   isWithinWorkspace client helper for the gate.
#2 DiffTab: untracked diff read resolves against diff.repoRoot (child-repo
   paths are repo-root-relative, not cwd-relative); fs.read route threads
   selectedRepoOf into resolveGitPath so the host resolves the right base.
#3 GitView: chooseRepo handler mirrors chooseWorktree — clears status/
   history/log and bumps generation before async refresh, preventing stale
   rows from acting on the newly selected repository.
#4 git.ts: repoRoots/repoRoot compare roots via pathIdentity() (platform-
   aware) instead of raw includes(), fixing win32 forward/backslash
   mismatch that silently fell back to roots[0].
#5 markdown-images: mask fenced code blocks and inline code spans before
   rewriting; only rewrite reference definitions whose label is actually
   referenced by image syntax (not plain links). +3 tests.
#6 package.json: downgrade unrun ^0.3.1 → ^0.2.39 (0.3.x requires Node
   ^22.13, incompatible with declared engines >=20).
#7 market-manifest.spec: shell:true on win32 so execFileSync resolves the
   pnpm .cmd shim.
#8 smoke.spec: build html-route URL via encodeHtmlUrl() (production
   encoder) so the Windows drive separator is correct.
#9 index.ts git.worktrees route: thread selectedRepoOf so a workspace
   container's selected child repo's linked worktrees appear.
2026-08-23 22:02:47 +08:00