dsh-speak 1.0.0 → 1.2.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.
- package/LICENSE +21 -21
- package/README.md +289 -186
- package/README.zh-CN.md +274 -177
- package/adapters/dsh/install.ps1 +81 -81
- package/adapters/dsh/speech-hook.js +142 -133
- package/docs/DESIGN.md +270 -245
- package/docs/DESIGN.zh-CN.md +253 -232
- package/engine/speak.ps1 +76 -76
- package/engine/speak.sh +89 -0
- package/engine/speech-prompt.ps1 +22 -22
- package/engine/speech-summary.ps1 +27 -27
- package/package.json +46 -43
package/docs/DESIGN.zh-CN.md
CHANGED
|
@@ -1,232 +1,253 @@
|
|
|
1
|
-
# DESIGN.zh-CN.md — dsh-speak:为 AI 编程 harness 提供语音播报
|
|
2
|
-
|
|
3
|
-
状态:**草稿** — 本文档描述当前(已验证的)本地实现与本文档仓库的目标通用结构,
|
|
4
|
-
是 README 的参考依据。
|
|
5
|
-
|
|
6
|
-
(英文版:docs/DESIGN.md)
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## 1. 为什么
|
|
11
|
-
|
|
12
|
-
Agent 工具会跑长任务(构建、测试、迁移、批量修改),而你正在忙别的。回复终于落地时,
|
|
13
|
-
你不得不反复看屏幕。**dsh-speak**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
最初实现是在本地 DSH(DeepSeek Harness)环境里搭建并验证过的。本仓库把这份可用的
|
|
17
|
-
实现通用化为:
|
|
18
|
-
|
|
19
|
-
- **与 harness 无关的引擎**(PowerShell + Windows SAPI5
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
|
141
|
-
|
|
|
142
|
-
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
|
152
|
-
|
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
|
161
|
-
|
|
|
162
|
-
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
`
|
|
172
|
-
`
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
npm
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
1
|
+
# DESIGN.zh-CN.md — dsh-speak:为 AI 编程 harness 提供语音播报
|
|
2
|
+
|
|
3
|
+
状态:**草稿** — 本文档描述当前(已验证的)本地实现与本文档仓库的目标通用结构,
|
|
4
|
+
是 README 的参考依据。
|
|
5
|
+
|
|
6
|
+
(英文版:docs/DESIGN.md)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. 为什么
|
|
11
|
+
|
|
12
|
+
Agent 工具会跑长任务(构建、测试、迁移、批量修改),而你正在忙别的。回复终于落地时,
|
|
13
|
+
你不得不反复看屏幕。**dsh-speak** 通过系统语音合成(Windows SAPI5 / macOS `say`)
|
|
14
|
+
把最终回复读出来,让你*不用看屏幕* 就知道长任务完成了——以及结果是什么。
|
|
15
|
+
|
|
16
|
+
最初实现是在本地 DSH(DeepSeek Harness)环境里搭建并验证过的。本仓库把这份可用的
|
|
17
|
+
实现通用化为:
|
|
18
|
+
|
|
19
|
+
- **与 harness 无关的引擎**(PowerShell + Windows SAPI5 / bash + macOS `say`),
|
|
20
|
+
任意进程都可调用;
|
|
21
|
+
- **适配层**,把 harness 专属事件转成引擎调用(DSH 会话事件、Claude Code Stop hook…)。
|
|
22
|
+
|
|
23
|
+
## 2. 目标 / 非目标
|
|
24
|
+
|
|
25
|
+
目标:
|
|
26
|
+
|
|
27
|
+
- DSH 用户一键安装(引擎 + 插件 + 注册)。
|
|
28
|
+
- 引擎可通过一行命令行从任意 harness 调用。
|
|
29
|
+
- 尽力而为的播报:绝不抛错、绝不阻塞 harness、绝不破坏会话。
|
|
30
|
+
- 自然语音:Windows 11 内置自然语音包,或 Windows 10 上经 NaturalVoiceSAPIAdapter
|
|
31
|
+
注册;优雅回退到系统自带语音。
|
|
32
|
+
|
|
33
|
+
非目标(当前阶段):
|
|
34
|
+
|
|
35
|
+
- Windows 引擎(`speak.ps1`)+ macOS 引擎(`speak.sh`,系统自带 `say`)均已
|
|
36
|
+
**正式支持**(macOS 自 1.2.0 起随 npm 包分发)。不支持 Linux/无头 TTS。
|
|
37
|
+
- 在仓库内打包 NaturalVoiceSAPIAdapter(仅 Windows 10 需要)或语音数据——
|
|
38
|
+
它们是前置依赖,不打进仓库。
|
|
39
|
+
- 流式/队列播放、按音色输出音频文件、非中文音色管理。
|
|
40
|
+
|
|
41
|
+
## 3. 架构
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
+--------------------------------------------------------------+
|
|
45
|
+
| harness |
|
|
46
|
+
| (DSH web 应用 | Claude Code | 任何有 shell 的东西) |
|
|
47
|
+
+--------+-----------------------------+-----------------------+
|
|
48
|
+
| |
|
|
49
|
+
| 会话事件 | Stop hook JSON (stdin)
|
|
50
|
+
v v
|
|
51
|
+
+------------------+ +--------------------------+
|
|
52
|
+
| adapters/dsh/ | | adapters/claude-code/ |
|
|
53
|
+
| speech-hook.js | | stop-hook.ps1 |
|
|
54
|
+
| (事件过滤、 | | (transcript 提取) |
|
|
55
|
+
| 节流、取消) | +------------+-------------+
|
|
56
|
+
+--------+---------+ |
|
|
57
|
+
| 文本 | 文本
|
|
58
|
+
v v
|
|
59
|
+
+---------------------------------------------------------------+
|
|
60
|
+
| engine/speak.ps1 / speak.sh(与 harness 无关) |
|
|
61
|
+
| 文本 -> 清洗(markdown/emoji/长度) -> 系统语音合成 |
|
|
62
|
+
+--------------------+------------------------------------------+
|
|
63
|
+
| |
|
|
64
|
+
v v
|
|
65
|
+
Windows SAPI5 (System.Speech) macOS say(系统音色):
|
|
66
|
+
* 优先:自然语音 — Windows 11 内置 * 默认跟随系统声音(可含
|
|
67
|
+
语音包,或 Windows 10 上经 Siri 音色,`say -v '?'`
|
|
68
|
+
NaturalVoiceSAPIAdapter 注册 不列出,无法按名选择)
|
|
69
|
+
(如 "Microsoft Xiaoxiao") * 或 -v 指定经典音色
|
|
70
|
+
* 回退:任意 zh 语音(如 "Microsoft (Eddy/Tingting/Flo…)
|
|
71
|
+
Huihui") * 无音量参数(随系统)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3.1 引擎 — `engine/speak.ps1`(macOS 上为 `engine/speak.sh`)
|
|
75
|
+
|
|
76
|
+
新适配器唯一需要打交道的文件。两种输入模式:`-Text "..."` 直接传入,或
|
|
77
|
+
`-File C:\path\msg.txt`(UTF-8)。另有 `-Volume`、`-Rate`、`-MaxChars`、
|
|
78
|
+
`-LongTextMessage`(见 §5)。在 macOS 上插件会自动改选 `speak.sh`
|
|
79
|
+
(`say` 命令;默认音色跟随系统——Siri 音色"声音 1-4"未暴露给 `say`,
|
|
80
|
+
需用 `-v` 强制指定名字;无音量参数)。
|
|
81
|
+
|
|
82
|
+
处理管线(按顺序):
|
|
83
|
+
|
|
84
|
+
1. **读取**文本(读文件一律 UTF-8)。
|
|
85
|
+
2. **剥离 markdown** — 代码块、行内代码、链接、裸 URL、强调符号。
|
|
86
|
+
3. **剥离 emoji / 不可打印字符** — 只保留中文汉字、中文标点、全角区间、
|
|
87
|
+
ASCII 可打印(正则 `[^一-龥 -〿- - -~]`)。
|
|
88
|
+
4. **压缩空白。**
|
|
89
|
+
5. **长度守卫** — 清洗后文本超过 `MaxChars`(默认 300)时,替换为
|
|
90
|
+
`LongTextMessage`(默认:`本次播报内容较长,请自行阅读。`)。
|
|
91
|
+
6. **朗读** — `System.Speech.Synthesis.SpeechSynthesizer`,应用音量/语速,
|
|
92
|
+
选择最佳 zh 自然语音,然后 `Speak()`。
|
|
93
|
+
|
|
94
|
+
引擎对适配器的契约:
|
|
95
|
+
|
|
96
|
+
- 总是以 0 退出;失败路径不向 stdout/stderr 写内容;
|
|
97
|
+
- 同步(读完整个句子才返回,或任何失败时立即返回);
|
|
98
|
+
- 沙箱进程可安全调用,*前提* 是调用方不需要在 harness 沙箱内再嵌套一个
|
|
99
|
+
`powershell.exe`(见 §6.3)。
|
|
100
|
+
|
|
101
|
+
### 3.2 DSH 适配层 — `adapters/dsh/speech-hook.js`
|
|
102
|
+
|
|
103
|
+
一个 DSH web 配置插件(Cordis 插件),通过 `cordis.patch.yml` 注册。DSH 没有
|
|
104
|
+
"回复完成" hook,所以插件观察会话事件流:
|
|
105
|
+
|
|
106
|
+
- 监听 `session/event`;
|
|
107
|
+
- 过滤 `assistant/message` 且 `surfaceOp == 'append'` 的事件;
|
|
108
|
+
- 只提取 `text` 内容块(reasoning / tool_use 块跳过);
|
|
109
|
+
- 缓冲文本并启动节流定时器(默认 1500 ms)以合并同一回复的多步消息;
|
|
110
|
+
- `tool/call` 事件会**取消**待播报——该轮 assistant 文本是过程旁白,不是最终回复;
|
|
111
|
+
- 触发时:把文本写入临时文件,`spawn` 出
|
|
112
|
+
`powershell.exe -File <engine> -File <tmp>`,带 `windowsHide` + `stdio: 'ignore'`,
|
|
113
|
+
绝不阻塞 harness;退出后删除临时文件。
|
|
114
|
+
|
|
115
|
+
注册片段(`install.ps1` 也会自动完成):
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
# ~/.dsh/profiles/web/cordis.patch.yml
|
|
119
|
+
- insert:
|
|
120
|
+
- id: speech-hook
|
|
121
|
+
# 把 <your-username> 换成你的 Windows 用户名
|
|
122
|
+
name: 'file:///C:/Users/<your-username>/.dsh/profiles/web/plugins/speech-hook.js'
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
> Node 的 ESM 加载器不接受 Windows 绝对路径作为插件名——必须用
|
|
126
|
+
> `file:///C:/...` URL 形式。
|
|
127
|
+
|
|
128
|
+
### 3.3 Claude Code 适配层 — `adapters/claude-code/stop-hook.ps1`
|
|
129
|
+
|
|
130
|
+
Claude Code *确实*有 Stop hook。hook JSON(含 `transcript_path`)从 stdin 传入;
|
|
131
|
+
脚本从后往前扫描 transcript,找最后一条含文本的 assistant 消息(末尾常常是纯
|
|
132
|
+
工具调用),写入临时文件后在自己独立的隐藏 powershell 进程里启动引擎,hook 立即
|
|
133
|
+
返回。(此处异步 spawn 是安全的——§6.3 的嵌套限制仅存在于 DSH 沙箱内。)
|
|
134
|
+
|
|
135
|
+
## 4. 事件流真值表(DSH)
|
|
136
|
+
|
|
137
|
+
| assistant 轮次包含 | 是否播报 |
|
|
138
|
+
| --------------------------------- | -------- |
|
|
139
|
+
| 最终文本回复,无工具调用 | ✅ 节流后播报 |
|
|
140
|
+
| 文本 + tool/call(s) | ❌(取消——旁白) |
|
|
141
|
+
| 只有 reasoning,无文本 | ❌(无 text 块) |
|
|
142
|
+
| 流式分块 | ❌(被过滤) |
|
|
143
|
+
|
|
144
|
+
## 5. 配置参考
|
|
145
|
+
|
|
146
|
+
### 引擎(`speak.ps1` 参数)
|
|
147
|
+
|
|
148
|
+
| 参数 | 默认值 | 含义 |
|
|
149
|
+
| ---- | ------ | ---- |
|
|
150
|
+
| `-Text` | `''` | 内联文本(`-File` 为空时使用) |
|
|
151
|
+
| `-File` | `''` | 要读取的 UTF-8 文件 |
|
|
152
|
+
| `-Volume` | `50` | 0–100 |
|
|
153
|
+
| `-Rate` | `1` | 语速(SAPI 刻度) |
|
|
154
|
+
| `-MaxChars` | `300` | 超过此长度时替换为 `LongTextMessage` |
|
|
155
|
+
| `-LongTextMessage` | `本次播报内容较长,请自行阅读。` | 超长文本时改念这句 |
|
|
156
|
+
|
|
157
|
+
### DSH 插件(环境变量)
|
|
158
|
+
|
|
159
|
+
| 变量 | 默认值 | 含义 |
|
|
160
|
+
| ---- | ------ | ---- |
|
|
161
|
+
| `DSH_SPEAK_ENGINE` | 空(自动解析) | 引擎路径覆盖;否则按"包内 `engine/<平台脚本>` → `~/.dsh/hooks/<平台脚本>`"顺序解析(Windows 为 `speak.ps1`,macOS 为 `speak.sh`) |
|
|
162
|
+
| `DSH_SPEAK_THROTTLE_MS` | `1500` | 播报前的合并延迟(毫秒) |
|
|
163
|
+
|
|
164
|
+
## 6. 踩坑记录(来之不易;不要随意"修复")
|
|
165
|
+
|
|
166
|
+
| # | 坑 | 现象 | 修复/规则 |
|
|
167
|
+
|---|-----|------|-----------|
|
|
168
|
+
| 6.1 | emoji / 代理对进入 `Speak()` | **静默**——没声音也没报错 | 朗读前剥离非 CJK/ASCII 字符(引擎第 3 步) |
|
|
169
|
+
| 6.2 | 文本超过适配器单次 `Speak` 上限(约 375–470 字) | **静默**——整段被丢弃,而不是截断 | 300 字长度守卫(引擎第 5 步) |
|
|
170
|
+
| 6.3 | 在 DSH 沙箱进程内嵌套 `Start-Process powershell` | 静默失败,无异常 | DSH 链路在适配器边界保持同步(插件只 spawn 一次;`speech-summary.ps1` 同步调用 `speak.ps1`) |
|
|
171
|
+
| 6.4 | `cordis.patch.yml` 里插件名用 Windows 原始路径 | 插件加载失败 | 用 `file:///C:/...` URL 形式 |
|
|
172
|
+
| 6.5 | 只按名字匹配适配器音色 | 回退到机械感的系统语音 | 用 `Name + Description` 匹配 `Natural\|Online` |
|
|
173
|
+
| 6.6 | 用 ANSI 读写播报文本 | 乱码或完全无声 | 一律 UTF-8(`[System.IO.File]::ReadAllText(..., UTF8)`) |
|
|
174
|
+
| 6.7 | 仓库内 `.sh` 被 git 按 `core.autocrlf=true` 检出为 CRLF,`npm pack` 打包的是**工作区**文件 | 发布包里的 `speak.sh` 在 macOS 上 bash 语法错误(`command not found`、`syntax error near {`),静默失败 | `.gitattributes` 里 `*.sh text eol=lf` 锁定 LF(发布前 `file engine/speak.sh` 确认无 CRLF) |
|
|
175
|
+
| 6.8 | 日志路径写死 `/tmp` | macOS 上 `os.tmpdir()` 是 `/var/folders/.../T`,`/tmp` 里找不到日志 | 日志路径按 `os.tmpdir()`(= `$TMPDIR`)查找 |
|
|
176
|
+
|
|
177
|
+
## 7. 扩展
|
|
178
|
+
|
|
179
|
+
### 新的引擎后端
|
|
180
|
+
引擎是 TTS 后端的唯一接缝。未来可以加 `speak-edge.ps1`(封装 `edge-tts`)或
|
|
181
|
+
`speak-piper.ps1`(本地离线模型)——同样的参数契约、同样的清洗管线,只换
|
|
182
|
+
`Speak()` 这一步。适配层永远不用改。
|
|
183
|
+
|
|
184
|
+
### 新的 harness 适配层
|
|
185
|
+
实现思路:*捕获最终回复文本 → 调用引擎*。DSH(事件流)、Claude Code(Stop
|
|
186
|
+
hook)、任意 shell harness(Agent 自己调 `speech-summary.ps1`)就是三种参考范式。
|
|
187
|
+
|
|
188
|
+
## 8. 项目定位
|
|
189
|
+
|
|
190
|
+
本项目**刻意不是**一个持续迭代的产品。它记录了一条被验证过的、让 harness
|
|
191
|
+
开口说话的实现路径:一个小引擎 + 两种可复用的适配范式(事件流 / Stop hook)。
|
|
192
|
+
如果你需要更多(音色管理界面、更多后端、跨平台),把引擎当作接缝在其上扩展——
|
|
193
|
+
本仓库保持为最小、自包含的参考实现。
|
|
194
|
+
|
|
195
|
+
## 9. 发布为 npm 插件(附录)
|
|
196
|
+
|
|
197
|
+
DSH 的插件机制基于 Cordis,官方安装树外插件的路径是
|
|
198
|
+
`dsh plugin --profile web add <包名>`(由 pnpm 管理 profile 依赖)。本仓库已为
|
|
199
|
+
该路径做好准备:
|
|
200
|
+
|
|
201
|
+
### 包结构
|
|
202
|
+
|
|
203
|
+
- `package.json` — `name: dsh-speak`,`main: adapters/dsh/speech-hook.js`,
|
|
204
|
+
`files` 白名单精确列出发布内容(插件、`engine/*.ps1`、`install.ps1`、文档、
|
|
205
|
+
LICENSE)。`prepublishOnly` 会对插件跑 `node --check`。
|
|
206
|
+
- 插件入口就是文件安装已用的同一个 CJS 模块(`module.exports = { apply(ctx) }`)
|
|
207
|
+
——发布**不需要改任何代码**。
|
|
208
|
+
|
|
209
|
+
### 引擎解析(npm 安装 vs 文件安装)
|
|
210
|
+
|
|
211
|
+
`speech-hook.js` 按以下顺序定位 `engine/speak.ps1`:
|
|
212
|
+
|
|
213
|
+
1. `DSH_SPEAK_ENGINE` 环境变量覆盖;
|
|
214
|
+
2. 相对插件文件解析 `<包>/engine/speak.ps1`——同时覆盖仓库检出和
|
|
215
|
+
`npm install` 后的 `node_modules/dsh-speak/`;
|
|
216
|
+
3. 旧的 `%USERPROFILE%\.dsh\hooks\speak.ps1`(文件安装的位置)。
|
|
217
|
+
|
|
218
|
+
因为引擎随 npm 包分发,用户只需 `dsh plugin --profile web add dsh-speak`
|
|
219
|
+
一条命令,无需额外拷贝。
|
|
220
|
+
|
|
221
|
+
### 发布步骤(维护者)
|
|
222
|
+
|
|
223
|
+
```powershell
|
|
224
|
+
npm login --registry=https://registry.npmjs.org # 官方源,npm 强制要求 2FA
|
|
225
|
+
npm publish # publishConfig.registry 已锁定官方源
|
|
226
|
+
# 后续每次发布前先在 package.json 里 bump "version"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
> 中国区注意:如果你的全局 `.npmrc` 指向镜像(如 `registry.npmmirror.com`),
|
|
230
|
+
> `npm login`/`npm publish` 会打到镜像站——镜像**不接受发布**。本包的
|
|
231
|
+
> `publishConfig.registry` 已把发布锁定到官方源;登录时也要用官方源。
|
|
232
|
+
|
|
233
|
+
### 安装步骤(DSH 用户)
|
|
234
|
+
|
|
235
|
+
```powershell
|
|
236
|
+
dsh plugin --profile web add dsh-speak
|
|
237
|
+
# 然后在 ~/.dsh/profiles/web/cordis.patch.yml 注册:
|
|
238
|
+
# - insert:
|
|
239
|
+
# - id: speech-hook
|
|
240
|
+
# name: 'dsh-speak'
|
|
241
|
+
# 重启 DSH web 应用
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
> 没装 pnpm?`dsh plugin` 内部转发给 pnpm;等价命令(效果相同:包进入 profile
|
|
245
|
+
> 的 dependencies 与 node_modules):
|
|
246
|
+
>
|
|
247
|
+
> - Windows(PowerShell):
|
|
248
|
+
> `npm install --prefix "$env:USERPROFILE\.dsh\profiles\web" dsh-speak`
|
|
249
|
+
> - macOS(bash):
|
|
250
|
+
> `npm install --prefix "$HOME/.dsh/profiles/web" dsh-speak`
|
|
251
|
+
>
|
|
252
|
+
> 改 `cordis.patch.yml` 时 patch 监视器会热更新插件树——已验证:插件以 npm 包内
|
|
253
|
+
> 引擎路径重新 apply,注册切换本身无需重启(macOS 上 1.2.0 实测通过)。
|