@nimoxie/dsh-ui-tweaks 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DEVELOPMENT.md CHANGED
@@ -7,7 +7,8 @@
7
7
  - **已知坑**:注入、类名、data 标记、Shadow DOM 浮层。
8
8
  - **更新检查(模块 3)**:成熟期门禁与豁免表、cooling、强制更新、兼容门禁、Auto review。
9
9
  - **动画修复(模块 4)**:删 `prefers-reduced-motion` 规则 + `matchMedia` 门控。
10
- - **回合改动补位卡(模块 5)**:用会话日志里的 `meta.diffs` 重建回合尾卡、探测式补位、`tool/ptc-dispatch` 的 turn 归属。
10
+ - **回合改动补位卡(模块 5)**:用会话日志里的 `meta.diffs` 重建回合尾卡、**必须实现 `buildLocationData` 才能被卡片读到**、补位条件是「官方那侧不会画」而非「探测到 404」、`tool/ptc-dispatch` 的 turn 归属。
11
+ - **官方改动卡数据适配层(模块 5b)**:包装 `window.fetch`,把日志重建的 summary/diff 喂给官方卡;坐标必须在渲染期登记(先 render 后 effect);其它请求一律透传、可卸载。
11
12
  - **窗口记忆(模块 6,仅 host 半区)**:helper + 预编译 DLL、宿主识别、编码坑、360 误报。
12
13
  - **立即重启(模块 7)**:三模式判定、会话运行态、蒙皮、弹窗定位。
13
14
  - **其余**:键盘与焦点、界面验证手法、迁移、待办、发布。
@@ -60,6 +61,8 @@
60
61
  - **cooling 文案(0.1.6 定稿)**:列表默认只有**一句话**——`0.70.0 还需等待 10 小时 40 分才能更新(10-15 07:54 到期,点标签看详情)`。完整解释走 `coolingReasonText(detail, windowMs)`,**只在点「冷静期中」标签展开时渲染**(`.dtl`):为什么等(dsh 的 24 小时策略讲成人话)→ 硬装的后果(连坐整个 profile,故不提供直接安装)→ 到点自动恢复 → 末尾附原始诊断(预检=registry 记录,反应式=pnpm 报错)。等待期已过 / 结束时间未知各有文案。换行由 `.why` 的 `white-space:pre-wrap` 呈现。
61
62
  - **到期自动重查(0.1.6)**:`scheduleCoolingRefresh(name, matureAt)` 给 cooling 行排到点(+3s 缓冲)的 `checkOne(name)` 定时器(按包名去重);触发点=`applyCoolingGuess` 落 cooling 后、`judge` 冷却分支落 cooling 后;上限(约 24.8 天)之外不排。
62
63
  - **兼容门禁(0.1.7,借鉴 plugin-manager)**:新版 registry 清单可能声明最低 DSH 版本(`dsh.engines.dsh` → 顶层 `engines.dsh` → `peerDependencies["@deepseek-ai/dsh"]`);本机版本由 host 半区读 `profileContext.installAnchor` 的清单,兜底读 profile 里的 `@deepseek-ai/dsh`。低于要求 → 标 **「DSH 不符」**、不给点、不计入「全部更新」。**只认 `>=x.y.z`**;未声明、写法不认识(`^`/`~`)、读不到版本 → 一律不拦。
64
+ - **更新=卸载 + 安装(0.1.8)**:官方 `installBundle` 在**开着 HMR 的运行时**里会直接拒绝已装过的包 —— `@deepseek-ai/dsh-plugin-manager/lib/index.js` 的 `installBundle`:`if (this.ownerContext.get("hmr") !== void 0 && known !== void 0 && Object.hasOwn(before, known)) throw new ManagementFailure("already-installed")`;判据是「包名已在 profile 依赖里」,**与版本无关**(所以 0.1.7 前直接 `installBundle("name@新版本")` 的更新必然以 `already-installed` 收场)。官方工具说明本身就写着:换版本要 **先 `removeBundle` 再 `installBundle`**,官方 UI 也只有「装 / 卸 / 开关」、没有更新。对策 `installBundleEx()`:① 先直接装(没有 HMR 的运行时一步到位、不碰卸载);② 只有被 `already-installed` 拒绝时才 `removeBundle(包名)` → 再装;③ 卸载也被拒就**把原始拒绝原样报出**(不掩盖原因,也别白拆一次)。**失败回滚**:卸载成功过而结果落 `failed`/`cancelled` 时用原版本 `name@busyBefore` 装回去;`unknown` 不回滚(安装可能仍在飞,硬回滚会打架)改为在文案里提醒确认。错误码统一翻人话(`installCodeText`:already-installed / incompatible-version / not-removable / bundle-in-use / operation-error / stale-approval …),带错误码的拒绝不再走「回包丢了」的恢复逻辑。**两种形状都要认**(`isAlreadyInstalledResult`):① 远程 API 的拒绝信封 `{ok:false, error:{code}}`;② **桌面端进程内管理器把它报成「应用层失败」** —— `{ok:true, value:{application:"failed", error:{code:"already-installed"}}}`(`failureText` 取的就是 `st.error.code`,真机上报的正是这条,0.2.1 第一版只认①所以没生效)。测试:`installBundleEx` 四条路径(直接成功 / 拒绝信封转两步 / 别的码不卸载 / 卸载被拒)+ **失败信封形状触发两步** + 判定谓词六种输入 + 错误码表 + 回滚与「不再单步安装」的静态断言(client 60/60)。
65
+ - **0.2.1 补丁二:失败信封也会骗人 + 等卸载落地 + 退避重试**:① `resultFailure()` 统一判定"这次调用的结果到底成没成" —— **不能只看 `ok`**:桌面端把失败包成 `{ok:true, value:{application:"failed", error:{code}}}`,0.2.1 第一版用 `rm.ok !== false` 判"卸载成功",于是**卸载被拒被当成成功**、随后重装又失败,最终还假报"已回滚到 0.4.6"、把真原因(`not-removable` 之类)吞掉。现在失败信息会把"卸载被拒(X)"如实带出。② `removeBundle` 会触发一次 profile 重载;真机上"卸载刚返回就重装"仍被打回 `already-installed`(新请求可能还在上一代管理器里跑、读的是卸载前的清单 —— 而紧接着的回滚安装却成功,差别只在"中间隔了一次重载")。对策:`waitBundlesGone()` 轮询 `listBundles()` 直到清单里没有该包(10s 上限、400ms 间隔),再 `installRetrying()` 退避重试(3 次 × 1.5s);拿不到清单就当"没有",绝不把更新卡死。测试:新增"等清单消失 + 重试到成功"的调用序列断言、"卸载被拒不会再被当成功"、"一直没消失就到点返回 false"、`resultFailure` 六种输入(client 64/64)。
63
66
  - **「Auto review」提醒条(0.1.7,只读不改)**:DSH 0.2.0-rc.2 的已知缺陷 —— `auto` 模式的会话会让 `permissionPresets` 在热重载(装/更新插件就会触发)时构造失败(`pinInitialPermission` 构造期遍历已驻留会话,`autoAdmit` 还没注册就抛错),表现为装插件报一长串错、连带 `sessionProjections` 也起不来,要重启客户端才恢复。面板顶部加琥珀色提醒,**只读检测**「是否有驻留会话的 permissions 投影 currentValue === 'auto'」(读法同官方权限面板:`ctx.get('sessions')` → `list.getSnapshot().ids` → `binding(id).session.projections.faceOf('permissions').getSnapshot()`);**不写设置、不拦操作**。
64
67
  - **0.2.1-rc.2 复核(2026-10-18)**:预设标识仍是 `AUTO_PRESET = "auto"`,界面文案改叫「自动审查」,判定串 `currentValue === 'auto'` **不受影响**;旧缺陷的 throw 仍在,但 auto-review 集成新增卸载时的收尾迁移(先把所有 auto 会话改成 `danger-full-access` 再退出),触发窗口收窄、日志无该错误痕迹。该模式还有**调用前审查**:服务不可用或限流时工具调用**直接被拒、工具体不执行**(`503` 与 `429 请求过于频繁(limit 30)`)。
65
68
  - **本机环境**:dsh 用**自带的 pnpm 11.7.0**,**不是** PATH 上那个(PATH 是 11.21.0);排查必须用前者复现,否则结论会反过来。自带运行时在 **`<客户端安装目录>/resources/runtime/`**:`pnpm/`(11.7.0 包)、`bin/node`(shim,exec `$DSH_DESKTOP_NODE_EXECUTABLE`=客户端 Electron + `ELECTRON_RUN_AS_NODE=1`)、`versions.json`(node 24.18.1 / pnpm 11.7.0)。复现:`ELECTRON_RUN_AS_NODE=1 npm_config_minimum_release_age=1440 "<客户端>/DeepSeek Harness.exe" --expose-internals "<客户端>/resources/runtime/pnpm/bin/pnpm.cjs" add <pkg>@<ver> --registry=https://registry.npmjs.org/`。
@@ -100,12 +103,36 @@
100
103
  - `ctx.uiConversation.events.register({ kind, match, start, update })`:`match(event) → {id, role:"start"|"update"}`,`id` 只是分组键(官方用 `String(turn)`);`update(context, match)` 第一个参数带 `.state`,**`match.event` 才是事件**(把 match 当事件读会全空);返回值经 `requireState` 校验,**不能 undefined**。
101
104
  - 槽位:`ctx.slots.register({ name:"conversation.chat.turnTail", id, order, inject }, Component)` —— 契约 `kind:"list"`,现有 deliverables / plan(order 20) / schedule 三家,我们取 **order 30**。
102
105
  - 卡片 props:`{ turn, seq, openFile, sessionId, t, …hooks }`;**Definition 的状态用 `props.turn.data.get(kind)` 读**(deliverables 的 `changesForClosing` 就是这么取)。
106
+ - ⚠️ **那份状态必须由本 Definition 自己发布**:装配器只为实现了 **`buildLocationData(context, scope, previous)`** 的 Definition 发布 Turn 作用域数据(`dsh-client-ui-conversation` 的 `buildLocationData` → `replaceLocationData` / `applyDirtyLocationData` → `locationIndex` 的 `MutableLocationDataStore`),而 `turn.data.get(key)` 返回的正是发布项里的 `value`。发布项还必须满足 `data.kind === scope`、`data.key === 本 Definition 的 kind`(不符装配器**直接抛错**)、`data.turn` 为安全整数 —— 所以取不到 `turn` 时返回 `null` 而不是硬发。**0.2.0 漏了这一步:`state` 恒为 `null`,卡片一次都没画出来**。离线 harness 当时把 `turn.data.get` 直接桩掉了,所以 31/31 是假通过;0.2.1 起注册前显式校验 `changesDefinition().buildLocationData` 存在,否则 guard 报错。
107
+ - 顺带一个性能约定:`buildLocationData` 在状态未变时**返回入参 `previous` 本身**,装配器据此判定「未变化」而跳过重发布(否则每回合重绘一次卡片子树)。
103
108
  - **嵌套调用的 turn 归属**:`tool/ptc-dispatch`(run_code 里的 edit/write)**没有 turn 字段**(只有 `rootCallId/parentCallId/subCallId` + `meta.diffs`),用 `tool/call`(有 `turn`/`callId`)建 `rootCallId → turn` 映射挂回去。前端**收得到** ptc 事件(`dsh-client-ui-chat`/`tool`/`plan` 都在匹配它),否则本模块会漏掉绝大多数改动。
104
- - **探测式补位**:`GET api/changes.summary?sessionId=…&seq=<workspace/changes 的 seq>`(**文档相对**,无前导斜杠;官方 `changesSummaryUrl` 同形)。**200 → 不画**(让位官方卡);**只有 404 才画**;401/其它状态/网络异常一律不画 —— 宁可漏补,不可误补出双份。
109
+ - **补位条件(0.2.1 修)**:先判断「官方那侧会不会画」= `configForms.developerTools.enabled`(设置项**「显示编码工具视图」**,正是官方卡注入的 `showCodeDiff`)**且**该回合有 `workspace/changes` 公告(`seq` 非 null)。缺任一个 → 官方一定不画,**直接补位、不发探测**;两者都满足 → 才探测 `GET api/changes.summary?sessionId=…&seq=<公告 seq>`(**文档相对**,无前导斜杠;官方 `changesSummaryUrl` 同形),**200 → 不画**(让位官方卡),**只有 404 才画**,401/其它状态/网络异常一律不画 —— 宁可漏补,不可误补出双份。0.2.0 只看 404,于是「开关关着」时两边都不画(全空白)。开关 store 用 `ctx.inject(["configForms"], …)` 取,拿不到就按「可能开着」走探测(与 0.2.0 同行为,不会多出卡)。
105
110
  - **缓存策略**:探测结果只缓存在**本次连接**内,`connection/reset` 清空。官方自己永久缓存 missing(`{failed:"missing", retryable:()=>false}`),那会在宿主恢复或探测期误判后留下双份卡且**无法自愈**。
106
111
  - **同文件多次改动**:按 old→new 链折成一份净变化(后段 `oldText` 应等于前段 `newText`);链断则分段显示并分别计数,不报错。
107
112
  - **边界**:只覆盖文件工具;pwsh / npm 等造成的改动进不来(只有官方卡含)。已释放的旧会话**不需要回填** —— 日志在磁盘上就能立刻重建(这是选 A 而非自己持久化的最大理由)。
108
- - **验证**:离线 harness(`%TEMP%\dshuiw-changes-test\test-changes.cjs`,vm + React/DOM 桩)**31/31** —— Definition 聚合与 turn 归属、链式合并、折叠/展开渲染与计数、200 让位、401 不画、fetch 抛异常不崩、链断降级、服务缺失只 warn 不拖垮其它模块、React 缺失不注册槽位。**真机待验证**。
113
+ - **验证**:离线 harness(`%TEMP%\dshuiw-changes-test\test-changes.cjs`,vm + React/DOM 桩)**31/31** —— Definition 聚合与 turn 归属、链式合并、折叠/展开渲染与计数、200 让位、401 不画、fetch 抛异常不崩、链断降级、服务缺失只 warn 不拖垮其它模块、React 缺失不注册槽位。但该 harness **把 `turn.data.get` 桩掉了**,所以没暴露 0.2.0「卡片一次都没画出来」的缺陷;0.2.1 补上 `buildLocationData` 后另有 21/21(见文末 0.2.1 条),并已真机验证。
114
+
115
+ ## 官方改动卡数据适配层(模块 5b,0.2.1 起)
116
+
117
+ - **为什么**:官方那张卡的 summary/diff 只活在 Host 的 Session 内存里,会话一释放就 404,卡直接不画。而它只要 `response.ok` + 形状合法,**不问数据来源**(`HostReadStore.read` 就是一句 `fetch(url, { signal })`,deliverables client.js:208)。所以这一版不再画卡,改成**喂数据**:官方组件原生渲染,卡头 / hover 预览 / 右侧 Review 全是官方的。
118
+ - **怎么喂**:幂等包装 `window.fetch`,只认 `/api/changes.summary` 与 `/api/changes.diff`,且只对索引里存在的 `(sessionId, seq)` 回合成 200;其它请求一律 `original.apply(this, arguments)` 透传;`ctx.effect` 里 yield 卸载函数还原原 fetch。
119
+ - **时序(最容易踩)**:坐标必须在官方组件发请求**之前**进索引。官方在 `useEffect` 里发请求,而 React 先跑完所有 slot 的 render 再跑 effect —— 所以登记放在卡片**渲染期**(`registerChangesCoordinates`),放 effect 里就是竞态。
120
+ - **turn 从哪来**:Definition 发布的状态只有 `{seq, files}`,轮号在 slot props 的 `owner.turn.turn`(TurnLocation)。官方 validator 要求 `turn` 是 ≥1 整数,取不到就**不拦**——宁可不补,也不能发非法形状。
121
+ - **形状**:`summary = {turn, files:[{path,display,added,deleted}], total, added, deleted}`;`diff = {kind:"text", path, display, before, after, coarse, hunks:[{oldStart,oldLines,newStart,newLines,lines}]}`,hunk 按 3 行上下文切、行号 1 基、每行带 `+`/`-`/空格 前缀、单文件上限 2000 行。
122
+ - **口径差异(有意为之)**:官方是回合首末**净变化**,旧自画卡是**分段累加**(链断时按段计),同一轮数字会不同(实测 +16 −13 vs +2 −12)。要官方外观就走官方口径。
123
+ - **display**:按官方规范取相对 cwd 的路径;**家目录 `~` 归一化暂缺**(客户端拿不到 home),仓库外文件退化为绝对路径,只影响观感、不影响校验。
124
+ - **验证**:离线 harness `.dsh-tmp/check-adapter.mjs`(临时脚本,未入库)—— 真 `client.js` + 假 ModuleLoader/React/slots/sessions + **官方 4 个 validator**,16 项(summary/diff 形状、净变化计数、hunk 行号与上下文、index 越界透传、跨会话/跨 seq/无关路由不拦、卸载复原);真机已在旧会话 `session-11fed76a` turn 57(seq 3156)验证:官方卡与右侧 Review 均正常,旧卡自动让位。
125
+
126
+ ### 自画卡的定位(切片 2 之后)
127
+
128
+ - **只在两种情形画**:编码视图关、无公告。其余情形一律让官方卡渲染,本卡不抢。
129
+ - **骨架照官方**:60px 卡头 + 40×40 图标块(自绘 chevron-code SVG)+ 标题(单文件用 basename,多文件「已编辑 N 个文件」)+ 千分位统计;**多于 4 个文件**才出「全部 N 个」,点了只展开**列表**,绝不展开 diff(官方也只展开列表)。
130
+ - **类名不硬编码**:运行时从官方注入的 `<style data-plugin-css$="ChangedFiles.module.css">` 里正则取 hash 前缀(`\.([A-Za-z0-9_-]{4,12})_card`),再拼 `_card/_header/_list/_row/...`;读不到就退回内置近似样式 `CHANGES_FALLBACK_STYLES`(只影响观感,不影响结构)。
131
+ - **数据复用 5b 入口**:卡片直接读 `changesEntryFor(sid, seq)` 的 files(同一份净变化与 hunk),保证卡上的数字与喂给官方卡的那份永远一致,不另算一套。
132
+ - **点击 = 打开官方 Review**:`sidebarRight.openResource("dsh-resource://changes-review/session/<sid>/<seq>/<turn>", { params: { index } })`。**无公告的回合用合成坐标 `seq = 0`**,同时把 `sid:0` 登记进 5b 索引,Review 面板的取数就有着落。
133
+ - **hover 迷你 diff**:500ms 延迟;浮层用 `position: fixed`(卡片带 `overflow:hidden`,绝对定位会被裁),只画 `+`/`-`/上下文行(官方预览里同样隐藏 hunk 头)。
134
+ - **小字规则**:无公告 → 卡内底部一行 11px 可见小字 + `title`;编码视图关 → 只走 `title`,不破坏与官方的一致性。
135
+ - **hover 预览与官方对齐**:行号单列(删除行给旧行号、新增行给新行号、上下文行给新行号)、改动行淡底色(绿/红 16%)、左侧 2px 色条、`white-space: pre` 不换行(长行横向滚动)、hunk 之间留 6px 分隔。
109
136
 
110
137
  ## 窗口记忆(模块 6,仅 host 半区)
111
138
 
@@ -184,6 +211,7 @@
184
211
  - [x] 0.1.7(2026-10-16,tag `v0.1.7`):立即重启(模块 7)、兼容门禁(`DSH 不符`)、按钮迁到「已安装」标题行、脚注。
185
212
  - [x] 0.1.8(2026-10-17 00:34,npm latest):弹窗定位实测外框(26px)、`room` 下限、重排判据;面板显示权归还「打开/收起」;蒙皮补 `inert` 与键盘滚动锁;控件补 `role/tabindex` + `Enter/Space` + 焦点环;README 补自带 CLI 例外。tag `v0.1.8`(`8aed2bc`)。
186
213
  - [x] 0.2.0(2026-10-18):回合改动补位卡(模块 5)—— 用会话日志里的 `meta.diffs` 重建回合尾卡、探测式补位(只在官方 404 时画)、`tool/ptc-dispatch` 的 turn 归属、缓存随连接重置。离线 31/31;**真机待验证**(刷新客户端 → 跑一轮改文件的对话 → 切走再切回 / 重启后重开,看卡是否仍在且不重复)。
214
+ - [x] 0.2.1(2026-10-20):① 修 0.2.0 补位卡「一次都没画出来」—— 补 `buildLocationData`(缺它则 `turn.data.get(kind)` 恒空)、注册前显式校验、状态未变时复用 `previous`。② 补位条件从「探测到 404」改为「官方那侧不会画」:`developerTools.enabled` 关 / 该回合无公告 → 直接补位且不探测;两者都满足才探测,非 404 不画。③「自动审查」提醒条文案 150+ 字压到 59 字,README 同段一并压缩。④ 新增**模块 5b 数据适配层**:包装 `window.fetch` 把日志重建的 summary/diff 顶给官方卡,已释放会话改由官方组件原生渲染(hover 预览、右侧 Review 都是官方的),自画卡自动让位。⑤ 自画卡只服务两种兜底(编码视图关 / 无公告):骨架照官方(60px 卡头、图标块、千分位统计、4 行折叠、hover 迷你 diff、点击开官方 Review),删掉内联展开与「第 N 段改动」文案,无公告用合成 `seq=0` 走官方 Review。⑥ hover 迷你 diff 补官方观感(行号列 / 改动行底色 / 左侧色条 / 不换行横向滚动);清掉切片后失效的 4 个死函数(`shortPath` / `foldParts` / `countParts` / `DIFF_ROW_LIMIT`)。⑦ 验证:离线 harness **21/21**(`check-ui-tweaks-changes.mjs`)+ **16/16**(`check-adapter.mjs`,两个脚本都在 `.dsh-tmp/`,未入库);真机通过(旧会话 `session-11fed76a` turn 57:官方卡 + 右侧 Review 正常,无双份)。
187
215
  - [ ] `shell` 模式重启不留日志(`ui-tweaks-restart.log` 只有 `relaunch` 分支写),要硬证据就在 `performRestart` 退出前追加一行;「点按钮 → 宿主退出」目前只有 `crash-*-host.log` 作间接证据。
188
216
  - [ ] 窗口记忆「零闪现」只能靠常驻 watcher 进程(代价:常驻 + 卸载残留),**待与用户确认**。
189
217
  - [ ] cooling 预检更准:现在只扫 importers 直连依赖,传递依赖靠反应式报错兜底;要覆盖全量 lockfile 得有更狠的缓存/批量策略。
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 NimoXie
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NimoXie
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,157 +1,120 @@
1
- # dsh-ui-tweaks
2
-
3
- 给 DSH(DeepSeek Harness)的 Web UI 的一批界面微调:装上即生效,无需配置。
4
-
5
- 官方界面上有几处用得难受的地方:宽表格会撑出对话区右沿、滚动条贴在屏幕最右端要横跨半屏去够、Windows 关闭「动画效果」时前端动画被系统设置一并关掉、插件版本更新只能去插件管理页挨个看。这个插件把它们一次性修掉,另附一项桌面客户端的窗口记忆。
6
-
7
- ## 功能
8
-
9
- **宽表格越界修复**
10
- - 宽表格(≥4 列)不再撑出对话区,收敛回正文列并支持横向滚动,观察沿裁掉的问题消失。
11
-
12
- **对话区左侧滚动条**
13
- - 在右侧宽度调整条的左边放一条自绘滚动条:拖拽、点轨道翻页、滚轮转动手感与原生一致,主题跟随明暗。
14
- - 只在会话页出现,切到插件页等非会话页自动移除。
15
-
16
- **回合尾「本回合改动」补位**
17
- - 官方那张「本回合改动」卡的数据只活在会话内存里,会话一被释放(切走、重启客户端、重开旧会话)就变成「这轮改动的内容已不可用」。本插件在同一位置补一张**从会话日志重建**的同名卡,所以**重启客户端、重开旧会话后它依然在**,逐行 diff 也点得开。
18
- - **只在官方那张已经失效时才出现**:官方数据还在时(会话活着)完全不画,避免出现两张重复的卡。
19
- - **口径**:只覆盖**文件工具**(写/改文件)造成的改动,同一文件在一个回合里改多次会按前后文链成一份净变化;用脚本、`npm install` 之类改出来的内容不在此列(那只有官方卡含)。卡片底部有一行小字标明口径。
20
-
21
- **动画修复**
22
- - Windows 关闭「动画效果」时 Chromium 会向网页报告 `prefers-reduced-motion: reduce`,本插件清除因此失效的前端动画规则,让动画恢复;web 与桌面客户端都生效。
23
-
24
- **插件更新检查**
25
- - 插件管理页「已安装」标题那一行的右侧多两枚按钮:「检查更新」比对已装插件与 npm registry 的版本,有新版本可点上就地更新,支持全部更新与中途取消(不检查 dsh 本体与官方 `@deepseek-ai` 插件——它们的更新走 dsh 本体流程)。
26
- - 新版本还没过 pnpm 的发布时长窗口(默认 24 小时)时,该行标 **「冷静期中」** 并给出可更新时间,到点自动变回可更新;确需立刻安装,可在详情里走「强制更新」,它会先检查这次安装会不会被别的包连累拦下。
27
- - 新版声明了更高的 DSH 最低版本时,该行标 **「DSH 不符」**(鼠标悬停显示「需要 DSH ≥ x」),不给点——省得装上去起不来。
28
- - 更新成功后,面板顶部常驻「重启客户端后生效」。旁边的「**立即重启**」会先看有没有会话在跑:**有**就列出来、说明会被中断,**没有**则说明不会打断任何任务;**任何情况都要你点一下「重启 dsh」才会执行**。桌面端要两步 —— dsh 先退出,再由客户端弹出官方的「应用无法启动或已意外停止」对话框,**在那里点「重启」才真正拉起来**(也可手动退出后重开)。点下去后**整页会被蒙住**(此刻客户端已不可用);20 秒没退成就自动撤掉、提示你刷新页面或手动重启。两个面板都**不可拖动**,位置只有一个来源:贴在触发它的那枚按钮旁,下方放不下就翻到上方。
29
- - 两个弹窗都能**纯键盘操作**:Tab 逐枚走过「重新检查 / 全部更新 / ×」和每一行的标签,**回车或空格**即触发(与鼠标走同一套逻辑,不存在两套行为),**Esc** 收起;焦点环用官方主题令牌,与原生控件同色同宽;收起后焦点回到触发它的那枚按钮。
30
- - 安装落地后会自动清理 profile 里会让后续所有安装都失败的豁免表冗余(后台静默完成,无需你操作)。
31
-
32
- **窗口记忆(仅桌面客户端)**
33
- - 官方客户端每次启动都是固定的 1280×820 居中小窗,本插件让它记住上次的窗口大小、位置和最大化状态,下次启动自动还原。
34
- - 不修改官方客户端任何文件,卸载即完全还原官方行为;浏览器版不动作。
35
- - 状态存在 profile 的 `ui-tweaks/window-state.json`,删掉即重置记忆。
36
-
37
- ## 安装
38
-
39
- 浏览器版(`web`):
40
-
41
- ```sh
42
- dsh plugin --profile web add @nimoxie/dsh-ui-tweaks
43
- ```
44
-
45
- 装完重启服务(关掉再 `dsh web`)。
46
-
47
- 桌面客户端:桌面 profile **保留给客户端**,PATH 上那个 `dsh`(npm 全局装的)会被拒。但客户端**自带的那份 CLI 可以** —— 它就在安装目录里,和「插件管理」页走的是同一套实现:
48
-
49
- ```sh
50
- # Windows 桌面端;<安装目录> 形如 E:\tools\DeepSeek Harness
51
- "<安装目录>\resources\runtime\cli\bin\dsh.cmd" plugin --profile desktop add @nimoxie/dsh-ui-tweaks
52
- ```
53
-
54
- 不想敲命令,也可以照旧在客户端「插件管理」页添加包名 `@nimoxie/dsh-ui-tweaks`,重启客户端生效。
55
-
56
- 卸载(CLI 可管理的 `web` 环境):
57
-
58
- ```sh
59
- dsh plugin --profile web remove @nimoxie/dsh-ui-tweaks
60
- ```
61
-
62
- 别人也可以从 GitHub 或本地目录装(开发用):
63
-
64
- ```sh
65
- dsh plugin --profile web add github:NimoXie15/dsh-ui-tweaks
66
- dsh plugin --profile web add link:/absolute/path/to/dsh-ui-tweaks
67
- ```
68
-
69
- > **要求**:dsh `>= 0.2.0-rc.1`(需要 `remote.pluginManager` / `remote.pluginInventory` 接口)。
70
- >
71
- > 升级插件后如果界面没变化,按 **Ctrl+Shift+R** 强刷一次(浏览器可能还在用缓存的旧版本)。
72
-
73
- ## 已知限制
74
-
75
- - 非 npm 来源的插件没有可比的 registry 版本,直接跳过比对:`link:` / `file:` 本地路径标「本地链接」,`git:` / `github:` / `http` 直装标「Git 直装」(例:`github:Fisfzy/dsh-ego-browser` 装的是仓库源码,与 npm 上的同名包不是一回事)。
76
- - 更新失败的行会直接给出原因(pnpm 输出与日志位置),点它可重试;取消只作用于你点的那一项,后续排队的会接着装。
77
- - 面板比对走 npm 官方 registry,安装走你本机 pnpm 配置的源(如 npmmirror 镜像);镜像尚未同步的新版本会出现「面板说有新版、装时报找不到版本」,稍后重试即可。
78
- - 会话正在用「**自动审查**」(Auto review)访问模式时,更新面板顶部会出现一条琥珀色提醒:该模式下装/更新插件有时会失败、要重启客户端才能恢复;而且它对每次工具调用会先审查一遍,**审查服务不可用或限流时这次调用会被直接拒绝、工具体不执行**(`503` / `429 请求过于频繁`),表现为助手突然什么都做不了。按提醒把该会话切成「工作区内修改」、装完再切回即可。本插件**只提示,不改动你的权限设置**。
79
- - 「本回合改动」补位卡的口径见上文(只含文件工具的改动);它每个回合会向官方接口探一次「官方数据还在吗」,探测结果**只在本次连接内有效**(刷新页面或重连后重新判断)——这是为了防止宿主恢复数据后出现双份卡。
80
- - 「DSH 不符」只在能确认版本时生效:本机 DSH 版本读不到、或新版写的是 `^`/`~` 这类无法判定的范围,就不拦(宁可漏拦,不误伤正常更新)。
81
- - 与启动器 dsh-web-shell 的分工:界面增强已由本插件接管;dsh-web-shell 的「检查更新」按钮只负责 **dsh 本体**的比对与升级提示。
82
- - 窗口记忆的归位发生在窗口显示后约 0.2~1 秒内,会有一帧跳变(官方客户端在插件加载之前就把窗口显示出来了,没法再早);窗口最小化不会中断记忆。
83
- - 个别插件(如社区插件管理页扩展)自带单独的「检查更新」入口,与本插件的检查互不关联,结果可能不同。
84
- - **360 提示「PowerShell 执行攻击命令」是误报**:桌面端的窗口记忆需要在 dsh 进程外跑一个隐藏的 PowerShell 小助手,360 对「非系统程序创建 powershell.exe」一律按高危拦截,选「允许」即可,功能不受影响。这不是本插件独有的问题 —— dsh 官方桌面版每次启动自己也会创建隐藏 PowerShell(采集系统信息、提取图标),所以关掉窗口记忆也消不掉这个弹窗。
85
-
86
- ## 本人常用插件(可选)
87
-
88
- > 本插件不会自动安装任何其他插件,插件也不属于必装项——不装同样能正常使用上述全部功能。
89
-
90
- 浏览器端操作:
91
-
92
- ```sh
93
- # 安装
94
- dsh plugin --profile web add <PluginName>
95
-
96
- # 卸载
97
- dsh plugin --profile web remove <PluginName>
98
-
99
- # 查看
100
- dsh --profile web --dump-config | findstr /i <PluginName子串>
101
- ```
102
-
103
- 桌面客户端:PATH 上的 `dsh` 装不了(桌面 profile 被保留给客户端),但客户端自带的那份 CLI 可以 —— 把上面的 `dsh plugin --profile web` 换成:
104
-
105
- ```sh
106
- "<安装目录>\resources\runtime\cli\bin\dsh.cmd" plugin --profile desktop add <PluginName>
107
- ```
108
-
109
- 也可以直接在客户端「插件管理」中进行安装、卸载和查看。
110
-
111
- 常用插件(web 与桌面端都能用):
112
-
113
- ```sh
114
- # @changfenhuang/dsh-genui:生成式消息回复
115
- dsh plugin --profile web add @changfenhuang/dsh-genui
116
-
117
- # @linxin666/dsh-session-archive:会话归档与批量清理
118
- dsh plugin --profile web add @linxin666/dsh-session-archive
119
-
120
- # @liustack/modsearch:联网搜索
121
- dsh plugin --profile web add @liustack/modsearch
122
-
123
- # @michengai/dsh-skills-manager:技能加载与管理
124
- dsh plugin --profile web add @michengai/dsh-skills-manager
125
-
126
- # @nimoxie/dsh-model-organizer:模型显示管理
127
- dsh plugin --profile web add @nimoxie/dsh-model-organizer
128
-
129
- # @nimoxie/dsh-ui-tweaks:界面优化调整
130
- dsh plugin --profile web add @nimoxie/dsh-ui-tweaks
131
-
132
- # cc-safety-net:危险命令与密钥防护
133
- dsh plugin --profile web add cc-safety-net
134
-
135
- # dsh-context:上下文管理
136
- dsh plugin --profile web add dsh-context
137
-
138
- # dsh-cost-meter:会话费用统计
139
- dsh plugin --profile web add dsh-cost-meter
140
-
141
- # dsh-ego-browser:模拟浏览器点击
142
- dsh plugin --profile web add dsh-ego-browser
143
-
144
- # dsh-ops:bash / PowerShell 7 与 Rust 高性能工具
145
- dsh plugin --profile web add dsh-ops
146
-
147
- # dsh-whale-widget:右下角小鲸鱼挂件
148
- dsh plugin --profile web add dsh-whale-widget
149
- ```
150
-
151
- ## 许可
152
-
153
- MIT
154
-
155
- ---
156
-
157
- 想自己改这个插件、或者想了解它在内部怎么实现的,见 [DEVELOPMENT.md](./DEVELOPMENT.md)。
1
+ # dsh-ui-tweaks
2
+
3
+ 给 DSH(DeepSeek Harness)的 Web UI 的一批界面微调:装上即生效,无需配置。
4
+
5
+ 官方界面有几处用得难受的地方:宽表格会撑出对话区右沿、滚动条贴在屏幕最右端要横跨半屏去够、Windows 关闭「动画效果」时前端动画被系统设置一并关掉、会话释放后回合尾的改动卡会消失、插件版本更新只能去插件管理页挨个看。这个插件把它们一次性修掉,另附桌面客户端的窗口记忆。
6
+
7
+ ## 功能
8
+
9
+ **宽表格越界修复**
10
+ - ≥4 列的宽表格不再撑出对话区,收敛回正文列并支持横向滚动。
11
+
12
+ **对话区左侧滚动条**
13
+ - 在右侧宽度调整条的左边放一条自绘滚动条:拖拽、点轨道翻页、滚轮手感与原生一致,主题跟随明暗,只在会话页出现。
14
+
15
+ **回合尾改动卡**
16
+ - 官方「本回合改动」卡在会话释放后(切走会话、重启客户端、重开旧会话)原本会消失;本插件用会话日志里的文件改动数据补上,卡片仍由**官方组件原样渲染**——卡头、统计、4 行折叠、hover 预览、右侧「改动审查」都与活会话里一致。
17
+ - 官方本来就不会画的两种情形(关着「显示编码工具视图」、该回合没有官方改动记录)才由插件画一张同款,两种情形都不会与官方卡重复。
18
+ - 口径:只含**文件工具**(写/改文件)造成的改动;数字按回合首末的**净变化**计。
19
+
20
+ **动画修复**
21
+ - Windows 关闭「动画效果」时,清除因此失效的界面动画;web 与桌面客户端都生效。
22
+
23
+ **插件更新检查**
24
+ - 插件管理页「已安装」标题行右侧多一组按钮:检查更新、逐个更新、全部更新与取消(不检查 dsh 本体与官方 `@deepseek-ai` 插件)。
25
+ - 未过 pnpm 发布冷静期的新版本标「冷静期中」并给出可更新时间,到点自动恢复;确需立刻安装可在详情里走「强制更新」。声明了更高 DSH 版本的标「DSH 不符」。两者默认都不给装。
26
+ - 更新成功的插件会在顶部提示「重启客户端后生效」;「立即重启」会先告诉你有没有会话在跑,**任何情况都要你点确认**才会执行。
27
+ - 面板与弹窗支持纯键盘操作(Tab / 回车 / 空格 / Esc),焦点环与官方控件一致。
28
+
29
+ **窗口记忆(仅桌面客户端)**
30
+ - 记住上次的窗口大小、位置与最大化状态,下次启动自动还原;不修改官方任何文件,卸载即恢复。
31
+ - 状态存在 profile 的 `ui-tweaks/window-state.json`,删掉即重置。
32
+
33
+ ## 安装
34
+
35
+ 浏览器版(`web`):
36
+
37
+ ```sh
38
+ dsh plugin --profile web add @nimoxie/dsh-ui-tweaks
39
+ ```
40
+
41
+ 装完重启服务(关掉再 `dsh web`)。
42
+
43
+ 桌面客户端:桌面 profile **保留给客户端**,PATH 上那个 `dsh`(npm 全局装的)会被拒。但客户端**自带的那份 CLI 可以** —— 它就在安装目录里,和「插件管理」页走的是同一套实现:
44
+
45
+ ```sh
46
+ # Windows 桌面端;<安装目录> 形如 E:\tools\DeepSeek Harness
47
+ "<安装目录>\resources\runtime\cli\bin\dsh.cmd" plugin --profile desktop add @nimoxie/dsh-ui-tweaks
48
+ ```
49
+
50
+ 不想敲命令,也可以照旧在客户端「插件管理」页添加包名 `@nimoxie/dsh-ui-tweaks`,重启客户端生效。
51
+
52
+ 卸载(CLI 可管理的 `web` 环境):
53
+
54
+ ```sh
55
+ dsh plugin --profile web remove @nimoxie/dsh-ui-tweaks
56
+ ```
57
+
58
+ 别人也可以从 GitHub 或本地目录装(开发用):
59
+
60
+ ```sh
61
+ dsh plugin --profile web add github:NimoXie15/dsh-ui-tweaks
62
+ dsh plugin --profile web add link:/absolute/path/to/dsh-ui-tweaks
63
+ ```
64
+
65
+ > **要求**:dsh `>= 0.2.0-rc.1`(需要 `remote.pluginManager` / `remote.pluginInventory` 接口)。
66
+ >
67
+ > 升级插件后如果界面没变化,按 **Ctrl+Shift+R** 强刷一次(浏览器可能还在用缓存的旧版本)。
68
+
69
+ ## 已知限制
70
+
71
+ - 非 npm 来源的插件没有可比的 registry 版本,直接跳过比对:`link:` / `file:` 本地路径标「本地链接」,`git:` / `github:` / `http` 直装标「Git 直装」(例:`github:Fisfzy/dsh-ego-browser` 装的是仓库源码,与 npm 上的同名包不是一回事)。
72
+ - 更新一个**已经装过**的插件时会先卸载再装回:DSH 安装接口在有热重载时不允许原地覆盖已装的包。中途失败会自动回滚到原版本,失败原因(pnpm 输出与日志位置)写在该行,点它可重试。
73
+ - 桌面端点「重启 dsh」后 dsh 会先退出,再由客户端弹出官方的「应用无法启动或已意外停止」对话框,**在那里点「重启」才真正拉起来**(也可手动退出后重开)。
74
+ - 取消只作用于你点的那一项,后续排队项会继续装;面板比对走 npm 官方 registry,安装走你本机 pnpm 配置的源(如 npmmirror 镜像),镜像尚未同步的新版本会出现「面板说有新版、装时报找不到版本」,稍后重试即可。
75
+ - 「本回合改动」卡只含文件工具的改动,且按官方净变化口径计数;「官方那侧会不会画」的判断结果**只在本次连接内有效**(刷新页面或重连后重新判断),用于避免宿主恢复数据后出现双份卡。
76
+ - 「DSH 不符」只在能确认版本时生效:本机 DSH 版本读不到、或新版写的是 `^` / `~` 这类无法判定的范围,就不拦(宁可漏拦,不误伤正常更新)。
77
+ - 会话在用「自动审查」时,更新面板顶部会有琥珀色提醒:该模式下装/更新插件可能失败,工具调用也可能被审查拦掉(`503` / `429`)。按提醒切成「工作区内修改」,装完再切回即可。本插件**只提示,不改动你的权限设置**。
78
+ - 与启动器 dsh-web-shell 的分工:界面增强已由本插件接管;dsh-web-shell 的「检查更新」按钮只负责 **dsh 本体**的比对与升级提示。
79
+ - 窗口记忆的归位发生在窗口显示后约 0.2~1 秒内,会有一帧跳变(官方客户端在插件加载之前就把窗口显示出来了);窗口最小化不会中断记忆。
80
+ - 个别插件(如社区插件管理页扩展)自带单独的「检查更新」入口,与本插件的检查互不关联,结果可能不同。
81
+ - **360 提示「PowerShell 执行攻击命令」是误报**:桌面端的窗口记忆需要在 dsh 进程外跑一个隐藏的 PowerShell 小助手,360 对「非系统程序创建 powershell.exe」一律按高危拦截,选「允许」即可。dsh 官方桌面版每次启动自己也会创建隐藏 PowerShell,所以关掉窗口记忆也消不掉这个弹窗。
82
+
83
+ ## 本人常用插件(可选)
84
+
85
+ > 本插件不会自动安装任何其他插件,插件也不属于必装项——不装同样能正常使用上述全部功能。
86
+
87
+ ```sh
88
+ # 浏览器版
89
+ dsh plugin --profile web add <PluginName>
90
+ dsh plugin --profile web remove <PluginName>
91
+ dsh --profile web --dump-config | findstr /i <PluginName子串> # 查看
92
+
93
+ # 桌面客户端(PATH 上的 dsh 装不了,用客户端自带的那份)
94
+ "<安装目录>\resources\runtime\cli\bin\dsh.cmd" plugin --profile desktop add <PluginName>
95
+ ```
96
+
97
+ 也可以直接在客户端「插件管理」中安装、卸载和查看。常用插件(web 与桌面端都能用):
98
+
99
+ | 插件 | 用途 |
100
+ | --- | --- |
101
+ | `@changfenhuang/dsh-genui` | 生成式消息回复 |
102
+ | `@linxin666/dsh-session-archive` | 会话归档与批量清理 |
103
+ | `@liustack/modsearch` | 联网搜索 |
104
+ | `@michengai/dsh-skills-manager` | 技能加载与管理 |
105
+ | `@nimoxie/dsh-model-organizer` | 模型显示管理 |
106
+ | `@nimoxie/dsh-ui-tweaks` | 界面优化调整(本插件) |
107
+ | `cc-safety-net` | 危险命令与密钥防护 |
108
+ | `dsh-context` | 上下文管理 |
109
+ | `dsh-cost-meter` | 会话费用统计 |
110
+ | `dsh-ego-browser` | 模拟浏览器点击 |
111
+ | `dsh-ops` | bash / PowerShell 7 与 Rust 高性能工具 |
112
+ | `dsh-whale-widget` | 右下角小鲸鱼挂件 |
113
+
114
+ ## 许可
115
+
116
+ MIT
117
+
118
+ ---
119
+
120
+ 想自己改这个插件、或者想了解它在内部怎么实现的,见 [DEVELOPMENT.md](./DEVELOPMENT.md)。
package/cordis.patch.yml CHANGED
@@ -1,7 +1,7 @@
1
- # dsh-ui-tweaks bundle patch: one host row over the web profile.
2
- # The row name resolves from the profile's own node_modules where
3
- # `dsh plugin --profile web add <path>` installed this package.
4
- # Scoped 包名的 name 必须写全(同 @linxin666 系插件),loader 按它解析 node_modules。
5
- - insert:
6
- - id: ui-tweaks
7
- name: '@nimoxie/dsh-ui-tweaks'
1
+ # dsh-ui-tweaks bundle patch: one host row over the web profile.
2
+ # The row name resolves from the profile's own node_modules where
3
+ # `dsh plugin --profile web add <path>` installed this package.
4
+ # Scoped 包名的 name 必须写全(同 @linxin666 系插件),loader 按它解析 node_modules。
5
+ - insert:
6
+ - id: ui-tweaks
7
+ name: '@nimoxie/dsh-ui-tweaks'