dsh-input-assistant 0.1.3 → 0.1.4

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/LICENSE +21 -21
  3. package/README.en.md +100 -0
  4. package/README.md +215 -184
  5. package/cordis.patch.yml +3 -3
  6. package/docs/CHANGELOG-0.1.2.md +102 -102
  7. package/docs/evaluation.md +111 -111
  8. package/docs/images/dark.png +0 -0
  9. package/docs/images/light.png +0 -0
  10. package/docs/images/optimize.png +0 -0
  11. package/docs/references.md +39 -39
  12. package/docs/smoke-comparison.md +37 -37
  13. package/docs/validation.md +180 -100
  14. package/lib/browser/components.d.ts +1 -1
  15. package/lib/browser/controller.d.ts +47 -4
  16. package/lib/browser/dom.d.ts +1 -1
  17. package/lib/browser/index.d.ts +1 -1
  18. package/lib/browser/public.d.ts +2 -2
  19. package/lib/browser/runtime.d.ts +4 -2
  20. package/lib/browser/settings.d.ts +1 -1
  21. package/lib/browser/styles.d.ts +1 -1
  22. package/lib/client.js +1164 -222
  23. package/lib/client.meta.json +40 -40
  24. package/lib/core/config.d.ts +1 -1
  25. package/lib/core/context.d.ts +1 -1
  26. package/lib/core/generation.d.ts +2 -2
  27. package/lib/core/index.d.ts +9 -8
  28. package/lib/core/models.d.ts +15 -0
  29. package/lib/core/protection.d.ts +3 -4
  30. package/lib/core/scheduler.d.ts +1 -1
  31. package/lib/core/snapshot.d.ts +1 -1
  32. package/lib/core/types.d.ts +11 -0
  33. package/lib/core.js +280 -53
  34. package/lib/core.js.map +2 -2
  35. package/lib/host/rpc.d.ts +2 -0
  36. package/lib/host/runtime.d.ts +5 -3
  37. package/lib/host/storage.d.ts +11 -3
  38. package/lib/host/transcript.d.ts +1 -1
  39. package/lib/index.d.ts +5 -3
  40. package/lib/index.js +451 -156
  41. package/lib/index.js.map +4 -4
  42. package/package.json +10 -3
@@ -1,100 +1,180 @@
1
- # 验收记录
2
-
3
- 此文件记录实际执行证据,不把发布接口核对、模拟模型测试或参考答案当作真实模型验收。
4
-
5
- 记录日期:2026 年 10 月 22 日(Asia/Shanghai)。下表记录开发机上的实际执行证据;其中的 `.test-runtime/` 是本仓库的临时证据目录(已被 `.gitignore` 排除),公开仓库不包含这些文件,列出的路径用于说明证据来源与生成方式,读者可在本地运行对应命令复现。
6
-
7
- `0.1.2` 的修正与新增证据见文末「0.1.2 修正复验」一节;`0.1.1` 时期的历史记录按原样保留,其中的测试计数(105)和版本号不再代表当前产物。
8
-
9
- ## 当前状态
10
-
11
- | 检查 | 状态 | 证据或待办 |
12
- |---|---|---|
13
- | DSH 目标版本发布契约 | 已核对 | `0.2.1-rc.2` 官方 conversation、LLM 等发布包 |
14
- | 60 条固定合成评测集 | 结构已校验,尚未经独立人工标注 | 由开发助手编写;optimize/next/complete 各 20 条,next、complete 各 8 条弃权案例 |
15
- | 离线评分空结果处理 | 已执行 | `evaluation/status.json`:0/60,`not_evaluated`,0 次模型调用 |
16
- | 评测脚本黑盒测试 | 8/8 通过 | `node node_modules/vitest/vitest.mjs run tests/evaluation.test.ts` |
17
- | 实际提示词导出与后处理合同 | 已执行 | 60 条调用真实 `lib/core.js` 导出;保护与弃权往返、raw 评分导入通过,0 次模型调用 |
18
- | 自动化测试 | 105/105 通过(`0.1.1` 时期);TypeScript 通过 | 12 个测试文件;含真实 Edge 主题/灰字、设置竞态、取消、存储、评测工具及实际安装包 Loader;命令输出 `pnpm test` 的输出 |
19
- | 实际 `.tgz` 的官方 Loader 加载 | 已通过 | `scripts/verify-package.mjs` 验证实际打包产物;启用、禁用、再启用、卸载及保留显式暂存草稿均已覆盖 |
20
- | 内置 CLI 隔离安装与移除 | 已通过 | `dsh plugin --profile <name> add <tgz>` 的隔离安装记录:隔离 `DSH_HOME` 中安装、配置层解析、remove 后依赖/层/链接清理;0 次模型请求,未改桌面 profile |
21
- | Edge 中真实编辑器输入回归 | 已通过 | `pnpm test:web` 的输出:Microsoft Edge headless、真实 Lexical 与生产 React 控制器;0 次付费模型调用 |
22
- | 完整官方 Web 应用组合回归 | 未单独标记通过 | 浏览器编辑器夹具通过不等于所有官方 Web 组合与其他插件组合已验证 |
23
- | 官方桌面端安装与升级 | 已通过 | 最终版本 `0.1.1`,内置 CLI 安装;宿主/浏览器文件哈希与构建一致。首次热加载可用;本次升级完全退出并重启 DSH 后才载入新宿主实例 |
24
- | 桌面真实宿主 Gateway 接口 | 已通过 | 最终 `node tests/support/run-desktop-probe.mjs` 生成的报告:加载 `0.1.1`、认证 Gateway 状态/草稿 CRUD/清理;0 次生成请求 |
25
- | 官方桌面端原生输入回归 | 已列场景通过,未宣称全覆盖 | `node tests/support/run-desktop-probe.mjs` 的人工观察记录:中文/emoji、优化、diff、还原、暂存、追加、Tab 采纳及相关一次撤销通过;IME 与附件/引用等组合仍未全部手测 |
26
- | DSH 设置专属页与模块开关 | 原生访问和保存通过 | 账号菜单 → 设置 → 输入助手;四开关、三档强度及高级设置可见,实际保存优化开关/深度强度后恢复标准配置;高级参数边界与失败由自动化覆盖 |
27
- | 深色主题、裁剪与设置竞态修复 | 已通过 | 原生菜单颜色与顶部显示复验;真实 Edge 测试覆盖灰字/候选定位,受控回归覆盖失败不重试、旧状态不覆盖设置、关闭期间暂存不清空 |
28
- | 原生灰字与 Tab | 已通过,0 付费请求 | 临时本地 adapter 精确返回固定后缀;正式插件与官方编辑器显示灰字、Tab 采纳且不发送、Ctrl+Z 一次撤销。`node tests/support/run-desktop-completion-fixture.mjs` 生成的完成标记 确认路由与设置已清理 |
29
- | 原生测试暂存精确清理 | 已通过 | `node tests/support/run-desktop-model-probe.mjs` 的清理记录:删除 1 条精确匹配测试稿,剩余 0 条,未碰其他暂存 |
30
- | 真实模型小样本对照 | 6 次已完成,非完整质量验收 | 输入 2,706 + 输出 101 = 2,807 tokens;每种操作仅 1 个案例、各候选/基线一次。另一次桌面优化用量未知;见 `docs/smoke-comparison.md` |
31
- | 60 条完整真实模型质量评测 | 未执行 | `evaluation/status.json` 仍为 0/60、`not_evaluated`;不能报告整套准确率或优于竞品 |
32
-
33
- 发行包的自动预测与续写默认均开启;本次在当前机器安装时已将两个开关关闭,以避免测试期间顺带发生模型调用。设置可以由用户在插件菜单中显式开启。
34
-
35
- 观察记录中的 `themeFixReverified` 和 `cleanupCompleted` 均已为 true。临时 adapter、探针、测试暂存与自有 quiet 配置块已清理;输入框恢复原先空稿,自动两开关的持久设置保持关闭,人工优化与暂存开启、强度为标准。没有开启或更改 DSH 的开发者工具偏好。
36
-
37
- 本机包管理器曾复用同版本同路径的旧 `.tgz`,`--force` 也未更新实际文件。最终使用新的 `0.1.1` 文件名安装,并比对 `lib/index.js`、`lib/client.js` 哈希。升级后仍需完全退出并重新打开 DSH,不能把文件已更新等同于旧宿主实例已切换。
38
-
39
- 实现者在完成实际执行后更新本表并注明命令、日期和结果;失败与未执行应保留。
40
-
41
- ## 已执行的浏览器与桌面证据
42
-
43
- Edge 夹具使用生产输入助手界面和控制器、真实 Lexical 编辑器,确认:优化回填后原生一次撤销恢复原文;改动查看和显式还原正常;暂存先保存再清空、仅经用户操作恢复;测量灰字后 Tab 插入正确。它使用测试模型输出,没有付费模型调用,记录中 `realDshDesktop:false`。
44
-
45
- 桌面探针运行在真正的 DeepSeek Harness 可执行进程中,核对加载服务确属已安装的 `dsh-input-assistant@0.1.0`。通过认证 Gateway 调用 `settings/get`、`status`、`drafts/list`、`drafts/save`、`drafts/delete` 和 `drafts/clear`,完成草稿持久化往返、单条删除、按会话隔离及清空。报告 `generatedRequests:0`,没有写入会话事件;探针结束后清除了测试草稿并拆除探针连接。该证据验证了真实宿主接线,尚不能替代生产编辑器的完整原生交互验收。
46
-
47
- 原生桌面操作使用可见的官方生产界面,没有向编辑器注入脚本:输入一条含中文和 emoji 的合成草稿,暂存后清空,一次 Ctrl+Z 精确恢复;显式追加暂存文字后,一次 Ctrl+Z 撤回追加;通过真实按钮调用辅助模型并回填,打开 diff,再还原原文。一次 Ctrl+Z 撤销还原,下一次 Ctrl+Z 撤销优化。验证完成后恢复起初的空草稿,并通过精确内容匹配清除测试暂存,保留用户其他数据。这些覆盖了已列出的操作;中文字符输入不等于已验证中文 IME 候选组合。
48
-
49
- 小样本使用 `deepseek-account / deepseek-flash`,6 次均记录为最低推理档 `off`、temperature 0、256 输出 token 上限。公开基线只是提示词研究适配,没有运行其完整插件。fishcg 的提取适配有一处语气提示偏差,报告保留了该限制;样例接近部分参考提示词示例,另有明显样本偏差。不能把这些结果解释为同类领先,完整 60 条结果与人工语义评分继续保持 `not_evaluated`。[完整小样本说明](smoke-comparison.md)
50
-
51
- ## 工程验收清单
52
-
53
- - [x] 对实际分发 `.tgz` 使用官方 Loader 检查配置层及入口;同包安装到官方桌面 profile 并热加载。
54
- - [x] Loader 生命周期及 CLI 隔离安装、配置解析和移除通过;桌面热加载和宿主接口另有实际记录。
55
- - [ ] 整稿、选区、Tab 采纳、还原、暂存清空、追加及替换均只产生一次可撤销编辑。
56
- - [ ] 中英文、emoji、多行文本的选区与范围准确。
57
- - [ ] 输入、发送、新回合、切模型、切会话、断线、卸载后的迟到结果不会改写新稿。
58
- - [ ] 中文输入法、`/` 与 `@` 原生菜单、Tab 焦点移动和已消费键事件互不抢占。
59
- - [ ] 缩放、滚动、换行、输入框重挂后灰字定位正确;无法定位时隐藏。
60
- - [ ] 普通附件原样保留;引用标签不被静默移除;不支持的范围有解释。
61
- - [ ] 草稿保存失败不清空,三条上限、删除、重启恢复及会话隔离有效。
62
- - [ ] 缺模型、超时、空输出、损坏保护映射及取消均保留原稿。
63
- - [ ] 官方桌面端使用同一 `.tgz` 单独验证,不能用 Web 通过替代。
64
-
65
- ## 质量验收清单
66
-
67
- - [ ] 保留准确的模型、提供商、推理档、预算和候选/基线版本。
68
- - [ ] 60 条案例均有实际生成结果,失败项明确记录或重跑。
69
- - [ ] 44 条预期文字结果均完成人工语义评审。
70
- - [ ] 对照报告意图符合、无根据新增要求、弃权与延迟,而非只报告采纳率。
71
- - [ ] 原文保护完整;重大约束丢失和新增实质任务或授权为零。
72
-
73
- 完整流程见 [质量评测说明](evaluation.md)。
74
-
75
- ## 0.1.2 修正复验
76
-
77
- 记录日期:2026 年 10 月 23 日(Asia/Shanghai)。逐条复现与修复说明见 [0.1.2 修正记录](CHANGELOG-0.1.2.md)。
78
-
79
- | 检查 | 状态 | 证据 |
80
- |---|---|---|
81
- | TypeScript | 通过 | `node node_modules/typescript/bin/tsc --noEmit`,无输出 |
82
- | 自动化测试 | **121/121 通过** | 12 个测试文件;`node node_modules/vitest/vitest.mjs run` |
83
- | 实际 `.tgz` 的官方 Loader 加载 | 通过 | `node scripts/verify-package.mjs dist/dsh-input-assistant-0.1.2.tgz` |
84
- | 真实 Edge 编辑器回归 | 通过 | `node scripts/smoke-web.mjs`:4 项断言,0 次付费模型调用 |
85
- | 评测集结构 | 通过 | `node scripts/evaluate.mjs validate`:60 例,16 条弃权 |
86
- | 构建可复现 | 通过 | 重新 `scripts/build.mjs` 后 `lib/` 与打包产物逐字节一致 |
87
- | 归档校验 | 通过 | `verify-archive.mjs`:32,5xx 个普通文件全部通过大小与 SHA256 |
88
- | 恢复脚本幂等 | 通过 | 第二次运行 `restore-windows.mjs` 报告 `restoredDirectories: 0`、`unchangedLinks: 2755`、`completed: true` |
89
- | 恢复后可构建可测试 | 通过 | 从外层 ZIP 干净解压 → 随包 Node → `restore-windows` → `tsc` → 121 条测试全部通过 |
90
-
91
- 本次修正**没有**新增真实模型调用。以下状态与 `0.1.1` 一致,不因本次修正而改变:
92
-
93
- - 60 条固定合成质量集仍为 `not_evaluated`(0/60),未做人工语义标注。
94
- - 6 次小样本对照的结论不变,仍不能据此排名或宣称领先。
95
- - 中文 IME 候选组合、附件/引用组合、完整官方 Web 组合、其他插件组合、非 Windows x64 平台仍未验证。
96
- - 本次未在官方桌面端重新做原生手测;桌面端证据仍来自 `0.1.1` 时期,不能写成 `0.1.2` 已在新设备验收。
97
-
98
- ### 关于恢复脚本的更正
99
-
100
- 开发过程中曾把"恢复脚本在 `originallyMissing` 链接处失败"记为 `0.1.1` 的阻断性缺陷。复核确认该现象由**开发会话沙箱对工作区盘符的文件系统重定向**引起(junction 被写成 `\??\Global\…`,同一进程无法跟随),不属于归档或脚本缺陷:在普通用户路径(C 盘临时目录、随包 Node 24.19.0)上,`0.1.1` 原始归档的完整流程可正常完成,105 条测试全部通过。`0.1.2` 对恢复脚本的改动因此是**健壮性改进**(幂等、`--repair`、缺目标跳过、链接识别、创建兜底),不是对既有缺陷的修复。
1
+ # 验收记录
2
+
3
+ 此文件记录实际执行证据,不把发布接口核对、模拟模型测试或参考答案当作真实模型验收。
4
+
5
+ ## 2026-11-10:0.1.4 发布准备复验(未发布)
6
+
7
+ 按照版本整理要求,将下方内部 0.1.6 的代码以 0.1.4 作为当前待发布版本;下方记录的内部版本号与哈希保留为历史事实。桌面上用户提供的原始同名 0.1.4 归档与本次重新构建的包内容不同。
8
+
9
+ Windows x64、Node 24.22.1 的完整工程测试为 **203/203**,无失败或跳过,包含正式包 Loader 和 Edge 主题。实际 0.1.4 包的 Edge 浏览器回归 **14/14**,使用真实归档 client/core、React、Lexical 和宿主主题,RPC 与模型输出为本地替身。类型检查、严格包消费者和两个负向控制通过;中英文 README 的本地链接均已核对。无需真实模型调用,模型质量、原生操作系统 IME、完整桌面及其他插件组合仍未验收。工作流已配置,远端 CI 尚未运行。
10
+
11
+ 记录位于本地忽略目录 `.test-runtime/verification-release-014-tests.txt`、`verification-release-014-packaged-web.txt` 与 `packaged-0.1.4/result.json`。这些文件不随安装包发布。`dist/` 仅保留本次构建的 0.1.4 归档。
12
+
13
+ ## 2026-11-10:内部 0.1.6 定制版整合与复验(历史记录,未发布)
14
+
15
+ 本轮以用户提供的 `dsh-input-assistant-0.1.4.tgz` 为审阅对象,其 SHA256 为 `fc89fb5bd8508c08c1d2c68f8bf66ebc5a43d6d3d03e62cec2ebd0edbb6983f8`。该包与此前本地构建的同版本不同;先隔离复现,再将其新增功能整合到已修复的本地源码,保留 core/host/browser 分层,形成 0.1.6。原始归档未修改。
16
+
17
+ | 检查 | 本轮实际结果 |
18
+ |---|---|
19
+ | 全量工程测试 | Windows x64、Node 24.22.1:13 个文件、203 个测试通过,0 失败、0 跳过;含正式 `.tgz` 官方 Loader 与真实 Edge 主题测试 |
20
+ | 最低 Node 版本 | 便携 Node 22.19.0:12 个文件、198 个非 Edge 测试通过;类型检查、严格安装包消费者通过;系统 Node 未修改 |
21
+ | 源码浏览器回归 | 真实 Edge、React、Lexical、生产组件及宿主主题,15 个场景通过,正常退出 |
22
+ | 安装包浏览器回归 | `pnpm test:package:web` 直接服务归档中未经改写的 `client.js`、`core.js`,夹具不得导入 `src/`;14 个场景通过,0 浏览器异常 |
23
+ | 安装包与类型 | 实际包宿主导入、浏览器 factory、独立消费者解析通过;core 和主入口在 Bundler/NodeNext/Node16 下均 strict、skipLibCheck=false;移除映射或声明的两个负向控制均确实失败 |
24
+ | 正式宿主链路 | 官方 Loader/Gateway 验证配置、固定辅助模型实际 dispatch、主会话路由保持、卸载重载保留设置;首次 storage.open 失败恢复及跨客户端设置取消另有回归 |
25
+ | 新功能与并发 | 三档详略度、三种待保存预设、独立预测、手动重试、复制、取消清空、配置与路由变更隔离均通过;删除与撤销不出现误导的取消入口 |
26
+ | 独立核心复验 | 直接读取实际归档:8 组检查通过,含三档共 33 组显式长度边界、5 种清理后空输出、18 组异常代理字符、路径引号与多行/前导空白 |
27
+ | 构建及 CI | 全部 `lib/` 产物重复构建哈希一致;CI/发布 YAML 解析通过;Windows CI 增加实际包浏览器回归及全部构建产物比较;未运行远端 CI |
28
+ | 质量评测工具 | 60 条结构校验及当前提示词导出通过;真实模型调用 0 次;完整模型效果集仍为 `not_evaluated` |
29
+
30
+ 安装包浏览器场景覆盖预览/明确采纳/一次原生撤销、原文路径引号、键盘预览焦点及失效回收、编辑中断后的迟到候选隔离、取消清空、失败后明确重试、精确草稿复制、限流至少等待返回期限且仅重试一次、合成 IME 事件、后台抑制、Esc 与菜单焦点、详尽多行及超限拒绝、预设保存与 601ms 精确数值、辅助模型重读、窄屏深色菜单滚动。
31
+
32
+ 本轮还修正了两个真实浏览器问题:`transition: all` 延迟预览可见性而导致键盘聚焦失败;隐藏滑块的步长校验阻止合法的精确整数保存。最终界面截图已更新。发行包包含当前更新日志和 README 引用的截图。
33
+
34
+ 本地证据位于 `.test-runtime/verification-016-tests.txt`、`verification-016-node22-tests.txt`、`verification-016-node22-package.txt`、`verification-016-web.txt`、`verification-016-packaged-web.txt`、`verification-016-independent-core.json` 及 `packaged-0.1.6/result.json`。最终归档 SHA256 和全部构建产物校验记录另存 `verification-016-final.json`,避免将归档自身哈希嵌入归档造成循环。运行证据不随发行包上传;可用仓库脚本复现。
35
+
36
+ 浏览器测试的 RPC 和模型输出使用本地替身,复制测试验证 Clipboard API 的传入文本;实际宿主接线由独立的 Loader/Gateway 测试承担。本轮未改实时 DSH、未提交或发布。原生操作系统 IME、完整桌面组合、其他插件组合和真实模型语义效果未验证,不能由以上通过项推定。
37
+
38
+ ## 2026-11-09:0.1.5 二次修复及功能验证(未发布)
39
+
40
+ 保留 core/host/browser 分层,本节保留 0.1.5 当时的本地验证;上方为内部 0.1.6 的历史验证,后面的 0.1.4 与 2026-10 记录同样为历史证据。
41
+
42
+ | 检查 | 本轮实际结果 |
43
+ |---|---|
44
+ | 全量工程测试 | Node 24.22.1:13 个文件、177 个测试通过,0 失败、0 跳过,含实际 0.1.5 安装包的官方 Loader 与真实 Edge 主题 |
45
+ | 最低 Node 版本 | 官方便携 Node 22.19.0(Windows x64,官方 SHA256 已核对):12 个文件、172 个非 Edge 主题测试通过;类型检查与严格包消费者通过。系统 Node 未变更 |
46
+ | 真实 Edge 冒烟 | 11 项通过并正常退出,包含预览/采纳/原生撤销、Esc、暂存、Tab、菜单焦点、手动失败后重试、草稿复制、预览自动失效焦点、页面可见性和辅助模型选择 |
47
+ | 辅助模型目录 | 无会话只读加载;部分目录失败与不可用能力降级为手填;保留现有选择;实际 Edge 验证选择辅助模型不会改变主会话路由或触发生成 |
48
+ | 手动建议 | 自动功能关闭仍可明确请求、失败/弃权可重试,限流仅延后一次且不形成自动循环;忙碌、IME、附件/引用、过期快照及后台状态限制仍保留 |
49
+ | 撤销所有权 | 删除完成或尚在回包时切换会话仍能找回原 ID/时间;原 10 秒截止不延长;容量失败目标独立保留;二次冲突不静默覆盖两批备份 |
50
+ | 文本完整性 | 中文紧贴文件名/dotfile/路径的精确保护与篡改拒绝;Unicode 码点预算在核心、RPC 和暂存一致;编辑器偏移仍使用宿主单位 |
51
+ | 打包与类型 | 实际归档宿主导入和浏览器 factory 通过;strict、skipLibCheck=false 下 Bundler/NodeNext/Node16 ESM core 消费者全部通过 |
52
+ | CI 配置 | Linux Node 22.19/24.19 矩阵,版本 tag 仅经发布流程调用完整 CI;YAML 与依赖检查通过,本轮未执行远端 CI 或发布 |
53
+ | 评测工具 | 60 条结构校验及当前提示词导出通过,0 次真实模型调用 |
54
+
55
+ 保护扫描的 5 次预热、50 次重复本机测量:连续中文 4k/8k/16k/32k 平均约 0.187/0.333/0.660/1.289ms,保留线性增长趋势。这是合成输入测量,不能作为用户平均延迟或模型质量证据。
56
+
57
+ 本轮本地记录:`.test-runtime/verification-015-tests.txt`、`verification-015-node22-tests.txt`、`verification-015-web.txt`、`015-protection-benchmark.json` 和 `web/result.json`。这些记录位于忽略的运行目录,不随发行包上传。
58
+
59
+ 本轮未改实时 DSH 配置、未调用付费模型。60 条完整模型质量集仍为 `not_evaluated`;原生 IME 和完整其他插件组合仍需单独验证。中文文件名与紧贴自然语言存在歧义时,使用引号、反引号或手动锁定。
60
+
61
+ ## 2026-11-09:0.1.4 源码修复复验(未发布)
62
+
63
+ 本节为 0.1.4 源码修复时的本地验证,后面的 2026-10 记录保留为历史证据。环境为 Windows x64、Node.js 24.22.1、pnpm 11.25.0,使用现有锁文件。
64
+
65
+ | 检查 | 本轮结果 |
66
+ |---|---|
67
+ | 类型、构建与安装包 | `pnpm typecheck`、`pnpm build`、`pnpm pack --pack-destination dist`、`pnpm test:package` 通过;包校验包括实际归档宿主导入与严格 TypeScript core 消费者 |
68
+ | 全套工程测试 | `pnpm test`:12 个文件、153 个测试通过,0 失败、0 跳过;包含真实 `.tgz` 官方 Loader 与 Edge 主题测试 |
69
+ | 真实 Edge 编辑器回归 | `pnpm test:web`:6 项场景通过,覆盖预览保留原稿、明确采纳及原生一次撤销、Esc 放弃、显式还原、暂存恢复、灰字 Tab/Esc 与菜单焦点 |
70
+ | 新增底层回归 | 固定辅助路由保存后实际调用、首次存储打开失败恢复、预测失败/切模型重试、限流到期恢复与真正弃权缓存、路径/URL 保护、旧回包隔离、删除原子撤销 |
71
+ | UI 与设置 | 预览/取消、IME/原生菜单/已消费事件保护、菜单键盘焦点、灰字可访问提示、菜单关闭后的删除撤销、设置加载失败重试均有回归 |
72
+ | 评测工具 | 60 条结构校验和当前提示词导出通过;真实模型请求 0 次 |
73
+ | 发布流程 | YAML 解析及验证依赖检查通过;发布复用完整 CI 产生的同一份包,tag 与版本校验已加入;本轮未执行云端发布 |
74
+
75
+ 主题测试原有清理钩子 10 秒预算在本机不足:诊断时 `browser.close()` 约 14.5 秒。现为明确的 30 秒预算,浏览器关闭异常时仍清理服务器,完整测试正常退出。
76
+
77
+ 保护匹配改为候选扫描。连续中文 4k/8k/16k/32k,在 5 次预热、50 次重复的本机测试中均值约为 0.189/0.345/0.711/1.405ms;此前 8k 单次探针约 5.84s。测量方法与重复次数不同,不据此给出精确加速倍数,也不把合成输入当作真实用户平均延迟。最大长度回归另设宽松时间上限,以捕获秒级同步阻塞。
78
+
79
+ 本地输出在 `.test-runtime/verification-tests.txt`、`.test-runtime/verification-web.txt`、`.test-runtime/protection-benchmark.json` 与 `.test-runtime/web/result.json`。这些临时运行记录不随仓库发布;README 截图使用本轮实际生产组件夹具渲染。
80
+
81
+ 本轮没有修改用户的实时 DSH 实例或使用真实模型。60 条模型质量集仍为 `not_evaluated`;原生中文 IME 候选组合、完整宿主及其他插件组合仍不能仅由本地夹具宣称验证通过。
82
+
83
+ ## 2026-10 历史记录
84
+
85
+ 记录日期:2026 年 10 月 22 日(Asia/Shanghai)。下表记录开发机上的实际执行证据;其中的 `.test-runtime/` 是本仓库的临时证据目录(已被 `.gitignore` 排除),公开仓库不包含这些文件,列出的路径用于说明证据来源与生成方式,读者可在本地运行对应命令复现。
86
+
87
+ `0.1.2` 的修正与新增证据见文末「0.1.2 修正复验」一节;`0.1.1` 时期的历史记录按原样保留,其中的测试计数(105)和版本号不再代表当前产物。
88
+
89
+ ## 当前状态
90
+
91
+ | 检查 | 状态 | 证据或待办 |
92
+ |---|---|---|
93
+ | DSH 目标版本发布契约 | 已核对 | `0.2.1-rc.2` 官方 conversation、LLM 等发布包 |
94
+ | 60 条固定合成评测集 | 结构已校验,尚未经独立人工标注 | 由开发助手编写;optimize/next/complete 各 20 条,next、complete 各 8 条弃权案例 |
95
+ | 离线评分空结果处理 | 已执行 | `evaluation/status.json`:0/60,`not_evaluated`,0 次模型调用 |
96
+ | 评测脚本黑盒测试 | 8/8 通过 | `node node_modules/vitest/vitest.mjs run tests/evaluation.test.ts` |
97
+ | 实际提示词导出与后处理合同 | 已执行 | 60 条调用真实 `lib/core.js` 导出;保护与弃权往返、raw 评分导入通过,0 次模型调用 |
98
+ | 自动化测试 | 105/105 通过(`0.1.1` 时期);TypeScript 通过 | 12 个测试文件;含真实 Edge 主题/灰字、设置竞态、取消、存储、评测工具及实际安装包 Loader;命令输出 `pnpm test` 的输出 |
99
+ | 实际 `.tgz` 的官方 Loader 加载 | 已通过 | `scripts/verify-package.mjs` 验证实际打包产物;启用、禁用、再启用、卸载及保留显式暂存草稿均已覆盖 |
100
+ | 内置 CLI 隔离安装与移除 | 已通过 | `dsh plugin --profile <name> add <tgz>` 的隔离安装记录:隔离 `DSH_HOME` 中安装、配置层解析、remove 后依赖/层/链接清理;0 次模型请求,未改桌面 profile |
101
+ | Edge 中真实编辑器输入回归 | 已通过 | `pnpm test:web` 的输出:Microsoft Edge headless、真实 Lexical 与生产 React 控制器;0 次付费模型调用 |
102
+ | 完整官方 Web 应用组合回归 | 未单独标记通过 | 浏览器编辑器夹具通过不等于所有官方 Web 组合与其他插件组合已验证 |
103
+ | 官方桌面端安装与升级 | 已通过 | 最终版本 `0.1.1`,内置 CLI 安装;宿主/浏览器文件哈希与构建一致。首次热加载可用;本次升级完全退出并重启 DSH 后才载入新宿主实例 |
104
+ | 桌面真实宿主 Gateway 接口 | 已通过 | 最终 `node tests/support/run-desktop-probe.mjs` 生成的报告:加载 `0.1.1`、认证 Gateway 状态/草稿 CRUD/清理;0 次生成请求 |
105
+ | 官方桌面端原生输入回归 | 已列场景通过,未宣称全覆盖 | `node tests/support/run-desktop-probe.mjs` 的人工观察记录:中文/emoji、优化、diff、还原、暂存、追加、Tab 采纳及相关一次撤销通过;IME 与附件/引用等组合仍未全部手测 |
106
+ | DSH 设置专属页与模块开关 | 原生访问和保存通过 | 账号菜单 → 设置 → 输入助手;四开关、三档强度及高级设置可见,实际保存优化开关/深度强度后恢复标准配置;高级参数边界与失败由自动化覆盖 |
107
+ | 深色主题、裁剪与设置竞态修复 | 已通过 | 原生菜单颜色与顶部显示复验;真实 Edge 测试覆盖灰字/候选定位,受控回归覆盖失败不重试、旧状态不覆盖设置、关闭期间暂存不清空 |
108
+ | 原生灰字与 Tab | 已通过,0 付费请求 | 临时本地 adapter 精确返回固定后缀;正式插件与官方编辑器显示灰字、Tab 采纳且不发送、Ctrl+Z 一次撤销。`node tests/support/run-desktop-completion-fixture.mjs` 生成的完成标记 确认路由与设置已清理 |
109
+ | 原生测试暂存精确清理 | 已通过 | `node tests/support/run-desktop-model-probe.mjs` 的清理记录:删除 1 条精确匹配测试稿,剩余 0 条,未碰其他暂存 |
110
+ | 真实模型小样本对照 | 6 次已完成,非完整质量验收 | 输入 2,706 + 输出 101 = 2,807 tokens;每种操作仅 1 个案例、各候选/基线一次。另一次桌面优化用量未知;见 `docs/smoke-comparison.md` |
111
+ | 60 条完整真实模型质量评测 | 未执行 | `evaluation/status.json` 仍为 0/60、`not_evaluated`;不能报告整套准确率或优于竞品 |
112
+
113
+ 发行包的自动预测与续写默认均开启;本次在当前机器安装时已将两个开关关闭,以避免测试期间顺带发生模型调用。设置可以由用户在插件菜单中显式开启。
114
+
115
+ 观察记录中的 `themeFixReverified` 和 `cleanupCompleted` 均已为 true。临时 adapter、探针、测试暂存与自有 quiet 配置块已清理;输入框恢复原先空稿,自动两开关的持久设置保持关闭,人工优化与暂存开启、强度为标准。没有开启或更改 DSH 的开发者工具偏好。
116
+
117
+ 本机包管理器曾复用同版本同路径的旧 `.tgz`,`--force` 也未更新实际文件。最终使用新的 `0.1.1` 文件名安装,并比对 `lib/index.js`、`lib/client.js` 哈希。升级后仍需完全退出并重新打开 DSH,不能把文件已更新等同于旧宿主实例已切换。
118
+
119
+ 实现者在完成实际执行后更新本表并注明命令、日期和结果;失败与未执行应保留。
120
+
121
+ ## 已执行的浏览器与桌面证据
122
+
123
+ Edge 夹具使用生产输入助手界面和控制器、真实 Lexical 编辑器,确认:优化回填后原生一次撤销恢复原文;改动查看和显式还原正常;暂存先保存再清空、仅经用户操作恢复;测量灰字后 Tab 插入正确。它使用测试模型输出,没有付费模型调用,记录中 `realDshDesktop:false`。
124
+
125
+ 桌面探针运行在真正的 DeepSeek Harness 可执行进程中,核对加载服务确属已安装的 `dsh-input-assistant@0.1.0`。通过认证 Gateway 调用 `settings/get`、`status`、`drafts/list`、`drafts/save`、`drafts/delete` 和 `drafts/clear`,完成草稿持久化往返、单条删除、按会话隔离及清空。报告 `generatedRequests:0`,没有写入会话事件;探针结束后清除了测试草稿并拆除探针连接。该证据验证了真实宿主接线,尚不能替代生产编辑器的完整原生交互验收。
126
+
127
+ 原生桌面操作使用可见的官方生产界面,没有向编辑器注入脚本:输入一条含中文和 emoji 的合成草稿,暂存后清空,一次 Ctrl+Z 精确恢复;显式追加暂存文字后,一次 Ctrl+Z 撤回追加;通过真实按钮调用辅助模型并回填,打开 diff,再还原原文。一次 Ctrl+Z 撤销还原,下一次 Ctrl+Z 撤销优化。验证完成后恢复起初的空草稿,并通过精确内容匹配清除测试暂存,保留用户其他数据。这些覆盖了已列出的操作;中文字符输入不等于已验证中文 IME 候选组合。
128
+
129
+ 小样本使用 `deepseek-account / deepseek-flash`,6 次均记录为最低推理档 `off`、temperature 0、256 输出 token 上限。公开基线只是提示词研究适配,没有运行其完整插件。fishcg 的提取适配有一处语气提示偏差,报告保留了该限制;样例接近部分参考提示词示例,另有明显样本偏差。不能把这些结果解释为同类领先,完整 60 条结果与人工语义评分继续保持 `not_evaluated`。[完整小样本说明](smoke-comparison.md)
130
+
131
+ ## 工程验收清单
132
+
133
+ - [x] 对实际分发 `.tgz` 使用官方 Loader 检查配置层及入口;同包安装到官方桌面 profile 并热加载。
134
+ - [x] Loader 生命周期及 CLI 隔离安装、配置解析和移除通过;桌面热加载和宿主接口另有实际记录。
135
+ - [ ] 整稿、选区、Tab 采纳、还原、暂存清空、追加及替换均只产生一次可撤销编辑。
136
+ - [ ] 中英文、emoji、多行文本的选区与范围准确。
137
+ - [ ] 输入、发送、新回合、切模型、切会话、断线、卸载后的迟到结果不会改写新稿。
138
+ - [ ] 中文输入法、`/` 与 `@` 原生菜单、Tab 焦点移动和已消费键事件互不抢占。
139
+ - [ ] 缩放、滚动、换行、输入框重挂后灰字定位正确;无法定位时隐藏。
140
+ - [ ] 普通附件原样保留;引用标签不被静默移除;不支持的范围有解释。
141
+ - [ ] 草稿保存失败不清空,三条上限、删除、重启恢复及会话隔离有效。
142
+ - [ ] 缺模型、超时、空输出、损坏保护映射及取消均保留原稿。
143
+ - [ ] 官方桌面端使用同一 `.tgz` 单独验证,不能用 Web 通过替代。
144
+
145
+ ## 质量验收清单
146
+
147
+ - [ ] 保留准确的模型、提供商、推理档、预算和候选/基线版本。
148
+ - [ ] 60 条案例均有实际生成结果,失败项明确记录或重跑。
149
+ - [ ] 44 条预期文字结果均完成人工语义评审。
150
+ - [ ] 对照报告意图符合、无根据新增要求、弃权与延迟,而非只报告采纳率。
151
+ - [ ] 原文保护完整;重大约束丢失和新增实质任务或授权为零。
152
+
153
+ 完整流程见 [质量评测说明](evaluation.md)。
154
+
155
+ ## 0.1.2 修正复验
156
+
157
+ 记录日期:2026 年 10 月 23 日(Asia/Shanghai)。逐条复现与修复说明见 [0.1.2 修正记录](CHANGELOG-0.1.2.md)。
158
+
159
+ | 检查 | 状态 | 证据 |
160
+ |---|---|---|
161
+ | TypeScript | 通过 | `node node_modules/typescript/bin/tsc --noEmit`,无输出 |
162
+ | 自动化测试 | **121/121 通过** | 12 个测试文件;`node node_modules/vitest/vitest.mjs run` |
163
+ | 实际 `.tgz` 的官方 Loader 加载 | 通过 | `node scripts/verify-package.mjs dist/dsh-input-assistant-0.1.2.tgz` |
164
+ | 真实 Edge 编辑器回归 | 通过 | `node scripts/smoke-web.mjs`:4 项断言,0 次付费模型调用 |
165
+ | 评测集结构 | 通过 | `node scripts/evaluate.mjs validate`:60 例,16 条弃权 |
166
+ | 构建可复现 | 通过 | 重新 `scripts/build.mjs` 后 `lib/` 与打包产物逐字节一致 |
167
+ | 归档校验 | 通过 | `verify-archive.mjs`:32,5xx 个普通文件全部通过大小与 SHA256 |
168
+ | 恢复脚本幂等 | 通过 | 第二次运行 `restore-windows.mjs` 报告 `restoredDirectories: 0`、`unchangedLinks: 2755`、`completed: true` |
169
+ | 恢复后可构建可测试 | 通过 | 从外层 ZIP 干净解压 → 随包 Node → `restore-windows` → `tsc` → 121 条测试全部通过 |
170
+
171
+ 本次修正**没有**新增真实模型调用。以下状态与 `0.1.1` 一致,不因本次修正而改变:
172
+
173
+ - 60 条固定合成质量集仍为 `not_evaluated`(0/60),未做人工语义标注。
174
+ - 6 次小样本对照的结论不变,仍不能据此排名或宣称领先。
175
+ - 中文 IME 候选组合、附件/引用组合、完整官方 Web 组合、其他插件组合、非 Windows x64 平台仍未验证。
176
+ - 本次未在官方桌面端重新做原生手测;桌面端证据仍来自 `0.1.1` 时期,不能写成 `0.1.2` 已在新设备验收。
177
+
178
+ ### 关于恢复脚本的更正
179
+
180
+ 开发过程中曾把"恢复脚本在 `originallyMissing` 链接处失败"记为 `0.1.1` 的阻断性缺陷。复核确认该现象由**开发会话沙箱对工作区盘符的文件系统重定向**引起(junction 被写成 `\??\Global\…`,同一进程无法跟随),不属于归档或脚本缺陷:在普通用户路径(C 盘临时目录、随包 Node 24.19.0)上,`0.1.1` 原始归档的完整流程可正常完成,105 条测试全部通过。`0.1.2` 对恢复脚本的改动因此是**健壮性改进**(幂等、`--repair`、缺目标跳过、链接识别、创建兜底),不是对既有缺陷的修复。
@@ -1,5 +1,5 @@
1
1
  import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
- import type { BrowserRuntime } from './runtime';
2
+ import type { BrowserRuntime } from './runtime.js';
3
3
  type RuntimeProps = {
4
4
  runtime: BrowserRuntime;
5
5
  };
@@ -1,5 +1,5 @@
1
- import { type AssistantConfig, type AssistantStatus, type InputSnapshot, type ModelRoute, type StoredDraft, type TokenSpan } from '../core/types';
2
- import { type ReferenceOccurrence } from './dom';
1
+ import { type AssistantConfig, type AssistantStatus, type GenerationRequest, type ModelRoute, type StoredDraft, type TokenSpan } from '../core/types.js';
2
+ import { type ReferenceOccurrence } from './dom.js';
3
3
  export interface BrowserInput {
4
4
  draft: string;
5
5
  draftRev: number;
@@ -26,9 +26,24 @@ export interface BrowserTransport {
26
26
  }
27
27
  export interface Suggestion {
28
28
  text: string;
29
- snapshot: InputSnapshot;
29
+ snapshot: GenerationRequest;
30
30
  kind: 'next' | 'complete';
31
31
  }
32
+ export interface OptimizationPreview {
33
+ request: GenerationRequest;
34
+ text: string;
35
+ beforeTarget: string;
36
+ clipboardStart: number;
37
+ clipboardEnd: number;
38
+ clientGeneration: string | null;
39
+ }
40
+ export interface UndoSnapshot {
41
+ recent: readonly StoredDraft[];
42
+ expiresAt: number;
43
+ pending: readonly StoredDraft[];
44
+ generation: string | null;
45
+ }
46
+ export type SuggestionStatus = 'idle' | 'waiting' | 'generating' | 'ready' | 'throttled' | 'abstained' | 'failed' | 'paused';
32
47
  export interface ChangeRecord {
33
48
  before: string;
34
49
  after: string;
@@ -44,10 +59,17 @@ export interface BrowserState {
44
59
  status: AssistantStatus | null;
45
60
  settings: AssistantConfig;
46
61
  busy: 'optimize' | 'stash' | null;
62
+ stashClearCancelled: boolean;
63
+ stashClearPending: boolean;
47
64
  notice: string;
48
65
  suggestion: Suggestion | null;
66
+ suggestionStatus: SuggestionStatus;
67
+ suggestionMessage: string;
68
+ preview: OptimizationPreview | null;
49
69
  change: ChangeRecord | null;
50
70
  drafts: readonly StoredDraft[];
71
+ deletedDrafts: readonly StoredDraft[];
72
+ pendingUndoDrafts: readonly StoredDraft[];
51
73
  locked: readonly string[];
52
74
  connected: boolean;
53
75
  settingsSaving: boolean;
@@ -73,14 +95,22 @@ export declare class InputAssistantController {
73
95
  private timer;
74
96
  /** Cache key the armed completion timer was scheduled for; null when no timer is armed. */
75
97
  private timerKey;
98
+ private manualTimerKey;
76
99
  private poll;
100
+ private undoTimer;
101
+ private undoExpiresAt;
102
+ private readonly requestPrefix;
103
+ private completionRetryAt;
77
104
  private polling;
78
105
  private lifecycle;
79
106
  private disposed;
80
107
  private composing;
81
108
  private settingsPending;
82
109
  private settingsEpoch;
110
+ private draftsEpoch;
111
+ private stashEpoch;
83
112
  private nextTurns;
113
+ private failedNextKey;
84
114
  private nextCache;
85
115
  private completionCache;
86
116
  private failedCompletionKey;
@@ -91,16 +121,22 @@ export declare class InputAssistantController {
91
121
  private lockedRanges;
92
122
  private exposed;
93
123
  private acceptance;
94
- constructor(sessionId: string, transport: BrowserTransport, metrics?: UsageMetrics, saveSettings?: ((update: Partial<AssistantConfig>) => Promise<AssistantConfig>) | undefined);
124
+ constructor(sessionId: string, transport: BrowserTransport, metrics?: UsageMetrics, saveSettings?: ((update: Partial<AssistantConfig>) => Promise<AssistantConfig>) | undefined, undo?: UndoSnapshot);
125
+ getUndoSnapshot(): UndoSnapshot;
126
+ private armUndoExpiry;
95
127
  getSnapshot: () => BrowserState;
96
128
  subscribe: (listener: () => void) => (() => void);
97
129
  private patch;
98
130
  start(): void;
131
+ private visibilityChanged;
132
+ private schedulePoll;
99
133
  dispose(): void;
100
134
  bind(binding: BrowserBinding): void;
101
135
  notifySelectionChange(): void;
102
136
  setComposing(value: boolean): void;
103
137
  dismissSuggestion(): void;
138
+ dismissOptimization(): void;
139
+ cancelOperation(): void;
104
140
  clearNotice(): void;
105
141
  notice(text: string): void;
106
142
  refresh(): Promise<void>;
@@ -112,6 +148,7 @@ export declare class InputAssistantController {
112
148
  lockSelection(): void;
113
149
  clearLocks(): void;
114
150
  optimize(): Promise<void>;
151
+ applyOptimization(): boolean;
115
152
  canRestore(): boolean;
116
153
  restoreOriginal(): boolean;
117
154
  acceptSuggestion(): boolean;
@@ -123,6 +160,11 @@ export declare class InputAssistantController {
123
160
  deleteDraft(id: string): Promise<void>;
124
161
  clearDrafts(): Promise<void>;
125
162
  private mutateDraft;
163
+ undoDeleteDrafts(target?: 'recent' | 'pending'): Promise<void>;
164
+ discardPendingUndo(): void;
165
+ retrySuggestion(): void;
166
+ private eligibleForManual;
167
+ private suggestionStatus;
126
168
  private captureTarget;
127
169
  private pureText;
128
170
  private eligible;
@@ -135,6 +177,7 @@ export declare class InputAssistantController {
135
177
  private validResult;
136
178
  private sameCaret;
137
179
  private routeKey;
180
+ private nextKey;
138
181
  private completionKey;
139
182
  private invalidate;
140
183
  private clearTimer;
@@ -1,4 +1,4 @@
1
- import type { TokenSpan } from '../core/types';
1
+ import type { TokenSpan } from '../core/types.js';
2
2
  export interface ReferenceOccurrence {
3
3
  offset: number;
4
4
  length: number;
@@ -3,4 +3,4 @@ export declare const name = "input-assistant.client";
3
3
  export declare const inject: string[];
4
4
  /** Slot registration stays inside the mounted fiber; unloading owns all timers and DOM. */
5
5
  export declare function apply(ctx: Context): void;
6
- export { BrowserRuntime, InputAssistantController } from './public';
6
+ export { BrowserRuntime, InputAssistantController } from './public.js';
@@ -1,2 +1,2 @@
1
- export { BrowserRuntime } from './runtime';
2
- export { InputAssistantController } from './controller';
1
+ export { BrowserRuntime } from './runtime.js';
2
+ export { InputAssistantController } from './controller.js';
@@ -1,5 +1,5 @@
1
- import { InputAssistantController, type BrowserTransport } from './controller';
2
- import type { AssistantConfig } from '../core/types';
1
+ import { InputAssistantController, type BrowserTransport } from './controller.js';
2
+ import type { AssistantConfig } from '../core/types.js';
3
3
  export interface ConnectionFace {
4
4
  rpc: {
5
5
  call(channel: string, endpoint: string, payload: unknown, signal?: AbortSignal): Promise<{
@@ -43,10 +43,12 @@ export declare class BrowserRuntime {
43
43
  private pendingSettings;
44
44
  private settingsQueue;
45
45
  private metrics;
46
+ private undo;
46
47
  readonly transport: BrowserTransport;
47
48
  constructor(connection: ConnectionFace, models?: ModelDirectoryFace | undefined);
48
49
  controllerFor(sessionId: string): InputAssistantController;
49
50
  retain(sessionId: string): () => void;
51
+ private saveUndo;
50
52
  applySettings(settings: AssistantConfig): void;
51
53
  saveSettings(update: Partial<AssistantConfig>): Promise<AssistantConfig>;
52
54
  dispose(): void;
@@ -1,5 +1,5 @@
1
1
  import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
- import type { BrowserRuntime } from './runtime';
2
+ import type { BrowserRuntime } from './runtime.js';
3
3
  type SettingsProps = PropsRuntime<'settings.section'> & {
4
4
  runtime: BrowserRuntime;
5
5
  };
@@ -1 +1 @@
1
- export declare const STYLE_TEXT = "\n.dsh-ia {--dsh-ia-fallback-bg:#fff;--dsh-ia-fallback-fg:#0f1115;--dsh-ia-fallback-muted:#61666b;--dsh-ia-fallback-border:#d7dce2;font-family:var(--dsw-font-family,system-ui,sans-serif);color:var(--dsw-alias-label-primary,var(--dsh-ia-fallback-fg));font-size:13px;line-height:1.5;box-sizing:border-box;color-scheme:light}\nbody[data-ds-dark-theme] .dsh-ia {--dsh-ia-fallback-bg:#232324;--dsh-ia-fallback-fg:#f3f4f6;--dsh-ia-fallback-muted:#adb2b8;--dsh-ia-fallback-border:#43454a;color-scheme:dark}\n.dsh-ia * {box-sizing:border-box}\n.dsh-ia button,.dsh-ia input,.dsh-ia select {font:inherit;color:inherit}\n.dsh-ia button {border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:7px;padding:5px 9px;background:transparent;cursor:pointer}\n.dsh-ia button:hover:not(:disabled) {background:var(--dsw-alias-interactive-bg-hover,#8882)}\n.dsh-ia button:disabled {opacity:.45;cursor:default}\n.dsh-ia button:focus-visible,.dsh-ia input:focus-visible,.dsh-ia select:focus-visible {outline:2px solid var(--dsw-alias-state-business-primary,#4c88e4);outline-offset:2px}\n.dsh-ia-root {display:flex;align-items:center;gap:3px;position:relative}\n.dsh-ia-settings {width:100%;max-width:760px}\n.dsh-ia-settings h2 {font-size:18px;margin:0 0 8px}.dsh-ia-settings h3 {font-size:14px;margin:0 0 10px}\n.dsh-ia-settings fieldset {padding:0;margin:0;border:0;min-width:0}\n.dsh-ia-settings-toggles {display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}\n.dsh-ia-settings-toggles label {display:flex;align-items:center;gap:7px}\n.dsh-ia-trigger {white-space:nowrap}\n.dsh-ia-menu {position:fixed;width:min(440px,calc(100vw - 24px));max-height:calc(100dvh - 24px);overflow:auto;overscroll-behavior:contain;padding:14px;border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:12px;background:var(--dsw-alias-bg-layer-2,var(--dsh-ia-fallback-bg));box-shadow:0 8px 32px #0003;z-index:1000}\n.dsh-ia-row {display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:8px 0}\n.dsh-ia-row label {display:flex;align-items:center;gap:6px}\n.dsh-ia-field {display:flex;flex-direction:column;gap:4px;margin:8px 0}\n.dsh-ia-field input,.dsh-ia select {border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:6px;background:var(--dsw-alias-bg-layer-1,var(--dsh-ia-fallback-bg));padding:6px}\n.dsh-ia-field input {width:100%}\n.dsh-ia-muted {color:var(--dsw-alias-label-secondary,var(--dsh-ia-fallback-muted));font-size:12px}\n.dsh-ia-notice {position:fixed;max-width:calc(100vw - 24px);overflow:auto;padding:8px 11px;background:var(--dsw-alias-bg-layer-2,var(--dsh-ia-fallback-bg));border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:9px;box-shadow:0 4px 18px #0002;z-index:999}\n.dsh-ia-menu .dsh-ia-notice {position:static;max-width:100%;margin:8px 0;box-shadow:none}\n.dsh-ia-section {border-top:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));margin-top:12px;padding-top:10px}\n.dsh-ia-section h4 {font-size:13px;margin:0 0 8px}\n.dsh-ia-pre {white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;font-size:12px;max-height:190px;overflow:auto;padding:9px;border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:7px;background:var(--dsw-alias-bg-module-platform,#8881)}\n.dsh-ia-diff ins {background:#27a35b26;text-decoration:none}.dsh-ia-diff del {background:#d9454526}\n.dsh-ia-draft {border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:8px;padding:8px;margin:7px 0}\n.dsh-ia-draft summary {cursor:pointer;overflow-wrap:anywhere}\n.dsh-ia-draft time {font-size:11px;opacity:.65}\n.dsh-ia-candidate {position:fixed;display:flex;align-items:center;gap:8px;padding:9px 12px;overflow:auto;border:1px solid var(--dsw-alias-border-l2,var(--dsh-ia-fallback-border));border-radius:10px;background:var(--dsw-alias-bg-layer-2,var(--dsh-ia-fallback-bg));box-shadow:0 4px 16px #0002;pointer-events:auto;z-index:998}\n.dsh-ia-candidate-text {flex:1;white-space:pre-wrap;overflow-wrap:anywhere}\n.dsh-ia-ghost {position:fixed;white-space:pre-wrap;overflow-wrap:anywhere;overflow:hidden;max-height:3lh;pointer-events:none;user-select:none;color:var(--dsw-alias-label-tertiary,#76808d);opacity:.9;z-index:34}\n[data-composer-card]:has([data-dsh-ia-empty-ghost]) [data-composer-placeholder] {visibility:hidden}\n";
1
+ export declare const STYLE_TEXT = "\n.dsh-ia {\n --dsh-ia-fallback-bg: #ffffff;\n --dsh-ia-fallback-fg: #111827;\n --dsh-ia-fallback-muted: #4b5563;\n --dsh-ia-fallback-border: #d1d5db;\n --dsh-ia-accent: var(--dsw-alias-state-business-primary, #3b82f6);\n --dsh-ia-accent-subtle: rgba(59, 130, 246, 0.1);\n --dsh-ia-pill-bg: var(--dsw-alias-interactive-bg-subtle, rgba(0, 0, 0, 0.04));\n --dsh-ia-pill-hover: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.08));\n font-family: var(--dsw-font-family, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif);\n color: var(--dsw-alias-label-primary, var(--dsh-ia-fallback-fg));\n font-size: 13px;\n line-height: 1.5;\n box-sizing: border-box;\n color-scheme: light;\n}\n\nbody[data-ds-dark-theme] .dsh-ia {\n --dsh-ia-fallback-bg: #1f2329;\n --dsh-ia-fallback-fg: #f3f4f6;\n --dsh-ia-fallback-muted: #9ca3af;\n --dsh-ia-fallback-border: #374151;\n --dsh-ia-pill-bg: var(--dsw-alias-interactive-bg-subtle, rgba(255, 255, 255, 0.06));\n --dsh-ia-pill-hover: var(--dsw-alias-interactive-bg-hover, rgba(255, 255, 255, 0.12));\n color-scheme: dark;\n}\n\n.dsh-ia * { box-sizing: border-box; }\n.dsh-ia button, .dsh-ia input, .dsh-ia select { font: inherit; color: inherit; }\n\n/* Global buttons within dsh-ia */\n.dsh-ia button {\n border: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n border-radius: 7px;\n padding: 5px 11px;\n background: var(--dsw-alias-bg-layer-1, transparent);\n color: var(--dsw-alias-label-primary, inherit);\n cursor: pointer;\n transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease, transform 0.15s ease;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n}\n.dsh-ia button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, #8882);\n border-color: var(--dsw-alias-state-business-primary, var(--dsh-ia-accent));\n}\n.dsh-ia button:active:not(:disabled) {\n transform: translateY(1px);\n}\n.dsh-ia button:disabled {\n opacity: 0.45;\n cursor: default;\n transform: none;\n}\n.dsh-ia button:focus-visible, .dsh-ia input:focus-visible, .dsh-ia select:focus-visible {\n outline: 2px solid var(--dsw-alias-state-business-primary, #3b82f6);\n outline-offset: 2px;\n}\n\n/* Smart Pill Trigger Group in Input Card */\n.dsh-ia-root {\n display: inline-flex;\n align-items: center;\n background: var(--dsh-ia-pill-bg);\n border: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n border-radius: 8px;\n padding: 2px;\n gap: 2px;\n position: relative;\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);\n}\n.dsh-ia-root .dsh-ia-trigger {\n border: none;\n background: transparent;\n padding: 4px 10px;\n font-weight: 500;\n border-radius: 6px;\n white-space: nowrap;\n}\n.dsh-ia-root .dsh-ia-trigger:hover:not(:disabled) {\n background: var(--dsh-ia-pill-hover);\n}\n.dsh-ia-root .dsh-ia-menu-btn {\n border: none;\n background: transparent;\n padding: 4px 6px;\n border-radius: 6px;\n min-width: 24px;\n}\n.dsh-ia-root .dsh-ia-menu-btn:hover:not(:disabled) {\n background: var(--dsh-ia-pill-hover);\n}\n.dsh-ia-root .dsh-ia-cancel-btn {\n border: none;\n background: rgba(239, 68, 68, 0.12);\n color: #ef4444;\n font-size: 11px;\n padding: 4px 8px;\n border-radius: 6px;\n}\n.dsh-ia-root .dsh-ia-cancel-btn:hover {\n background: rgba(239, 68, 68, 0.2);\n}\n\n/* Floating Menu Panel */\n.dsh-ia-menu {\n position: fixed;\n width: min(480px, calc(100vw - 24px));\n max-height: calc(100dvh - 24px);\n overflow-y: auto;\n overscroll-behavior: contain;\n padding: 16px;\n border: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n border-radius: 14px;\n background: var(--dsw-alias-bg-layer-2, var(--dsh-ia-fallback-bg));\n box-shadow: 0 12px 36px rgba(0, 0, 0, 0.22);\n z-index: 1000;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.dsh-ia-preview {\n z-index: 1001;\n width: min(580px, calc(100vw - 24px));\n}\n.dsh-ia-preview .dsh-ia-pre {\n margin-top: 10px;\n max-height: 360px;\n}\n\n/* Form Controls & Fields */\n.dsh-ia-row {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n margin: 6px 0;\n}\n.dsh-ia-row label {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n cursor: pointer;\n user-select: none;\n}\n.dsh-ia-field {\n display: flex;\n flex-direction: column;\n gap: 5px;\n margin: 6px 0;\n}\n.dsh-ia-field input, .dsh-ia select {\n border: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n border-radius: 7px;\n background: var(--dsw-alias-bg-layer-1, var(--dsh-ia-fallback-bg));\n padding: 7px 10px;\n color: var(--dsw-alias-label-primary, inherit);\n transition: border-color 0.15s ease;\n}\n.dsh-ia-field input:focus, .dsh-ia select:focus {\n border-color: var(--dsw-alias-state-business-primary, var(--dsh-ia-accent));\n}\n.dsh-ia-field input { width: 100%; }\n.dsh-ia-muted {\n color: var(--dsw-alias-label-secondary, var(--dsh-ia-fallback-muted));\n font-size: 12px;\n line-height: 1.45;\n}\n\n/* Sections */\n.dsh-ia-section {\n border-top: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n margin-top: 8px;\n padding-top: 10px;\n}\n.dsh-ia-section h4 {\n font-size: 13px;\n margin: 0 0 8px;\n font-weight: 600;\n}\n\n/* Notices & Alerts */\n.dsh-ia-notice {\n position: fixed;\n max-width: min(360px, calc(100vw - 32px));\n overflow: auto;\n padding: 6px 12px;\n background: var(--dsw-alias-bg-layer-2, var(--dsh-ia-fallback-bg));\n border: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n border-radius: 20px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.14);\n z-index: 1002;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n animation: dshIaFadeIn 0.2s ease-out;\n}\n@keyframes dshIaFadeIn {\n from { opacity: 0; transform: translateY(4px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.dsh-ia-menu .dsh-ia-notice {\n position: static;\n max-width: 100%;\n margin: 6px 0;\n box-shadow: none;\n}\n.dsh-ia-notice button { margin-left: 6px; padding: 3px 8px; font-size: 11px; }\n\n/* Diff / Pre formatting */\n.dsh-ia-pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font: inherit;\n font-size: 12px;\n max-height: 200px;\n overflow-y: auto;\n padding: 10px;\n border: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform, rgba(128, 128, 128, 0.08));\n}\n.dsh-ia-diff ins {\n background: rgba(39, 163, 91, 0.22);\n color: #107c41;\n text-decoration: none;\n border-radius: 2px;\n padding: 0 2px;\n}\nbody[data-ds-dark-theme] .dsh-ia-diff ins {\n color: #4ade80;\n background: rgba(34, 197, 94, 0.22);\n}\n.dsh-ia-diff del {\n background: rgba(217, 69, 69, 0.22);\n color: #c42b1c;\n text-decoration: line-through;\n border-radius: 2px;\n padding: 0 2px;\n}\nbody[data-ds-dark-theme] .dsh-ia-diff del {\n color: #f87171;\n background: rgba(239, 68, 68, 0.22);\n}\n\n/* Draft Card */\n.dsh-ia-draft {\n border: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n border-radius: 9px;\n padding: 9px 12px;\n margin: 8px 0;\n background: var(--dsw-alias-bg-layer-1, transparent);\n transition: border-color 0.15s ease;\n}\n.dsh-ia-draft summary {\n cursor: pointer;\n overflow-wrap: anywhere;\n font-weight: 500;\n}\n.dsh-ia-draft time {\n display: block;\n font-size: 11px;\n color: var(--dsw-alias-label-tertiary, var(--dsh-ia-fallback-muted));\n margin: 3px 0 6px;\n}\n\n/* Candidate Panel & Ghost Text */\n.dsh-ia-candidate {\n position: fixed;\n display: flex;\n align-items: center;\n gap: 9px;\n padding: 10px 14px;\n max-width: min(640px, calc(100vw - 32px));\n max-height: 240px;\n overflow-y: auto;\n border: 1px solid var(--dsw-alias-border-l2, var(--dsh-ia-fallback-border));\n border-radius: 11px;\n background: var(--dsw-alias-bg-layer-2, var(--dsh-ia-fallback-bg));\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.2);\n pointer-events: auto;\n z-index: 998;\n}\n.dsh-ia-candidate-text {\n flex: 1;\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n font-size: 13px;\n line-height: 1.5;\n}\n.dsh-ia-ghost {\n position: fixed;\n white-space: pre-wrap;\n word-break: break-word;\n overflow-wrap: break-word;\n overflow: hidden;\n max-height: 100%;\n pointer-events: none;\n user-select: none;\n color: var(--dsw-alias-label-tertiary, #76808d);\n opacity: 0.88;\n z-index: 34;\n}\n[data-composer-card]:has([data-dsh-ia-empty-ghost]) [data-composer-placeholder] {\n visibility: hidden;\n}\n\n/* Settings Form page */\n.dsh-ia-settings { width: 100%; max-width: 760px; }\n.dsh-ia-settings h2 { font-size: 18px; margin: 0 0 8px; }\n.dsh-ia-settings h3 { font-size: 14px; margin: 0 0 10px; font-weight: 600; }\n.dsh-ia-settings fieldset { padding: 0; margin: 0; border: 0; min-width: 0; }\n.dsh-ia-settings-toggles { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; }\n.dsh-ia-settings-toggles label { display: flex; align-items: center; gap: 7px; cursor: pointer; }\n.dsh-ia-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n\n.dsh-ia-preview .dsh-ia-pre { max-height: 320px; }\n.dsh-ia-notice { flex-wrap: wrap; border-radius: 12px; }\n.dsh-ia-route, .dsh-ia-suggestion-state { overflow-wrap: anywhere; }\n.dsh-ia-suggestion-state { margin: 6px 0; }\n.dsh-ia-inline-status { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--dsw-alias-label-secondary,var(--dsh-ia-fallback-muted)); }\n.dsh-ia summary:focus-visible { outline: 2px solid var(--dsh-ia-accent); outline-offset: 2px; }\n.dsh-ia-settings-presets { display: grid; grid-template-columns: repeat(auto-fit,minmax(180px,1fr)); gap: 10px; }\n.dsh-ia .dsh-ia-preset { display: flex; flex-direction: column; align-items: flex-start; text-align: left; padding: 12px; gap: 5px; }\n.dsh-ia .dsh-ia-preset[aria-pressed=true] { border-color: var(--dsh-ia-accent); background: var(--dsh-ia-accent-subtle); }\n.dsh-ia-setting-grid { display: grid; grid-template-columns: repeat(auto-fit,minmax(min(280px,100%),1fr)); gap: 14px; margin-top: 12px; }\n.dsh-ia-number-control { display: flex; align-items: center; gap: 10px; }\n.dsh-ia-number-control input[type=number] { width: 100px; flex: 0 0 auto; }\n.dsh-ia-number-control input[type=range] { min-width: 0; flex: 1; accent-color: var(--dsh-ia-accent); }\n.dsh-ia-setting-heading { display: flex; justify-content: space-between; gap: 8px; align-items: center; }\n.dsh-ia-setting-heading label { font-weight: 500; }\n@media (prefers-reduced-motion: reduce) { .dsh-ia *, .dsh-ia-notice { transition: none !important; animation: none !important; } }\n";