sqs-dsh-better-input 0.1.0

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 (40) hide show
  1. package/LICENSE +27 -0
  2. package/README.md +218 -0
  3. package/assets/banner.png +0 -0
  4. package/cordis.patch.yml +6 -0
  5. package/lib/about.d.ts +65 -0
  6. package/lib/client/MicrophoneButton.d.ts +64 -0
  7. package/lib/client/OptimizeButton.d.ts +33 -0
  8. package/lib/client/VoiceRecognitionBar.d.ts +14 -0
  9. package/lib/client/index.d.ts +14 -0
  10. package/lib/client/settings-controller.d.ts +80 -0
  11. package/lib/client/settings.d.ts +15 -0
  12. package/lib/client/strings.d.ts +113 -0
  13. package/lib/client/templates-controller.d.ts +45 -0
  14. package/lib/client/templates-section.d.ts +17 -0
  15. package/lib/client/templates-source.d.ts +16 -0
  16. package/lib/client/voice-session.d.ts +35 -0
  17. package/lib/client/web-speech.d.ts +35 -0
  18. package/lib/client.d.ts +1 -0
  19. package/lib/client.js +2925 -0
  20. package/lib/client.js.map +1 -0
  21. package/lib/config.d.ts +100 -0
  22. package/lib/identity-CzaR1Taa.js +18 -0
  23. package/lib/identity-CzaR1Taa.js.map +1 -0
  24. package/lib/identity.d.ts +24 -0
  25. package/lib/index.d.ts +11 -0
  26. package/lib/index.js +920 -0
  27. package/lib/index.js.map +1 -0
  28. package/lib/polish/prompts.d.ts +37 -0
  29. package/lib/polish/service.d.ts +45 -0
  30. package/lib/remote-contract.d.ts +166 -0
  31. package/lib/remote.d.ts +56 -0
  32. package/lib/remote.js +226 -0
  33. package/lib/remote.js.map +1 -0
  34. package/lib/settings/store.d.ts +41 -0
  35. package/lib/templates/model.d.ts +30 -0
  36. package/lib/templates/store.d.ts +27 -0
  37. package/lib/typert.d.ts +107 -0
  38. package/lib/typert.js +468 -0
  39. package/lib/typert.js.map +1 -0
  40. package/package.json +116 -0
package/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 sanqianshuang
4
+
5
+ This project is a secondary development (fork) of `dsh-better-input`
6
+ (https://github.com/DIAG5/dsh-better-input), which is also MIT licensed.
7
+ The original copyright notice is retained below, as the MIT terms require.
8
+
9
+ Copyright (c) 2026 dsh-better-input contributors
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,218 @@
1
+ <p align="center">
2
+ <img src="./assets/banner.png" width="100%" alt="sqs-dsh-better-input banner" />
3
+ </p>
4
+
5
+ <h1 align="center">🎤 sqs-dsh-better-input</h1>
6
+
7
+ <p align="center"><b>给 DeepSeek Harness 更好的「输入」体验。</b></p>
8
+
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/sqs-dsh-better-input"><img src="https://img.shields.io/npm/v/sqs-dsh-better-input.svg" alt="npm version" /></a>
11
+ <a href="https://www.npmjs.com/package/sqs-dsh-better-input"><img src="https://img.shields.io/npm/dm/sqs-dsh-better-input.svg" alt="npm downloads" /></a>
12
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="license MIT" /></a>
13
+ </p>
14
+
15
+ <p align="center">
16
+ 输入体验增强插件 · 基于 dsh-better-input 的二次开发
17
+ </p>
18
+
19
+ > 💡 **它解决什么?** 与智能体对话,输入不只靠键盘打字。本插件把**语音识别、AI 润色、提示词优化、提示词模板**四件事做顺:说出来的话自动变成干净、可直接发送的文字;写好的提示词一键优化;常用提示词随用随插。
20
+
21
+ ***
22
+
23
+ ## ⚠️ 关于这个版本(二次开发说明)
24
+
25
+ 本仓库是 [`dsh-better-input`](https://github.com/DIAG5/dsh-better-input)(MIT)的**二次开发版本**,由 **sanqianshuang** 维护,专门适配 **DSH `0.1.7-rc.2`**。与原版的主要差别:
26
+
27
+ | 变更 | 说明 |
28
+ | --- | --- |
29
+ | 🗑️ **移除「文件输入 / 文件转 Markdown / OCR」整块** | DSH `0.1.7` 已原生支持文件拖拽上传、上传进度、文件卡片与重试(`conversation.input.attachments` / `DropOverlay` / `FileCard`),插件再挂一套 📎 文件面板与 `@` 引用芯片属于重复实现,故整体删除。 |
30
+ | 🔧 **修复 Typert 兼容性(关键)** | `0.1.7` 收紧了 Typert 边界:`mode: 'strict'` 的 codec 必须带 **`create()` 工厂**;旧版把 schema 直接放在 `schema` 属性上,会被 `requireStrictCodec` 拒绝(报 `strict codec has no create() factory`),导致整个 entry 无法激活、插件根本不加载。现已全部改为工厂形式。 |
31
+ | 🔧 **修复设置存储被移除的 API** | `0.1.7` 删除了 `settings.register(namespace, schema)`,改为按 profile entry 的 `SettingsForms`(带 revision CAS)。本插件的设置改为**自持 JSON 文件**,不再依赖该 API,因而不会被后续版本反复打破。 |
32
+ | 🔧 **对齐依赖版本** | `@deepseek-ai/cordis` → `~4.0.4`、`@deepseek-ai/schemastery` → `~3.18.4`,与 `0.1.7-rc.2` 的 peer 要求一致。 |
33
+ | 🏷️ **身份与命名** | 包名 `sqs-dsh-better-input`(npm 同名)、作者 `sanqianshuang`;设置与模板数据目录为 `~/.dsh/sqs-dsh-better-input/`(与原版互不干扰,可并存安装)。 |
34
+
35
+ > 原版的 LICENSE 与版权声明已在 [LICENSE](./LICENSE) 中保留,符合 MIT 要求。
36
+
37
+ ## ✨ 功能
38
+
39
+ <table>
40
+ <tr><th align="center" width="120">模块</th><th align="left">说明</th></tr>
41
+ <tr>
42
+ <td align="center">🎙️<br/><b>语音输入</b></td>
43
+ <td>点击麦克风,边说边转写,文字<strong>实时流式</strong>进入输入框。浏览器原生识别(Web Speech API),<strong>无需 API Key</strong>、不走服务器。识别因静音自行中断时会自动重启。</td>
44
+ </tr>
45
+ <tr>
46
+ <td align="center">🤖<br/><b>AI 润色</b></td>
47
+ <td>识别后自动清理:去口头禅、修同音错字(根木鹿→根目录、脱肯→Token)、补标点、把口语列举转成编号列表、并处理自我纠正(「不对,我说的是…」只保留最终语义)。<strong>复用 dsh 已配置的模型,无需额外 Key</strong>。</td>
48
+ </tr>
49
+ <tr>
50
+ <td align="center">✨<br/><b>提示词优化</b></td>
51
+ <td>输入框右侧一个 ✨ 图标,AI 帮你把写好的提示词优化得更精准;点击后弹出<strong>原文 / 优化结果对比</strong>,确认满意再采用。可引用最近 N 轮对话作为语境。</td>
52
+ </tr>
53
+ <tr>
54
+ <td align="center">📝<br/><b>提示词模板</b></td>
55
+ <td>常用提示词存成模板,输入框键入 <code>/</code> 搜索并一键插入正文;设置页内新建 / 编辑 / 删除,<strong>本地存储</strong>不经服务器。</td>
56
+ </tr>
57
+ <tr>
58
+ <td align="center">🐘<br/><b>防覆盖保护</b></td>
59
+ <td>润色 / 优化进行中你手动改了草稿,结果<strong>不会覆盖</strong>你的编辑;失败保留原文。</td>
60
+ </tr>
61
+ <tr>
62
+ <td align="center">⏱️<br/><b>录音自动停止</b></td>
63
+ <td>可自定义单次录音上限(1–600 秒,默认 120),到点自动停止,不占麦克风。</td>
64
+ </tr>
65
+ <tr>
66
+ <td align="center">⚙️<br/><b>可视化设置页</b></td>
67
+ <td>识别语言、录音时长、润色开关 / 模型 / 思考强度 / 自定义提示词,优化模型 / 思考强度 / 提示词 / 上下文轮数,全部可在设置里配置;内置提示词可一键展开查看。首次打开会自动选中一个已配置模型。</td>
68
+ </tr>
69
+ <tr>
70
+ <td align="center">🔄<br/><b>更新检查</b></td>
71
+ <td>设置页底部「关于与更新」一键检测 npm 最新版,发现新版会给出<strong>一键复制更新命令</strong>。</td>
72
+ </tr>
73
+ </table>
74
+
75
+ ## 🚀 安装
76
+
77
+ 前置:[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`0.1.7-rc.2`)+ Node.js `^22.19.0 || >=24.0.0` + Chrome/Edge 浏览器(语音识别需要 Chromium 内核)。
78
+
79
+ ### 方式 A:从 npm 安装(推荐)
80
+
81
+ ```sh
82
+ # 有全局 dsh CLI
83
+ dsh plugin --profile web add sqs-dsh-better-input
84
+
85
+ # 没有全局 dsh(用 npx 拉取)
86
+ npx -y @deepseek-ai/dsh plugin --profile web add sqs-dsh-better-input
87
+ ```
88
+
89
+ 升级到最新版:
90
+
91
+ ```sh
92
+ dsh plugin --profile web update sqs-dsh-better-input
93
+ ```
94
+
95
+ 卸载:
96
+
97
+ ```sh
98
+ dsh plugin --profile web remove sqs-dsh-better-input
99
+ ```
100
+
101
+ ### 方式 B:从本地目录安装(开发 / 二次开发)
102
+
103
+ ```sh
104
+ dsh plugin --profile web add /path/to/sqs-dsh-better-input
105
+ npx -y @deepseek-ai/dsh plugin --profile web add /path/to/sqs-dsh-better-input
106
+ ```
107
+
108
+ ### 方式 C:从源码构建
109
+
110
+ ```sh
111
+ git clone https://github.com/sanqianshuang/sqs-dsh-better-input.git
112
+ cd sqs-dsh-better-input
113
+ npm install --legacy-peer-deps # 见下方说明
114
+ npm run build
115
+ dsh plugin --profile web add "$PWD"
116
+ ```
117
+
118
+ > `--legacy-peer-deps`:`0.1.7` 的这批类型包(dev 依赖)之间存在 npm 难以自解的 peer 链(如 `dsh-api-remotes` → `dsh-scope`)。它们只用于编译期类型、不会被打进产物(客户端 bundle 已把 `@deepseek-ai/*` 全部外置),因此放宽 peer 校验是安全的。
119
+
120
+ ### 备选:不装依赖,写进 preset 的 `cordis.yml`
121
+
122
+ ```yaml
123
+ - insert:
124
+ - id: sqs-dsh-better-input
125
+ name: sqs-dsh-better-input
126
+ ```
127
+
128
+ 安装后刷新 Web UI,输入框右侧会出现**麦克风图标** 🎤。
129
+
130
+ ## 📖 使用
131
+
132
+ ### 1. 语音输入
133
+
134
+ 1. 打开任意对话,点击输入框右侧的**麦克风按钮**
135
+ 2. 开始说话,识别文字**实时流入**输入框
136
+ 3. 再点按钮(或识别条上的**停止**)结束
137
+ 4. 检查、修改、发送
138
+
139
+ > 识别完全在浏览器本地完成(Web Speech API)。Firefox / Safari 不支持时按钮自动禁用。
140
+
141
+ ### 2. AI 润色
142
+
143
+ 设置 → **BetterInput** → 打开 **AI 润色** → 选择一个 dsh 里已配置的模型。
144
+
145
+ 内置提示词会:去口头禅、修 ASR 同音错字、补标点、把口语列举转成编号列表(如「第一…第二…」→ `1.` `2.`)。留空用内置提示词,点「查看内置提示词」可展开原文;或粘贴自定义提示词(总会追加输出契约保护,保证只返回正文、不答非所问)。
146
+
147
+ ### 3. 提示词优化
148
+
149
+ 1. 在输入框里写好你的提示词
150
+ 2. 点击输入框右侧的 **✨ 优化** 图标
151
+ 3. 稍等,弹出**原文 / 优化结果对比**画面
152
+ 4. 点 **采用** 用优化结果替换草稿,或点 **取消** 保留原文
153
+
154
+ > 默认关闭思考,追求快速、低成本的直出结果。从设置页可手动提高思考强度。
155
+
156
+ ### 4. 提示词模板
157
+
158
+ 1. 到 设置 → **BetterInput** → 「**提示词模板**」分节,点「**新建模板**」
159
+ 2. 填写名称、描述(可选)、正文与标签(可选,逗号分隔,用于搜索),保存
160
+ 3. 回到输入框键入 `/`,模板候选即弹出;继续输入按名称 / 描述 / 标签实时过滤
161
+ 4. 选中候选,模板正文直接插入输入框,可继续修改后发送
162
+
163
+ > 模板保存在宿主本地 `~/.dsh/sqs-dsh-better-input/templates.json`,不经服务器、不上传;最多 200 个模板,正文上限 8000 字,列表按最近更新排序。写入走「临时文件 + 原子重命名」,文件意外损坏时自动隔离为 `*.corrupt-<时间戳>` 并重建。
164
+
165
+ ### 5. 设置
166
+
167
+ | 设置项 | 说明 |
168
+ | --- | --- |
169
+ | 界面语言 | 插件界面文案支持中文 / 英文,跟随 DSH 界面语言切换,即时生效 |
170
+ | 识别语言 | 留空自动跟随浏览器语言(如 `zh-CN`、`en-US`) |
171
+ | 单次录音上限 | 1–600 秒,默认 120,到点自动停止 |
172
+ | AI 润色 | 开 / 关;开启后每次语音识别结束自动润色进草稿 |
173
+ | 润色模型 / 思考强度 / 自定义提示词 | 各自独立配置 |
174
+ | 优化模型 / 思考强度 / 自定义提示词 | 各自独立配置 |
175
+ | 上下文引用轮数 | 优化时引用最近 N 轮对话(0 为关闭,默认 3) |
176
+ | 提示词模板 | 设置页内新建 / 编辑 / 删除,数据保存在宿主本地 JSON |
177
+ | 关于与更新 | 显示当前版本 / 许可证 / 仓库,一键「检查更新」 |
178
+
179
+ > 以上设置保存在 `~/.dsh/sqs-dsh-better-input/settings.json`。
180
+
181
+ ## 🧩 兼容性
182
+
183
+ - DeepSeek Harness `0.1.7-rc.2`(peer 范围 `>=0.1.7-rc.2 <0.2.0-0`)
184
+ - Node.js `^22.19.0 || >=24.0.0`
185
+ - Chromium 内核浏览器(Chrome / Edge)
186
+
187
+ ## 🛠️ 开发
188
+
189
+ ```sh
190
+ npm install --legacy-peer-deps
191
+ npm run check # 类型检查
192
+ npm run build # 构建 lib/(Host ESM + 浏览器 bundle)
193
+ ```
194
+
195
+ 改 Client 端:`npm run dev:watch` 后刷新 UI;改 Host 端:重启 `dsh web`。
196
+
197
+ ## 🏗️ 架构
198
+
199
+ - `src/index.ts` — Host 插件入口,挂载润色服务
200
+ - `src/identity.ts` — 包名 / 作者 / 仓库等身份信息的唯一来源
201
+ - `src/polish/service.ts` — `BetterInputPolishService`(Typert remote):设置读写、dsh 模型路由发现、LLM 润色与提示词优化、提示词模板存取
202
+ - `src/polish/prompts.ts` — 内置润色 / 优化提示词与输出契约守卫
203
+ - `src/settings/store.ts` — 插件自持设置的 JSON 存储(原子写入、损坏自愈)
204
+ - `src/templates/` — 提示词模板的数据模型与宿主端 JSON 存储
205
+ - `src/about.ts` — 插件身份读取与 npm 版本检查
206
+ - `src/client/` — 浏览器端:麦克风 / 优化按钮(`conversation.input.right`)、识别条(`conversation.input.dock`)、设置页与模板管理(`settings.section`)、`/` 模板候选源
207
+ - `src/typert.ts` / `src/remote.ts` — Client↔Host 类型化通信契约
208
+
209
+ ## 📄 License
210
+
211
+ [MIT](./LICENSE) — 保留原 `dsh-better-input` 项目的版权声明。
212
+
213
+ ## ⭐ 支持
214
+
215
+ - 提交 Issue / PR
216
+ - 分享给同样用 DSH 的朋友
217
+
218
+ 感谢原版作者与社区 ❤️
Binary file
@@ -0,0 +1,6 @@
1
+ # The sqs-dsh-better-input bundle patch. The package entry is
2
+ # intentionally small; browser behavior is discovered through the package's
3
+ # dsh.client manifest.
4
+ - insert:
5
+ - id: sqs-dsh-better-input
6
+ name: sqs-dsh-better-input
package/lib/about.d.ts ADDED
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Plugin identity and update-check helpers. The Host reads the installed
3
+ * package.json and queries the npm registry for the latest released version.
4
+ * The browser never talks to the npm registry directly — the Host owns the
5
+ * check and merely reports back a status plus the command the user runs to
6
+ * update (DSH has no programmatic self-update API).
7
+ *
8
+ * Pattern follows the official `dsh-ears` plugin, used by plugins in the
9
+ dsh ecosystem.
10
+ */
11
+ export declare const PLUGIN_LICENSE = "MIT";
12
+ export declare const PLUGIN_REPOSITORY_URL = "https://github.com/sanqianshuang/sqs-dsh-better-input";
13
+ /**
14
+ * Fallback repository slug (owner/repo), used only when a repository URL cannot
15
+ * be parsed. It must be the *repository* slug, not an npm package name: the
16
+ * package is unscoped, so prefixing it with the npm scope would invent a
17
+ * package that does not exist.
18
+ */
19
+ export declare const PLUGIN_REPOSITORY_SLUG = "sanqianshuang/sqs-dsh-better-input";
20
+ export declare const PLUGIN_PACKAGE_NAME = "sqs-dsh-better-input";
21
+ /** Global-CLI form (works when `dsh` is installed globally). */
22
+ export declare const UPDATE_COMMAND = "dsh plugin --profile web update sqs-dsh-better-input";
23
+ /** npx form (works without a global `dsh` CLI; DSH is pulled on demand). */
24
+ export declare const UPDATE_COMMAND_NPX = "npx -y @deepseek-ai/dsh plugin --profile web update sqs-dsh-better-input";
25
+ export declare const NPM_LATEST_URL = "https://registry.npmjs.org/sqs-dsh-better-input/latest";
26
+ export type AboutInfo = {
27
+ readonly repository: string;
28
+ readonly repositorySlug: string;
29
+ readonly version: string;
30
+ readonly license: string;
31
+ readonly updateCommand: string;
32
+ readonly updateCommandNpx: string;
33
+ };
34
+ export type UpdateCheckStatus = 'up-to-date' | 'update-available' | 'unpublished' | 'error';
35
+ export type UpdateCheckResult = {
36
+ readonly status: UpdateCheckStatus;
37
+ readonly installed: string;
38
+ readonly latest: string | null;
39
+ readonly updateCommand: string;
40
+ readonly updateCommandNpx: string;
41
+ };
42
+ export declare function readInstalledAboutInfo(packageJsonPath?: string): AboutInfo;
43
+ export declare function repositoryUrlFromPackage(value: unknown): string;
44
+ export declare function repositorySlugFromUrl(url: string): string;
45
+ export declare function resolvePackageJsonPath(): string;
46
+ /** Compare dotted numeric cores only. `1.2` equals `1.2.0`. Null if either is not a version. */
47
+ export declare function compareReleaseVersions(left: string, right: string): number | null;
48
+ export declare function interpretUpdateCheck(installed: string, latest: string): Exclude<UpdateCheckStatus, 'unpublished' | 'error'> | null;
49
+ export declare function fetchLatestPublishedVersion(options?: {
50
+ readonly fetchImpl?: typeof fetch;
51
+ readonly signal?: AbortSignal;
52
+ }): Promise<{
53
+ status: 'ok';
54
+ version: string;
55
+ } | {
56
+ status: 'unpublished';
57
+ } | {
58
+ status: 'error';
59
+ message: string;
60
+ }>;
61
+ export declare function checkForPluginUpdate(options?: {
62
+ readonly installed: string;
63
+ readonly fetchImpl?: typeof fetch;
64
+ readonly signal?: AbortSignal;
65
+ }): Promise<UpdateCheckResult>;
@@ -0,0 +1,64 @@
1
+ import type { SnapshotSelectorHook, TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { InputState } from '@deepseek-ai/dsh-client-ui-conversation/client';
3
+ import { type BetterInputSettings, type BetterInputSettingsPatch } from '../config.js';
4
+ import type { BetterInputRemote } from '../remote.js';
5
+ import { type VoiceInputSession } from './voice-session.js';
6
+ /** The framework-injected `t` seat for the BetterInput namespace. */
7
+ type Translate = TranslateNS<'better-input'>;
8
+ /**
9
+ * Standard props the conversation input zone hands to every
10
+ * `conversation.input.right` entry, plus the injected voice session and
11
+ * settings controller face.
12
+ */
13
+ export type InputZoneLikeProps = {
14
+ readonly useInput: SnapshotSelectorHook<InputState>;
15
+ readonly inputActions: {
16
+ setDraft(text: string): void;
17
+ };
18
+ readonly voiceSession: VoiceInputSession;
19
+ readonly remote: BetterInputRemote;
20
+ readonly useSettings: () => SettingsFace;
21
+ readonly t: Translate;
22
+ };
23
+ export type SettingsFace = {
24
+ readonly status: 'loading' | 'ready' | 'error';
25
+ readonly settings: BetterInputSettings;
26
+ };
27
+ /**
28
+ * The microphone button in the composer tool row. Click to start listening,
29
+ * click again to stop. Transcripts stream into the draft in real time; when
30
+ * polishing is enabled, the committed transcript is polished through the Host
31
+ * LLM route and replaces the draft (unless the user edited it meanwhile).
32
+ */
33
+ export declare function MicrophoneButton({ useInput, inputActions, voiceSession, remote, useSettings, t }: InputZoneLikeProps): import("react").JSX.Element;
34
+ export interface PolishDraftOptions {
35
+ transcript: string;
36
+ baseDraft: string;
37
+ draftAtStop: string;
38
+ provider: string;
39
+ model: string;
40
+ remote: BetterInputRemote;
41
+ setState: (state: 'idle' | 'error' | 'polish-error' | 'polishing', detail?: string) => void;
42
+ latestDraftRef: {
43
+ current: string;
44
+ };
45
+ actionsRef: {
46
+ current: {
47
+ setDraft(text: string): void;
48
+ };
49
+ };
50
+ polishAbortRef: {
51
+ current: AbortController | null;
52
+ };
53
+ }
54
+ export declare function polishDraft(options: PolishDraftOptions): Promise<void>;
55
+ /**
56
+ * Only replace the draft when the user has not edited it since the transcript
57
+ * landed. Both the transcript-at-stop and the base draft count as unchanged
58
+ * (the user may have reverted the interim edits).
59
+ */
60
+ export declare function shouldApplyPolishResult(currentDraft: string, draftAtStop: string, baseDraft: string): boolean;
61
+ /** Append transcript to a base draft with one space separator. */
62
+ export declare function updateDraft(baseDraft: string, transcript: string): string;
63
+ export declare function isSupported(): boolean;
64
+ export type { BetterInputSettingsPatch };
@@ -0,0 +1,33 @@
1
+ import type { SnapshotSelectorHook, TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { InputState } from '@deepseek-ai/dsh-client-ui-conversation/client';
3
+ import type { ChatSnapshot } from '@deepseek-ai/dsh-client-ui-chat/client';
4
+ import type { BetterInputRemote } from '../remote.js';
5
+ import type { SettingsFace } from './MicrophoneButton.js';
6
+ /** The framework-injected `t` seat for the BetterInput namespace. */
7
+ type Translate = TranslateNS<'better-input'>;
8
+ /**
9
+ * Props handed to a `conversation.input.right` entry, plus the injected
10
+ * remote and settings face. In dsh 0.1.2 the slot standard kit supplies
11
+ * `useChat` (Chat target snapshot, whose `legacy.nodes` carries the message
12
+ * array) and `useInput` (draft); message history is no longer exposed through
13
+ * a top-level `session` owner.
14
+ */
15
+ export type OptimizeButtonProps = {
16
+ readonly useChat: SnapshotSelectorHook<ChatSnapshot>;
17
+ readonly useInput: SnapshotSelectorHook<InputState>;
18
+ readonly inputActions: {
19
+ setDraft(text: string): void;
20
+ };
21
+ readonly remote: BetterInputRemote;
22
+ readonly useSettings: () => SettingsFace;
23
+ readonly t: Translate;
24
+ };
25
+ /**
26
+ * The ✨ optimize button rendered above the composer card (in
27
+ * `conversation.input.dock`), right-aligned. Click reads the current draft,
28
+ * calls the Host LLM to optimize it, then shows a confirmation panel with
29
+ * the original and optimized text. The draft is replaced only when the user
30
+ * clicks "Adopt".
31
+ */
32
+ export declare function OptimizeButton({ useChat, useInput, inputActions, remote, useSettings, t }: OptimizeButtonProps): import("react").JSX.Element;
33
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import { type VoiceInputSession } from './voice-session.js';
3
+ /** The framework-injected `t` seat for the BetterInput namespace. */
4
+ type Translate = TranslateNS<'better-input'>;
5
+ export type RecognitionBarProps = {
6
+ readonly voiceSession: VoiceInputSession;
7
+ readonly t: Translate;
8
+ };
9
+ /**
10
+ * The recognition status bar above the composer. Shows live state and a stop
11
+ * button while recording; the bar renders nothing when idle.
12
+ */
13
+ export declare function VoiceRecognitionBar({ voiceSession, t }: RecognitionBarProps): import("react").JSX.Element | null;
14
+ export {};
@@ -0,0 +1,14 @@
1
+ import type { Context as ClientContext } from '@deepseek-ai/cordis';
2
+ /**
3
+ * Required Client services: the slot registry, the Typert remote hub, and
4
+ * the DSH locale runtime. `remote.betterInput` is mounted by this plugin's
5
+ * own apply() via `ctx.remote.$mount`, so it MUST NOT appear here — the
6
+ * outer inject gates plugin activation and would deadlock waiting for
7
+ * itself. It is declared only on the inner ctx.inject() below, which runs
8
+ * after the mount. Settings reach the browser through `SettingsScopeBinder`
9
+ * (provided by `@deepseek-ai/dsh-client-ui-settings`) and are read inside
10
+ * the settings section slot itself, not via a top-level `settings` service
11
+ * here.
12
+ */
13
+ export declare const inject: string[];
14
+ export declare function apply(ctx: ClientContext): Promise<() => Promise<void>>;
@@ -0,0 +1,80 @@
1
+ import { type BetterInputSettingsPatch, type BetterInputSettingsView, type PolishRoute, type ReasoningEffortInfo } from '../config.js';
2
+ import type { AboutInfoWire, UpdateCheckResultWire } from '../remote-contract.js';
3
+ import type { BetterInputRemote } from '../remote.js';
4
+ export type SettingsStatus = 'loading' | 'ready' | 'error';
5
+ export type SettingsSnapshot = {
6
+ readonly status: SettingsStatus;
7
+ readonly view: BetterInputSettingsView;
8
+ readonly detail: string;
9
+ };
10
+ export type RoutesSnapshot = {
11
+ readonly status: 'loading' | 'ready' | 'error';
12
+ readonly routes: readonly PolishRoute[];
13
+ readonly detail: string;
14
+ };
15
+ /** Keyed by `${provider}\u0000${model}` — undefined effort = loading requested,
16
+ * null effort = load failed, object = resolved efforts. */
17
+ export type EffortsSnapshot = Readonly<Record<string, EffortsEntry>>;
18
+ export type EffortsEntry = {
19
+ readonly status: 'loading' | 'ready' | 'error';
20
+ readonly efforts: readonly ReasoningEffortInfo[];
21
+ readonly defaultEffort?: string;
22
+ readonly detail: string;
23
+ };
24
+ export type AboutSnapshot = {
25
+ readonly status: 'loading' | 'ready' | 'error';
26
+ readonly about: AboutInfoWire;
27
+ readonly detail: string;
28
+ };
29
+ export type UpdateSnapshot = {
30
+ readonly status: 'idle' | 'loading' | 'ready' | 'error';
31
+ readonly update: UpdateCheckResultWire | null;
32
+ readonly detail: string;
33
+ };
34
+ type Listener = () => void;
35
+ /**
36
+ * Settings read/write controller for the settings page and the microphone
37
+ * flow. Owns the remote calls and a simple external store so both the page
38
+ * and the voice button observe the same values. Also caches per-model
39
+ * reasoning-effort metadata loaded lazily through resolveModelEfforts so
40
+ * opening the effort dropdown never double-fetches across renders.
41
+ */
42
+ export declare class SettingsController {
43
+ private readonly remote;
44
+ private settingsSnapshot;
45
+ private routesSnapshot;
46
+ private effortsSnapshot;
47
+ private aboutSnapshot;
48
+ private updateSnapshot;
49
+ private readonly listeners;
50
+ private disposed;
51
+ constructor(remote: BetterInputRemote);
52
+ readonly getSettingsSnapshot: () => SettingsSnapshot;
53
+ readonly getRoutesSnapshot: () => RoutesSnapshot;
54
+ readonly getEffortsSnapshot: () => EffortsSnapshot;
55
+ readonly getAboutSnapshot: () => AboutSnapshot;
56
+ readonly getUpdateSnapshot: () => UpdateSnapshot;
57
+ readonly subscribe: (listener: Listener) => (() => void);
58
+ refreshSettings(): Promise<void>;
59
+ refreshRoutes(): Promise<void>;
60
+ private readonly autoPopulateDefaultRoutesIfNeeded;
61
+ update(patch: BetterInputSettingsPatch): Promise<boolean>;
62
+ /**
63
+ * Lazily fetch reasoning efforts for a route. Results are cached in the
64
+ * controller so changing the effort dropdown back and forth doesn't
65
+ * re-trigger remote calls. Returns a snapshot entry immediately — the
66
+ * caller subscribes via `useEffortsSnapshot` to re-render when the data
67
+ * lands.
68
+ */
69
+ ensureEffortsFor(provider: string, model: string): Promise<void>;
70
+ refreshAbout(): Promise<void>;
71
+ checkForUpdate(): Promise<void>;
72
+ dispose(): void;
73
+ private emit;
74
+ }
75
+ export declare function useSettingsSnapshot(controller: SettingsController): SettingsSnapshot;
76
+ export declare function useRoutesSnapshot(controller: SettingsController): RoutesSnapshot;
77
+ export declare function useEffortsSnapshot(controller: SettingsController): EffortsSnapshot;
78
+ export declare function useAboutSnapshot(controller: SettingsController): AboutSnapshot;
79
+ export declare function useUpdateSnapshot(controller: SettingsController): UpdateSnapshot;
80
+ export {};
@@ -0,0 +1,15 @@
1
+ import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { SettingsController } from './settings-controller.js';
3
+ /** The framework-injected `t` seat for the BetterInput namespace. */
4
+ type Translate = TranslateNS<'better-input'>;
5
+ export type SettingsSectionProps = {
6
+ readonly close: () => void;
7
+ readonly t: Translate;
8
+ readonly settingsController: SettingsController;
9
+ };
10
+ /**
11
+ * The BetterInput settings page. Renders the recognition and polishing
12
+ * configuration; every field edits a local draft and saves on blur/change.
13
+ */
14
+ export declare function BetterInputSettingsSection({ close, settingsController, t }: SettingsSectionProps): import("react").JSX.Element;
15
+ export {};
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Bilingual UI strings for sqs-dsh-better-input (zh/en). Registered as one
3
+ * namespace into the DSH locale runtime; every slot component declares that
4
+ * namespace and reads copy through the framework-injected `t` seat, so the
5
+ * UI follows the DSH settings language switch automatically.
6
+ */
7
+ export type BetterInputStrings = {
8
+ voiceStart: string;
9
+ voiceStop: string;
10
+ voiceBusy: string;
11
+ voiceUnavailable: string;
12
+ listening: string;
13
+ transcribing: string;
14
+ polishing: string;
15
+ voiceFailed: string;
16
+ polishNotConfigured: string;
17
+ polishFailedKeepOriginal: string;
18
+ settingsTitle: string;
19
+ settingsDescription: string;
20
+ loading: string;
21
+ saveFailed: string;
22
+ languageLabel: string;
23
+ languageHint: string;
24
+ languagePlaceholder: string;
25
+ recordingLimitLabel: string;
26
+ recordingLimitHint: string;
27
+ polishLabel: string;
28
+ polishHint: string;
29
+ on: string;
30
+ off: string;
31
+ polishModelLabel: string;
32
+ polishModelHint: string;
33
+ polishModelNone: string;
34
+ polishEffortLabel: string;
35
+ polishEffortHint: string;
36
+ polishPromptLabel: string;
37
+ polishPromptHint: string;
38
+ polishPromptPlaceholder: string;
39
+ showDefaultPrompt: string;
40
+ hideDefaultPrompt: string;
41
+ defaultPromptLabel: string;
42
+ effortDefaultLabel: string;
43
+ effortLoadingLabel: string;
44
+ routesStatus: string;
45
+ routesUnavailable: string;
46
+ optimizeButton: string;
47
+ optimizeBusy: string;
48
+ optimizeFailed: string;
49
+ optimizeEmpty: string;
50
+ optimizePanelTitle: string;
51
+ optimizeOriginalLabel: string;
52
+ optimizeOptimizedLabel: string;
53
+ optimizeAdopt: string;
54
+ optimizeCancel: string;
55
+ optimizeNotConfigured: string;
56
+ optimizeSectionLabel: string;
57
+ optimizeModelLabel: string;
58
+ optimizeModelHint: string;
59
+ optimizeEffortLabel: string;
60
+ optimizeEffortHint: string;
61
+ optimizePromptLabel: string;
62
+ optimizePromptHint: string;
63
+ optimizePromptPlaceholder: string;
64
+ contextTurnsLabel: string;
65
+ contextTurnsHint: string;
66
+ aboutTitle: string;
67
+ aboutVersionLabel: string;
68
+ aboutRepositoryLabel: string;
69
+ aboutChangelogLabel: string;
70
+ aboutLicenseLabel: string;
71
+ checkUpdateButton: string;
72
+ checkingUpdate: string;
73
+ updateUpToDate: string;
74
+ updateAvailable: string;
75
+ updateUnpublished: string;
76
+ updateCheckFailed: string;
77
+ updateCommandLabel: string;
78
+ updateCommandNpxLabel: string;
79
+ updateCommandPick: string;
80
+ voiceSectionLabel: string;
81
+ polishSectionLabel: string;
82
+ templatesTitle: string;
83
+ templatesDescription: string;
84
+ templatesNew: string;
85
+ templatesEdit: string;
86
+ templatesSave: string;
87
+ templatesCancel: string;
88
+ templatesDelete: string;
89
+ templatesDeleteConfirm: string;
90
+ templatesEmpty: string;
91
+ templatesLoadFailed: string;
92
+ templatesRetry: string;
93
+ templatesActionFailed: string;
94
+ templatesNameLabel: string;
95
+ templatesNamePlaceholder: string;
96
+ templatesDescriptionLabel: string;
97
+ templatesDescriptionPlaceholder: string;
98
+ templatesContentLabel: string;
99
+ templatesContentPlaceholder: string;
100
+ templatesTagsLabel: string;
101
+ templatesTagsHint: string;
102
+ };
103
+ export declare const zh: BetterInputStrings;
104
+ export declare const en: BetterInputStrings;
105
+ /** Namespace owning every BetterInput surface string. Registered into the DSH
106
+ * locale runtime; slots declaring this namespace receive the typed `t`. */
107
+ export declare const BETTER_INPUT_NS = "better-input";
108
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
109
+ /** BetterInput dictionary keys (one shared key set, zh/en bilingual). */
110
+ interface LocaleNamespaceMap {
111
+ 'better-input': keyof BetterInputStrings;
112
+ }
113
+ }