Atlas Zeng
2dc2dcf418
Merge pull request #569 from omdsh-dev/fix/markdown-preview-local-images
...
fix(editor): rewrite local images in markdown runs of the split renderer
2026-09-06 22:52:37 +08:00
Menghuan1918
2a99968fa3
fix(editor): rewrite local images in markdown runs of the split renderer
...
Every .md preview renders through MarkdownDocument (htmlInfo is ungated),
but its markdown segments passed the raw source into MarkdownText, whose
chat-security stance drops non-http(s) image destinations — so local
markdown-syntax images (, reference-style definitions)
always fell back to alt text. Only HTML <img src> tags were rewritten
(postProcessSanitized).
Apply rewriteLocalImageUrls to each markdown run (segment + appended
reference definitions) inside MarkdownDocument's prepared memo, through
the same media trust fence the sanitized HTML leaves already use.
Idempotent for already-absolute media URLs; remote destinations
untouched. Also correct the stale "non-null only for HTML documents"
comment on TextEditor's htmlInfo.
2026-09-06 21:53:49 +08:00
Atlas Zeng
bb21657eae
Merge pull request #562 from omdsh-dev/fix/sidechat-seed-inherited-inbox
...
fix(sidechat): 种子补 fork 标记,子会话不再继承父会话未领取的 inbox 消息
2026-09-06 21:43:13 +08:00
Menghuan1918
93ad87dfe7
fix(sidechat): stamp the seed with fork markers so the child inherits no pending inbox
...
sidechat.start passed `seed` without `meta.isSeeded: true` +
`inheritedEventCount`, so dsh-session treated the whole seed as the
child's OWN events and the child's Inbox constructor replayed the
parent's `agent/inbox/spliced` history — inheriting whatever input sat
UNCLAIMED in the parent at the click moment:
- next-turn: a queued follow-up behind a still-running turn;
- next-step (the reported long-context case, parent queue empty): a
tool-result context / steering spliced between step boundaries.
The first side prompt then claimed [phantom, boundary, question] — the
stale parent message was sent to the model BEFORE the boundary and
logged as a user/message. The fix passes the exact marker pair the
host's own session.fork uses (api-session-controller); ownEvents() now
stops at the end-seed boundary and the inherited inbox replays empty.
Regression tests run the REAL Session.create + Inbox in both
directions (old shape inherits the phantom, marked shape stays empty);
routes tests pin the two create options. Verified: pnpm typecheck /
test (5 pre-existing unrelated UI-spec failures on main unchanged) /
build.
2026-09-06 00:59:03 +08:00
Atlas Zeng
a5c52b3f1b
Merge pull request #550 from omdsh-dev/feat/file-tree-rename-delete
...
feat(files): 文件树重命名/删除 + 右键菜单减重与子菜单钳制
2026-09-04 23:04:37 +08:00
Menghuan1918
e39ea92ade
feat(files): tree rename (inline) + delete (confirmed) + submenu visual tether
...
资源管理器补全:文件树右键菜单新增「重命名」(行内编辑:预填+全选、
Enter/失焦提交、Esc 取消、IME 组合键守卫)与「删除」(Modal 确认,文件/
目录文案区分,永久删除——宿主无回收站)。根行(工作区根)不提供两项,
服务端 fs.rename/fs.remove 双保险拒绝;目标已存在 409;link-aware——
symlink 行只改/删链接本身(lstat 判定),fence 校验对解析后目标进行。
落定收尾:pruneTree 清旧前缀缓存 + 收起 stale expanded + 单层重载父目录;
tab 调解走 service(rename→updateTab 改路径改标题、delete→closeTab 关
受影响 tab,覆盖两侧分栏/底栏/浮动窗口,经 tree-mutations.ts)。
二级菜单视觉关系(layout.css,仍限 data-dsh-sidebar-submenu 作用域):
父行在子菜单打开期间保持高亮(宿主已渲染 aria-expanded="true"),
卡片间距 10px→4px(悬停走廊同步收窄),翻转规则一并 4px。
i18n 新增 7 key × 20 语言文件(locales.spec 的 key-set-parity 门禁)。
测试:fs-operations 追加 12 例(rename/remove 全失败面);新增
file-tree-rename-delete.spec.tsx 8 例(菜单可见性/重命名流/删除流/错误条);
menu-flip.spec.tsx 契约扩展覆盖 tether 规则。设计文档
docs/plans/2026-09-04-file-tree-rename-delete-design.md。
2026-09-04 22:08:02 +08:00
Menghuan1918
76b57508f4
fix(ui): compact context menus + viewport-clamped submenu flip
...
减重:全部右键菜单(FileTree 行菜单 / TabBar tab 菜单 / GitLens 文件与
历史菜单 / FreeWindow 标题菜单)与「+」菜单切到宿主 Menu 原语的 compact
密度(26px 行高 / 12px 字 / 164px 卡片),图标随槽位 16→14,「打开方式」
子菜单图钉 20→16,还原工具型右键菜单的趁手感。
越界:宿主子菜单纯 CSS 定位(从父行向上、向右生长)不受视口钳制——树顶
部右键时「打开方式 ▸」子菜单伸出视口上沿,窄面板(280–400px)时伸出右
沿。新增 menu-flip.ts:菜单打开期间在 <body> 发布 data-dsh-sidebar-submenu
="down|left" 方向 token(y < vh/2 → down;x + 400 > vw → left),layout.css
据此翻转子菜单生长方向与 ::before 悬停桥;属性存续期即作用域,宿主自有
菜单不受影响。刻意不做 max-height 滚动钳制——overflow 裁剪会切断悬停桥。
测试:menu-flip.spec.tsx(token 纯函数 + hook 生命周期 + CSS 契约跨文件
一致性);tab-bar / file-tree 两个 spec 追加翻转向量断言;mount.e2e 追加
compact 行高(≤30px)布局级证据。设计偏差记录同步至
docs/plans/2026-08-22-open-with-menu-design.md。
2026-09-04 20:28:35 +08:00
Atlas Zeng
e1b9b539e4
Revise version details and update QR codes
...
Updated version information and fixed QR code image links in README.
2026-09-04 17:33:42 +08:00
Menghuan1918
f59ffd0741
docs(plans): 全方位代码防腐审查报告与 backlog(2026-09-03)
2026-09-03 21:21:22 +08:00
Atlas Zeng
f7332f332b
Merge pull request #542 from omdsh-dev/feat/split-sidebar
...
feat(client): Sidebar.tsx 按关注点增量拆分
2026-09-03 21:20:15 +08:00
Menghuan1918
e105b01f2b
refactor(client): 抽取自由窗口拖出检测与浮窗层到 sidebar/free-windows.tsx
...
Sidebar.tsx 拆分第五块:useFloatDragout(document 捕获态 dragover/
drop/dragend/blur 监听、会话列矩形命中测试、hint 状态去抖)与
FreeWindowLayer(floats.map 渲染 + 拖出 hint 覆盖层,fragment 渲染
保证 DOM 顺序与原先逐字一致)原样迁出,注释逐字保留。
行为不变:effect 依赖与回调闭包相同;层组件接收的 renderTab/
getTabIcon/store/ctx/sessionId/cwd 即原先 JSX 内联闭包捕获的同一批
每 render 新建的值,FreeWindow 收到的 props 与回调语义不变。
2026-09-03 21:09:20 +08:00
Menghuan1918
b4ab3f154f
refactor(client): 抽取 pinned 虚拟 tab 注入与动作包装到 sidebar/use-pinned-tabs.ts
...
Sidebar.tsx 拆分第四块:activePinnedTabId/pinnedRevision 状态、
pinnedEntries/pinnedVirtualTabs/augmentedTree 三个 memo(含
exhaustive-deps 豁免注释随迁)与 wrappedActions(虚拟 id 路由回
HOME 会话的 reduceFor + ptyClose 语义)原样迁出,注释逐字保留。
调用点移到 actions memo 之后(hook 无 effect,仅 useState/useMemo,
位置调整不改变行为)。
行为不变:memo 依赖数组逐字相同;wrappedActions 的 actions 入参即
原先闭包捕获的同一个 memo 产物。
2026-09-03 21:08:03 +08:00
Menghuan1918
d5b1201ad8
refactor(client): 抽取宿主推送与自动激活触发器到 sidebar/use-host-feeds.ts
...
Sidebar.tsx 拆分第三块:agent-terminals / agent-opens 两条 WS 推送
(含重连退避与失败上限)、子代理自动激活(去抖重估)、后台任务自动
激活、拓扑跳回(subagentJumpRef)连同 FAILURE_LIMIT /
AUTO_OPEN_DEBOUNCE_MS 常量原样迁出,注释逐字保留。Sidebar 侧仅
消费返回的 subagentJumpRef(renderTab 的 onSubagentJump 装填)。
行为不变:五个 effect 的依赖数组与闭包值逐字相同,hook 每 render
无条件调用,effect 挂载顺序保持(feeds → center → float →
bottomAuto → drag)。
2026-09-03 21:05:41 +08:00
Menghuan1918
6bccd21a49
refactor(client): 抽取中心列定位/测量链到 sidebar/use-center-column.ts
...
Sidebar.tsx 拆分第二块:centerRectRef/centerMeasured/centerColRef/
draggingRef、measureCenter(ref + 直写 DOM,避免动画帧级 re-render)
与整条 locate/ResizeObserver/MutationObserver/1.5s 重试链原样迁出到
src/client/sidebar/use-center-column.ts,注释逐字保留。bottomRef 与
state?.bottomOpen 由调用方传入(bottomRef 在主文件先建再共享,行为与
原先 measureCenter 闭包捕获一致)。
行为不变:hook 每次 render 全量重跑,effect 依赖与值完全相同;唯一
文字差异是三处依赖数组补列了跨 hook 边界后失去 useRef 溯源的稳定
ref 对象(centerColRef/draggingRef,标识恒定,不改变触发时机),
为 react-hooks/exhaustive-deps 零告警所需。
2026-09-03 21:03:14 +08:00
Menghuan1918
dbc73f0bf3
refactor(client): 抽取 TabContent 单元格与 + 菜单构建到 sidebar/TabContent.tsx
...
Sidebar.tsx 拆分第一块:memo 化的 TabContent(含 TabContentProps 与
tabContentCompare 比较器)和 buildNewTabOptions 原样迁出到
src/client/sidebar/TabContent.tsx,注释逐字保留。
行为不变:组件体零改动,仅模块路径与 import 调整(相对路径加一层
../);Sidebar.tsx 改为 import 该模块,对外导出面不变(仍只有
Sidebar 具名导出)。
2026-09-03 21:00:20 +08:00
Atlas Zeng
68839aa5fb
Merge pull request #541 from omdsh-dev/feat/unify-polling
...
feat(client): 收敛四处轮询习语到共享 use-polling 原语
2026-09-03 20:45:46 +08:00
Menghuan1918
1ec1565b13
refactor(client): 四处轮询站点迁移到 use-polling,语义逐一保持
...
- SubagentView useSubagentLive:self-scheduling(上一请求 settle 后才排
下一次,不重叠)+ 每代 AbortSignal + signal.aborted 拦迟到写入,行为
与原 disposed 标志等价(teardown 同步置 disposed 并 abort)。
- SideChatView:立即拉取 effect 与 2s 定时拆分——输入变化(含 running
翻转)仍先拉一次转录,运行中间隔 tick 拉转录+徽章;fetchThread 自带
的逐次 abort 与卸载 abort 原样保留。
- GitLens:可见时 2s 固定静默 tick,无初始突发(mount/scope 变更的完整
刷新在别处);refresh 身份变化照旧重启间隔相位。
- ChangesTab:输入变化即拉一次(含隐藏态翻转),可见时 2.5s 固定间隔;
pull 内部 pollGen 代际守卫不动。
守护 spec 全绿:subagent-live-polling + subagent-jobs-view 13/13、
sidechat-view + sidechat-transcript 29/29、git-view-worktree +
changes-tab + changes-ops 13/13;断言零改动。
2026-09-03 20:35:59 +08:00
Menghuan1918
6ef11ae010
feat(client): 引入共享 use-polling 轮询原语
...
四处站点(SubagentView 活动预览 / SideChatView 转录 / GitLens 状态 /
ChangesTab 会话事件)各自手写取消安全与代际失效,机制各异。先落地共享
原语:间隔与调度模式(fixed-interval / self-scheduling)参数化、每代一个
AbortSignal + 卸载/依赖变更即失效(迟到响应靠 signal.aborted 拦截,不信任
abort 必然触发 reject)、任务异常静默保留旧值由下一 tick 重试。
2026-09-03 20:35:59 +08:00
Atlas Zeng
aa01140252
Merge pull request #540 from omdsh-dev/feat/drop-rc7-fallback
...
feat(client): 删除 rc.7 宿主的 __DSH_MODULES__ 回退路径
2026-09-03 20:35:46 +08:00
Menghuan1918
dc33087ce1
feat(client): 删除 rc.7 宿主的 __DSH_MODULES__ 回退路径
...
peer 基线已是 ^0.1.2-rc.1(全部 dsh-* peer),最后提供
window.__DSH_MODULES__ 页面全局的宿主是 0.1.0-rc.7,远低于下限,
装不上本插件——回退在受支持宿主上不可达。受支持宿主上 apply() 在
任何懒加载发生前调 setChunkModuleSystem(ctx.modules),moduleSystem()
前两跳(注入变量 + 插件全局 __dshSidebarModuleSystem__)必中。
回退的唯一活消费者是 vitest fixture:installModuleSystem() 原先经
rc.7 全局投递 fake 模块系统,现改为与生产同路径的 setChunkModuleSystem
注入;无任何专测回退分支的用例,全部断言保持不变。
- chunk-loader.ts: 删 moduleSystem() 第三跳,同步头注 /
ChunkModuleSystem 接口注中的回退描述
- index.tsx: 删「falls back to the rc.7 global」注释
- README v0.14.0 changelog 与 docs/plans 设计文档中的提及属历史
存档(描述 PR #232 当时的迁移),保留不改
验证:lint / typecheck / build / vitest 119 文件 1243 用例全绿;
真机挂载 lane(钉版 @deepseek-ai/dsh@0.1.2-rc.1 CLI)mount.e2e
全内置 tab sweep(含终端 / editor 懒加载 chunk)通过;lib/*.js
产物中无 __DSH_MODULES__ 残留。
2026-09-03 20:29:59 +08:00
Menghuan1918
8820efd6bf
fix(tests): 补回 add-plugin-modal.spec 缺失的 builtinTabPlugins import
...
#535(i18n catalog names)给 tests/add-plugin-modal.spec.tsx 新增
sentinelEntry 行时漏了 import;#535 自身 CI run 被 cancel,#536 带病
合入,main HEAD 7b5c7dd 的 typecheck/test 双红(本地 stash 复现一致:
TS2304 / ReferenceError: builtinTabPlugins is not defined,CI run
33754439466 failure)。补上与 plugin-list.spec.ts 同源的 import。
与本 PR 主题无关,仅为本流验证门(typecheck/test 全绿)所需的最小
main 修复,独立成 commit 便于 review 剔除。
2026-09-03 20:29:50 +08:00
Atlas Zeng
7b5c7ddcc4
Merge pull request #536 from omdsh-dev/feat/eslint
...
feat(lint): 引入 ESLint flat config 并接入 CI 与 Makefile
2026-09-03 20:18:10 +08:00
Atlas Zeng
f8bb3013ff
Merge pull request #535 from omdsh-dev/feat/i18n-catalog-names
...
feat(i18n): 目录项与 shell 预设文案词典化,兜底错误条改皮肤令牌链
2026-09-03 20:18:05 +08:00
Atlas Zeng
463e96b6b4
Merge pull request #534 from omdsh-dev/feat/palette-single-source
...
refactor(theme): One Dark/Light 语法色板单源化
2026-09-03 20:18:01 +08:00
Menghuan1918
98e9a4ff0f
docs(readme): 开发与构建命令清单补 pnpm lint(双语镜像)
2026-09-03 20:00:08 +08:00
Menghuan1918
5a1e75e46b
fix(lint): 清零存量 lint 告警并接入 CI / Makefile 门禁
...
存量清理(首跑 141 errors / 21 warnings → 0 / 0):
- 删除孤儿 disable:SideChatView / Sidebar / selection-popup 三处 exhaustive-deps 豁免与 chunk-artifact 的 no-new-func 豁免(多行理由注释把 disable-next-line 顶离了实报行;selection-popup 改为提取 popupOpen 标志真修复)
- 死代码:未用导入(Sidebar×7、TextEditor、SideCardSection、config、fs-operations 及 6 个 spec)、sidechat-core 死累加器 total、chunk-loader.spec 死助手 registry、sidechat-seed-validation 死助手 toolResultMessage
- 真实小修:agent-opens 三处 throw 补 cause;lazy-chunk any → ComponentType<P>(P extends object);service.ts claimed 初值改定值赋值;chunk-loader task / spec 内 etag / pendingLoad / snapshot 改 const;terminal-links 去掉字符类内多余转义;SubagentView catalogs 空兜底 useMemo 稳定标识;editor-host.spec 组件提出大写 FakeViewer(rules-of-hooks);pty-helpers.spec 内联 require 提升为静态导入;panel-host-css 注释里的零宽空格改为可见写法
- 依赖数组豁免(均带理由):granular scope 字段(EditorHost / PdfView / ChangesTab / GitLens×2)、job.status 粒度(SubagentView×2)、清理期读 ref、mount-only 注册等;ctx(挂载期恒定)直接入 deps(Sidebar×3)、TextEditor previewScroll 补 scope(幂等)
- 刻意控制字符正则(conversation-draft / markdown-images)与宿主槽位 any 签名(context-types)以带理由豁免保留
接入:
- Makefile:lint 目标(typecheck 旁),check 聚合补 lint 保持「对齐 CI」语义
- ci.yml ci / ci-windows 两 job 与 release.yml 在 Typecheck 后加 Lint 步骤(release 注释同步顺序)
2026-09-03 20:00:08 +08:00
Menghuan1918
f418692ad0
build(lint): 引入 ESLint 工具链与 flat config 最小规则集
...
- devDependencies: eslint 10 / typescript-eslint 8 / eslint-plugin-react-hooks 7 / globals / @eslint/js(ESLint 10 起 @eslint/js 不再随 eslint 自带,需显式安装)
- eslint.config.js:@eslint/js recommended + typescript-eslint recommended(非 type-checked)+ react-hooks recommended(v7 的 React Compiler 语义规则档整体关闭——57 处存量误报,保留经典 rules-of-hooks / exhaustive-deps 双规则)
- globals 分域:src/client → browser;src 根 / scripts / 根级 config → node;tests → node+browser
- reportUnusedDisableDirectives: error 揪孤儿豁免;no-unused-vars 对齐仓库既有 _ 前缀占位约定
- package.json 增加 lint script(eslint .)
2026-09-03 20:00:07 +08:00
Menghuan1918
e8834bd349
feat(theme): drive the last-resort error bar through skin tokens
...
The host-anchor fallback diagnostic strip inlined hardcoded colors
(#f2a1a1 on #1b1b22). Route them through var() chains like the existing
SideChatView.module.css fallback pattern: text/border read
--dsw-alias-state-error-primary (the codebase's canonical error color,
23 existing usages) and the background reads
--dsw-alias-bg-layer-3,var(--dsw-alias-bg-base,...) (elevated surface,
then page base). The old hexes ride as the chain tails, so with no skin
tokens on the page the bar renders byte-identical to before, while any
--dsw-alias-* skin re-themes it (guide §12: no hardcoded colors). The
guide does not cover this strip and tests/theme.spec.ts asserts
effectiveTokenValue semantics only, so neither needs a follow-up.
2026-09-03 19:59:00 +08:00
Menghuan1918
040b182b1c
refactor(theme): One Dark/Light 语法色板单源化
...
新增 src/client/one-dark-palette.ts,作为 one-dark / one-light 两套语法
色系的唯一来源:TerminalView 的 ANSI 16 与 cm-themes 的 CodeMirror 高亮
规则改为从色板常量组装各自的映射(ANSI 槽位 / lezer tag 到色相的映射
仍留在各消费方——两边的角色映射本就不同)。
行为不变的纯重构:每个 hex/rgba 迁移前后逐字节一致(旧新片段在桩
tags 下求值深度比对相等;产物 hex 清单无删除、非色板 hex 计数零变化)。
TerminalView 的 token 兜底色与 cm-themes 的 selection/activeLine rgba
与语法色系无关,保留原处未合并。
chunk 边界:色板为纯常量,被 terminal / editor 两个懒 chunk 各自内联
(每 chunk 约 200B 字面量),不引入跨 chunk import;核心 bundle
(client.js / client-registry.js)对该模块零引用(grep 产物验证)。
tests/one-dark-palette.spec.ts 钉住色板字面量防意外漂移。
2026-09-03 19:59:00 +08:00
Menghuan1918
fa301da29e
feat(i18n): localize plugin catalog names and shell preset desc
...
Catalog entry names (15 tab + 4 viewer) and the dsh-desktop shell preset
desc were raw hardcoded zh strings rendered straight into the add-plugin
modals and the title-bar scheme dropdown. Mirror the existing desc
pattern exactly: PluginEntry.name / ShellPreset.desc widen to the
i18n-friendly string-or-() =>-string union, the catalogs carry lazy
t('pluginXxxName') / t('presetDshDesktopDesc') lookups, and the
add-plugin modal (render, search filter, aria-labels) plus the scheme
SelectMenu resolve them like every other copy. The plain-string arm of
the union stays as the raw-name fallback, and t() itself never yields
empty text (missing keys render the key), so a dict gap can never blank
a name.
20 new dictionary keys added to zh/en (locales.ts), ja (locales-ja.ts),
and all 18 third-language dictionaries — tests/locales.spec.ts enforces
key-set equality against zh for every shipped dict (precedent: 9cc642b ),
so the 'leave other locales-* untouched' shortcut would fail the hard
parity gate; real translations are provided instead.
Spec follow-ups (behavior change: names/descs now render through t()):
- plugin-list.spec.ts: name non-empty assertion resolves the union.
- add-plugin-modal.spec.tsx: sentinel/office name assertions resolve
from the catalog (en locale in tests) instead of pinning zh literals.
- shell-presets.spec.ts: desc non-empty assertion resolves the union.
2026-09-03 19:59:00 +08:00
Atlas Zeng
9e1a034527
Merge pull request #537 from omdsh-dev/feat/adapt-dsh-0.1.2-rc.1
...
feat: adapt to DSH 0.1.2-rc.1 and bump to v0.18.0 (stable)
v0.18.0
2026-09-03 19:38:01 +08:00
Menghuan1918
ab6f960fe4
fix(ui): animate the toggle cluster's recenter between tab strip and session header
...
The viewport-corner toggle cluster sits at top:3 riding the right panel's
tab strip while expanded, and recenters to top:14 over DSH's session
header row when collapsed — an 11px snap on every expand/collapse. Ride
the panel slide's own duration/easing (--ds-transition-duration-slow +
--ds-ease-in-out) so both moves stay in lockstep; prefers-reduced-motion
already clears .toggleCluster transitions.
2026-09-03 18:15:41 +08:00
Menghuan1918
fbfd59bd1b
feat: adapt to DSH 0.1.2-rc.1 and bump to v0.18.0 (stable)
...
Graduate from the alpha track to the stable channel:
- Baseline: CI mount pin, dsh.plugin.json engines floor, and every
@deepseek-ai/* peer floor / devDependencies pin move to 0.1.2-rc.1
(published on the `next` dist-tag). alpha.5 -> rc.1 is a pure version
bump in the harness (all package.json "version" lines, zero source
delta), so no code adaptation; every host contract was re-verified
unchanged and the real-host mount smoke passes.
- dsh-client-locale resumed publishing; its trailing-pin exception is
gone — peers and devDeps align at 0.1.2-rc.1 (pnpm peers check clean).
- Version: fold the unpublished v0.18.1-alpha.0 / v0.19.0-alpha.0 bumps
into the v0.18.0 stable release; SIDEBAR_SERVICE_VERSION follows
package.json (asserted by tests/service.spec.ts).
- Docs: README/README_EN badges + channel notes + a full "since v0.17.1"
changelog entry (the two folded alpha numbers are annotated), AGENTS.md
§2/§3 baseline wording, external-plugin-guide version line, and the
e2e-host-protocol header's re-verified list gains 0.1.2-rc.1.
2026-09-03 17:32:04 +08:00
Atlas Zeng
60f9acdcbe
Merge pull request #527 from omdsh-dev/fix/scripts-hardening
...
fix(scripts): e2e 脚本加固——tarball mtime 选取/DSH_CMD 统一/registry mermaid chunk/e2e-common.sh 去重
2026-09-03 16:30:12 +08:00
Atlas Zeng
dd47a2c864
Merge pull request #526 from omdsh-dev/feat/dev-commands
...
feat(dev): 引入 Makefile 规范化命令面
2026-09-03 16:30:08 +08:00
Atlas Zeng
f24f95f6d2
Merge pull request #525 from omdsh-dev/feat/dedup-core
...
feat(client): 收敛重复实现(api envelope/extOf/lineage/错误归一化)并删除死代码
2026-09-03 16:30:04 +08:00
Atlas Zeng
ceed6b244e
Merge pull request #524 from omdsh-dev/feat/test-utils
...
feat(tests): 收敛组件测试样板到共享 test-utils
2026-09-03 16:30:00 +08:00
Menghuan1918
3d23ceb467
fix(ci): pnpm 版本统一由 packageManager 字段供版,移除 action 显式 version 输入
2026-09-03 12:17:28 +08:00
Menghuan1918
c026676f41
refactor(e2e): 抽取 e2e-common.sh,收敛两挂载脚本的重复骨架
...
e2e-mount.sh 与 e2e-aggregate-mount.sh 约 40% 逐字重复:say/warn/die、
node/pnpm 前置校验、DSH_CMD 与 tarball 解析、scratch home + 清理 trap、
profile 三件套 heredoc、dsh web 启动与就绪轮询。收敛为 scripts/
e2e-common.sh 纯函数库(日志前缀 E2E_TAG 参数化),两脚本 source 之。
行为等价性(差异点全部参数化,既有注释语义原位保留):
- DSH_HOME 子路径:mount 用 $SCRATCH/home,aggregate 直接用 $SCRATCH
(调用点各自 export);
- 就绪行 grep:mount 要带 token 的完整 URL(head -1 取首个),aggregate
只取裸 origin(tail -1 取末个)——E2E_READY_RE / E2E_READY_PICK 传入,
两侧论证注释保留在各自脚本;URL 提取统一为命中串取末段(mount 模式带
`dsh web: ` 两段前缀故等价于原 awk '{print $3}',aggregate 模式不含
空白故等价于原整行);
- 额外清理项:aggregate 的 fixture TMP_DIR(mount 不设该变量即跳过);
- 就绪失败文案/尾部行数差异(提前退出 tail -30 vs 超时 tail -40 vs 双
日志 tail -5)留在调用点。
e2e-common.sh 为纯开发侧文件,不进 npm files 白名单;install.sh /
install.ps1 随 npm 包独立分发,保持自包含,不 source 它。
2026-09-03 12:08:43 +08:00
Menghuan1918
35111e163c
docs(readme): 双语补 Makefile 用法、聚合挂载回归与一键安装入口
...
- 开发与构建:补 Makefile 薄封装示例(help/check/mount/clean)与
pnpm check:consumer-types 的定位说明(浏览器-only 消费者视角)
- 参与贡献:提交前自检补 make check 与 pnpm test:mount:aggregate
- 安装:补方式三一键脚本(bash scripts/install.sh;Windows install.ps1,
-h 查看参数);README 与 README_EN 同步镜像
2026-09-03 12:07:35 +08:00
Menghuan1918
6201a2c6e6
build(ci): 补 test:mount:aggregate / clean / packageManager 并对齐 release 校验顺序
...
- package.json 新增 test:mount:aggregate(scripts/e2e-aggregate-mount.sh 的
npm 别名,CI plugin-mount lane 改经它驱动,保留 DSH_CMD/DSH_TELEMETRY_DISABLED
env)与 clean(node rmSync 删 lib,与 build 开头清理同款、跨平台);
只新增普通 script,不动任何生命周期钩子(market-manifest.spec.ts 对
packed manifest 的 lifecycle 断言不受影响,已实跑验证)
- packageManager 钉 pnpm@11.8.0(本地实装版本;pnpm 10+ 运行时按该字段
自切版本,CI action-setup 的 version: 11 输入与其兼容不冲突)
- release.yml 校验顺序统一为 typecheck → test → build → check:consumer-types
(与 ci.yml 一致),补上缺失的 consumer 类型面守卫;tag 校验等非构建
步骤位置不变
2026-09-03 12:07:29 +08:00
Menghuan1918
789696aa31
build(dev): 引入 Makefile 命令面薄封装与 .editorconfig 基线
...
- Makefile 仅转发 package.json scripts(唯一事实源),补 help 自说明、
clean 清理与 check / mount / mount-aggregate / registry 四个聚合目标;
check 用单条 recipe 串 typecheck → build → test → check:consumer-types,
避免 make 前置依赖在 -j 下乱序;lint 目标留给引入 ESLint 的后续 PR
- .editorconfig:root + utf-8/lf/末尾换行/去尾随空格,默认 2 空格,
Makefile recipe 保持 tab
2026-09-03 12:07:23 +08:00
Menghuan1918
bc1984b2f2
refactor(sidechat): 删除零引用的 sidechatSeed
...
src/sidechat-core.ts 的 sidechatSeed()(buildSidechatInheritance 的
seed 半边,doc 注明 test convenience)在 src+tests 全仓零引用,也无
barrel 转出口,删除。同文件的 SeedEvent 类型与 copyEvents 仍被
SidechatInheritance 使用,保留;其余导出不动。
2026-09-03 12:05:48 +08:00
Menghuan1918
4002f3cc5c
refactor(client): 统一 GitLens 错误归一化与 SubagentView 日志分级
...
- GitLens.tsx:六处 catch 里的 reason instanceof Error ?
reason.message : String(reason)(refreshTarget/refresh/loadMoreLog/
commit/checkout/runConfirmed)收敛为模块级 errorMessage(),
两处模板字符串插值场景(historyLoadError/checkoutError 前缀)
同样复用;归一化表达式与输出文本逐字不变。
- SubagentView.tsx:openSubagent/open session 失败的 console.warn
改为 console.error,与同严重度失败路径对齐(Sidebar.tsx tab
badge、TerminalView.tsx xterm open、service.ts urlTarget/plugin
callback 均为 console.error);前缀与消息文本不变。tests/ 无任何
钉 console.warn 的断言,已核实。
2026-09-03 12:05:48 +08:00
Menghuan1918
69cc8014a7
refactor(client): subagent lineage 遍历收敛为共享 subagent-lineage 模块
...
rootAncestor / countSubagentDescendants / treeSessionIds 三份「沿
subagent-origin 链上行 + seen 集合防环 fail-soft」实现收敛到新模块
src/client/subagent-lineage.ts:核心走链是单个私有生成器
subagentOriginChain()(seen 防环、只在节点为 subagent 且有 parent 时
前行),三个公开函数迁入并基于它重写;isSideThreadSummary 一并迁入
(countSubagentDescendants 依赖它,迁入可避免 detect↔lineage 循环
依赖),subagent-detect.ts / subagent-jobs.ts re-export 全部迁出
符号,既有 import 调用点零变化。
语义逐字保留的等价性论证:
- rootAncestor:链为空返回 start.id(原循环条件不满足即返回
current?.id);链非空返回 byId[末节点.parentId]?.id ?? sessionId
(原循环退出时 current 恰为该行,断链/行缺失回退 sessionId 不变)。
- countSubagentDescendants:生成器在 seen.add 后 yield、消费方判
parentId === sessionId 即 break——与原循环体内判断顺序一致;
descendant 的 running 判定、side-thread 过滤位置不变。
- treeSessionIds:根行缺失(byId[rootId] 无行)时任何上行都不可能
「访问到」根(原实现只匹配真实访问过的行),故提前返回空集;
根行自身(非 subagent)经 summary.id === rootId 特判入集;其余
行经链节点 parentId === rootId 判定,等价于原「上行走到 id ===
rootId 的行」——两种表述指向同一行(链上节点的 next 行)。
directSubagentCount 不迁移:它是对直接子行的单层过滤,没有上行
walk,无共享逻辑(背景侦查将其归入 walk 家族与实际代码不符)。
collectBranchIds 遍历的是 catalog 结构而非 session 链,保持不动。
2026-09-03 12:05:41 +08:00
Menghuan1918
857646ea66
refactor(client): 收敛 /sidebar envelope 解析与取扩展名双实现
...
- api.ts:call 与 fetchUpload 里逐字相同的响应 envelope 解析
(json().catch(null) + ok/value 判断 + SidebarApiError 构造)收敛为
私有 readEnvelope<T>(),两处调用;判断顺序与错误码回退逻辑不变。
- 取扩展名双实现收敛:extOf 的实现迁至零依赖的 paths.ts(lang.ts 与
service.ts 均可达的基础模块),lang.ts re-export 保持既有导入面
(tests/file-types.spec.ts 从 lang.ts 导入 extOf);service.ts 删除
模块私有的同体 extOfPath,matchFileViewer 改用 extOf。方向说明:
service.ts 不能反向 import lang.ts——lang.ts 携带全部 @codemirror/*
依赖且只经 editor 懒加载 chunk 进入浏览器,core bundle 静态引用它
会把 CodeMirror 拉进核心包(构建产物已验证:client.js /
client-registry.js 中 0 处 codemirror,client-editor.js 不变)。
2026-09-03 12:05:29 +08:00
Menghuan1918
0831505854
test(lib-guards): lib 产物缺失时 chunk-artifact / manifest-consistency 跳过而非 ENOENT
...
fresh clone 未 build 直接 pnpm test 时,两 spec 的 readFileSync 会
ENOENT 崩溃(此前靠 package.json prepare 钩子隐式兜底)。改为文件级
describe.skipIf 守卫:缺产物时整套显示为 skipped 并 console 提示先
pnpm build(exit 0);产物存在时行为与之前完全一致(本仓 prepare 钩
子产出 lib 后两 spec 照常执行,已验证 9 passed 非 skipped)。
2026-09-03 12:04:41 +08:00
Menghuan1918
936df662b0
test(specs): 收敛 28 个组件 spec 的渲染样板到共享 test-utils
...
- 7 个 spec 的本地 mount()(createRoot + act 容器循环)替换为
renderRoot():sidechat-view、subagent-jobs-view、subagent-live-polling、
lazy-chunk、side-card-section-rows(本地 mount 删除,调用点改名);
editor-refresh、markdown-manual-refresh(EditorHost 包装 mount 改为
委托 renderRoot,调用点不动)
- 24 个 spec 的内联 IS_REACT_ACT_ENVIRONMENT 赋值替换为 setupReactAct()
(subagent-jobs-view / subagent-live-polling / lazy-chunk 原本未设
flag,保持原样不引入)
全部为语义相同的样板替换:迁移后全量 118 files / 1241 passed +
9 skipped,与迁移前一致。
2026-09-03 12:04:35 +08:00
Menghuan1918
a627a4c84d
test(utils): 新建共享 React 测试工具 setupReactAct / renderRoot
...
收敛组件 spec 两类样板的最小共享面:IS_REACT_ACT_ENVIRONMENT 幂等设置
(vitest 按文件隔离 global,逐 spec 调用与原内联语句语义一致)与
createRoot + act 的分离容器渲染循环。刻意不做查询 DSL / 自动清理 /
新依赖。
2026-09-03 12:04:24 +08:00
Menghuan1918
61c9c550d9
fix(registry): registry 打包补上 mermaid 懒加载 chunk
...
package.json files 白名单与 tsdown 产物都含 lib/client-mermaid.js(+
.map),registry 通道的复制清单却缺它——经 dsh registry 安装后 Markdown
预览首次加载 mermaid 会拿到 /sidebar/bundle 404。与 terminal/editor
两 chunk 同款补齐。
2026-09-03 12:03:05 +08:00