Commit Graph
64 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 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
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
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 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
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
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 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
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
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
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 5951bae1ad integrate train/misc: mermaid + layout-push + fs-search + markdown-images 2026-08-23 20:28:49 +08:00
HuanLinOTO af8ec58f4c integrate train/css: panel z-index + overflow clip + mobile sidebar 2026-08-23 20:27:37 +08:00
HuanLinOTO ed3083d133 merge #338: 移除公开版 cordis peer,迁移类型基底到 @deepseek-ai/cordis
# Conflicts:
#	README.md
#	README_EN.md
#	package.json
2026-08-23 20:18:55 +08:00
HuanLinOTO 60b9c867d8 merge #342: fs-search skip node_modules and other noise dirs 2026-08-23 20:17:22 +08:00
HuanLinOTO c88eccfadb merge #330: drop panel host below DSH cordis dynamic-plugin layer 2026-08-23 20:17:16 +08:00
leokuang d0f194b67a fix(explorer): 文件名搜索跳过 node_modules 等噪声目录
右侧文件窗口的全局文件名搜索会深度优先遍历整个工作区,原先只跳过
.git。含大型 node_modules 的仓库会先把 10 万条访问预算耗尽,导致
docs/ 等后序目录里的真实文件搜不到。

搜索改为跳过依赖、包管理存储和常见构建缓存目录(不匹配也不下降),
并补回归测试钉住 node_modules / dist 内的命中不会泄漏。
2026-08-23 02:50:37 +08:00
HuanLinOTO 38dc807d15 refactor(i18n): 覆盖只在 DSH active=en 时生效(借用英文槽位)
better-locale 的覆盖本质上是借用 DSH 的英文槽位来渲染第三语言:
- store.getOverride(dshActive, ns, key) 改为只在 dshActive === 'en'
  时返回覆盖文本;DSH 在 zh 下覆盖完全惰性(保持原生 zh)
- 新增 store.isOverrideActive(dshActive):返回 active !== undefined
  && dshActive === 'en',供 better-sidebar 的 isZh() 判断
- isZh() 改用 isOverrideActive(dshActive) 判断(仅在 DSH=en 且有
  override 时返回 false),zh 下返回 true
- LanguageSwitcher 接收 dshActive prop,选了非 native 且 DSH 非 en
  时显示「请将 DSH 切换到英文以查看 [语言名]」提示
- 新增 switchToEnHint copy key(zh + en)
- 测试:better-locale +3 store tests(en-only / inert on zh /
  isOverrideActive),+1 patch test(inert on zh);better-sidebar
  +1 locales test(override inert while DSH on zh),FakeBetterLocale
  加 isOverrideActive 方法
2026-08-23 01:42:01 +08:00
HuanLinOTO 7ceee777b4 feat(i18n): 接入 @huanlin/dsh-plugin-better-locale 支持 ja 覆盖
新增 ja 词典(src/client/locales-ja.ts,326 keys,与 zh key-set-equal),
通过可选 peer @huanlin/dsh-plugin-better-locale 接入第三语言覆盖:

- locales.ts: 新增 attachBetterLocale(store) + ja dict export;t() 先查
  store.getOverride(active, 'betterSidebar', key),命中则返回覆盖文本,
  否则走原 zh/en 链;isZh() 在 override 激活时返回 false
- client/index.tsx: apply 中 ctx.get('betterLocale') 取得 override store
  (optional,未安装时为 undefined),attachBetterLocale 注入 t();同时
  register('betterSidebar', { ja }) 把 ja 词典注册进 better-locale 的
  store,让外部 ctx.locale.lookup 调用者也能拿到 ja 文本
- Sidebar.tsx: 新增 betterLocaleActive uSES 订阅 store.subscribe,覆盖
  切换时全树重渲染(DSH locale 的 active 字段不变,既有 localeRevision
  uSES 不会触发)
- package.json: @huanlin/dsh-plugin-better-locale 加为 optional peer
  + devDep link
- tests/locales.spec.ts: 新增 7 个 better-locale override 测试(命中/
  fallback/detach/interpolate/ja dict 完整性 smoke check)

未安装 better-locale 时 ctx.get 返回 undefined,整段为 no-op,zh/en
行为完全不变。
2026-08-23 00:52:20 +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
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
ZgblKylin e24d9bf879 fix(sidebar): drop panel host below DSH cordis dynamic-plugin layer (z 40→25)
The ui-cordis CordisPanel is position:fixed at z-index 30; the unified
panel host at 40 made the bottom workbench cover the cordis inventory
and approval surfaces. Host now sits at 25 (above AppFrame overlay 20,
below cordis 30 and the 100+ float stack). Update skin contract docs
and add a mount e2e assertion for the layering band.
2026-08-22 19:10:02 +08:00
Atlas Zeng c62ba4a565 feat(ci): DSH CLI 钉版平移至 0.1.1-rc.2(挂载冒烟验证基线) (#305) 2026-08-21 21:53:04 +08:00
Atlas Zeng 0fdf63b081 feat(settings): 侧边卡片设置页 UI/UX 现代化——卡片底部设置条替代隐形齿轮 (#300)
* feat(settings): 侧边卡片设置页 UI/UX 现代化——卡片底部设置条替代隐形齿轮,协调双色启用态

- 二级设置入口:卡片右下 16px 幽灵齿轮(tertiary 色、像素钉位)改为
  卡片底缘全宽设置条(hairline 分隔 + 齿轮图标 + 「功能设置」文字
  标签),常态可发现;hover 换品牌淡底 + brand 字色引导。可见性条件
  与 aria-label 契约不变(仅父级启用且声明 settings)
- 常规行齿轮升级为带 border-l2 边框的 22px 芯片按钮,hover 同样
  accent 引导
- 启用卡片:品牌描边柔化为 color-mix(45%),勾选徽标改用
  state-success-primary(绿=已开启确认,brand=激活强调的协调双色)
- 节奏:section gap 16 / group padding 20 / 网格 minmax(180px) gap 12;
  计数徽章改为 accent-soft 淡底 pill;开关关态 thumb 降档 +
  track 底 layer-2
- 动效纪律:全部过渡 ≤160ms 且仅颜色属性;prefers-reduced-motion
  扩展覆盖设置条/行齿轮/弹窗行
- 清理:合并 .pluginEntries 重复定义;文档同步(AGENTS.md §5 +
  设计文档新增 §9 偏差记录)

* feat(settings): 按反馈迭代——卡片开关滑块、二级弹窗长列表滚动、卡片等高

- 勾选徽标 → 紧凑品牌开关滑块(30×16 track + 10px thumb,开=品牌填充
  反色拇指,关=中性且不渲染;纯视觉指示,卡片本身仍是 aria-pressed
  开关,语义契约不变)
- 二级弹窗长列表:popupRows 内部滚动 max-height min(52vh,440px) +
  细滚动条(--dsw-alias-scrollbar-* 令牌),终端 6 行场景弹窗壳体与
  Done 固定、仅行区滚动;行密度收紧(padding 12/14、gap 8)
- 卡片等高:.card min-height 106px + .cardMain flex:1 + .cardTop
  min-height 28px——带设置条/不带设置条/无图标卡片全部等高
- prefers-reduced-motion 覆盖 cardSwitch 过渡;文档同步(AGENTS.md
  §5 + 设计文档 §9 迭代记录)

* fix(settings): 二级设置弹窗行区取消横向滚动——box-sizing:border-box + overflow-x:hidden

popupRows 的 width:100% 配 content-box 会在 padding-right:4px 时把
内容盒撑宽 4px,overflow-y:auto 隐式启用的 overflow-x 因此出现横向
滚动条;改为 border-box 并显式 overflow-x:hidden(minifier 输出
overflow:hidden auto),行区始终填满弹窗宽度、无左右滑动。add-plugin
弹窗的 pluginEntries 同步加 overflow-x:hidden。
2026-08-21 21:39:59 +08:00
Atlas Zeng a9d3451415 feat(adapt): 适配 DSH 0.1.1-rc.1(@next)——devDeps/lockfile/CI 基线平移,peer 下限保持 rc.8 (#297)
调研结论:0.1.1-rc.1 为常规 rc 递进(依赖图零增删、纯版本平移),
所有 sidebar 消费的公开契约(DOM 槽位 / CSS 令牌 / boot 协议 /
MarkdownText codeLabels / webServer 路由 / agents-session API)
逐包比对无破坏,无需代码逻辑改动。

- package.json: devDependencies 14 个升至 0.1.1-rc.1;peer 下限保持
  ^0.1.0-rc.8(rc.8 与 0.1.1-rc.1 双向兼容,rc.8 用户无需升级 DSH);
  version 0.14.1 -> 0.14.2(cordis ^4.0.0-rc.8 不变)
- dsh.plugin.json / src/client/service.ts: 版本锁步同步
- pnpm-lock.yaml: 全量重解析,零 rc.8 残留(干净解析验证)
- CI 挂载冒烟钉版 @deepseek-ai/dsh@0.1.1-rc.1(验证基线)
- README(EN) 横幅/changelog/安装注释、ISSUE_TEMPLATE、AGENTS.md 同步
2026-08-21 18:15:25 +08:00
Atlas Zeng 7f4f84c4cf feat(sidechat): 侧边对话——每对话一 Tab(Codex 对齐)+ 完整上下文继承 + 保存为新会话 (#286)
三轮实测驱动迭代:种子信封透传(surfaceOp 校验)、每线程一 Tab 交互重做完、四连修(fork 丢 this / 自绘 history+save 图标 / collectOwnEvents 大页回源修重开丢工具行 / descriptor 入种子修目录 corrupt 行 + 前缀过滤保拓扑零噪音)。739 单测 + 挂载冒烟 12/12 全绿。
2026-08-21 15:41:14 +08:00
Atlas Zeng 50a888845f feat(sidebar): 桌面兼容三方案——自动检测(WCO 标准几何)/壳预设/自定义 CSS (#284)
* feat(sidebar): 桌面兼容三方案——自动检测(WCO 标准几何)/壳预设/自定义 CSS

核心只保留 Web 标准机制,壳专属适配全部下沉到用户空间(KISS):
- prefs 新增 titleBarScheme(默认 auto)/titleBarPresetId/customCss,旧 titleBarCompat
  布尔自动迁移(true→custom 保留 stripPx,false/缺失→auto)
- wco.ts:navigator.windowControlsOverlay 反应式几何(geometrychange 实时更新;
  visible=false 的幽灵 API 视为缺失),实现 #257
- titlebar-strip.ts 唯一 strip 取值链:WCO → dsh-desktop-titlebar-inset 契约参数
  → 预设 stripFor → 手动 px → 0;desktop-env.ts 移除 win32 32px 硬编码
- shell-presets.ts 数据驱动预设(准入:issue/PR 提及 + 100+ star;v1 仅
  anywhere-labs DSH Desktop:darwin 20px / win32 无 WCO 时 32px),opt-in 手动
- 预设/自定义 CSS 注入(data-dsh-preset-css / data-dsh-custom-css 标签),
  chrome 补稳定寻址面 data-dsh-toggle-cluster / data-dsh-panel
- 交互 chrome 统一 -webkit-app-region: no-drag(吸收 #111/#153)
- layout.css 底栏推挤复合锚点([data-pane] 与 :has(> [data-slot]) 双保险,
  rc.8 实测前者失效、后者命中,吸收 #226 思路)
- 设置 UI:位置兼容模式齿轮弹窗改三方案(自动检测/壳兼容方案/自定义方案)
- 测试:wco/titlebar-strip/shell-presets 单测 + prefs 迁移 + e2e 5 场景
  (保守 auto/WCO 反应式/预设/自定义 CSS/复合锚点),挂载门禁 12/12 全绿

核心 grep 无壳专属类名;为某壳做的兼容在另一壳会再坏——预设与自定义 CSS
是唯一出路(AGENTS.md §8 契约已更新)。

* refine(sidebar): 位置兼容模式改主行下拉四选项——自动检测/DSH官方Web/壳预设/自定义

按用户反馈定稿 UI:
- 主行下拉:自动检测(默认)/ DSH官方Web(显式零适配,连 WCO 也强制 0)/
  各壳预设(命中环境带「已检测」后缀,仅提示)/ 自定义方案(保留齿轮弹窗:
  下移距离 + 自定义 CSS)
- 旧文档迁移:titleBarCompat=true 或 titleBarStripPx 非默认值(此前已有配置)
  → 默认落到 custom 方案保留用户数值;干净文档 → auto
- prefs 新增 'web' 方案;strip 取值链最优先处理 web→0
- 测试:prefs 迁移(stripPx 48→custom / 40→auto)、web 强制 0、下拉渲染断言
- 单测 693 通过,挂载 e2e 12/12 全绿

* refine(sidebar): 方案下拉复用 SelectMenu 组件,不用原生 <select>

- 抽出可复用 SelectMenu(primitives Menu:锚点按钮 + 下拉选项卡,支持
  icon/desc/多选),SelectRow 改为其薄壳
- 位置兼容模式方案下拉改用 SelectMenu;选项带描述(自动检测/DSH官方Web/
  各壳预设(命中带「已检测」后缀)/自定义方案)
- 移除原生 select 样式;单测 693 通过,挂载 e2e 12/12 全绿
2026-08-21 01:28:17 +08:00
Atlas Zeng 6c891514b5 feat(injection): 统一面板宿主注入重构——含块层+几何写路径+chunk缓存+锚点弱化+桌面/移动适配 (#232)
* feat(injection): 统一面板宿主——固定含块层 + 挂载自检降级 + body 锚点守卫

- Sidebar 渲染根包 [data-dsh-panel-host](fixed inset-0 pointer-events:none)
- 面板/开关簇由 fixed 改 absolute(层内视口坐标等价),免疫套壳中间层 transform 劫持
- 挂载后一次性几何自检:页面级 transform 时降级 absolute + rAF 视口同步
- MutationObserver(body childList)守卫锚点被宿主清空时重挂

* perf(injection): 几何写路径统一为 writeGeometry + 面板 layout 隔离

- 拖拽帧与打开态共用单一推挤写入器(--dsh-sidebar-width/height)
- .panel/.bottomPanel contain: layout style——内部重排不外泄
- 拖拽期(body[data-dsh-sidebar-dragging])才挂 will-change: transform

* perf(chunks): HMR 激活保留未变 chunk 的已解析 exports + ETag HEAD 重验证

- 新增 revalidateChunksOnReactivate():激活时 HEAD 每个已加载 chunk 对比 ETag,
  未变保留内存缓存(跳过重注入/重执行),变更或不可达则 fail-open 重取
- 测试夹具与孤儿缓存条目不跨激活存活
- index.tsx 激活路径由 resetChunks() 改为 revalidateChunksOnReactivate()

* fix(layout): 推挤锚点改 data 属性 + #root calc 宽度防桌面壳溢出

- nth-child(2) → #root [data-dsh-frame] > [data-pane="conversation"](实证同元素)
- #root 宽度 calc(100% - var) 与 margin 同步过渡:web 视觉不变(实测 1140+300=1440 无溢出),
  Desktop 壳(#208)width:100% 的加性溢出根因消除

* feat(desktop): 桌面信号自动探测 + win32 顶栏 overlay 自动避让 + 键盘/safe-area 适配

- 新增 desktop-env.ts:解析 dsh-desktop-mode/platform URL 信号与 preload 标记
- win32 advanced 壳自动启用 titleBarCompat(32px overlay),手动 pref 仍可覆盖
- visualViewport 键盘 inset:底部面板/窄屏抽屉键盘弹起时上移
- 面板与开关簇 safe-area-inset 适配(env() 桌面端为 0)
- 单测 7 例(含 URLSearchParams 前导 ? 剥除修复)

* docs+e2e: 注入方案实施记录(路线B关闭、偏差记录、基线数据)+ 契约同步 + e2e 新断言

- 设计文档:路线 B 标记关闭、§8.1 改单 PR 步骤(含 commit 对照)、拖拽基线数据、实施偏差记录
- AGENTS.md §8:data-dsh-panel-host 含块层、推挤锚点契约(禁 nth-child)、桌面信号
- mount.e2e:data-dsh-panel-host 断言 + win32 advanced 桌面信号场景

* fix(cr): 响应 #232 CR 三条 findings

- P1 降级同步:按未修正几何判定(跟踪自身补偿量),祖先 transform 消失才退出循环——
  修正后矩形不再被误判为无需修正(自清除缺陷)
- P1 chunk 重验证成为 loadChunk 屏障:重验证挂起期间不提供缓存,杜绝 HMR 竞态陈旧 exports;
  测试夹具加载不再被误记为生产加载
- P2 键盘 inset:innerHeight - (vv.height + vv.offsetTop),并监听 scroll(offsetTop 变化)
- 新增屏障单测 1 例;设计文档偏差记录更新

* fix(chunks): 屏障 HEAD 加超时兜底 + resetChunks 清 revalidation

- revalidateChunksOnReactivate 的 HEAD 与 recordEtag 均带
  AbortSignal.timeout(5s):路由挂起时 fail-open(drop + 重取),
  屏障不再可能无限期阻塞所有懒加载 chunk(CR #232 P1 修复的健壮性缺口)
- resetChunks 同步清 revalidation:重验证挂起期间重置后,
  loadChunk 不再等待已丢弃状态的孤儿任务(finally 身份判断 no-op)
- 单测 +2:HEAD 挂起超时 fail-open(fake AbortSignal.timeout 触发中止)、
  resetChunks 清屏障后 loadChunk 立即放行

* fix(deps): align @deepseek-ai/* peers with DSH 0.1.0-rc.8

- peer/devDependencies: 13 个 @deepseek-ai/* 从 ^0.1.0-rc.7 升至
  ^0.1.0-rc.8;删除随 rc.8 消失的 dsh-client-web-react / dsh-client-schema-form
  (无 rc.8 发布、rc.8 依赖树与壳 bundle 零引用、插件 src 零引用);
  cordis peer/devDep 同步升 ^4.0.0-rc.8
- 版本 0.13.1 -> 0.14.0(package.json / dsh.plugin.json /
  SIDEBAR_SERVICE_VERSION 三处同步)
- CHUNK_EXTERNALS / CLIENT_EXTERNALS / CLIENT_REQUIRE_ALLOWED 三处镜像
  同步删除两个死包(primitives/slots 仍是 rc.8 壳静态模块表种子,保留)
- CI 挂载冒烟钉版 @deepseek-ai/dsh@0.1.0-rc.7 -> rc.8
- pnpm clean --lockfile 全量重解析:lockfile 内 @deepseek-ai/* rc.7 残留
  清零(传递链同升 rc.8,杜绝 #206 式混用树);pnpm-workspace.yaml
  minimumReleaseAgeExclude 按 #207 模式整体换为 rc.8 列表
- 文档同步:README 安装说明、AGENTS.md CI 钉版、外部插件指南与设计文档
  cordis 示例、issue 模板版本示例

* feat(prefs): editorExplorer 默认独立(关)——文件各自新开 tab

- SIDEBAR_PREFS_DEFAULTS 与 host PrefsSchema 的 editorExplorer 默认
  true -> false:新会话树点击/打开文件按 path 新开 tab,无路径窗口即
  纯资源管理器;合并模式保留为可选手动开启(持久化过的用户设置不受影响)
- 测试同步:prefs.spec 默认断言翻转、plugin-shape.spec 与 smoke.spec
  默认对象翻转;editor-host 合并模式用例显式开启 editorExplorer(split
  用例本已显式);side-card-section-rows 的 select 行用例固定选中 Merged
- e2e 重写:mount.e2e 文件打开流程从 in-place 断言改为独立模式
  (新开 hello.txt tab、Files home tab 保留),文件头注释同步
- 契约文档同步:AGENTS.md §3.4 editor 行默认描述翻转 + CI 冒烟描述、
  README/README_EN v0.13.0 特性描述 + v0.14.0 changelog

* fix(client): rc.8 模块系统经 ctx.modules 注入 + chunk 副本全局共享

rc.8 不再暴露 window.__DSH_MODULES__ 页面全局(改由 ctx.modules 服务
提供),chunk 外部依赖解析全面失效(terminal/editor/mermaid 全部
"client module system unavailable")。修复:

- src/client/index.tsx: inject 增加 'modules'(Cordis 服务访问守卫,
  此前直接读 ctx.modules 抛 "cannot get property modules without
  inject");apply() 激活时 setChunkModuleSystem(ctx.modules)
- package.json dsh.client.inject 增加 @deepseek-ai/dsh-client-modules
- chunk-loader: 注入写插件自有页面全局 __dshSidebarModuleSystem__——
  懒加载 chunk bundle 各自内联一份 loader(rc.7 靠官方全局回退工作,
  rc.8 全局消失后副本注入变量恒空);moduleSystem() 按
  注入变量 → 插件全局 → rc.7 全局回退解析
- context-types: Context 镜像补 modules 服务声明(client half)
- e2e: assertNoCrash 失败时输出错误条文本;独立模式断言修正
  (Files 数量按存在性、mermaid 流程先切回 Files、md 预览 locator 去掉
  重复的 [data-dsh-better-sidebar] 嵌套)

验证:typecheck / 639 测试全绿;本地 rc.8 CLI + Chromium 挂载冒烟 3/3
通过(drag-layout、mount 深扫含 editor/mermaid chunk、桌面信号)

* feat(settings): 终端 shell/shellArgs 可在设置页配置(bash 管理)

- SidebarPrefs 新增 terminalShell / terminalShellArgs(默认空 = 保持
  yaml config.shell → $SHELL / 登录 shell / powershell.exe 的既有解析)
- 终端卡齿轮二级页面新增两行 text 配置(与字体行同列)
- host 侧生效链路:UI 终端 WS 打开与 agent terminal_create 均读取
  设置文档覆盖(ptyManager.open / AgentPtyRegistry.create 增加可选
  shell 覆盖参数;shellOverridesOf 解析设置文档);设置页写入即时
  影响之后打开的终端(既有 pty 保持原 shell)
- locales zh/en 文案;parsePrefs 校验新字段;测试同步

* feat(settings): 侧边卡片设置页加 DSH-better-sidebar 版本徽标

- 设置页 intro 下新增身份徽标:名称 + v{service.version}(服务实例
  版本,与 package.json 由 tests/service.spec.ts 保持同步)
- token 驱动样式(--dsw-alias-*),名称/版本 pill 布局

* fix(drag): 快速拖动提交最后位置 + HMR 后中心列重定位兜底

快速释放(浏览器合并/丢失 pointermove 突发,超快速 flick 甚至可能
完全无 move)时的回退问题:
- pointerup 优先采用最后一次已知拖动值(rAF pending),而非 up 位置
  (事件合并时可能等于按下位置)
- pointercancel / lostpointercapture 中断时同样提交最后已知位置;
  无 move 时用中断事件自身的坐标计算(clamp 后提交)——只有真正
  未产生位移的拖动才回滚
- commitDrag 统一 flush + 同值提交 + 立即重测中心列(消除提交后
  React 用旧 centerRect 覆盖底栏 right 的中间帧)

HMR 重激活后底栏空白(输入框被推挤上移、强制刷新恢复):
- 根因:新组件实例重跑 locate 时壳的 centerCol 尚未就绪,而壳重建
  复用 #root 子节点(childList 观察器不触发)→ centerRect 卡 {0,0}
  → 底栏 visibility:hidden 永久空白
- 修复:额外观察 <html> 的 style 属性(layout push 写回 --dsh-sidebar-*
  时重定位重测);底栏打开时 effect 重跑 locate/measure 兜底
- 底栏未测量时由「不渲染」改为 visibility:hidden(渲染链不被几何
  门控,jsdom 测试不回归)

e2e 新增:极快拖动(单 move 立即 up)提交拖动位置、稳定后不回退

* feat(plugins): 添加插件目录支持搜索/分组/独立滚动(多插件场景)

- PluginListBody 顶部加实时搜索框(按名称/id/描述过滤,空结果提示)
- PluginEntry 增加可选 category 分组字段(i18n 友好),目录条目按组
  渲染(未分类条目保持平铺);数量徽标跟随过滤结果
- 条目列表 max-height + overflow-y 独立滚动,插件多时弹窗不再无限
  增长;渲染数量由搜索天然收敛
- locales zh/en(搜索占位、无匹配);测试文件固定英文环境
  (vitest 4.1.11+ jsdom 跟随系统 locale,本机 zh-CN 导致英文文案
  断言漂移)

* chore(deps): 适配 pnpm 11.8 supply-chain 校验(exclude 通配)

pnpm 11.8.0 起对 lockfile 既有条目强制 minimumReleaseAge 校验,
且精确 exclude(@scope/pkg@version)对带 peer 依赖后缀的解析条目
匹配失效(44 条误报违规,CI 全红)。@deepseek-ai/* scope 为官方
可信 scope,minimumReleaseAgeExclude 改为 '@deepseek-ai/*' 通配
(保留 rc.1 历史与 stable 条目);通配经实测通过全部 504 条校验。

* docs: v0.14.0 changelog 补全(自 v0.13.1 全部更改 + 特别声明 rc.8 适配)

新增条目:终端 shell/shellArgs 设置页配置、设置页版本徽标、
添加插件目录搜索/分组/滚动、rc.8 模块系统迁移、拖拽健壮性修复;
版本说明块醒目声明本版适配 DSH 0.1.0-rc.8(rc.7 及更早无法解析依赖)
2026-08-20 02:09:36 +08:00
Atlas Zeng e8757026a1 fix(deps): align @deepseek-ai/* peers with DSH 0.1.0-rc.7 (fixes #206) (#207) 2026-08-18 21:41:28 +08:00
Atlas Zeng 9ad0a49b8a feat(settings): mutual exclusion with the dsh-web-ui aionui-panel provider (v0.13.0) (#181)
Reads the aionui-panel settings namespace's rightPanel provider choice: while
it resolves to 'aionui-panel', the whole sidebar does not mount (host
settings.get reports externalDisable, the client mount gate skips mounting
and the link/open-path/turn-tail takeovers step aside). Live via the
settings/document-updated push (best effort; deployments without the
'remote' service fall back to boot-time evaluation). No new user-facing
setting — the aionui panel card remains the single source of truth.
2026-08-18 00:44:22 +08:00
Atlas Zeng 6ee1ba11d0 feat(editor): 文件窗口与资源管理器二合一 + 声明式设置 select 行 (#151)
* feat(editor): merged explorer mode — path input, docked file tree, global name search

New editorExplorer pref (default on, editor card gear): the editor tab gains
a path-input header and a toggleable right-docked tree panel (per-tab state
in tab.meta.treeOpen; file tabs default closed, the seeded path-less home
tab defaults open). Fresh sessions seed that empty editor tab instead of
the explorer tab when merged mode is on; the standalone explorer tab stays
in the + menu unchanged.

- Extract FileTree.tsx from ExplorerView (shared by both hosts)
- Host fs.search route: recursive case-insensitive name search rooted at
  the session cwd, budget-capped (200 matches / 100k visited), skips .git,
  never descends symlink dirs
- EditorHost reads the pref reactively (boolean snapshot) and keeps the
  pre-merge layout verbatim when off

* feat(settings): select row type for declarative settings; editorExplorer as iconed select

- SidebarSettingToggle gains type 'select' with options {value,title,desc,icon}
  and multi (default false; stores the picked values as an array in options
  order). Any option carrying an icon renders big-icon option cards in the
  dropdown and the icon in the closed anchor; icon-less rows are one-line text.
- SelectRow in SideCardSection rides the primitives Menu (portal); single-pick
  commits and closes, multi toggles and stays open. Wired for both host-prefs
  toggles and plugin-owned pluginToggles via the new onSelectValue seam.
- The editorExplorer merged-mode pref is now an iconed select (merged vs
  separate) instead of a switch; the stored value stays boolean.
- Advertise the capability as 'settingSelect' in SIDEBAR_FEATURES.

* feat(editor): unify explorer into the editor surface, resizable tree dock, hoisted toolbar

- One tree implementation, two presentations: the shared TreePanel (global
  name search + refresh + FileTree) docks as the editor tab's right panel
  and — in merged mode — fills the explorer tab's window; the pref-off
  explorer keeps its legacy header shell.
- The docked panel drag-resizes from its left edge (160-480px clamp),
  persisted as tab.meta.treeWidth alongside treeOpen.
- The text editor's preview/edit/save toolbar moves into the path-input
  header row: FileViewerProps gains internal toolbar fields ('host' mode
  skips the viewer's own row, reports EditorToolbarState and registers
  EditorToolbarControls); non-merged mode is byte-identical to before.

* feat(editor): single files window with in-place switching; explorer descriptor removed

- editor tab replaces explorer on the + menu (order 10, Files); persisted
  explorer tabs migrate to the editor home tab via sanitizeState
- editorExplorer now only controls open behavior: merged = in-place
  updateTab, independent = openSidebarFile; both modes share the merged
  chrome (path input + hoisted preview/edit/save toolbar + tree toggle)
- file tree context menu gains 'open in new tab' / 'open to the side'
  (mintTabId avoids the id safety net; insertLeafAt splits right)
- tree dock resize uses pointer capture (touch-action none, 6px handle)
- defaults: openByDefault off, sidebar width 35%
- file tree clips horizontal overflow (no sideways scroll)
- e2e: mount lane arms the editor-chunk wait before goto and clicks the
  tree row's left edge (hover @-reference button sits mid-row); drag lane
  expands the panel first (collapsed push writes 0px), waits for the
  slide-in to settle, and picks the leftmost col-resize strip; 'Files'
  title assertions require draggable to skip the bottom panel's welcome
  cards

* feat(editor): split mode turns the path-less window into the standalone explorer

In independent (split) mode a path-less files window renders ONLY the
tree panel (search + FileTree, full-window form) — no path input, no
hoisted toolbar, no tree toggle. File clicks open per-path editor tabs
(full chrome, tree docked closed by default) through openSidebarFile,
unchanged. Merged mode is untouched (chrome + docked tree, in-place
switching). TreePanel's previously reserved 'full' prop now has its
consumer.
2026-08-17 15:00:03 +08:00
Atlas Zeng a673f2399f ci: GitHub Release 自动触发 npm 发版(Trusted Publishing) (#148)
- 新增 .github/workflows/release.yml:release published 事件触发,
  校验 tag 与 package.json 版本一致后 pnpm publish --provenance
- 认证走 npm Trusted Publishing(OIDC),无需 NPM_TOKEN secret
- workflow_dispatch 提供 dry_run 调试入口(只打包不发版)
- AGENTS.md 补充发版流程与 npm 后台一次性配置说明
2026-08-17 00:16:03 +08:00
Atlas Zeng 3c196fffc3 feat: 皮肤兼容(令牌驱动)+ CSS 修复(#106 #105 #90 #60,附带 #52 #57 #92) (#110)
令牌驱动方案(主目标:与 dsh-web-ui 皮肤中心兼容):
- 面板表面改用通用卡片令牌 --dsw-alias-bg-layer-1,不再消费宿主左导航专属
  --dsw-specific-sidebar-fill——dsh-web-ui 10 款皮肤全部覆盖 --dsw-alias-*
  层,换肤后侧边栏自动跟随,零每皮肤适配(#60/#105/#106)。
- effectiveTokenValue 增加 alpha 阈值(新增 colorAlpha 解析 computed 颜色):
  transparent 与 alpha<0.9 的半透明玻璃值(dsh-web-ui 皮肤 bg-base 为
  rgba 0.16–0.7)一律回退不透明底色,终端/编辑器文字永不叠在皮肤背景画上
  (#90);≥0.9 的近不透明值放行,皮肤仍可控终端表面。

独立修复(保留):
- z-index 降到 DSH 浮层栈(100+)之下:面板 40 / 按钮簇 45 / 角手柄面板内
  局部 2,Cordis 弹出框不再被底部工作台遮挡(#52)。
- 角手柄移入右面板、CSS 相对定位(bottom: calc(var(--dsh-sidebar-height)
  + 6px)),删除 JS 内联 viewport 坐标。
- 刷新按钮统一 14px(#57 前半)。
- 拖拽逐帧回归 e2e(#92):真实挂载下 rAF 采样(拖条以 cursor: col-resize
  语义定位),断言拖拽期间 data-dsh-sidebar-dragging 存在、#root transition
  为 none、会话列与面板边单调 1:1 跟随(实测通过)。

按 KISS 回退首版契约:类名 kebab-case 改名与 data-bs-* 语义钩子全部移除
(令牌驱动下不需要,改名引入无谓 breaking),skin-hooks 测试删除;
mount e2e 改为断言 --dsh-sidebar-width 布局变量随面板挂载生效。

文档:AGENTS.md §8 重写为「皮肤兼容(令牌驱动)」;设计文档记录决策与
回退。README 与版本号不在本批更新(发布流程统一处理)。

测试:tests/theme.spec.ts(colorAlpha + effectiveTokenValue 阈值);
typecheck/vitest(511)/build/consumer-types/test:mount 全绿。
2026-08-16 16:37:11 +08:00
Menghuan1918 5c27882995 docs: 仓库硬约束新增「代码改动必须走 PR,仅文档类改动可直推 main」 2026-08-15 15:36:12 +08:00
Menghuan1918 29f162dac0 feat: 服务化 API 新增 urlTarget 外链认领 + 浏览器 HTTP/HTTPS 二级设置开关
基于 PR #74 的颗粒度讨论向前兼容拓展服务化 API:
- TabDescriptor 新增可选 urlTarget(url) 谓词:聊天/界面外链被拦截时按注册
  顺序路由到第一个命中的插件 tab 类型(openTab({ type, url, title })),
  内置 browser 退居隐式兜底;SIDEBAR_FEATURES 追加 'urlTarget'
- 浏览器链接设置改为二级菜单(齿轮弹窗):新增 browserInterceptHttp
  (默认开)+ browserInterceptHttps(默认关);browserInterceptLinks
  保留为总闸(默认开,旧文档零迁移)
- 拦截管线:registerLinkInterception 的 takeoverEnabled 改收解析后的
  URL,协议/同源纯判定(shouldInterceptLink)签名不变
- 测试:matchUrlTarget(注册顺序/抛错吞掉/browser 永不命中)、jsdom
  点击接管门控、parsePrefs 新字段默认值;全默认字面量同步
- 文档:设计文档 + AGENTS.md(字段/示例/设置键)+ README(外链分流)
2026-08-15 15:05:06 +08:00
Menghuan1918 f903ac77d6 test(e2e): 落实 Codex 审查意见 — 强制覆盖 editor 懒加载 chunk + 缺失内置 tab 即失败
- seed hello.txt,经 Explorer 打开文件并等待 /sidebar/bundle/editor.js 响应,
  缺失/损坏的 editor chunk 会令门禁变红(已实测:删 chunk → 错误条被检出)
- + 菜单缺失内置 tab 由跳过改为 toHaveCount(1) 硬失败,防深扫悄悄缩水
- AGENTS.md CI 冒烟说明同步
2026-08-15 01:52:54 +08:00
Menghuan1918 7ee0b457a3 feat: CI 挂载冒烟门禁 — npm 打包 → 真实挂载 DSH → 无头渲染防 crash
新增 plugin-mount job(pnpm test:mount):
- scripts/e2e-mount.sh:scratch profile 引导(allowBuilds/minimumReleaseAgeExclude 预写)→ 官方
  dsh plugin --profile web add file:<tarball> 挂载(dsh.profile.bundles 协调校验)→ keyless
  dsh web --port 0 → Playwright 无头渲染 → trap 清理
- tests/e2e/mount.e2e.ts:seed 工作区+会话(宿主 RPC)→ 断言 #root 与 [data-dsh-better-sidebar]
  挂载、无崩溃标记(错误条/pageerror/插件 console 错误)→ + 菜单逐个打开内置 tab 深扫
- playwright.config.ts:chromium headless、单 worker、retries 0、失败留 trace/截图/HTML 报告
- vitest exclude 与 *.e2e.ts 命名双保险隔离;exclude 整体替换默认值,须保留默认排除项
- CI 钉住 @deepseek-ai/dsh@0.1.0-rc.6;DSH_TELEMETRY_DISABLED=1;workflow_dispatch + PR 并发取消

已验证:本地端到端全绿;人为注入 tab 组件 crash → 门禁变红(错误条检出),还原后变绿;
typecheck/vitest 全绿;CI 同款 npm 安装 CLI 路径实测通过
2026-08-15 01:21:21 +08:00
Menghuan1918 cbc28473a0 feat: 设置页「添加插件」推荐目录 + 复制安装命令;移除内置 Office 预览
- 设置页侧边栏内容/文件预览两个网格末尾各增虚线卡片,弹出对应 kind 的插件弹窗
- 弹窗:GitHub topic 按钮(新标签页)+ 推荐插件目录(plugins-tabs.ts / plugins-viewers.ts)
- 每条目「跳转」(window.open 新标签页直达仓库)与「复制」(writeClipboard + 已复制反馈)
- 不做终端预填流:不关闭弹窗、不打开终端、无失败路径(install/installNotice/installError* 文案删除)
- 内置 Office 预览(docx/xlsx/pptx)整体移除,chunk 白名单 5→2(terminal/editor)
- 文案「内置插件」→「推荐插件」;AGENTS.md/README/设计文档同步
2026-08-14 22:30:34 +08:00
Menghuan1918 0995a58454 fix: 回应独立 CR 的 P2/P3 意见(0×P1)
- P2-1 onOpen 收到真正落地的 tab:url 新建场景从 landed 态按 id 反查
  (补丁后对象),回调不再拿到未打 url 的 tab
- P2-2 插件设置行显式取值源:FeatureSettingsRows 新增 valueSource prop,
  插件行读自己的 pluginSettings blob——插件键与宿主 pref 同名时不再
  静默读宿主值(原投影合并有读宿主写插件的读写不对称);prop 命名避开
  Object.prototype.valueOf 冲突
- P2-3 consumer 类型检查接入工程:package.json 新增 check:consumer-types
  脚本 + CI 在 build 后执行;脚本补 lib/types 存在性前置检查(防假绿)
- P3-1 url seed 只在新建时应用:dedupe 聚焦的 tab 不再被覆写 path
- P3-2 closeTab/activateTab 未知 id 严格 no-op:store.reduce 对同引用
  结果短路(不 notify、不重写 localStorage),根因修复 + 回归测试
- P3-3 closeTab/activateTab 增加可选 scope(cwd 随回调传递),Sidebar
  双树激活/关闭路径传入 { sessionId, cwd }
- P3-4 定向打开不再自动展开不可见 session 的面板
- P3-5 Sidebar 终端 pty 释放查找覆盖双树(底部面板终端不再漏掉 HTTP
  兜底)
- P3-6/P3-7 与 Nits:AGENTS.md/指南文档化(dedupeKey 纯函数、meta 用
  null 清除、回调 scope 的 cwd 语义);consumer fixture 补常量导出覆盖

测试 +6(url 落地保真 / url 不覆写聚焦 / 未知 id 无 notify / 定向打开
不展开 / scope 随回调 / valueSource 键隔离),464 全绿;typecheck、
build、consumer 校验全部通过。
2026-08-14 21:28:41 +08:00
Menghuan1918 82a69546d2 feat: 公共 API 基座化(v0.12.0,纯增量)— 类型/能力/设置 seam 全面补齐
- 类型生态:service 模块 re-export SidebarTab/SidebarState/SidebarStore/
  SidebarSnapshot/SidebarDiffRef/TabType/SessionScope/SidebarPrefs 等公共
  状态词汇(此前 TS2459 无法命名);context-types 去 Node 依赖(结构镜像
  SidebarHttpRequest/Response/UpgradeSocket/Head),client 可达声明图零
  node:* 引用,外部消费者无 @types/node + skipLibCheck:false 可编译
  (scripts/check-consumer-types.sh 守护)
- 服务能力:version/features 版本与能力探测(单调只增)、getSnapshot/
  subscribeState 状态订阅、updateTab(title/path/meta)、activateTab、
  openFile(路径派生 id 与内置拦截一致)、openTab(seed, scope?) 定向到
  指定 session(store.reduceFor 不扰动 UI)
- TabDescriptor:badge 角标(99+ 封顶,抛错吞掉)、onOpen/onActivate/
  onClose 生命周期回调(service 路径派发,dedupe 聚焦触发 onActivate
  而非 onOpen,抛错不打断流程);SidebarTab.meta JSON 可序列化跨刷新
  持久化(sanitize 宽松保留)
- 设置 seam 开放:PrefsSchema 增 pluginSettings 开放嵌套 map(z.dict),
  settings.pluginToggles(插件自有行,同 switch/text/number 控件)与
  settings.render(自定义面板,含 store/service/prefs/updatePluginSetting/
  close props);viewer 卡片 v0.12.0 起也有齿轮设置弹窗
- FileViewerDescriptor.load 增第三参 AbortSignal(EditorHost 生命周期中止)
- UI 接线:tab 激活/关闭改走 service(跨树激活修复 + 回调触发)、+ 菜单
  传 scope、TabBar badge pill 渲染;active-session scope 走原 reduce 路径
  保证 notify
- 测试 +23:生命周期/定向打开/updateTab/activateTab/openFile/meta 持久化/
  reduceFor/能力常量(与 package.json 锁步)、consumer-types.ts 编译门、
  api-surface.spec.ts(client 图零 node 依赖守护);既有 430 测试全绿
- 文档:AGENTS.md 修 available 三参示例并补全部新 API;external-plugin-
  guide.md 刷新至 v0.12.0(7 tab + 9 viewer、设置 seam 开放、类型导入
  路径建议);README×2 服务化小节同步

未发版 npm(用户决定);分支 feat/plugin-api-v012。
2026-08-14 20:44:43 +08:00
Menghuan1918 d83490c93e feat: 终端二级设置支持自定义字体(字体族 + 9–32px 字号,实时生效)
- SidebarPrefs 新增 terminalFontFamily(空 = 跟随主题等宽字体)/ terminalFontSize(9–32,默认 13),PrefsSchema 与 parsePrefs 同步校验
- 声明式设置 API 扩展:SidebarSettingToggle 支持 type: 'switch' | 'text' | 'number'(缺省 switch,向后兼容)+ min/max/placeholder/unit
- 终端卡片齿轮弹窗新增「终端字体」「终端字号」两行:blur/Enter 提交、number 钳制、提交失败回滚草稿
- TerminalView 经 store 订阅实时应用字体(options + re-fit + resize),懒加载 chunk 无新增依赖
- 新增 resolveTerminalFont 纯函数(回退链:用户字体 → 主题 token → 内置等宽栈)并单测
- 版本 0.11.0,README/AGENTS.md/设计文档同步
2026-08-14 14:36:49 +08:00