@dnalec/dsh-auto-approve 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/CHANGELOG.md +64 -0
- package/README.md +21 -12
- package/README.zh.md +21 -10
- package/client.js +300 -54
- package/locales.mjs +40 -4
- package/package.json +3 -2
- package/src/index.mjs +99 -16
- package/src/preset-patch.mjs +331 -76
- package/src/rules.mjs +214 -70
- package/src/util.mjs +43 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
> 如果你用 0.2.0 装过、且 profile patch 还是出厂模板(注释 + `[]`),请升级:0.2.0 会把预设块追加在 `[]` 之后,写出 DSH 解析不了的 YAML,下次 `dsh web` 起不来。
|
|
6
|
+
> 0.2.1 还修掉了沙箱模式静默失效、非 web 组合不挂载、判定可被卡片回显诱导放行等问题。
|
|
7
|
+
|
|
8
|
+
### Fixes(本仓库 review 后的修复)
|
|
9
|
+
|
|
10
|
+
- **全新安装不再写坏 profile patch**:空 patch 的判定改为「剥掉注释后为空数组」,`注释 + []` 这种 DSH 出厂模板会被整段替换,不再产出 `[]` 后面跟条目的非法 YAML(那会让下次 `dsh web` 启动直接解析失败)。同时修掉「注释里提过 `auto-approve:` 就以为已配置」的子串假阳性。
|
|
11
|
+
- **沙箱模式不再静默失效**:`danger-full-access` 之类手改值会被改写;块里没有 `sandbox:` 行时返回 `err.presetSandboxMissing`,不再假装成功(以前 UI 说只读、实际全权限且不提示重启)。
|
|
12
|
+
- **profile 路径不再硬编码 `profiles/web`**:从 `ctx.baseUrl`(app-boot 锚在 profile 目录)推导,可用插件配置 `profilePatch` 覆盖;写入失败会打印具体文件与原因。
|
|
13
|
+
- **`inject` 去掉 `webServer`**:它是 fiber 的必需服务而 `webserver` 行只在 web-app bundle 里,之前 headless / acp / sdk 组合下整个审批门控都不会挂载。
|
|
14
|
+
- **判官卡片加围栏**(`<<<TOOL_CARD` … `TOOL_CARD>>>`):出厂提示词明确声明围栏内是不可信数据;类别解析改为取**最后一个**「类别: id」行,卡片回显不能覆盖结论。
|
|
15
|
+
- **取消即停**:判定过程观察 `req.signal`,请求取消后不再跑完模型调用、也不再重试(返回 `cancelled`,不弹人工框)。
|
|
16
|
+
- **凭据关键词边界**:`.env` / `.netrc` 增加「路径干草」放宽匹配(`prod.env`、`x.env` 命中;命令里的 `process.env` 仍不误伤);`id_rsa.pub` / `id_ed25519` 后跟 `.pub` 不再当凭据。
|
|
17
|
+
- **迁移只增不删**:不再从用户文件里删掉 `shutdown` / `reboot` 等旧预置词(分不清出厂继承与用户手写);v10/v11 的出厂文案刷新改为逐字段比对出厂中/英原文,只刷新仍是原文的字段,不覆盖用户自定义 label/description。
|
|
18
|
+
- **缓存参数只按会话键取**:有 sessionId 时不再回落裸 `callId`,避免跨会话串味;裸键仍会在命中时清理。
|
|
19
|
+
- **推理档位留输出预算**:带 `reasoningEffort` 时 `maxTokens` 从 256 提到 1024,避免推理 token 吃光预算导致全量转人工。
|
|
20
|
+
- **访问模式徽标可撤销**:切走「自动审批」后盾牌+A 会被摘掉;扫描忽略文本节点,不再对每次文本变化做整篇 `querySelectorAll`。
|
|
21
|
+
- 新增:`CI`(push/PR 跑 test + check)、`npm run locales:sync`(client.js 内联字典由 `locales.mjs` 生成,`npm run check` 校验同步)。
|
|
22
|
+
|
|
23
|
+
### 复审补丁(修复本身的问题)
|
|
24
|
+
|
|
25
|
+
- 空 patch 判定再收紧:`[] # empty`(行尾注释)、`---` / `...` 文档标记也算空;`description: |` 之类**块标量**里的同名行不再被当成「已配置」。
|
|
26
|
+
- 预设插入位置改为按 `presets:` 的相对缩进计算,不再写死 4/6/8 空格:`- insert:` 形式(缩进的 `- id: permission`)、CRLF、`presets:` 下还没有子键、行尾带注释的 permission 行都能正确落位,不会追加出第二个 permission 行。
|
|
27
|
+
- `profilePatchFromBaseUrl` 用 URL 的 pathname 判断目录(`file:///x/?a=1` 不再少切一段),根目录 / 非法 URL 一律回落。
|
|
28
|
+
- `save-plugin` 改成事务式:沙箱写不进 patch 就回滚 `config.json`,避免「配置说只读、patch 是全权限」。
|
|
29
|
+
- 判官超时/重试的取消链接加了防御(`addEventListener` 不存在时不炸)、并补了竞态窗口;新增用例覆盖取消、卡片回显注入、决策事件、关键词改名、跨会话事件过滤。
|
|
30
|
+
|
|
31
|
+
### 复审第二轮(实机截图反馈 + 预设表冻结)
|
|
32
|
+
|
|
33
|
+
- **访问模式下拉里的「自动审批」现在也有盾牌+A**:React 先插入空按钮、再把标签塞进去,
|
|
34
|
+
旧扫描只看 `addedNodes`,那条记录的 target 是标签自己,按钮永远不会被重新评估。
|
|
35
|
+
现在对 childList 记录额外沿 target 向上找最近的触发器/menu 项重扫(不是扫整棵子树,
|
|
36
|
+
流式输出时不会全量查询)。用 jsdom 复现并验证:静态渲染、分步提交、切走撤销、流式 20 次追加只触发 3 次子树查询。
|
|
37
|
+
- **下拉项徽标颜色对齐 DSH**:菜单行的注入图标改用 `var(--dsw-alias-label-tertiary)`(DSH `.itemIcon` 用的同一个 token),
|
|
38
|
+
否则会继承菜单按钮的 `label-primary`,比旁边三个图标明显更黑;触发器保持 `color:inherit`(DSH `.trigger` 就是 `label-secondary`,与 `.triggerIcon` 一致)。
|
|
39
|
+
- **预设表冻结新增检测**:插件写进 profile patch 的 `permission` 行会整块替换 base 的 config
|
|
40
|
+
(patch 语义不做深合并),DSH 新增出厂预设不会自动出现。启动时读 `@deepseek-ai/dsh-base`
|
|
41
|
+
的 `cordis.patch.yml` 比对,缺哪些预设就打印日志并在设置页显示一张卡片(只提示,不自动改写用户文件)。
|
|
42
|
+
|
|
43
|
+
### 发布前复审(0.2.1 定稿)
|
|
44
|
+
|
|
45
|
+
- **文档结束标记不再写坏 patch**:列 0 的 `...`(以及 `---`)在写入前一律去掉。以前在 `...` 后面追加条目会产出**多文档** YAML,DSH 的 parsePatchList 直接抛错。
|
|
46
|
+
- **没有 `presets:` 的 permission 行不再变成死路**:行里有块状 `config:` 时把出厂表插进去(保留用户已有的 `defaultPreset` 等键);连 `config` 都没有时追加整块;只有行内 flow config 才明确报 `err.noPresetsKey`(文本插入不安全,不猜)。
|
|
47
|
+
- **判定不再能被卡片回显诱导放行**:解析前先剥掉 `<<<TOOL_CARD … TOOL_CARD>>>` 围栏(未闭合的开围栏之后一律丢弃)。以前模型整段复述卡片时,卡片里的 `类别: safe` 会成为「最后一个匹配」。
|
|
48
|
+
- 「是否已配置」只看 permission 行自己的 `presets` 块:别的插件 presets 里的同名键不再被误认。
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- Keyword layer: `.pem` matches as a file extension (`certs/server.pem`).
|
|
53
|
+
- Approval history shows empty write/edit bodies as `(empty)` / `(空)`, plus extra tool-card fields (input/text/body/message/pattern/selector/workdir).
|
|
54
|
+
- Settings: criteria label/description remount independently; add-forms clear only after RPC success; sandbox mode is not optimistic; judge catalog/info ignore stale responses.
|
|
55
|
+
- 关键词:`.pem` 按扩展名匹配(`certs/server.pem`)。
|
|
56
|
+
- 审批历史展示空写入/替换为 `(空)` / `(empty)`,并补齐工具卡片其它字段。
|
|
57
|
+
- 设置页:审核表标签/说明各自换 key;添加表单失败不清空;模式点选失败不改本地状态。
|
|
58
|
+
- Settings: mode applies on click (no extra Save). Judge model, prompt, and timeout share one Save. Status flashes at the top.
|
|
59
|
+
- 设置页:模式点选即写入;审核模型 / 提示词 / 超时共用一个保存。反馈条置顶。
|
|
60
|
+
- Settings: editable judge prompt per language, with restore-default. Empty `judgePrompts.zh` / `en` uses the shipped template (`{{criteria}}` inserts the current table).
|
|
61
|
+
- Shipped judge prompt is table-agnostic: generic classify rules only; no default criterion ids. Table-specific exceptions live in row descriptions.
|
|
62
|
+
- 设置页可按语言改审核提示词并恢复默认;空则用该语言出厂模板。
|
|
63
|
+
- 出厂提示词与审核表解耦,不再点名默认类别 id。
|
|
64
|
+
- Access chip: plugin client paints a shield+A on Auto-approve (no DSH patch).
|
|
65
|
+
- 访问模式芯片:插件客户端给「自动审批」补盾牌+A,不改 DSH。
|
|
66
|
+
|
|
3
67
|
## 0.2.0
|
|
4
68
|
|
|
5
69
|
### Breaking
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) plugin tha
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
dsh plugin --profile web add github:DNAlec/dsh-auto-approve#v0.2.
|
|
10
|
+
dsh plugin --profile web add github:DNAlec/dsh-auto-approve#v0.2.1
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Or from npm, after a tagged release:
|
|
@@ -16,24 +16,25 @@ Or from npm, after a tagged release:
|
|
|
16
16
|
dsh plugin --profile web add @dnalec/dsh-auto-approve
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
Restart `dsh web`. The first start adds the **Auto-approve** permission preset.
|
|
19
|
+
Restart `dsh web`. The first start adds the **Auto-approve** permission preset to the current profile's `cordis.patch.yml`; if that write fails, the log line names the file and the reason.
|
|
20
20
|
|
|
21
21
|
## Setup
|
|
22
22
|
|
|
23
23
|
Settings → **Auto-approve**:
|
|
24
24
|
|
|
25
|
-
1. **Mode** — in-workspace writes skip approval (`workspace-write`, recommended), or send them through the judge (`read-only`).
|
|
25
|
+
1. **Mode** — in-workspace writes skip approval (`workspace-write`, recommended), or send them through the judge (`read-only`). Clicking a mode writes it; restart `dsh web`, then re-select **Auto-approve** or start a new session.
|
|
26
26
|
2. **Keywords** and **criteria table** as needed. Restore default criteria loads the shipped pack for the selected judge-prompt language.
|
|
27
|
-
3. **Judge model** — empty follows the deployment default.
|
|
28
|
-
4.
|
|
27
|
+
3. **Judge model** — empty follows the deployment default. Saved together with the prompt and timeout.
|
|
28
|
+
4. **Judge prompt** — language-specific built-in default, editable; restore default writes that language’s shipped template. Use `{{criteria}}` to insert the current criteria table.
|
|
29
|
+
5. Set the session permission to **Auto-approve**.
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
## How it works
|
|
32
33
|
|
|
33
34
|
Runs only when the session preset is Auto-approve. With `workspace-write`, in-workspace writes never reach approval. `danger-full-access` uses the same pipeline. Missing or truncated tool args go to a human and are never auto-allowed.
|
|
34
35
|
|
|
35
|
-
1. **Keywords** (reject > human > allow). Match tool name, command, path, and working directory. Allow words do not match the tool name or the session directory. Shipped reject words cover disaster commands (`rm -rf`, `git push -f`, `drop table`, `dd of=`), approval-config paths, and credential paths such as `.env` / `id_rsa`.
|
|
36
|
-
2. **Criteria table**. The judge model sees the same fields as the Web tool card
|
|
36
|
+
1. **Keywords** (reject > human > allow). Match tool name, command, path, and working directory. Allow words do not match the tool name or the session directory. Shipped reject words cover disaster commands (`rm -rf`, `git push -f`, `drop table`, `dd of=`), approval-config paths, and credential paths such as `.env` / `id_rsa`. Dotfiles are matched loosely against path fields, so `prod.env` counts while `process.env` in a command does not; `id_rsa.pub` is not treated as a credential.
|
|
37
|
+
2. **Criteria table**. The judge model sees the same fields as the Web tool card, fenced as untrusted data; it outputs a category and the plugin runs that row’s action. Parse failure or timeout goes to a human. The category is read from the **last** `Category:` line, so a tool card echoed back into the answer cannot override the verdict.
|
|
37
38
|
|
|
38
39
|
Default criteria (actions are editable; **Other** cannot be deleted):
|
|
39
40
|
|
|
@@ -48,9 +49,7 @@ Default criteria (actions are editable; **Other** cannot be deleted):
|
|
|
48
49
|
| safe | Safe/routine reversible | allow |
|
|
49
50
|
| other | Other (unsure) | human |
|
|
50
51
|
|
|
51
|
-
Judge prompt language (Chinese or English) only changes the framework
|
|
52
|
-
|
|
53
|
-
## Data
|
|
52
|
+
Judge prompt language (Chinese or English) only changes the framework, card labels, and that language’s default prompt, not the current table. The shipped prompt is generic classify rules and does not name default category ids; table-specific exceptions live in row descriptions. Custom prompts are stored per language.
|
|
54
53
|
|
|
55
54
|
## Data
|
|
56
55
|
|
|
@@ -59,7 +58,7 @@ Under `$DSH_HOME` (default `~/.dsh/`), never committed:
|
|
|
59
58
|
| Path | Purpose |
|
|
60
59
|
|---|---|
|
|
61
60
|
| `auto-approve/allowlist.json` | Keywords, criteria, judge timeout |
|
|
62
|
-
| `auto-approve/config.json` | Judge model and plugin settings |
|
|
61
|
+
| `auto-approve/config.json` | Judge model, prompt language/custom prompts, and plugin settings |
|
|
63
62
|
| `auto-approve/audit.log` | `ALLOW` / `REJECT` / `HUMAN` / `FAILED` / `OUTCOME` |
|
|
64
63
|
| `auto-approve/events.jsonl` | Approval tab events |
|
|
65
64
|
|
|
@@ -72,20 +71,30 @@ Corrupt files are not overwritten. Uninstalling the plugin does not delete this
|
|
|
72
71
|
config:
|
|
73
72
|
onlyAutoApprovePreset: true
|
|
74
73
|
presetSandbox: workspace-write # or read-only
|
|
74
|
+
judgePromptLang: zh # or en: prompt framework, card labels, shipped pack
|
|
75
|
+
judgePrompts: # optional per-language template override; '' = shipped
|
|
76
|
+
zh: ''
|
|
77
|
+
en: ''
|
|
75
78
|
judge:
|
|
76
79
|
provider: ''
|
|
77
80
|
model: ''
|
|
78
81
|
reasoningEffort: ''
|
|
79
82
|
timeoutMs: 20000
|
|
83
|
+
# profilePatch: /home/me/.dsh/profiles/web/cordis.patch.yml # optional explicit override
|
|
80
84
|
```
|
|
81
85
|
|
|
82
86
|
Empty judge fields follow the deployment default. With no usable route, that request goes to a human. Settings “judge timeout” writes `allowlist.json` and wins at runtime.
|
|
83
87
|
|
|
88
|
+
The auto-approve preset is written into the running profile's patch file, resolved from the profile directory (`ctx.baseUrl`); `profilePatch` pins it explicitly when a deployment keeps profiles elsewhere.
|
|
89
|
+
|
|
90
|
+
A patch replaces a row's whole `config`, so the permission table this profile uses is the copy the plugin wrote (the shipped presets plus `auto-approve`). If a DSH upgrade adds or renames a shipped preset, startup compares against `@deepseek-ai/dsh-base`'s patch, logs the missing names, and the settings page shows a card telling you to update the plugin or merge that row by hand. The plugin never rewrites your file on its own.
|
|
91
|
+
|
|
84
92
|
## Development
|
|
85
93
|
|
|
86
94
|
```sh
|
|
87
95
|
node --test tests/*.test.mjs
|
|
88
|
-
npm run check
|
|
96
|
+
npm run check # syntax + locale sync check
|
|
97
|
+
npm run locales:sync # regenerate client.js inline dictionaries from locales.mjs
|
|
89
98
|
```
|
|
90
99
|
|
|
91
100
|
See [AGENTS.md](AGENTS.md) and [CHANGELOG.md](CHANGELOG.md).
|
package/README.zh.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
## 安装
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
dsh plugin --profile web add github:DNAlec/dsh-auto-approve#v0.2.
|
|
10
|
+
dsh plugin --profile web add github:DNAlec/dsh-auto-approve#v0.2.1
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
打 tag 发布后也可从 npm 安装:
|
|
@@ -16,23 +16,24 @@ dsh plugin --profile web add github:DNAlec/dsh-auto-approve#v0.2.0
|
|
|
16
16
|
dsh plugin --profile web add @dnalec/dsh-auto-approve
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
重启 `dsh web
|
|
19
|
+
重启 `dsh web`。首次启动会把「自动审批」权限预设写进当前 profile 的 `cordis.patch.yml`;写失败时日志会指出文件和原因。
|
|
20
20
|
|
|
21
21
|
## 设置
|
|
22
22
|
|
|
23
23
|
设置页 → **自动审批**:
|
|
24
24
|
|
|
25
|
-
1. **模式** — 工作区内不审批(`workspace-write`,推荐),或工作区也走判定(`read-only
|
|
25
|
+
1. **模式** — 工作区内不审批(`workspace-write`,推荐),或工作区也走判定(`read-only`)。点选即写入;然后重启 `dsh web`,再重新选择「自动审批」或开新会话。
|
|
26
26
|
2. 按需改**关键词**和**审核表**。恢复默认会按所选审核提示词语言加载出厂包。
|
|
27
|
-
3. **审核模型** —
|
|
28
|
-
4.
|
|
27
|
+
3. **审核模型** — 空则跟随部署默认。与提示词、超时一起保存。
|
|
28
|
+
4. **审核提示词** — 按语言内置默认文案,可改;恢复默认写回该语言出厂模板。用 `{{criteria}}` 插入当前审核表。
|
|
29
|
+
5. 会话权限选 **自动审批**。
|
|
29
30
|
|
|
30
31
|
## 怎么判定
|
|
31
32
|
|
|
32
33
|
仅当会话预设是「自动审批」时介入。`workspace-write` 下,工作区内写入不会进审批。`danger-full-access` 走同一条管道。缺参或字段被截断会转人工,禁止自动放行。
|
|
33
34
|
|
|
34
|
-
1. **关键词**(拒绝 > 人工 > 允许)。匹配工具名、命令、路径和工作目录。允许词不匹配工具名,也不匹配会话目录名。预置拒绝词覆盖灾难命令(`rm -rf`、`git push -f`、`drop table`、`dd of=`)、审批配置路径,以及 `.env` / `id_rsa`
|
|
35
|
-
2.
|
|
35
|
+
1. **关键词**(拒绝 > 人工 > 允许)。匹配工具名、命令、路径和工作目录。允许词不匹配工具名,也不匹配会话目录名。预置拒绝词覆盖灾难命令(`rm -rf`、`git push -f`、`drop table`、`dd of=`)、审批配置路径,以及 `.env` / `id_rsa` 等凭据路径。点文件按路径字段放宽匹配:`prod.env` 命中,命令里的 `process.env` 不误伤;`id_rsa.pub`(公钥)不算凭据。
|
|
36
|
+
2. **审核表**。审核模型看到与网页工具卡片相同的字段(并明确标记为不可信数据),只输出类别;程序按该行动作执行。解析失败或超时转人工。类别取**最后一个**「类别:」行,卡片回显不能覆盖结论。
|
|
36
37
|
|
|
37
38
|
默认审核表(动作可改;**其他**不能删除):
|
|
38
39
|
|
|
@@ -47,7 +48,7 @@ dsh plugin --profile web add @dnalec/dsh-auto-approve
|
|
|
47
48
|
| safe | 安全/常规可回补 | 允许 |
|
|
48
49
|
| other | 其他(拿不准) | 人工 |
|
|
49
50
|
|
|
50
|
-
审核提示词语言(中文 / English
|
|
51
|
+
审核提示词语言(中文 / English)只换框架、卡片标签和该语言的默认提示词,不改当前审核表。出厂提示词是通用归类规则,不绑死默认类别;表相关特例写在各行说明里。自定义提示词按语言分别保存。
|
|
51
52
|
|
|
52
53
|
## 数据
|
|
53
54
|
|
|
@@ -56,7 +57,7 @@ dsh plugin --profile web add @dnalec/dsh-auto-approve
|
|
|
56
57
|
| 路径 | 用途 |
|
|
57
58
|
|---|---|
|
|
58
59
|
| `auto-approve/allowlist.json` | 关键词、审核表、审核超时 |
|
|
59
|
-
| `auto-approve/config.json` |
|
|
60
|
+
| `auto-approve/config.json` | 审核模型、提示词语言/自定义提示词与插件配置 |
|
|
60
61
|
| `auto-approve/audit.log` | `ALLOW` / `REJECT` / `HUMAN` / `FAILED` / `OUTCOME` |
|
|
61
62
|
| `auto-approve/events.jsonl` | 审批 tab 事件 |
|
|
62
63
|
|
|
@@ -69,20 +70,30 @@ dsh plugin --profile web add @dnalec/dsh-auto-approve
|
|
|
69
70
|
config:
|
|
70
71
|
onlyAutoApprovePreset: true
|
|
71
72
|
presetSandbox: workspace-write # 或 read-only
|
|
73
|
+
judgePromptLang: zh # 或 en:提示词框架、卡片标签、出厂审核表
|
|
74
|
+
judgePrompts: # 可选:按语言覆盖提示词模板;'' = 用出厂模板
|
|
75
|
+
zh: ''
|
|
76
|
+
en: ''
|
|
72
77
|
judge:
|
|
73
78
|
provider: ''
|
|
74
79
|
model: ''
|
|
75
80
|
reasoningEffort: ''
|
|
76
81
|
timeoutMs: 20000
|
|
82
|
+
# profilePatch: /home/me/.dsh/profiles/web/cordis.patch.yml # 可选:显式指定 patch 文件
|
|
77
83
|
```
|
|
78
84
|
|
|
79
85
|
审核模型字段为空则跟随部署默认。没有可用路由时当次转人工。设置页「审核超时」写入 `allowlist.json`,运行时以此为准。
|
|
80
86
|
|
|
87
|
+
「自动审批」预设写进当前运行 profile 的 patch 文件(路径从 profile 目录 `ctx.baseUrl` 推导);profile 不放在默认位置时可用 `profilePatch` 显式指定。
|
|
88
|
+
|
|
89
|
+
patch 是按 id **整块替换** `config` 的,所以这个 profile 用的权限表就是插件写进去的那份副本(出厂预设 + auto-approve)。DSH 升级后如果出厂预设表新增/改名,插件启动时会和 `@deepseek-ai/dsh-base` 的 patch 比对,把缺的名字打进日志,并在设置页显示一张提示卡片(更新插件或手工合并那一行);插件不会自动改写你的文件。
|
|
90
|
+
|
|
81
91
|
## 开发
|
|
82
92
|
|
|
83
93
|
```sh
|
|
84
94
|
node --test tests/*.test.mjs
|
|
85
|
-
npm run check
|
|
95
|
+
npm run check # 语法检查 + 文案同步校验
|
|
96
|
+
npm run locales:sync # 按 locales.mjs 重新生成 client.js 内联字典
|
|
86
97
|
```
|
|
87
98
|
|
|
88
99
|
见 [AGENTS.md](AGENTS.md) 与 [CHANGELOG.md](CHANGELOG.md)。
|