Commit Graph
100 Commits
Author SHA1 Message Date
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
Atlas Zeng dd499b2560 Merge pull request #508 from Awesome-AI-Pedia/fix/504-windows-reveal
fix: preserve Windows Explorer reveal selection
2026-09-02 10:45:46 +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 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 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
Menghuan1918 427552e4f9 perf: cut the boot and poll overhead (one settings fetch, one git process per tick, one fold per poll)
Boot: loadPrefs and loadExternalDisable each fetched the settings
document, serially, before the first paint — and the second had no
timeout, so a stalled wire kept the sidebar unmounted forever. Both
decisions now ride ONE fetch (loadBootDecision) under the existing
2s race.

GitLens: the 2s silent poll re-listed worktrees on every tick (a
second git process per tick for a list that almost never changes, and
a fresh worktrees array re-render each time). Silent ticks now fetch
only the selected checkout's status; every 15th tick (~30s) re-lists
and re-runs auto-selection, so an agent-created linked checkout is
still picked up mid-session.

ChangesTab: extractFileOps parses every accumulated tool/call (up to
4000 events); the poll ran it once for the badge and the render ran
it AGAIN per tick, and the fresh array defeated the downstream memo.
The fold now runs once per poll and its result rides a ref shared by
badge and render (reset on session switch).
2026-09-01 15:58:44 +08:00
Menghuan1918 e2699a099e test: add the perf measurement lane (mount latency, longtasks, bundle cost, drag frames)
A measurement harness, not a pass/fail gate (beyond the mount sanity
it shares with the other lanes): an init-script probe samples the
navigationStart → host-attach latency, a longtask collector runs
through the full built-in tab sweep, sidebar-shaped resource entries
report transfer/decoded/duration, and a frame sampler records the
bottom-strip drag's pacing (p50/p95/max) plus the width-leak guard.

Results print as single-line PERF_JSON records so a shell run can tee
and grep them; before/after comparisons land in
docs/plans/2026-08-31-perf-optimization.md. Baseline (main @ d70db8f,
3 runs): mount ≈ 377ms, 2 longtasks ≈ 161ms, drag p95 = 10ms,
width leak = 504px.
2026-09-01 15:58:44 +08:00
Menghuan1918 659c2a20e2 fix: bottom-strip drag no longer leaks the panel width into the host layout
The bottom drag applied the panel's persisted width preference to
--dsh-sidebar-width regardless of panelOpen (only the idle push effect
gated it through layoutPushSize). With the right panel closed, the
first drag frame jumped the variable 0 → ~400px: #root lost 400px
instantly, the host frame's viewport dropped across its 1024px
auto-collapse breakpoint, and the NATIVE left sidebar snapped to its
56px rail — then snapped back on release. The bottom strip is the only
drag reachable with the panel closed, which is why only it showed.

applyDrag now rides the same gate as the push effect for the PUSHED
width; the panel-side DOM writes (panelRef/bottomRef/lastDragSize)
keep the raw width — the bottom panel's right edge derives from it.

The e2e regression pins the pose: panel closed + bottom open, drag the
strip, and every sampled frame must keep the pushed width at 0, the
host grid template, the left column width and #root's right edge
unchanged. Verified red on the old code (leaked 504px).
2026-09-01 15:58:44 +08:00
Atlas Zeng c1992125d0 Merge pull request #497 from omdsh-dev/fix/dsh-0.1.2-alpha.3
feat: adapt to DSH 0.1.2-alpha.3 and bump to v0.18.1-alpha.0
2026-09-01 15:56:53 +08:00
Menghuan1918 f78da4079a refactor: hoist the alpha.3 transitive peers into devDependencies
Replace the pnpm-workspace.yaml overrides with the plain-repo pattern:
install every peer the dev tree touches (dsh-attachment, dsh-code-runtime,
dsh-scope, dsh-session-projection, dsh-system-prompt, dsh-user-approval,
dsh-util-time) as direct devDependencies pinned to the baseline, same
as the thirteen already there. Root-level hoisting makes pnpm resolve
the peers natively (peers check: zero unmet, no global forcing), and
the list extends the existing bump workflow instead of introducing a
new mechanism.

Verified: typecheck clean, 107 test files / 1137 tests green, and the
real-host mount smoke passes 14/14 against @deepseek-ai/dsh@0.1.2-alpha.3.
2026-09-01 15:47:44 +08:00
Menghuan1918 27a1f405dd docs: correct the alpha.3 peer note — dsh-attachment is declared as a peer, not missing
Upstream declares its dsh-* siblings (dsh-attachment included) as
peerDependencies provided by the host bundle tree, so the host-side
mount is unaffected. The stale copies only surface in this repo's dev
tree, which installs a subset of the peers directly — making the
overrides a standing shim to extend on each baseline bump, not a
temporary patch awaiting an upstream fix.
2026-09-01 15:42:59 +08:00
Menghuan1918 b2722ece5d feat: adapt to DSH 0.1.2-alpha.3 and bump to v0.18.1-alpha.0
Point-by-point audit of all 117 commits between alpha.2 and alpha.3:
every host contract this plugin relies on (token auth, slash RPC,
MarkdownText labels, the event-stream/persistence APIs behind
sidechat.events, SettingsNamespaceInput, SUBAGENT_DESCRIPTOR_VERSION
(still 3), dsh-client-store, the profile loader, the node-pty pin) is
unchanged, so no plugin code needed rewiring. alpha.3's breaking
changes (required BeginSubmissionInput.mode, the renamed
attachment-invalid subagent error, the removed SQLite persistence
backend, the identity-gated projection change feed) do not touch this
plugin.

What did need adapting was the dependency tree: the alpha.3 npm
artifacts ship with workspace-era metadata that does not match their
published code —

- dsh-subagent@0.1.2-alpha.3 imports `admitPromptContent` from
  @deepseek-ai/dsh-attachment without declaring that dependency, so
  resolution floats to a stale 0.1.1-rc.1 copy that lacks the export
  (broke 5 test files at load time);
- six transitive peers (dsh-scope, dsh-session-projection,
  dsh-system-prompt, dsh-user-approval, dsh-util-time, dsh-code-runtime)
  drifted to pre-alpha.3 versions against the ^0.1.2-alpha.3 ranges the
  alpha.3 packages declare;
- the alpha.3 line peers on @deepseek-ai/cordis ^4.0.2 (was ^4.0.1).

Fix: pin the seven stragglers via pnpm-workspace.yaml overrides (with
a note to drop them once upstream fixes its metadata), narrow the
cordis peer to ^4.0.2, and bump the baseline pins — CI mount gate,
dsh.plugin.json engines, peer/devDependencies, README badges, plus
SIDEBAR_SERVICE_VERSION in lockstep.

Verified on the npm-published @deepseek-ai/dsh@0.1.2-alpha.3:
typecheck clean, 107 test files / 1137 tests green, `pnpm peers check`
reports zero unmet peers, and the real-host mount smoke passes 14/14.
2026-09-01 15:02:28 +08:00
Atlas Zeng c567c4cef7 Merge pull request #486 from omdsh-dev/feat/sidechat-render-upgrade
feat(sidechat): main-conversation Blocks, turn usage tail, reconnect banner
2026-08-31 23:32:05 +08:00
Menghuan1918 a48459c5de feat(sidechat): tool-kind leading icons on tool rows
The main conversation's tool row head is a 16px leading slot with the
tool-kind glyph at 14 (GenericToolCard's variant table), swapped for an
error StateDot on failed rows. Mirror it: bash/pwsh -> IconApiOutline14,
read/web_fetch -> IconBrowseOutline16, edit/write -> IconEditOutline16,
grep/glob/web_search -> IconSearchOutline16, anything else ->
IconSparkle16, all from the ui-primitives module seed; CollapsibleRow
gains the matching icon slot. Thinking/injection rows keep their bare
chrome (the host's equivalents are a different row family).
2026-08-31 23:28:20 +08:00
Menghuan1918 561ad66071 feat(sidechat): main-conversation Blocks, turn usage tail, reconnect banner
Rendering-layer upgrade for the Side Chat transcript (data already rides
the raw events; the mapping just stopped discarding it):

- Tool rows with a derivable structure now render the host's
  ui-primitives atoms instead of a generic double <pre>: bash calls map
  onto TerminalBlock (command from call args, output + exit pill
  recovered from the result's trailing exit marker), edit/write map onto
  DiffBlock (call-time literal replacement, refined by the result meta's
  contextual hunks), read maps onto ReadBlock (line-window meta, same
  semantic narrowing the host applies). Every narrowing declines to the
  generic row on malformed input.
- turn/end now emits a turnSummary row: token usage aggregated from
  assistant/message.usage (output summed across steps, input from the
  last request) plus the envelope-time wall duration, printed with the
  main conversation's formatTokens/formatDurationMs cadence.
- The client entry injects 'connection' (DSH 0.1.2-alpha.2+) and the
  thread view shows the host's ConnectionIndicator while the Remote
  transport is down; the reconnect control calls reconnect() and a
  disconnected -> connected transition pulls the transcript immediately
  instead of waiting for the next poll tick.

19 new locale keys propagated across zh/en and all 19 third-language
dictionaries; unit coverage in sidechat-transcript.spec and a new
sidechat-view render spec (jsdom). Real-host mount smoke: 14/14.
2026-08-31 23:28:20 +08:00
Atlas Zeng d70db8fb02 Merge pull request #475 from omdsh-dev/feat/unified-file-changes
feat!: 文件变动统一 tab——Git 面板 + 文件追踪(PR #471)二为一,统一 diff 渲染栈
2026-08-31 18:11:21 +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
Atlas Zeng 9494774c48 Merge pull request #472 from omdsh-dev/fix/dsh-0.1.2-alpha.2
feat!: alpha track v0.18.0-alpha.0 — adapt to DSH 0.1.2-alpha.2, drop pre-alpha hosts, fix blank Side Chat transcripts
2026-08-30 23:45:47 +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
Atlas Zeng 3aab7ca3a5 Merge pull request #458 from omdsh-dev/feat/workspace-fence-toggle
feat: workspace fence toggle (workspaceFence pref + one-click off in error surfaces)
2026-08-30 15:48:44 +08:00
Atlas Zeng 3941bd5f3a Merge pull request #370 from Hoemr/add/better-overleaf-catalog
Add dsh-better-overleaf to the tab plugin catalog
2026-08-29 17:10:18 +08:00
Menghuan1918 a733425d34 fix(i18n): move pluginBetterOverleafDesc en entry into the en dictionary 2026-08-29 17:09:14 +08:00
Menghuan1918 9cc642b57e fix(i18n): add pluginBetterOverleafDesc to third-language dictionaries (locale key-set test) 2026-08-29 17:09:14 +08:00
Atlas Zeng 7d0860ebfe Merge pull request #392 from YZDame/feat/add-dsh-suhuang-scroll
feat: add Suhuang Scroll plugin to catalog
2026-08-29 17:09:10 +08:00
Menghuan1918 3e8d0214e9 fix(i18n): add missing en entry for pluginSuhuangScrollDesc 2026-08-29 17:06:11 +08:00
Atlas Zeng 64afc554ec Merge pull request #404 from AnakinCao/feat/dsh-code-nav-catalog
Add dsh-code-nav to the file-viewer plugin catalog
2026-08-29 17:01:50 +08:00
Menghuan1918 28b74a27f3 fix(i18n): add pluginCodeNavDesc to third-language dictionaries (locale key-set test) 2026-08-29 16:57:23 +08:00
Atlas Zeng f32149d7cb Merge pull request #405 from AnakinCao/feat/dsh-md-export-catalog
Add dsh-md-export to the file-viewer plugin catalog
2026-08-29 16:57:19 +08:00
Menghuan1918 8ab02a9f9d fix(i18n): add pluginMdExportDesc to third-language dictionaries (locale key-set test) 2026-08-29 16:56:01 +08:00
Atlas Zeng f70cb91d23 Merge pull request #413 from meyaomiao/feat/server-deck-catalog
feat(catalog): add dsh-server-deck (server card dashboard + xterm terminal) to the tab plugin catalog
2026-08-29 16:55:40 +08:00
Atlas Zeng b2ab82cefd Merge pull request #379 from Johnblur/feat/add-bilingual-reader
feat: add dsh-bilingual-reader to tab plugin catalog
2026-08-29 16:29:32 +08:00
Atlas Zeng 2a4493db37 Merge pull request #410 from meyaomiao/feat/github-workbench-catalog
feat(catalog): 收录 dsh-github-workbench(GitHub 工作台)Tab 插件
2026-08-29 16:29:23 +08:00
Atlas Zeng 44ad014293 Merge pull request #451 from g-yixuan/feat/catalog-dsh-sidenote
feat(plugins): add dsh-sidenote to the tab-plugin catalog
2026-08-29 16:29:12 +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
Atlas Zeng 2088ef6891 Merge pull request #453 from omdsh-dev/fix/reveal-scroll-panel-shift
fix: scope the "Show in folder" reveal scroll to the tree body (panel shift on 0.1.2-alpha.1)
2026-08-29 11:48:58 +08:00
Menghuan1918 41d303623f style: restyle the reveal highlight as a merged business-blue block
The reveal tint now uses the DSH business-blue surface
(--dsw-alias-state-business-tertiary, the same source the host's nav
items use for their active accent, skin-aware) instead of a neutral
accent wash, and drops the 2px left bar. Consecutive revealed rows
square off their touching edges (sibling combinator + :has), so a
multi-file highlight renders as ONE rounded block — per-row radius
notches no longer fragment it; a solo row keeps the full radius.
2026-08-29 11:45:29 +08:00
Menghuan1918 052edb7685 fix: scope the "Show in folder" reveal scroll to the tree body
A reveal on a deep tree shifted the whole panel (tab bar included) out
of the viewport: the reveal used native scrollIntoView, which scrolls
every scrollable ancestor, and the fixed panel host
([data-dsh-panel-host], overflow hidden) is still a programmatically
scrollable container — the host scrolled instead of (or besides) the
tree, with no way to scroll back. Reported on DSH 0.1.2-alpha.1.

Two layers:
- FileTree: compute the centered, clamped target and scrollTo the tree
  body only; scrollIntoView is never called.
- panel host: overflow hidden -> clip. A hidden box remains
  programmatically scrollable; clip keeps the same viewport-edge
  clipping (collapsed panels sliding off-screen) while making the host
  impossible to scroll, killing the whole leak class (md-toc jumps,
  future consumer scrollIntoView calls).
2026-08-29 01:52:55 +08:00
Menghuan1918 50e05ecea0 docs(agents): slim AGENTS.md to repo-global rules, single-source the API reference
AGENTS.md (546 -> 63 lines) now carries only project-global development
rules: hard constraints, mount-smoke CI, DSH 0.1.2-alpha.1 adaptation
notes, npm release, a quick-rule list, and a docs/tests map. The
consumer plugin API reference lives solely in
docs/external-plugin-guide.md.

Reference sync:
- README/README_EN: collapse the dual 'full integration docs' links to
  the guide; AGENTS.md stays linked as the repo rules
- shell-presets.ts / mount.e2e.ts comments: skinning contract pointer
  moved from AGENTS.md §8 to guide §12
2026-08-28 21:42:39 +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
Menghuan1918 3b1898f9cb docs: refresh issue-template DSH version examples to 0.1.1-rc.2 2026-08-28 16:04:36 +08:00
Atlas Zeng c894163b17 Merge pull request #435 from omdsh-dev/feat/dsh-0.1.2-alpha.1-compat
feat: adapt to DSH 0.1.2-alpha.1 (Remote gateway + token auth + MarkdownText labels)
2026-08-28 16:04:27 +08:00
Menghuan1918 6cfe7a736f feat: adapt to DSH 0.1.2-alpha.1 (Remote gateway + token auth + MarkdownText labels)
Dual-version compatibility: the plugin now works identically on
0.1.0-rc.8 ~ 0.1.1-rc.2 and 0.1.2-alpha.1 (the latter verified against a
source build of the dsh-v0.1.2-alpha.1 tag: mount smoke 14/14 + aggregate
double-mount; 0.1.1-rc.2 re-verified 14/14).

- MarkdownText: alpha.1 renamed the flat optional `codeLabels` prop to a
  required nested `labels: { code: {copyLabel, copiedLabel}, footnotes }`;
  the old prop alone crashes fence rendering with "reading 'code'". All
  four render sites (mermaid / MarkdownHtml / TextEditor / SideChatView)
  now go through src/client/markdown-labels.tsx (dual-shape object passed
  under both prop names).
- e2e mount lanes speak both host dialects (tests/e2e/host-protocol.ts +
  host.ts, unit-locked by tests/e2e-host-protocol.spec.ts):
  - one-time-token browser auth: the launch URL grep extends past the
    `/?token=` query (truncating at `/` loses the token), goto navigates
    the token URL (browser cookie exchange), and stamped navigations
    pre-seed the context cookie via addCookies — the exchange 303 drops
    sibling query params;
  - Remote gateway: dot endpoints first, slash endpoints on 404 fallback,
    with args keyed by the controller parameter name (workspace/create ->
    {request}, session/list -> {_request}; verified on a live host).
- package.json: drop the @deepseek-ai/dsh-client-runtime peer (package
  removed upstream in alpha.1; zero references in the source — the chunk
  externals entry stays and is resolution-tolerant).
- scripts/e2e-mount.sh: fix a latent set -u crash in the npx fallback
  branch ($DSH_CMD followed by a full-width comma parsed as part of the
  variable name).
- CI pin stays at @deepseek-ai/dsh@0.1.1-rc.2 until alpha.1 publishes to
  npm (comment updated); README/AGENTS document the new contracts.
- Version lockstep bumped to 0.17.1.
2026-08-28 04:20:36 +08:00
Atlas Zeng 20da6479f1 Merge pull request #414 from omdsh-dev/feat/pinned-terminal
feat: 固定终端 (Pinned Terminals, v0.17.0)
2026-08-26 23:39:35 +08:00
Menghuan1918 f9153dfc1c chore(release): 0.16.1
- bump package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION to 0.16.1
- README / README_EN: add v0.16.1 changelog (git panel freeze + restart
  loop #369: status truncation, bounded repo discovery, ?dsh-sidebar-reset
  escape hatch) and update the npm-channel install pin to ^0.16.1
2026-08-25 11:20:42 +08:00
Atlas Zeng bba7bb6073 Merge pull request #376 from omdsh-dev/fix/369-git-panel-freeze
fix(git): bound status payload and repo discovery; add reset escape hatch
2026-08-25 11:19:06 +08:00
Menghuan1918 eed40bb11a fix(git): raise the discovery probe timeout to 5s (#369)
3s was tight for cold caches on large home directories; 5s still bounds a
stalled mount well below the 30s command budget while cutting false
negatives on slow-but-healthy checkouts.
2026-08-25 11:15:16 +08:00
Menghuan1918 2cbcba8d11 fix(git): bound status payload and repo discovery; add reset escape hatch (#369)
Opening the source-control panel could freeze the whole sidebar, and the
frozen layout restored itself after every reload, leaving no way out
(issue #369). Three unbounded layers compounded:

- `git status --porcelain -z --untracked-files=all` shipped every row of a
  pathological untracked set into one response; the browser main thread
  froze on response.json() plus the unvirtualized change list, and the 2s
  poll replayed the freeze. status() now caps entries at 2000 and reports
  `truncated` (the panel shows a notice, mirroring fs.read's truncation
  semantics); worktree change counts inherit the bound for free.
- repoRoots() probed every visible child directory of a non-repo cwd
  (e.g. ~) serially, once per git.* call, each with the full 30s command
  budget. Discovery now uses a 3s probe timeout, caps probes at 200
  directories, and shares one in-flight scan plus a 60s TTL cache per cwd.
- A hung layout persisted `panelOpen: true` with the git tab active, so a
  reload remounted straight back into the freeze with no escape hatch.
  Loading with `?dsh-sidebar-reset` now drops the persisted layout (and
  the shared width) and starts from the default.

statusTruncated copy synced across all 19 shipped dictionaries.
2026-08-25 11:04:43 +08:00
Atlas Zeng 6f6568d29f Update README.md 2026-08-25 00:09:10 +08:00
Menghuan1918 9c4a8270a7 docs(release): reword #47 changelog entry to not trip the install-powershell README heuristic 2026-08-25 00:02:00 +08:00
Menghuan1918 e5f106b576 docs(release): add #254 mobile fix to v0.16.0 changelog 2026-08-25 00:00:58 +08:00
Menghuan1918 e18528b716 chore(release): 0.16.0
- README / README_EN: add v0.16.0 changelog (free windows #354, model-driven
  sidebar opens #353, Markdown inline HTML + TOC #360, 19-language overlays
  #339, multi-repo git + linked worktrees #326/#285, browser loopback
  allowlist, Vue + 28 legacy languages #202, preview refresh trio #215/#228,
  local Markdown images #292, ego-browser catalog #340; fixes: market/cordis
  #338, ctx.get() reads #357, workspace boundary #345, panel-host layering
  #330/#278, layout-push hardening #310/#130/#180, width sharing #36, terminal
  cleanup #130, fs-search noise dirs #342, mermaid #341, Nerd Font #190,
  UTF-8 HTML #193, trust-fence #182, reveal-in-explorer #94, PowerShell #47,
  GET probe fallback #69, unrun devDep #336) and move v0.15.2 into history
- feature tour: free windows + Markdown inline HTML/TOC (EN), feature list
- plugin ecosystem: add ego-browser (24 tab plugins), install pin ^0.16.0
2026-08-24 23:59:10 +08:00
Atlas Zeng 256256e543 Merge pull request #371 from omdsh-dev/fix/locales-ego-browser-desc
fix(i18n): 补齐 pluginEgoBrowserDesc 的 19 个语言词典翻译
2026-08-24 23:43:06 +08:00
Menghuan1918 78f22f2425 fix(i18n): 补齐 pluginEgoBrowserDesc 的 19 个语言词典翻译
PR #340 新增 zh/en 词典 key 时未同步其他语言,导致
tests/locales.spec.ts 的 ja / 第三方语言 key-set parity 断言失败(337 vs 338)。
为 19 个语言文件(ar/de/fr/hi/id/it/ja/ko/nl/pl/pt/ru/sv/th/tr/vi/zh-HK/zh-MO/zh-TW)
补充对应翻译。
2026-08-24 23:37:10 +08:00
Atlas Zeng 1a18f75641 Merge pull request #340 from Fisfzy/add-ego-browser-tab-catalog
feat(catalog): add ego-browser to built-in tab catalog
2026-08-24 21:17:27 +08:00
Atlas Zeng f5ba7e082b Merge pull request #365 from HuanLinOTO/merge/bug-pr-train-2
merge: bug-PR 合并列车 2 —— 13 个 OPEN bug PR 一次性合入(保留作者归属)
2026-08-24 19:47:12 +08:00
Atlas Zeng 4631a02db0 Merge pull request #360 from omdsh-dev/feat/markdown-html-toc
feat(editor): Markdown 预览内嵌 HTML 安全渲染 + 目录大纲(TOC)
2026-08-24 14:31:58 +08:00
Menghuan1918 2b757cfe24 fix(test): 测试间状态串台与 macOS 临时目录路径导致的用例失败
两处既有测试基建问题(在慢 runner 的 CI 上表现为 free-window 用例
间歇性失败,阻塞 PR 合并):

- free-window/sidebar-crash/bottom-auto-terminal 三个 spec 共用 session
  id 's1':store 会按 200ms 防抖把每会话状态持久化到
  localStorage['dsh-sidebar:v1:s1'],前一个用例的迟写(drop 点 400,300
  → 浮窗 left=205)被下一用例 setSession 恢复,新浮窗断言(期望 317)
  被 querySelector 拿到的旧窗口炸掉——用例间隔是否超过 200ms 决定成
  败,本地快时常过、CI 慢必挂。修复:挂载 helper 缺省生成唯一
  session id(持久化往返用例显式传固定 id),afterEach 在 unstub 之后
  清 localStorage 兜底
- git/git-worktree 两个用例在 macOS 上必挂:tmpdir() 返回 /var 符号
  链接而 git 报告解析后的 /private/var 前缀,路径比较与
  resolveWorktree 的恒等匹配失配(CI 的 Linux 路径规范所以一直绿)。
  修复:期望值与传入 git API 的路径统一 realpathSync 规范化

本地全量 vitest 963 通过 0 失败(此前 free-window 间歇 0~2 失败 +
git 2 个环境性失败);free-window 单文件连跑 8 次稳定。
2026-08-24 14:18:18 +08:00
Menghuan1918 8e0ef7a175 merge: 合入 main(PR #353 agent-open-tools),AGENTS.md 参考实现清单两条例目并存 2026-08-24 13:58:58 +08:00
Atlas Zeng 4c0da8119b Merge pull request #353 from omdsh-dev/feat/agent-open-tools
feat: 侧边栏全局设置「模型主动打开」——sidebar_open 工具(默认关闭)
2026-08-24 12:27:02 +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
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
Atlas Zeng b7229aec67 Merge pull request #351 from HuanLinOTO/merge/bug-pr-train
merge: bug PR train (12 PRs, --no-ff to preserve authors)
2026-08-24 00:43:39 +08:00
Menghuan1918 f648b0c006 fix(ui): 浮窗内容区改为列方向 flex 契约,修复插件 tab 内容 0 宽白窗
.floatContent 原为行方向 flex——弹性子项主尺寸(宽)按内容收缩,内在宽度为
0 的插件宿主(如深迹 DeepTrace)塌成 0px 宽:DOM 在、内容画不出(可见白窗
但 DevTools 有内容)。对齐 pane 的内容契约:.floatContent 复制 .paneContent
的列方向 + overflow hidden,浮窗内再包一层 .paneTab(pane 的 per-tab 包装,
flex:1),子项宽度由 align-stretch 撑满——浮窗里的 tab 获得与 pane 内完全
一致的尺寸契约。e2e 增加内容绘制断言(浮动后内容子项实际宽度 > 200px),
真实浏览器回归。
2026-08-24 00:35:58 +08:00
Menghuan1918 e20b95024b fix(ui): 浮窗内 tab 的 visible 恒为 true,不再跟随面板开合
renderTab 的可见性原为 panelOpen && active——浮窗内容随侧边栏收起被判定为
不可见,遵守 visible 契约(不可见时暂停/空渲染)的消费插件 tab 会在浮窗里
白屏。改为 placement 三态(top/bottom/float),float 恒 true(兑现 AGENTS
§7.5 契约);回归测试断言面板收起后浮窗内的注册插件 tab 仍收到
visible=true。
2026-08-24 00:01:41 +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
Menghuan1918 ddb66c9c08 fix(market): 移除公开版 cordis peer 并迁移类型基底到 @deepseek-ai/cordis
DSH 市场(dsh-community-market)预览硬拒依赖字段出现 'cordis'
(dependencies/peerDependencies/optionalDependencies 任一字段、
optional 均无效),导致 dshfind/1024Store 目录拿不到
repository_backlink 验证目标,点击安装报
"This catalog item has no verified install target"。

- package.json: 删除 cordis peer + peerDependenciesMeta;版本 0.15.2
- context-types.ts: Context 基底改 @deepseek-ai/cordis,结构服务面改
  交集(避免 DS host/client 对同一成员类型不同导致的 TS2717 merge
  冲突),仅保留 betterSidebar 的 module augmentation;删除
  declare module 'cordis'
- client/index.tsx: 4 处 effect 体失败分支改返回 no-op disposer
  (vendored cordis effect 契约拒绝 undefined 形状)
- 新增 tests/market-manifest.spec.ts:无 cordis 依赖字段、打包产物
  无生命周期脚本、bundle patch 安全路径、仓库身份、精确稳定版本
- 消费者检查扩展:@deepseek-ai/cordis 路径的 Context augmentation
  断言;文档示例同步迁移
2026-08-23 00:26:39 +08:00
Menghuan1918 d9b8f15d9e chore(release): 0.15.2
- bump version: package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION
- README / README_EN: feature tour converted to a table (two screenshots
  per row, saves space); add v0.15.2 changelog (file-tree open-in-app
  menu #334, tab context menu #331, diff collapse by default #270, prune
  empty restored panes #268, hide git windows on Windows #301, untracked
  files inside new folders #242, toggle/drag per-frame re-render perf
  #315); community QR codes landed in #325
2026-08-22 23:30:19 +08:00
Atlas Zeng 22a5d372be feat(editor): 文件树「在应用中打开」子菜单(外部编辑器/图钉固定/SSH 远端/自定义编辑器) (#334)
* feat(editor): file tree 'open with' submenu (external editors, pin, SSH-remote, custom editors)

The file tree right-click menu gains an 'Open with >' submenu with the
resource manager (reveal in file manager), VS Code, Cursor and Zed, plus
user-defined custom editors (name + URL template + VSCode-family flag).
Each submenu row carries a pushpin that promotes the target to a direct
top-level menu item.

A configurable SSH host (settings: Files card gear) switches VSCode-family
openers to <scheme>://vscode-remote/ssh-remote+<host>/<path> and hides
host-local targets (file manager / Zed / non-VSCode custom editors).

External opens run through the new fenced /sidebar/api/open.external route
which spawns the platform opener with an argv array (no shell); the client
never navigates raw scheme URLs itself. The settings seam's render panel now
appends after the declarative rows instead of replacing them.

* feat(editor): polish open-with menu UI — brand icons, pushpin, chevron, row alignment

- Submenu rows: the custom label is now a block-level flex row filling the
  primitives itemLabel, so the pushpin docks at the row's far right (matching
  the trailing check of every other menu); menu row icons normalized to 16px
  (DSH native menus use 16, ours were 14).
- The submenu parent row gains a right-aligned chevron (the primitives Menu
  renders no arrow for submenu parents).
- Icons via react-icons: codicons VscPin/VscPinned pushpins (replacing the
  hand-drawn pin), VscFile/VscFolder/VscFolderOpened tree glyphs (replacing
  the </> file mark), VscLinkExternal for the open-with parent and the
  browser tab's open-external button (globally), SiCursor/SiZedindustries
  brand silhouettes; the VS Code mark is inlined from simple-icons@11.0.0
  (CC0) as IconVscode16 since later simple-icons releases dropped it. All
  monochrome currentColor to follow the active skin.
- tsdown: pin react-icons si/vsc to their ESM entries via resolve.alias —
  the package's exports map lists require before import, so the shared
  conditionNames picked the unshakeable CJS entry and bloated the core
  bundle by ~6.4 MB; tree-shaken it now adds only ~12 KB.
2026-08-22 23:19:17 +08:00
Atlas Zeng 4148130aac perf(sidebar): 消除开关/拖拽的每帧 React 重渲染
- 根因:开关过渡期 ResizeObserver→setCenterRect 每帧重渲染整棵 Sidebar;TabContent 无 memo;内部 Divider/文件树 dock 每 pointermove 全量更新;拖拽残余为 `#root` 每帧 reflow(动画固有成本,A/B 实证非回归)。
- 修复:centerRect 改 ref + 底栏 DOM 直写(零 React 渲染);TabContent memo(显式比较器,locale/registry/paneId 保持新鲜);新增 frame-batcher 对 Divider/dock 拖拽按帧合并;拖拽期跳过无意义 locate。
- 验证:单测 76 文件 773 通过;`pnpm test:mount` 12/12(含新 toggle-layout e2e:开关过渡底栏逐帧 0.0px 贴合);4x CPU 节流 A/B:开关 >17ms 帧 collapse 19→6 / expand 24→4~6,p95 21ms→15ms;拖拽不变(非回归)。
- CR(@codex P1)已修复:`moveTab` 复用同一 tab 对象,比较器改显式比较 `paneId`(含回归单测)。
- 本地 DSH Web 实测通过后按用户要求合入。

fixes #315
2026-08-22 22:50:13 +08:00
Atlas Zeng 924f377fa1 Update README.md 2026-08-22 20:12:32 +08:00
Atlas Zeng d3c0f22345 feat(tab-bar): add right-click close context menu on tabs (#331)
Right-clicking a tab now takes over the browser menu and shows four
close operations scoped to the current pane:
- Close
- Close Other Tabs
- Close Tabs to the Left
- Close Tabs to the Right

Items gray out when nothing is eligible (single tab / strip ends).
Bulk closes reuse the per-tab onClose path, so descriptor onClose
callbacks and terminal pty release still run for every close. Labels
are i18n'd (zh/en).
2026-08-22 19:57:34 +08:00
Atlas Zeng 67271e54c8 Clean up community section in README
Removed commented-out QR code sections for WeChat and QQ from the community section.
2026-08-22 18:00:24 +08:00
Atlas Zeng 9b4240449c Update README.md (#325) 2026-08-22 17:59:20 +08:00
Atlas Zeng ef8d3a9050 chore(release): 0.15.1 (#324)
* chore(release): 0.15.1

- bump version: package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION
- README / README_EN: add v0.15.1 changelog (sidechat Codex-style transcript
  rework, terminal park-frame pty keep-alive, file-tree drag gating, README
  rewrite); plugin ecosystem 28+ with two new entries
  (dsh-better-sidebar-starter, my-dsh-plugins) and per-category <details>
  collapsible listings

* docs(readme): add community section placeholder for WeChat/QQ group QR codes
2026-08-22 17:46:26 +08:00
Atlas Zeng 9a40164d1a fix(explorer): 非文件拖拽不再触发文件树上传遮罩 (#317)
拖动 Tab(重排/跨 pane split)经过资源管理器文件树时,FileTree 的
dragenter/dragover/drop 此前对任何拖拽都响应:显示上传遮罩并吞掉
事件,导致 pane 根的 Tab-drop 处理收不到、Tab 无法落下。

统一按 dataTransfer.types 含 'Files' 门控(与 Sidebar.tsx 面板宿主
shield 一致):非文件拖拽原样冒泡给 pane 根,OS 文件拖拽行为不变。

回归测试:应用内 Tab 拖拽不出现 uploadDropZone、不改 dropTarget、
不 preventDefault、不触发 onUploadRequest。
2026-08-22 17:22:10 +08:00
Atlas Zeng b7aab48deb feat(sidechat): Codex 风格转录重构 — 首问显示 / 注入拆分 / 折叠行 / 弹窗去抖 (#314)
* fix(sidechat): split context injection from the first user message

The first composer message rode the same user/message event as the side
boundary prompt (+ parked snapshot), and the transcript dropped that whole
row by its boundary prefix — swallowing the user's first question.

Deliver first contact as TWO messages: the boundary+snapshot rides
agent.inject (queued next-step context, claimed first at the opening step,
no wake) stamped with source kind 'plugin', and the question is the
follow-up that wakes the driver. The log records injection and question as
separate events; the transcript maps injections (plugin-sourced, or the
legacy boundary-prefix blob of pre-split threads) onto a collapsible
injection row and renders genuine user messages — the first one included —
as user rows. boundaryDelivered still recognizes the injection by its
unchanged boundary-prefix opening.

* feat(sidechat): codex-style collapsible rows and creating shimmer

Tool calls, thinking and context injections now share one quiet
single-line chrome (chevron + label + a one-line argument summary) that
expands into an indented body on a hairline thread — no cards or fills.
Streaming labels and the creating hero shimmer (shimmer = generating);
failed tools go danger; reduced-motion stills every loop.

* fix(sidebar): debounce subagent auto-open past the title frame

The host delivers a new child's origin and title in separate frames, so a
Side Chat thread's first visible frame lacks its 'Side: ' label and
tripped the 0→N auto-open — every thread creation popped the task page.
The trigger now rearms for 500ms and re-evaluates the original baseline
against the live snapshot, by which time the title filter recognizes the
thread. Genuine subagents still auto-open, half a second later.

* fix(sidechat): render legacy threads' first message as its own bubble

Threads created before the host split still log the boundary (+snapshot)
and the question as ONE 'user' message; the transcript mapped that row
wholly onto the injection row, so the user's first question only appeared
inside the expansion. The boundary prompt is a known constant, so the
legacy row now splits THERE: the injection row keeps the prompt, the
remainder renders as the user's real message (a pre-split snapshot, when
present, rides along — the common case is a pure question). Row React keys
become kind:seq so the split's two rows never collide.
2026-08-22 15:34:05 +08:00
Menghuan1918 7dbd9b75e2 docs(readme): simplify install to add -> approve-builds -> add
The node one-liner prewrite was overkill for the README. Plain double
'add' does NOT work (both runs exit 1 on ERR_PNPM_IGNORED_BUILDS,
verified in scratch); the working minimal flow is add (fails, dep
written) -> pnpm approve-builds --all (re-runs install scripts) ->
add (succeeds, bundle registered). Verified end-to-end in a scratch
profile.
2026-08-22 12:10:24 +08:00
Menghuan1918 cdda072973 docs(readme): make first-run install succeed (pre-write allowBuilds before dsh plugin add)
pnpm 11's strict-dep-builds blocks node-pty/protobufjs build scripts and
makes the FIRST 'dsh plugin add' exit non-zero (dsh aborts on
ERR_PNPM_IGNORED_BUILDS), forcing a second run after approve-builds.

The install block now pre-writes allowBuilds (node-pty/protobufjs) and
minimumReleaseAgeExclude (dsh-better-sidebar) into the profile's
pnpm-workspace.yaml with the same idempotent merge as scripts/install.sh
ensure_workspace_settings, so the first add succeeds. Verified in a
scratch DSH_HOME: preflight -> add exit 0 (node-pty postinstall ran),
rerun unchanged (no duplicate keys), second add exit 0; merge branch
tested when allowBuilds already exists. Paste-to-DSH prompt updated to
match.
2026-08-22 12:06:32 +08:00
Menghuan1918 646c91cf70 docs(readme): sync EN with uploaded screenshots, normalize image sizes, add Side Chat badge
- Mirror the zh feature tour (user-uploaded CDN images) into
  README_EN.md: real screenshots for explorer/editor, markdown,
  image, terminal, git, browser, tasks, side chat, settings, mobile;
  drop manual-shot placeholders (git-diff, bottom-panel) and the
  CodeMirror subsection (folded into the explorer section)
- Normalize image display size to width=880 (mobile 360) across both
  languages; remove the stale 'placeholders to come' note
- Add the missing Side Chat badge to the hero feature-chip row
  (zh + en)
- Mirror user's trim: 'Office' removed from the features bullet
  (Office preview is an ecosystem plugin), Git panel ecosystem
  sentence dropped
2026-08-22 02:03:25 +08:00
Atlas Zeng 55ad7eec8d Update README.md 2026-08-22 01:29:06 +08:00
Menghuan1918 d38a411f6d docs(readme): user-facing DSH compat badge, node-pty-safe install script, paste-to-DSH install prompt
- Drop peer-floor / CI-baseline jargon everywhere; supported DSH
  versions are stated only via the shields badge
- Install block: add 'pnpm approve-builds --all && pnpm rebuild
  node-pty' unconditionally so the terminal's prebuilt binary is
  always in place (pnpm 11 blocks build scripts by default)
- Add a copy-paste prompt block that lets a DSH session install the
  plugin itself (mirrors the manual script + node-pty step)
- Trim internal process detail from historical changelog bullets
  (v0.14.0 / v0.13.1), keep the user-facing symptoms and gates
2026-08-22 01:04:16 +08:00
Menghuan1918 940d0a8928 docs(readme): feature tour with screenshots, plugin ecosystem section, DSH compat badges
- Hero badge wall: npm version/downloads, CI, stars, DSH compat
  (0.1.0-rc.8 / 0.1.1-rc.1 / 0.1.1-rc.2), ecosystem topic badge
- New 🖼️ feature tour: one subsection per feature with real UI
  screenshots (10 captured from a scratch DSH instance; 4 slots left
  as commented placeholders for manual upload via GitHub web)
- New 🌐 plugin ecosystem section: 26 topic plugins in three grouped
  tables (tab / viewer / enhancement) with live star badges, the two
  extension points, and curation instructions
- Recent updates: keep v0.15.0 visible, collapse v0.12-v0.14 into
  <details>; add Releases link and per-version DSH support line
- Add TOC, contributing section, star history chart, contributors wall
- Bilingual README.md / README_EN.md kept in sync
2026-08-22 00:49:08 +08:00
Atlas Zeng f0965e1d61 chore(release): 0.15.0 (#309)
- bump version: package.json / dsh.plugin.json / SIDEBAR_SERVICE_VERSION
- README / README_EN: consolidate the two unreleased v0.14.1 sections into
  v0.15.0 covering everything since v0.14.0 (side chat beta, file-window
  upload, desktop-compat four options, settings-page modernization,
  recommended-plugin catalog additions, subagent live batch route, drag and
  push fixes, DSH 0.1.1-rc adaptation, upload hardening); restore the
  historical v0.14.0 section; fix the glued '### v0.13.1### v0.13.1'
  heading in README_EN
2026-08-21 23:21:38 +08:00
Atlas Zeng f268d35f8b feat(sidechat): rename feature label to 侧边对话(beta) / Side Chat (beta) (#307)
The sidechat feature is still experimental; rename its display label so
users see it is beta. The label reads from the single sideChat locale
key, which drives both the "+" new-tab menu entry and the Side card
settings card title, so both update with this one change. Update the
e2e mount sweep expected built-in label and the README feature bullets.
2026-08-21 22:48:00 +08:00
Atlas Zeng c62ba4a565 feat(ci): DSH CLI 钉版平移至 0.1.1-rc.2(挂载冒烟验证基线) (#305) 2026-08-21 21:53:04 +08:00