dsh-permission-rules 0.7.21 → 0.7.22
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 +7 -0
- package/README.en.md +504 -0
- package/README.es.md +504 -0
- package/README.hi.md +504 -0
- package/README.md +309 -245
- package/README.pt.md +504 -0
- package/docs/assets/dsh-permission-rules-flow-dark.svg +58 -0
- package/docs/assets/dsh-permission-rules-flow-light.svg +58 -0
- package/docs/assets/dsh-permission-rules-flow-v5-dark.svg +103 -0
- package/docs/assets/dsh-permission-rules-flow-v5-light.svg +103 -0
- package/docs/assets/dsh-permission-rules-hero-en-dark.webp +0 -0
- package/docs/assets/dsh-permission-rules-hero-en-light.webp +0 -0
- package/docs/assets/dsh-permission-rules-hero-zh-dark.webp +0 -0
- package/docs/assets/dsh-permission-rules-hero-zh-light.webp +0 -0
- package/docs/rules-format.en.md +5 -4
- package/docs/rules-format.md +5 -4
- package/lib/index.js +230 -40
- package/lib/types/config.d.ts +9 -4
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/prose.d.ts +6 -0
- package/lib/types/prose.d.ts.map +1 -1
- package/lib/types/rules.d.ts +74 -15
- package/lib/types/rules.d.ts.map +1 -1
- package/lib/types/runtime.d.ts +59 -12
- package/lib/types/runtime.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/config.ts +9 -4
- package/src/prose.ts +21 -0
- package/src/rules.ts +131 -24
- package/src/runtime.ts +140 -24
- package/README-es.md +0 -443
- package/README-hi.md +0 -445
- package/README-pt.md +0 -443
- package/README-zh.md +0 -443
package/README.md
CHANGED
|
@@ -1,92 +1,160 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/dsh-permission-rules-hero-zh-dark.webp">
|
|
5
|
+
<img src="docs/assets/dsh-permission-rules-hero-zh-light.webp" width="100%" alt="dsh-permission-rules 的裁决台账:有序规则链首个匹配命中、deny 裁决卡,以及 shell 出站流量的代理侧带">
|
|
6
|
+
</picture>
|
|
7
|
+
|
|
8
|
+
# dsh-permission-rules
|
|
9
|
+
|
|
10
|
+
**把工具调用的裁决权拿回自己手里——每一条 allow / deny / ask 都写在 YAML 里,确定、即时、可审计。**
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
面向 DeepSeek Harness 的 Claude Code 风格声明式权限中间件:规则裁决已知的,评审模型裁决未知的;另带一套 Codex 风格的进程级网络策略与本地代理,管住 shell 子进程的出站流量。
|
|
10
13
|
|
|
11
|
-
|
|
14
|
+
[安装](#三步上手) · [配置](#配置) · [FAQ](#faq) · [简体中文](README.md) · [English](README.en.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
|
|
12
15
|
|
|
13
|
-
[](https://github.com/PerryLink/dsh-permission-rules/actions)
|
|
19
|
-
[](https://github.com/PerryLink/dsh-permission-rules/releases)
|
|
20
|
-
[](https://www.npmjs.com/package/dsh-permission-rules)
|
|
21
|
-
[](https://www.npmjs.com/package/dsh-permission-rules)
|
|
16
|
+
[](LICENSE)
|
|
17
|
+
[](#兼容性)
|
|
18
|
+
[](https://www.npmjs.com/package/dsh-permission-rules)
|
|
19
|
+
[](https://github.com/PerryLink/dsh-permission-rules/actions/workflows/ci.yml)
|
|
20
|
+
[](#兼容性)
|
|
22
21
|
|
|
23
|
-
[
|
|
22
|
+
[](https://github.com/PerryLink/dsh-permission-rules/stargazers)
|
|
23
|
+
[](https://www.npmjs.com/package/dsh-permission-rules)
|
|
24
|
+
[](https://dshfind.com/plugins/PerryLink/dsh-permission-rules?ref=badge)
|
|
25
|
+
[](https://securityscorecards.dev/viewer/?uri=github.com/PerryLink/dsh-permission-rules)
|
|
26
|
+
[](https://dsh.market/)
|
|
27
|
+
[](https://gitee.com/perrylink/dsh-permission-rules)
|
|
24
28
|
|
|
25
29
|
```sh
|
|
26
30
|
dsh plugin --profile <name> add dsh-permission-rules
|
|
27
31
|
```
|
|
28
32
|
|
|
29
|
-
|
|
30
33
|
</div>
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
<sub>社区插件,与 DeepSeek 官方无关。唯一仓库:<https://github.com/PerryLink/dsh-permission-rules>(Gitee 为镜像)。</sub>
|
|
36
|
+
|
|
37
|
+
## 它是什么
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
`dsh-permission-rules` 在 `tools/pre-execute` waterfall 上为每次工具调用前置一份有序的 **`allow` / `deny` / `ask`** 规则列表——确定、即时、可审计,由你用纯 YAML 编写。规则裁决已知的调用;没把握的交给官方审批接缝,由评审模型或人裁决。它另外带一层 Codex 风格的进程级网络策略:shell 子进程的出站流量经内置本地 HTTP/CONNECT 代理,由网络规则或映射到官方沙箱预设的三档模式裁决。
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
<picture>
|
|
42
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/assets/dsh-permission-rules-flow-v5-dark.svg">
|
|
43
|
+
<img src="docs/assets/dsh-permission-rules-flow-v5-light.svg" width="100%" alt="dsh-permission-rules 结构:工具调用与 shell 出站两条通道汇入同一条有序规则链,分流为工具裁决与网络出口两组结果,底部是两个仅日志审计事件">
|
|
44
|
+
</picture>
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
- **npm channel** (published releases): `dsh plugin --profile web add dsh-permission-rules`.
|
|
41
|
-
- **tarball channel**: `pnpm pack` in this repo, then `dsh plugin --profile web add ./dsh-permission-rules-<version>.tgz`.
|
|
42
|
-
- **uninstall**: `dsh plugin --profile web remove dsh-permission-rules`.
|
|
46
|
+
*结构:两条通道(工具调用 / shell 出站)汇入同一条有序规则链,首个匹配胜出;随后分流为工具调用与网络出口两组裁决,收束于两个仅日志审计事件。*
|
|
43
47
|
|
|
44
|
-
##
|
|
48
|
+
## 三步上手
|
|
45
49
|
|
|
46
|
-
|
|
50
|
+
1. **安装**(三选一):
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
```sh
|
|
53
|
+
# git 通道(最新 main;prepare 脚本只用生产依赖构建)
|
|
54
|
+
dsh plugin --profile web add github:PerryLink/dsh-permission-rules
|
|
55
|
+
# npm 通道(已发布版本)
|
|
56
|
+
dsh plugin --profile web add dsh-permission-rules
|
|
57
|
+
# tarball 通道:本仓库 pnpm pack 后
|
|
58
|
+
dsh plugin --profile web add ./dsh-permission-rules-<version>.tgz
|
|
59
|
+
```
|
|
49
60
|
|
|
61
|
+
2. **写第一条规则**(项目根的 `.dsh/rules.yaml`;不写也能用,内置高危基线默认开启):
|
|
50
62
|
|
|
51
|
-
|
|
63
|
+
```yaml
|
|
64
|
+
# <project>/.dsh/rules.yaml
|
|
65
|
+
rules:
|
|
66
|
+
- match: { tools: [bash, pwsh], params: { command: "git push*" }, paths: ["**/secrets/**"] }
|
|
67
|
+
action: deny
|
|
68
|
+
reason: "No pushes from protected paths"
|
|
52
69
|
|
|
53
|
-
|
|
70
|
+
- match: { tools: [edit, write] }
|
|
71
|
+
action: ask
|
|
72
|
+
reason: "File writes need confirmation"
|
|
73
|
+
```
|
|
54
74
|
|
|
55
|
-
|
|
75
|
+
3. **验证已生效**:
|
|
56
76
|
|
|
57
|
-
|
|
77
|
+
```sh
|
|
78
|
+
# 重启 profile 后确认插件行已挂载
|
|
79
|
+
dsh --profile web --dump-config | grep -A4 'id: permission-rules'
|
|
80
|
+
# 用真实命令面试跑一条假设调用,不执行任何工具
|
|
81
|
+
/rules test bash {"command":"git push origin main","cwd":"src/secrets/app"}
|
|
82
|
+
```
|
|
58
83
|
|
|
59
|
-
|
|
84
|
+
```text
|
|
85
|
+
"bash" matches rule 1 (deny): 禁止 push 到受保护路径
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**卸载**:`dsh plugin --profile web remove dsh-permission-rules`(或从 profile patch 删掉该行)。
|
|
60
89
|
|
|
90
|
+
<details>
|
|
91
|
+
<summary>从 DSH Desktop 市场安装</summary>
|
|
61
92
|
|
|
93
|
+
所有 PerryLink 插件均可在 DSH Desktop 内置市场中浏览:**市场 → 来源 → 添加来源 → 粘贴** `https://perrylink-dsh-catalog.perrylink.workers.dev/catalog-source.json` **→ 选中**。安装仍需通过市场的 npm 身份校验与你的确认。
|
|
62
94
|
|
|
63
|
-
|
|
95
|
+
</details>
|
|
64
96
|
|
|
65
|
-
|
|
66
|
-
|---|---|
|
|
67
|
-
| Harness | DeepSeek Harness `dsh-v0.2.1-alpha.1` (adapted 2026-09-22, full gate chain): its plugin config is the live settings contract — every field is declared `.volatile()`, the Loader hands `apply` a live reference per field, and a saved edit is committed into the running references WITHOUT remounting the plugin, with out-of-range values refused by the schema before anything is written. A host whose Schemastery predates `volatile()` (before 3.18.3) still mounts and runs this plugin — the fields simply stay ordinary values and the live config form is unavailable — because the marker is applied through a capability probe rather than assumed. `Session.append` on this line still cannot stamp the `ignorable` marker (its third argument is the surface-intent bag, and the envelope field survives for stored-log reads only), so the whole `0.2-alpha` line is pre-checked as unmarked and session-log audit stays disabled by default — `append` reads only `sourceEventSeqs`/`surfaceOp` and freezes the envelope, so it has no code path that could stamp the marker; the earlier `0.1.7-alpha` (adapted 2026-09-22), `0.1.5-rc.2` (adapted 2026-09-09) and `0.1.3-alpha` lines keep the same surface-only append signature, and every `0.2` prerelease is classified with them (a STABLE `0.2.x` release is left to the append probe, so a restored marker surface is adopted without a new plugin release). Those lines' log migrations refuse unclassified plugin events even when marked, so `strip` v1 audit rows before a `0.1.3-alpha` host opens the log and v2 audit rows before a `0.1.5-alpha` host migrates it (native v3 logs only need `repair`). |
|
|
68
|
-
| Node | `^22.19.0 || >=24.0.0` |
|
|
69
|
-
| Platforms | All (host + web settings client) |
|
|
70
|
-
| Model | Any (deny/ask reasons surface through tool results) |
|
|
97
|
+
## 核心能力
|
|
71
98
|
|
|
72
|
-
|
|
99
|
+
`dsh-permission-rules` 在 `tools/pre-execute` 上为每次工具调用前置有序规则——确定、即时、可审计:
|
|
73
100
|
|
|
74
|
-
|
|
101
|
+
- **`deny`** 阻断调用;规则的 `reason` 成为模型可见的错误。
|
|
102
|
+
- **`ask`** 走官方审批接缝(挂载 `dsh-auto-review` 用第二模型作答,或由人作答;两者皆无时 harness 失败关闭)。
|
|
103
|
+
- **`allow`**(及未命中)严格经 `next()` 委托——下游监听器绝不会被短路。
|
|
75
104
|
|
|
76
|
-
|
|
77
|
-
- **`ask`** rides the official approval seam (mount `dsh-auto-review` for a second-model answerer, or a human answers; with neither, the harness fails closed).
|
|
78
|
-
- **`allow`** (and no-match) strictly delegates via `next()` — downstream listeners are never short-circuited.
|
|
105
|
+
每次命中**和**每次透传都作为 `permissionRules/decision` 会话事件审计落盘(仅日志——不会向模型上下文额外注入任何内容)。
|
|
79
106
|
|
|
80
|
-
|
|
107
|
+
- **丰富匹配** —— 工具名 glob(含 `mcp__*`)、agent 身份选择器(`main` / `subagent` / `preset:*`)、参数键/值 glob **或** 正则(含 `!pattern` 取反与 `absent` 键维度)、**任意嵌套深度**的工作区相对路径 glob、`when` 宿主条件(环境变量、平台),以及 **shell 命令分解**(`argv`:命令词、参数 token、管道签名)用于 token 级精确命令匹配。
|
|
108
|
+
- **内置高危基线** —— 随附的 deny/ask 规则集(破坏性命令、权限提升、下载即执行、敏感路径),默认开启并追加在用户规则之后(更近的用户规则可覆盖);用 `builtin.enabled` 开关。
|
|
109
|
+
- **分层规则文件** —— 可选 `searchUp` 从会话 cwd 到文件系统根合并每个 `.dsh/rules.yaml`,就近优先。
|
|
110
|
+
- **试运行上线** —— `enforce: false` 审计策略*会*做什么,同时放行每个调用。
|
|
111
|
+
- **热重载** —— Chokidar 监听带去抖;文件级损坏的编辑保留旧规则、绝不崩溃,单条规则错误只禁用该条。在 WSL 主机上(或规则文件位于 `/mnt/<盘符>` 下时)监听切换为轮询,因为该处的原生变更事件不可靠。
|
|
112
|
+
- **失败大声、爆炸半径受限** —— 非法 YAML 等文件级错误按 `badFilePolicy` 处理;单条规则的坏 glob/正则、未知字段/action 只禁用该条,并在启动提示与 `/rules` 中标红,其余规则照常生效(issue #49)。
|
|
113
|
+
|
|
114
|
+
### 命令与工具面
|
|
115
|
+
|
|
116
|
+
| 表面 | 类型 | 说明 |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `tools/pre-execute` | listener | 首个匹配的 allow/deny/ask 规则 + 网络 URL 候选抽取 |
|
|
119
|
+
| `/rules` | command | `list` · `reload` · `decisions [n]` · `test <tool> <json>` |
|
|
120
|
+
| `permissionRules/decision` | event | 每次命中与透传的仅日志审计 |
|
|
121
|
+
| `permissionRules/network` | event | 被拒连接的代理层审计 |
|
|
122
|
+
| HTTP/CONNECT proxy | service | 治理 shell 子进程流量的内置本地代理 |
|
|
123
|
+
| settings page | client | 网络模式编辑器、规则编辑器、块计数器、近期拦截(每条可一键放行) |
|
|
124
|
+
|
|
125
|
+
```text
|
|
126
|
+
/rules list the active rules, their source files, and any last-reload error
|
|
127
|
+
/rules list explicit alias for the bare listing
|
|
128
|
+
/rules reload re-read the rule-file chain for this workspace
|
|
129
|
+
/rules decisions [n] show the last n permission decisions of this session (default 10)
|
|
130
|
+
/rules test <tool> <json> dry-evaluate the rules against a hypothetical call
|
|
131
|
+
```
|
|
81
132
|
|
|
82
|
-
|
|
83
|
-
- **Built-in high-risk baseline** — a shipped deny/ask ruleset (destructive commands, privilege escalation, download-and-execute, sensitive paths) enabled by default and appended after user rules so a nearer user rule can override it; toggle with `builtin.enabled`.
|
|
84
|
-
- **Hierarchical rule files** — optional `searchUp` merges every `.dsh/rules.yaml` from the session cwd to the filesystem root, nearest first.
|
|
85
|
-
- **Dry-run rollout** — `enforce: false` audits what the policy *would* do while passing every call through.
|
|
86
|
-
- **Hot reload** — Chokidar watch with debounce; a broken edit keeps the previous rules, never crashes. On a WSL host, or for a rule file under `/mnt/<drive>`, the watch switches to polling because native change events are unreliable there.
|
|
87
|
-
- **Fail loud** — invalid YAML, unknown actions/fields, bad globs/regexes, backtracking-prone patterns, or more than `maxRules` rules fail the load.
|
|
133
|
+
`/rules test` 也接受前置标志:`--cwd <dir>`、`--env KEY=VALUE`(可重复)、`--agent <selector>`(可重复)与 `--platform <name>`。在多文件链(如 `searchUp`)中,每条列出的规则行都归属到其自身源文件。
|
|
88
134
|
|
|
89
|
-
|
|
135
|
+
### 示例
|
|
136
|
+
|
|
137
|
+
以下为插件真实入口;安装后调用一个即可。
|
|
138
|
+
|
|
139
|
+
**详细示例** — 命令 `/rules test bash {"command":"git push origin main","cwd":"src/secrets/app"}`,输出:
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
"bash" matches rule 1 (deny): 禁止 push 到受保护路径
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
*Observed from `test/command.spec.ts:204-219 (assertions at :209-213); src/prose.ts:121`*
|
|
146
|
+
|
|
147
|
+
**失败分支** — 输入 `/rules test bash {not json`,输出:
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
Invalid JSON arguments "{not json": the arguments must parse as JSON.
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
*Observed from `plugins/dsh-permission-rules/src/prose.ts:123; plugins/dsh-permission-rules/src/runtime.ts:1266-1272; plugins/dsh-permission-rules/test/command.spec.ts:221-228`*
|
|
154
|
+
|
|
155
|
+
**简短示例**:`tools/pre-execute` · `/rules test <tool> <json>`
|
|
156
|
+
|
|
157
|
+
## 规则语法
|
|
90
158
|
|
|
91
159
|
```yaml
|
|
92
160
|
# <project>/.dsh/rules.yaml
|
|
@@ -100,258 +168,250 @@ rules:
|
|
|
100
168
|
reason: "File writes need confirmation"
|
|
101
169
|
```
|
|
102
170
|
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
- **Schema**
|
|
171
|
+
- **匹配维度** —— `tools`(glob,含 `mcp__*`)、`agents`(`main` / `subagent` / `preset:<name>`;未知身份永不匹配——失败关闭)、`params`(键/值 glob 或正则,`!pattern` 取反,`absent` 键维度)、`paths`(任意嵌套深度抽取的工作区相对 glob)、`when`(`env` 变量 glob/正则 + 封闭 `platform` 列表),以及 `network`(`domains` / `ips` / `ports` / `schemes`——glob、通配符、CIDR、端口范围)。
|
|
172
|
+
- **动作** —— `allow` / `deny` / `ask`,按文件顺序求值,首个命中胜出。
|
|
173
|
+
- **规则元数据** —— `enabled: false`(可见但失效)、`description`、`tags`;未知字段加载失败。
|
|
174
|
+
- **Schema** —— JSON Schema 见 [docs/rules-format.schema.json](docs/rules-format.schema.json)(编辑器补全 `# yaml-language-server: $schema=...`);完整词汇表与 5 条安全基线见 [docs/rules-format.md](docs/rules-format.md)。
|
|
107
175
|
|
|
108
|
-
##
|
|
176
|
+
## 网络策略
|
|
109
177
|
|
|
110
|
-
|
|
178
|
+
Codex 风格的**进程级网络策略**:shell 子进程流量经内置本地 **HTTP/CONNECT 代理**,每个连接由有序网络规则或映射到官方沙箱预设的三档模式裁决:
|
|
111
179
|
|
|
112
|
-
- **`deny-all`**
|
|
113
|
-
- **`whitelist`**
|
|
114
|
-
- **`allow-all`**
|
|
115
|
-
- **`auto
|
|
180
|
+
- **`deny-all`** —— 只读沙箱预设:阻断所有出站。
|
|
181
|
+
- **`whitelist`** —— workspace-write 预设:放行列表目标,其余按 `unlisted: ask`(或 `deny`)。
|
|
182
|
+
- **`allow-all`** —— danger-full-access 预设:放行一切。
|
|
183
|
+
- **`auto`**(默认)—— 跟随沙箱预设;无沙箱策略服务的宿主上解析为 `autoFallback`(`allow-all`)。
|
|
116
184
|
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
185
|
+
- **匹配** —— `match.network` 用 `domains` / `ips` / `ports` / `schemes`(glob、通配符、CIDR、端口范围;数值型 YAML 端口可接受)。`tools/pre-execute` 热路径上的 URL 候选抽取作用于 web 工具参数与嵌入 bash/pwsh 命令文本的 URL;回环目标可按 `loopback` 策略短路规则。IPv4 映射的 IPv6 字面量在匹配前归一化为 IPv4 形式;代理按裁决到的地址建连,不做二次 DNS 解析——裁决未解析出任何地址的连接以 502 关闭失败,绝不按名字拨号。
|
|
186
|
+
- **上游链式** —— `network.upstreamProxy`(默认 `off`)把本代理**放行**的连接送上上游代理:CONNECT 向上游要一条隧道(`CONNECT host:port`),纯 HTTP 请求以绝对形式转发给它。被拦截的目标永远到不了上游——它照旧收到本插件的结构化 403。即使配置了上游,两类情况也绝不链式:**回环**目标(本机之外的代理无法路由它的回环),以及由 **`ips` 作用域规则**产生的任何裁决(链式会把主机名交给上游,"连接落在规则看过的地址上"(issue #21)恰恰会在规则真正在意地址的地方不再成立;这些裁决仍按裁决到的地址直连),再加上目标 scheme 没有可用上游的情况。上游自身的主机名是运维配置而非 agent 输入,不参与这些规则的裁决。带凭据的 URL 绝不原样输出:警告、`/rules network` 与设置页快照都会把口令打码(`http://user:***@host:port`)。上游不可达、超时(10 秒)或返回非 2xx 一律 **502**——刻意没有静默回退直连,配置错误因此始终可见。
|
|
187
|
+
- **审计** —— 被拒连接向所属会话追加 `permissionRules/network`(同样的自适应 `ignorable` 门),块计数器与近期拦截在 `/rules network` 与设置页展示。
|
|
188
|
+
- **诊断** —— 被拦截的连接带 `[network: …]` 消息,点名被拦目标、做出裁决的模式或规则,以及处置办法。
|
|
189
|
+
- **设置页放行** —— 每条近期拦截都提供**放行**动作:它在真正裁决该连接的最近一个规则文件的**最前面**(索引 0)写入一条最小的 `match: { network: { domains: [<主机>] } }` / `action: allow` 规则——被拦截连接所归属工作区的项目文件(配置了绝对 `rulesFile` 时即该文件);对无会话归属的宿主级拦截,则写宿主链解析出的文件(绝对 `rulesFile` → 已存在的 `<processCwd>/<rulesFile>` → 配置的 `fallbackPath` → `<processCwd>/<rulesFile>`,不存在则创建)。加载了多个工作区时,页面先提供工作区选择器——任何已加载的工作区链都优先于宿主链。之所以放在索引 0:规则首个匹配生效,追加在既有 `deny` 之后只会成为死文本。只写 `domains`:该维度包含子域且与端口/scheme 无关,因此同一主机在下一个端口上不会被重新拦截;既有注释与未改动规则原样保留,文本与手工编辑走同一道校验门。写入即刻生效——缓存的工作区链**与**无会话宿主链都会重读,无需重启、无需 `/rules reload`——随后重新计算裁决,因此提示报告的是**真实**结果,绝不在连接仍被拦截时声称成功。以下情况一律拒绝且磁盘文件分毫不动:未知工作区、不在已知规则源内的目标、只读的内置基线、无法读取或解析的文件;连接已被放行时不写入任何内容。`network.allowHostAction: false` 隐藏按钮并让 RPC 拒绝。
|
|
122
190
|
|
|
123
|
-
##
|
|
191
|
+
## 配置
|
|
124
192
|
|
|
125
|
-
|
|
126
|
-
dsh plugin --profile web add github:PerryLink/dsh-permission-rules
|
|
127
|
-
```
|
|
193
|
+
所有可调项均为 Schemastery `Config` 字段(可在 cordis.yml 中修改)。按 id 覆盖会整行替换——重述你需要的每个键。在 `0.1.7-alpha` 宿主上每个字段都以 `.volatile()` 声明,因此还可在 Plugins 设置页就地编辑:编辑直接写入运行中的引用、不重挂插件,运行期在下次读取时取到新值,且改动 `network.proxyPort`、`proxyBind`、`injectEnv` 或 `noProxy` 会立即重绑本地代理。数值边界声明在 schema 上,配置编辑器在持久化前用该 schema 解析合并后的配置,故越界值在写入时即被拒绝。Schemastery 早于 `volatile()` 的宿主上,这些字段只能通过 cordis.yml 修改。
|
|
128
194
|
|
|
129
|
-
|
|
130
|
-
# 1. install the bundle into your profile
|
|
131
|
-
dsh plugin --profile web add github:PerryLink/dsh-permission-rules
|
|
195
|
+
最常用键:
|
|
132
196
|
|
|
133
|
-
|
|
134
|
-
|
|
197
|
+
| 键 | 默认值 | 含义 |
|
|
198
|
+
|---|---|---|
|
|
199
|
+
| `rulesFile` | `.dsh/rules.yaml` | 规则文件位置;相对 = 相对调用会话 cwd 解析,绝对 = 全局并在挂载时校验 |
|
|
200
|
+
| `fallbackPath` | *(none)* | 按 cwd 发现无果时使用的规则文件;挂载时校验 |
|
|
201
|
+
| `badFilePolicy` | `fail` | 文件级坏规则文件:`fail` 响亮地令待处理工具调用出错;`ignore-with-warning` 警告并空继续。单条规则的错误总是只禁用该条,并在启动提示与 `/rules` 中报告 |
|
|
202
|
+
| `maxRules` | `256` | 生效源链上规则总数的硬上限 |
|
|
203
|
+
| `patternMode` | `glob` | `params`/`paths`/`when.env` 模式风格:`glob` 或 `regex`(工具名始终为 glob) |
|
|
204
|
+
| `watch` | `true` | Chokidar 监听 + 变更重载 |
|
|
205
|
+
| `enforce` | `true` | `false` = 试运行:deny/ask 命中带 `dryRun` 标记审计,每个调用都透传 |
|
|
206
|
+
| `language` | `en` | `/rules` 输出语言:`en`、`zh`、`es`、`pt`、`hi` |
|
|
135
207
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
208
|
+
<details>
|
|
209
|
+
<summary>完整配置表(29 个键)</summary>
|
|
210
|
+
|
|
211
|
+
| 键 | 默认值 | 含义 |
|
|
212
|
+
|---|---|---|
|
|
213
|
+
| `rulesFile` | `.dsh/rules.yaml` | 规则文件位置;相对 = 相对调用会话 cwd 解析,绝对 = 全局并在挂载时校验 |
|
|
214
|
+
| `fallbackPath` | *(none)* | 按 cwd 发现无果时使用的规则文件;挂载时校验 |
|
|
215
|
+
| `badFilePolicy` | `fail` | 文件级坏规则文件:`fail` 响亮地令待处理工具调用出错;`ignore-with-warning` 警告并空继续。单条规则的错误总是只禁用该条,并在启动提示与 `/rules` 中报告 |
|
|
216
|
+
| `maxRules` | `256` | 生效源链上规则总数的硬上限 |
|
|
217
|
+
| `maxCachedWorkspaces` | `512` | 缓存的工作区规则加载硬上限(LRU 逐出) |
|
|
218
|
+
| `patternMode` | `glob` | `params`/`paths`/`when.env` 模式风格:`glob` 或 `regex`(工具名始终为 glob) |
|
|
219
|
+
| `watch` | `true` | Chokidar 监听 + 变更重载 |
|
|
220
|
+
| `watchStabilityThresholdMs` | `200` | 重载去抖窗口(毫秒) |
|
|
221
|
+
| `language` | `en` | `/rules` 输出语言:`en`、`zh`、`es`、`pt`、`hi` |
|
|
222
|
+
| `caseInsensitivePaths` | *(win32)* | `paths` 模式与工作区根比较忽略 ASCII 大小写;Windows 上为 `true` |
|
|
223
|
+
| `audit` | `all` | 审计粒度:`all` 记录每次命中与透传;`hits` 跳过透传事件 |
|
|
224
|
+
| `searchUp` | `false` | 从会话 cwd 向上遍历父目录并合并每个找到的规则文件,就近优先 |
|
|
225
|
+
| `maxGlobStars` | `2` | 每个 glob 模式无界 `*`/`**` 量词的硬上限 |
|
|
226
|
+
| `enforce` | `true` | `false` = 试运行:deny/ask 命中带 `dryRun` 标记审计,每个调用都透传 |
|
|
227
|
+
| `allowUnmarkedAudit` | `false` | 前标记宿主丢弃 `ignorable` 标记;插件以一次性警告禁用会话日志审计。设 `true` 重新启用 |
|
|
228
|
+
| `network.enabled` | `true` | 代理、环境注入与 web 工具模式默认的总开关 |
|
|
229
|
+
| `network.mode` | `auto` | 策略模式:`auto` 跟随沙箱预设,或 `deny-all` / `whitelist` / `allow-all` |
|
|
230
|
+
| `network.autoFallback` | `allow-all` | `auto` 无沙箱策略服务时使用的模式 |
|
|
231
|
+
| `network.unlisted` | `ask` | 白名单模式下未命中规则目标:`ask` 或 `deny` |
|
|
232
|
+
| `network.proxyBind` | `127.0.0.1` | 本地代理绑定地址(仅回环) |
|
|
233
|
+
| `network.proxyPort` | `0` | 本地代理端口;`0` 选空闲临时端口 |
|
|
234
|
+
| `network.proxyMaxRecent` | `100` | 设置页保留的近期拦截记录上限 |
|
|
235
|
+
| `network.loopback` | `allow` | 回环目标:`allow`(Codex 对齐)或 `policy` |
|
|
236
|
+
| `network.injectEnv` | `true` | 是否为子进程注入代理环境变量 |
|
|
237
|
+
| `network.noProxy` | `clear` | 子进程 NO_PROXY 处理:`clear` 强制策略或 `preserve` |
|
|
238
|
+
| `network.upstreamProxy` | `off` | 本插件**放行**连接的上游代理:`off` 直连、`inherit` 沿用启动环境的代理名,或显式 `http(s)://` 代理 URL |
|
|
239
|
+
| `network.allowHostAction` | `true` | 设置页逐条「放行」动作:`false` 隐藏「放行」按钮并让 `permissionRules/allowHost` RPC 拒绝(规则编辑器不受影响) |
|
|
240
|
+
| `builtin.enabled` | `true` | 内置高危基线:`false` 完全禁用随附的 deny/ask 规则集 |
|
|
241
|
+
| `builtin.path` | *(随附)* | 替换基线文件(绝对路径,或相对 `process.cwd()`);挂载时校验 |
|
|
139
242
|
|
|
140
|
-
|
|
243
|
+
</details>
|
|
141
244
|
|
|
142
|
-
|
|
245
|
+
## FAQ
|
|
143
246
|
|
|
144
|
-
|
|
247
|
+
<details>
|
|
248
|
+
<summary>规则文件存在哪?插件会不会乱写我的文件?</summary>
|
|
145
249
|
|
|
146
|
-
|
|
250
|
+
规则从磁盘读取:项目根的 `.dsh/rules.yaml`,或配置的 `rulesFile` / `fallbackPath`,`searchUp` 时逐级向上合并。常规裁决路径不写任何规则数据。唯一的写面是设置页的规则编辑器,以及「放行」动作——后者只向已知规则源的最前面写一条最小 allow 规则,写前重新走一遍与手工编辑相同的解析/编译校验(详见「网络策略」)。
|
|
147
251
|
|
|
148
|
-
|
|
149
|
-
/rules test bash {"command":"git push origin main","cwd":"src/secrets/app"}
|
|
150
|
-
~~~
|
|
252
|
+
</details>
|
|
151
253
|
|
|
152
|
-
|
|
254
|
+
<details>
|
|
255
|
+
<summary>没有挂载 dsh-auto-review 时,ask 会怎样?</summary>
|
|
153
256
|
|
|
154
|
-
|
|
155
|
-
"bash" matches rule 1 (deny): 禁止 push 到受保护路径
|
|
156
|
-
~~~
|
|
257
|
+
`ask` 走官方审批接缝:挂了 `dsh-auto-review` 就由只读的第二模型裁决,否则由人作答;两者都不存在时 harness 失败关闭,调用不会静默放行。本插件自己绝不生成子代理、不调用模型——产出 `ask` 就是它工作的终点。
|
|
157
258
|
|
|
158
|
-
|
|
259
|
+
</details>
|
|
159
260
|
|
|
160
|
-
|
|
261
|
+
<details>
|
|
262
|
+
<summary>宿主自身的出站请求会被这个代理拦住吗?</summary>
|
|
161
263
|
|
|
162
|
-
|
|
264
|
+
不会。注入的代理环境覆盖**派生的 shell 子进程**,以及在请求时读取代理变量名的消费者;**不覆盖**宿主进程自身基于 `fetch` 的流量——launcher 在第一个插件挂载前就用启动环境装好了 undici 的全局 dispatcher,该 dispatcher 按策略而非按环境路由。因此供应商端点不需要允许规则,`network.injectEnv: false` 也不会把宿主进程移出任何东西。2026-09-10 实测于 Node 22,可用 `scripts/host-egress-probe.mjs` 复现。
|
|
163
265
|
|
|
164
|
-
|
|
165
|
-
/rules test bash {not json
|
|
166
|
-
~~~
|
|
266
|
+
</details>
|
|
167
267
|
|
|
168
|
-
|
|
268
|
+
<details>
|
|
269
|
+
<summary>热路径上的性能开销多大?</summary>
|
|
169
270
|
|
|
170
|
-
|
|
171
|
-
Invalid JSON arguments "{not json": the arguments must parse as JSON.
|
|
172
|
-
~~~
|
|
271
|
+
规则求值是纯内存的首个匹配遍历,不调模型、不发网络请求;命中的裁决与透传只追加会话审计。监听失败只告警并保留旧规则;规则文件多时可把 `audit` 设为 `hits` 跳过透传事件,或用 `maxRules` / `maxCachedWorkspaces` 设定上限。
|
|
173
272
|
|
|
174
|
-
|
|
273
|
+
</details>
|
|
175
274
|
|
|
176
|
-
|
|
275
|
+
<details>
|
|
276
|
+
<summary>会和其他插件抢事件、命令名或 slot 吗?</summary>
|
|
177
277
|
|
|
178
|
-
|
|
278
|
+
不会。工具名带命名空间、不占裸名,服务键 `permissionRules` / `permissionRulesRuntime` 不是内置 seam,也不注册客户端 slot 与 `webServer` 前缀,patch 只 `insert` 自己那一行;共享事件一律经 `next()` 委托。逐条论证见「与其他 DSH 插件的互操作性」。
|
|
179
279
|
|
|
180
|
-
|
|
280
|
+
</details>
|
|
181
281
|
|
|
182
|
-
|
|
282
|
+
## 安全边界
|
|
183
283
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
| `maxCachedWorkspaces` | `512` | Hard cap on cached per-workspace rule loads (LRU eviction) |
|
|
191
|
-
| `patternMode` | `glob` | `params`/`paths`/`when.env` pattern flavor: `glob` or `regex` (tool names are always globs) |
|
|
192
|
-
| `watch` | `true` | Chokidar watch + reload on change |
|
|
193
|
-
| `watchStabilityThresholdMs` | `200` | Reload debounce window (ms) |
|
|
194
|
-
| `language` | `en` | `/rules` output language: `en`, `zh`, `es`, `pt`, `hi` |
|
|
195
|
-
| `caseInsensitivePaths` | *(win32)* | `paths` patterns and workspace-root comparison ignore ASCII case; `true` on Windows |
|
|
196
|
-
| `audit` | `all` | Audit granularity: `all` logs every hit AND passthrough; `hits` skips passthrough events |
|
|
197
|
-
| `searchUp` | `false` | Walk parent directories from the session cwd and merge every found rule file, nearest first |
|
|
198
|
-
| `maxGlobStars` | `2` | Hard cap on unbounded `*`/`**` quantifiers per glob pattern |
|
|
199
|
-
| `enforce` | `true` | `false` = dry-run mode: deny/ask hits are audit-logged with a `dryRun` marker and every call passes through |
|
|
200
|
-
| `allowUnmarkedAudit` | `false` | Pre-marker hosts drop the `ignorable` marker; the plugin disables session-log audit with a warning. Set `true` to opt back in |
|
|
201
|
-
| `network.enabled` | `true` | Master switch for the proxy, env injection, and web-tool mode defaults |
|
|
202
|
-
| `network.mode` | `auto` | Policy mode: `auto` follows the sandbox preset, or `deny-all` / `whitelist` / `allow-all` |
|
|
203
|
-
| `network.autoFallback` | `allow-all` | Mode used when `auto` has no sandbox-policy service |
|
|
204
|
-
| `network.unlisted` | `ask` | Whitelist-mode handling of targets no rule matched: `ask` or `deny` |
|
|
205
|
-
| `network.proxyBind` | `127.0.0.1` | Local proxy bind address (loopback only) |
|
|
206
|
-
| `network.proxyPort` | `0` | Local proxy port; `0` picks a free ephemeral port |
|
|
207
|
-
| `network.proxyMaxRecent` | `100` | Cap on recent-block records kept for the settings page |
|
|
208
|
-
| `network.loopback` | `allow` | Loopback targets: `allow` (Codex parity) or `policy` |
|
|
209
|
-
| `network.injectEnv` | `true` | Whether proxy environment variables are injected for subprocesses |
|
|
210
|
-
| `network.noProxy` | `clear` | Subprocess NO_PROXY handling: `clear` enforces the policy or `preserve` |
|
|
211
|
-
| `network.upstreamProxy` | `off` | Upstream proxy for connections this plugin ALLOWS: `off` dials directly, `inherit` reuses the launch environment's proxy names, or an explicit `http(s)://` proxy URL |
|
|
212
|
-
| `network.allowHostAction` | `true` | Settings-page per-block "allow this host" action: `false` hides the Allow button and makes the `permissionRules/allowHost` RPC refuse (the rule editor is not affected) |
|
|
213
|
-
| `builtin.enabled` | `true` | Built-in high-risk baseline: `false` disables the shipped deny/ask ruleset entirely |
|
|
214
|
-
| `builtin.path` | *(shipped)* | Replacement baseline file (absolute, or relative to `process.cwd()`); validated at mount |
|
|
215
|
-
|
|
216
|
-
## Tools & surfaces
|
|
217
|
-
|
|
218
|
-
| Surface | Kind | Notes |
|
|
219
|
-
|---|---|---|
|
|
220
|
-
| `tools/pre-execute` | listener | First-match allow/deny/ask rules + network URL-candidate extraction |
|
|
221
|
-
| `/rules` | command | `list` · `reload` · `decisions [n]` · `test <tool> <json>` |
|
|
222
|
-
| `permissionRules/decision` | event | Log-only audit for every hit and passthrough |
|
|
223
|
-
| `permissionRules/network` | event | Proxy-layer audit for blocked connections |
|
|
224
|
-
| HTTP/CONNECT proxy | service | Built-in local proxy governing shell subprocess traffic |
|
|
225
|
-
| settings page | client | Network-mode editor, rule editor, block counters, recent interceptions with a per-block allow action |
|
|
284
|
+
- **是策略,不是内核。** `paths` 候选只来自一组文档化的参数键(任意嵌套深度、有深度上限),且仅工作区相对路径匹配。
|
|
285
|
+
- **这里没有评审者。** 插件绝不生成子代理或调用模型——产出 `ask` 决策就是其工作的终点。
|
|
286
|
+
- **不改沙箱。** OS 级沙箱策略属于沙箱接缝,与本插件无关。
|
|
287
|
+
- **响亮地拒绝错误配置。** 未知 YAML 字段、未知 action 与坏模式在加载期被拒绝。
|
|
288
|
+
- **回溯界限。** glob 模式以 `maxGlobStars` 限制无界星号展开;正则模式拒绝嵌套无界量词与量化重叠字面交替。
|
|
289
|
+
- **关闭失败的拨号。** 明文 HTTP 转发与 CONNECT 隧道只连接裁决到的地址;裁决未解析出任何地址的 allow 以 502 关闭失败,而不是按名字拨号(issue #23)。
|
|
226
290
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
/
|
|
232
|
-
|
|
233
|
-
|
|
291
|
+
## 权限与数据
|
|
292
|
+
|
|
293
|
+
- **权限**:workshop 清单声明 `files:read`、`files:watch`、`files:write`、`session:append` 与 `network:outbound`。`ask` 决策走官方审批接缝——不重实现、不绕过。
|
|
294
|
+
- **数据**:规则文件从磁盘读取;常规裁决不写任何规则数据,唯一的写面是设置页的规则编辑器与「放行」动作。无模型调用、无评审子代理。
|
|
295
|
+
- **会话日志**:`permissionRules/decision` 绝不注入模型上下文,并以信封的 `ignorable: true` 标记追加,任何 harness 构建都能加载日志。
|
|
296
|
+
|
|
297
|
+
## 已知限制
|
|
298
|
+
|
|
299
|
+
- **前标记宿主与拒绝型宿主上的审计标记。** `permissionRules/decision` 以 `ignorable: true` 追加;`Session.append` 早于该标记的宿主(`0.1.0-rc.1`–`rc.7` 与 `0.1.1-rc.1`–`rc.7` 线)静默丢弃它,`0.1.2-rc` 线沿用 alpha.5 表面(append 无任何选项能写该标记),`0.1.2-alpha` 线在读取时连已标记的插件事件也拒绝,`0.1.3-alpha` 与 `0.1.5-alpha` 线同样沿用 surface-only 追加签名(已在已发布的 `0.1.3-alpha.1`/`0.1.5-alpha.1` 包上核验)——运行时在首次追加前即预检这些线并以一次性警告禁用会话日志审计。跨代迁移同样拒绝已标记的审计行:`0.1.3-alpha` 的 v1→v2 门拒绝未知 v1 事件,`0.1.5-alpha` 的 v2→v3 门拒绝一切未分类事件(其清单冻结为已发布 v2 词汇),故在 0.1.3 宿主打开日志前 `strip` v1 行、在升级到 0.1.5 宿主前 `strip` v2 行。v3 原生日志接受已标记的插件行,只需 `repair`。设 `allowUnmarkedAudit: true` 重新启用;用 `scripts/repair-session-logs.mjs` 修复已写日志(标记无济于事的宿主用其 `strip` 模式移除审计行)。
|
|
300
|
+
- **路径候选是启发式的。** 只有文档化的参数键参与路径匹配,且工作区相对匹配仅在 `caseInsensitivePaths` 开启时忽略 ASCII 大小写。
|
|
301
|
+
- **glob 是保守子集。** 无花括号展开——写两个模式,或用正则模式。
|
|
302
|
+
- **正则回溯守卫是结构性的、非穷尽的。** 对不可信文件优先用 glob 模式。
|
|
303
|
+
- **宿主自身的出站请求不经过本代理。** 注入的代理环境覆盖**派生的 shell 子进程**(这正是注入的用途),以及在请求时读取代理变量名的消费者;它**不覆盖**宿主进程自身基于 `fetch` 的流量——launcher 在第一个插件挂载之前就用**启动环境**装好了 undici 的全局 dispatcher,该 dispatcher 按策略而非按环境路由,且 Node 在启动时采样代理环境,因此后挂载的插件无法改变它。结论:供应商端点**不需要**允许规则,`network.injectEnv: false` 也不会把宿主进程移出任何东西。2026-09-10 实测于 Node 22;用 `scripts/host-egress-probe.mjs` 可复现。
|
|
304
|
+
- **链式只覆盖到达本代理的流量。** 在 `dsh-v0.1.7-alpha.1` 及之后的宿主上,harness 自身的启动期代理策略与其子进程环境覆盖可能优先于本插件注入的代理名,因此 `network.upstreamProxy` 描述的是本代理所处理连接的去向——它不是关于宿主进程每一条出站路径的断言。
|
|
234
305
|
|
|
235
|
-
|
|
306
|
+
## 与其他 DSH 插件的互操作性
|
|
236
307
|
|
|
237
|
-
|
|
308
|
+
已对照 **DSH `0.2.0-rc.2`**(本 README 面向的运行时)与 2026-10-05 实测的高星插件集验证。
|
|
238
309
|
|
|
239
|
-
|
|
240
|
-
- **Data**: rule files are read from disk; no rule data is written. No model calls, no reviewer subagents.
|
|
241
|
-
- **Session log**: `permissionRules/decision` is never injected into the model context and is appended with the envelope's `ignorable: true` marker so any harness build loads the log.
|
|
310
|
+
本插件**不干扰**其他插件,包括广泛安装的高星插件:
|
|
242
311
|
|
|
243
|
-
|
|
312
|
+
- **无工具名冲突。** 所有工具都带命名空间,不占用任何已被内置工具或其他插件持有的裸名。
|
|
313
|
+
- **无服务键冲突。** 只提供 `permissionRules`, `permissionRulesRuntime`;该键既不是内置 seam,也没有被任何已调研的高星插件提供。
|
|
314
|
+
- **无 slot 冲突。** 不注册客户端 slot key,因此不参与 `shadows-shipped-ui` 座位争抢。
|
|
315
|
+
- **无 HTTP 路由冲突。** 不注册任何 `webServer` 前缀。
|
|
316
|
+
- **无 patch 层冲突。** 组合包 patch 只 `insert` 自己那一行,从不覆写内置行的 `config`。
|
|
317
|
+
- **无全局改写。** 不改原型、不改写 `process.env`、不替换全局 fetch dispatcher。
|
|
244
318
|
|
|
245
|
-
|
|
246
|
-
- **No reviewer here.** The plugin never spawns subagents or calls models — producing an `ask` decision is the end of its work.
|
|
247
|
-
- **No sandbox changes.** OS-level sandbox policy belongs to the sandbox seam, not this plugin.
|
|
248
|
-
- **Loud misconfiguration.** Unknown YAML fields, unknown actions, and bad patterns are rejected at load.
|
|
249
|
-
- **Backtracking bounds.** Glob patterns are capped at `maxGlobStars` unbounded star expansions; regex-mode patterns reject nested unbounded quantifiers and quantified overlapping literal alternations.
|
|
250
|
-
- **Fail-closed dialing.** Plain-HTTP forwards and CONNECT tunnels connect only to adjudicated addresses; an allow whose adjudication resolved no address fails closed with 502 instead of dialing the name (issue #23).
|
|
319
|
+
**共享事件监听器在构造上就不互相干扰。** 它用 `ctx.on()` 监听顺序敏感事件 `tools/post-execute`, `tools/pre-execute` —— Cordis 的**广播**语义:每个监听器都会运行,任何一个都无法饿死其他监听器。**此处每个监听器都通过 `next()` 委托**,因此链条绝不会被短路;改写作用在 `next()` 产出的值上,而不是用它顶替返回:
|
|
251
320
|
|
|
252
|
-
|
|
321
|
+
- `tools/post-execute` — also used by `cc-safety-net` (1576★).
|
|
322
|
+
- `tools/pre-execute` — also used by `cc-safety-net` (1576★).
|
|
253
323
|
|
|
254
|
-
-
|
|
255
|
-
- **Path candidates are heuristic.** Only the documented argument keys feed path matching, and workspace-relative matching is ASCII-case-insensitive only when `caseInsensitivePaths` is on.
|
|
256
|
-
- **Globs are a conservative subset.** No brace expansion — write two patterns, or use regex mode.
|
|
257
|
-
- **The regex backtracking guard is structural, not exhaustive.** Prefer glob mode for untrusted files.
|
|
258
|
-
- **The host's own outbound requests do not go through this proxy.** The injected proxy environment covers **spawned shell children** — which is what the injection is for — and any consumer that reads the proxy names at request time. It does **not** cover the host process's own `fetch`-based traffic: the launcher installs undici's global dispatcher from the **launch environment** before the first plugin mounts, that dispatcher routes by its policy rather than by the environment, and Node samples the proxy environment at start — so a plugin mounting later cannot redirect it. Consequences: provider endpoints do **not** need an allow rule, and `network.injectEnv: false` does not take the host process out of anything. Measured 2026-09-10 on Node 22; reproduce with `scripts/host-egress-probe.mjs`.
|
|
259
|
-
- **Upstream chaining covers only what reaches this proxy.** On `dsh-v0.1.7-alpha.1` and later, the harness's own launch-time proxy policy and its subprocess environment overlay can take precedence over the proxy names this plugin injects, so `network.upstreamProxy` describes what happens to the connections this proxy handles — it is not a claim about every outbound path in the host process.
|
|
324
|
+
静态证据:`dsh-plugin-doctor` 的 K10–K13 在本仓全部为 `pass`。
|
|
260
325
|
|
|
261
|
-
##
|
|
326
|
+
## 与 dsh-auto-review 协作
|
|
262
327
|
|
|
263
|
-
- `dsh-permission-rules`
|
|
264
|
-
-
|
|
265
|
-
-
|
|
328
|
+
- `dsh-permission-rules` 产出 `ask`;`dsh-auto-review` 在 `approval/request` waterfall 上以只读第二模型裁决作答(或委托给人)。两者都挂载即得完整闭环。
|
|
329
|
+
- 集成测试:`permissionRules/decision` → `approval/asked` → `autoReview/verdict` → `approval/decided`,评审者以脚本化 mock 替换。
|
|
330
|
+
- 官方 harness 的 `never` 审批策略与每个失败关闭保证保持不变。
|
|
266
331
|
|
|
267
|
-
##
|
|
332
|
+
## 会话日志修复
|
|
268
333
|
|
|
269
|
-
|
|
334
|
+
在 `ignorable` 标记出现之前写入的会话日志可能被较新 harness 构建拒绝(`SessionFormatUnsupportedError`)。随附的 `scripts/repair-session-logs.mjs` 仅重写目标审计行以携带 `ignorable: true`,保帧、带备份:
|
|
270
335
|
|
|
271
336
|
```sh
|
|
272
|
-
node scripts/repair-session-logs.mjs scan [--home DIR] #
|
|
337
|
+
node scripts/repair-session-logs.mjs scan [--home DIR] # 报告外来行,不改任何内容
|
|
273
338
|
node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
|
|
274
339
|
node scripts/repair-session-logs.mjs strip [--home DIR] [--dry-run]
|
|
275
340
|
```
|
|
276
341
|
|
|
277
|
-
`--home`
|
|
342
|
+
`--home` 默认 `$DSH_HOME/sessions`(或 `~/.dsh/sessions`)。工具按规范基名发现每一代日志——`session.jsonl`、`session.v2.jsonl`、`session.v3.jsonl`,各自可选 `.zstd` 压缩——请按世代选择模式:
|
|
343
|
+
|
|
344
|
+
- **v3(`session.v3.jsonl`,`0.1.5-alpha` 线原生写出)** —— 读取路径接受已标记的插件行,`repair` 即可。
|
|
345
|
+
- **v2(`session.v2.jsonl`,`0.1.3-alpha` 线写出)** —— `repair` 可让写出它的宿主打开日志,但 `0.1.5-alpha` 的 v2→v3 迁移连已标记的未分类事件也拒绝:请在升级到 `0.1.5-alpha` 宿主**之前**对 v2 日志执行 `strip`。
|
|
346
|
+
- **v1(`session.jsonl`)** —— `0.1.3-alpha` 的 v1→v2 迁移连已标记的未知 v1 事件也拒绝:请在 0.1.3 或更新宿主首次打开日志前执行 `strip`。
|
|
347
|
+
|
|
348
|
+
## 兼容性
|
|
349
|
+
|
|
350
|
+
| 维度 | 状态 |
|
|
351
|
+
|---|---|
|
|
352
|
+
| Harness | DeepSeek Harness `dsh-v0.2.1-alpha.1`(2026-09-22 已适配,完整门禁链):其插件配置即新的 live settings 契约——每个字段都以 `.volatile()` 声明,Loader 向 `apply` 逐个交付活引用,保存的编辑直接写入运行中的引用、**不重挂插件**,越界值在写入前即被 schema 拒绝。Schemastery 早于 `volatile()`(3.18.3 之前)的宿主仍能挂载并运行本插件——字段退化为普通值、live 配置表单不可用——因为该标记是**能力探测**而非假定存在。本线的 `Session.append` 仍无法盖章 `ignorable` 标记(第三参数是 surface-intent 包,信封字段仅用于存量日志读取),故整条 `0.2-alpha` 线在首次追加前即被预检为未盖章,会话日志审计默认停用——其 `append` 只读取 `sourceEventSeqs`/`surfaceOp` 并冻结信封,没有任何可盖章标记的代码路径;更早的 `0.1.7-alpha`(2026-09-22 已适配)、`0.1.5-rc.2`(2026-09-09 已适配)与 `0.1.3-alpha` 线同样沿用 surface-only 追加签名,且每个 `0.2` 预发布版都与它们同类(`0.2.x` 的**稳定版**交由追加探测判定,因此恢复盖章能力无需本插件再发版)。这些线的日志迁移连已标记的未分类插件事件也拒绝:在 `0.1.3-alpha` 宿主打开日志前 `strip` 掉 v1 审计行,在 `0.1.5-alpha` 宿主迁移前 `strip` 掉 v2 审计行(v3 原生日志只需 `repair`)。 |
|
|
353
|
+
| Node | `^22.19.0 || >=24.9.0` |
|
|
354
|
+
| Platforms | 全部(host + Web 设置客户端) |
|
|
355
|
+
| Model | 任意(deny/ask 原因经工具结果呈现) |
|
|
356
|
+
|
|
357
|
+
## 生态与质量
|
|
278
358
|
|
|
279
|
-
-
|
|
280
|
-
-
|
|
281
|
-
-
|
|
359
|
+
- [Gitee 镜像](https://gitee.com/perrylink/dsh-permission-rules)(同步镜像,以 GitHub 为准)
|
|
360
|
+
- [dshfind 插件页](https://dshfind.com/plugins/PerryLink/dsh-permission-rules)(安装量与排名)
|
|
361
|
+
- [OpenSSF Scorecard 报告](https://securityscorecards.dev/viewer/?uri=github.com/PerryLink/dsh-permission-rules)(由 [.github/workflows/scorecard.yml](.github/workflows/scorecard.yml) 驱动)
|
|
362
|
+
- [dsh-plugin-doctor 验证报告](https://github.com/PerryLink/dsh-plugin-doctor#verified-徽章)(K10–K13 全 `pass`)
|
|
363
|
+
- [DSH Market](https://dsh.market/)(已上架)
|
|
364
|
+
- **1024 商店渠道**:先 `npm i -g dsh1024`,再 `dsh1024 plugin --profile web add dsh-permission-rules`(计入 [deepseek1024.com](https://deepseek1024.com) 安装排行)
|
|
365
|
+
- [生态实测知识库](https://perrylink.github.io/dsh-plugin-guide/):插件开发指南 · 选型实测数据 · 维护取舍判据
|
|
282
366
|
|
|
283
|
-
##
|
|
367
|
+
## 开发
|
|
284
368
|
|
|
285
369
|
```sh
|
|
286
|
-
pnpm install # node ^22.19 || >=24
|
|
370
|
+
pnpm install # node ^22.19 || >=24.9
|
|
287
371
|
pnpm run typecheck # tsc, src + tests
|
|
288
372
|
pnpm run lint # eslint, src + tests + scripts
|
|
289
373
|
pnpm test # vitest: 24 spec files
|
|
290
374
|
pnpm run test:coverage # coverage gate (90/80/90/90)
|
|
291
375
|
pnpm run build # tsc declarations + tsdown bundles (lib/)
|
|
292
376
|
pnpm run pack:check # build + pack (the published artifact)
|
|
293
|
-
node scripts/check-readme-sync.mjs #
|
|
377
|
+
node scripts/check-readme-sync.mjs # 五语 README 一致性门(CI 同款)
|
|
294
378
|
```
|
|
295
379
|
|
|
296
|
-
|
|
380
|
+
无头端到端验证记录见 [VERIFICATION.md](VERIFICATION.md)。README 配图由 [`scripts/gen-readme-assets.py`](scripts/gen-readme-assets.py) 程序化生成(Pillow 绘制 1440×576 中英深浅双版 hero,手写 1100×660 双通道结构 SVG),可重复执行。
|
|
297
381
|
|
|
298
|
-
|
|
382
|
+
Topics:`dsh`, `dsh-plugin`, `deepseek-harness`, `permission`, `policy`, `allow-deny-ask`, `approval`, `safety`, `network`, `network-policy`, `proxy`
|
|
299
383
|
|
|
300
|
-
|
|
384
|
+
## 家族与致谢
|
|
301
385
|
|
|
302
|
-
|
|
386
|
+
本项目是 [PerryLink](https://github.com/PerryLink) 维护的 DeepSeek Harness 插件家族成员(全部 Apache-2.0)。如果这个插件帮到了你,**给个 star**——它不解锁任何功能,但会让下一个人更容易找到它。
|
|
303
387
|
|
|
304
|
-
-
|
|
305
|
-
-
|
|
306
|
-
-
|
|
307
|
-
-
|
|
308
|
-
-
|
|
309
|
-
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
- `tools/post-execute` — also used by `cc-safety-net` (1576★).
|
|
313
|
-
- `tools/pre-execute` — also used by `cc-safety-net` (1576★).
|
|
314
|
-
|
|
315
|
-
Static evidence: `dsh-plugin-doctor` K10–K13 report `pass` for every check on this repository.
|
|
316
|
-
|
|
317
|
-
## Topics
|
|
318
|
-
|
|
319
|
-
`dsh`, `dsh-plugin`, `deepseek-harness`, `permission`, `policy`, `allow-deny-ask`, `approval`, `safety`, `network`, `network-policy`, `proxy`
|
|
320
|
-
|
|
321
|
-
## Contributors
|
|
322
|
-
|
|
323
|
-
- [@am-i-dead](https://github.com/am-i-dead) — split the client-safe allow-host helpers out of the host-only module (#24).
|
|
324
|
-
|
|
325
|
-
- [@PerryLink](https://github.com/PerryLink) — creator and maintainer: rule vocabulary and evaluation, runtime, HMR watch, session-log audit, network policy + proxy, and the five-language docs.
|
|
326
|
-
- [@22xuan](https://github.com/22xuan) — the detailed report on rc.6 hosts silently dropping the audit event's `ignorable` marker ([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2)) and the upstream harness discussion; the v0.4.1 runtime host-capability detection and the documentation correction drew directly from that analysis.
|
|
327
|
-
- [@sjh9714](https://github.com/sjh9714) — proposed the shared rule-syntax test-vector corpus ([#4](https://github.com/PerryLink/dsh-permission-rules/issues/4), [#5](https://github.com/PerryLink/dsh-permission-rules/issues/5)), shipped in v0.5.1 as `docs/rule-test-vectors/`, and supplied the AST-decomposition boundary cases on the [design discussion](https://github.com/PerryLink/dsh-permission-rules/discussions/10).
|
|
328
|
-
- [@weipeng1999](https://github.com/weipeng1999) — the AST-based command-decomposition feature proposal ([#8](https://github.com/PerryLink/dsh-permission-rules/issues/8)) behind the design discussion.
|
|
329
|
-
- [@alexchenzl](https://github.com/alexchenzl) — the DSH Directory listing request ([#7](https://github.com/PerryLink/dsh-permission-rules/issues/7)).
|
|
330
|
-
- [@zl190](https://github.com/zl190) — reported and verified the `0.1.0-rc.7` harness compatibility gap ([PR #9](https://github.com/PerryLink/dsh-permission-rules/pulls/9)).
|
|
331
|
-
- [@cuohua](https://github.com/cuohua) — reported that the `0.1.1-rc` line still drops the `ignorable` marker even though the version gate covered only `0.1.0` ([#11](https://github.com/PerryLink/dsh-permission-rules/issues/11)); the widened gate drew directly from that analysis.
|
|
332
|
-
|
|
333
|
-
## PerryLink DSH Plugin Family
|
|
334
|
-
|
|
335
|
-
This project is part of the DeepSeek Harness plugin family from [PerryLink](https://github.com/PerryLink). The roster stays collapsed below so every README keeps a short first screen; expand it to see every row and its status.
|
|
388
|
+
- [@PerryLink](https://github.com/PerryLink) —— 创建者与维护者:规则词汇与求值、运行时、HMR 监听、会话日志审计、网络策略 + 代理,以及五语文档。
|
|
389
|
+
- [@am-i-dead](https://github.com/am-i-dead) —— 把客户端安全的 allow-host helper 从 host-only 模块中拆出([#24](https://github.com/PerryLink/dsh-permission-rules/issues/24))。
|
|
390
|
+
- [@22xuan](https://github.com/22xuan) —— 关于 rc.6 宿主静默丢弃审计事件 `ignorable` 标记的详细报告([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2))与上游 harness 讨论;v0.4.1 的运行时宿主能力检测与文档更正直接源自该分析。
|
|
391
|
+
- [@sjh9714](https://github.com/sjh9714) —— 提出共享规则语法测试向量语料([#4](https://github.com/PerryLink/dsh-permission-rules/issues/4)、[#5](https://github.com/PerryLink/dsh-permission-rules/issues/5)),已于 v0.5.1 以 `docs/rule-test-vectors/` 落地,并在[方案讨论](https://github.com/PerryLink/dsh-permission-rules/discussions/10)中补充了 AST 分解的边界用例。
|
|
392
|
+
- [@weipeng1999](https://github.com/weipeng1999) —— 提出基于 AST 的命令分解功能([#8](https://github.com/PerryLink/dsh-permission-rules/issues/8)),促成该方案讨论。
|
|
393
|
+
- [@alexchenzl](https://github.com/alexchenzl) —— DSH 目录收录请求([#7](https://github.com/PerryLink/dsh-permission-rules/issues/7))。
|
|
394
|
+
- [@zl190](https://github.com/zl190) —— 报告并验证了 `0.1.0-rc.7` harness 兼容性缺口([PR #9](https://github.com/PerryLink/dsh-permission-rules/pulls/9))。
|
|
395
|
+
- [@cuohua](https://github.com/cuohua) —— 报告版本门仅覆盖 `0.1.0` 线后,`0.1.1-rc` 线仍静默丢弃 `ignorable` 标记([#11](https://github.com/PerryLink/dsh-permission-rules/issues/11));加宽后的版本门直接源自该分析。
|
|
336
396
|
|
|
337
397
|
<details>
|
|
338
|
-
<summary
|
|
398
|
+
<summary>展开全部插件</summary>
|
|
339
399
|
|
|
340
|
-
|
|
|
400
|
+
| 插件 | 状态 |
|
|
341
401
|
|---|---|
|
|
342
402
|
| **[dsh-aqua-input-check](https://github.com/PerryLink/dsh-aqua-input-check)** | |
|
|
343
403
|
| **[dsh-archive-check](https://github.com/PerryLink/dsh-archive-check)** | |
|
|
344
404
|
| **[dsh-auto-review](https://github.com/PerryLink/dsh-auto-review)** | |
|
|
345
|
-
| **[dsh-autotier](https://github.com/PerryLink/dsh-autotier)** | 🧊
|
|
405
|
+
| **[dsh-autotier](https://github.com/PerryLink/dsh-autotier)** | 🧊 已冻结 — 见仓库 README |
|
|
346
406
|
| **[dsh-bid-ca-precheck](https://github.com/PerryLink/dsh-bid-ca-precheck)** | |
|
|
347
407
|
| **[dsh-bid-qual-check](https://github.com/PerryLink/dsh-bid-qual-check)** | |
|
|
348
|
-
| **[dsh-cert-mcp](https://github.com/PerryLink/dsh-cert-mcp)** | 🧊
|
|
408
|
+
| **[dsh-cert-mcp](https://github.com/PerryLink/dsh-cert-mcp)** | 🧊 已冻结 — 见仓库 README |
|
|
349
409
|
| **[dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind)** | |
|
|
350
410
|
| **[dsh-click](https://github.com/PerryLink/dsh-click)** | |
|
|
351
411
|
| **[dsh-composer-history](https://github.com/PerryLink/dsh-composer-history)** | |
|
|
352
412
|
| **[dsh-contract-stance](https://github.com/PerryLink/dsh-contract-stance)** | |
|
|
353
413
|
| **[dsh-customs-doc-check](https://github.com/PerryLink/dsh-customs-doc-check)** | |
|
|
354
|
-
| **[dsh-data-quality](https://github.com/PerryLink/dsh-data-quality)** |
|
|
414
|
+
| **[dsh-data-quality](https://github.com/PerryLink/dsh-data-quality)** | 🧊 已冻结 — 见仓库 README |
|
|
355
415
|
| **[dsh-demurrage-ledger](https://github.com/PerryLink/dsh-demurrage-ledger)** | |
|
|
356
416
|
| **[dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck)** | |
|
|
357
417
|
| **[dsh-drill-script-check](https://github.com/PerryLink/dsh-drill-script-check)** | |
|
|
@@ -384,7 +444,7 @@ This project is part of the DeepSeek Harness plugin family from [PerryLink](http
|
|
|
384
444
|
| **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | |
|
|
385
445
|
| **[dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel)** | |
|
|
386
446
|
| **[dsh-medrec-qc](https://github.com/PerryLink/dsh-medrec-qc)** | |
|
|
387
|
-
| **[dsh-memento](https://github.com/PerryLink/dsh-memento)** |
|
|
447
|
+
| **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | 🧊 已冻结 — 见仓库 README |
|
|
388
448
|
| **[dsh-nsfc-form-check](https://github.com/PerryLink/dsh-nsfc-form-check)** | |
|
|
389
449
|
| **[dsh-nurse-record-check](https://github.com/PerryLink/dsh-nurse-record-check)** | |
|
|
390
450
|
| **[dsh-observe](https://github.com/PerryLink/dsh-observe)** | |
|
|
@@ -396,10 +456,10 @@ This project is part of the DeepSeek Harness plugin family from [PerryLink](http
|
|
|
396
456
|
| **[dsh-permit-report-check](https://github.com/PerryLink/dsh-permit-report-check)** | |
|
|
397
457
|
| **[dsh-pipeline-check](https://github.com/PerryLink/dsh-pipeline-check)** | |
|
|
398
458
|
| **[dsh-pleading-draft](https://github.com/PerryLink/dsh-pleading-draft)** | |
|
|
399
|
-
| **[dsh-plugin-doctor](https://github.com/PerryLink/dsh-plugin-doctor)** |
|
|
459
|
+
| **[dsh-plugin-doctor](https://github.com/PerryLink/dsh-plugin-doctor)** | 🚫 已退役(仓库已归档) |
|
|
400
460
|
| **[dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide)** | |
|
|
401
|
-
| **[dsh-plugin-kit](https://github.com/PerryLink/dsh-plugin-kit)** |
|
|
402
|
-
| **[dsh-plugin-upgrade](https://github.com/PerryLink/dsh-plugin-upgrade)** |
|
|
461
|
+
| **[dsh-plugin-kit](https://github.com/PerryLink/dsh-plugin-kit)** | 🚫 已退役(仓库已归档) |
|
|
462
|
+
| **[dsh-plugin-upgrade](https://github.com/PerryLink/dsh-plugin-upgrade)** | 🚫 已退役(仓库已归档) |
|
|
403
463
|
| **[dsh-policy-brief-draft](https://github.com/PerryLink/dsh-policy-brief-draft)** | |
|
|
404
464
|
| **[dsh-power-loss-split](https://github.com/PerryLink/dsh-power-loss-split)** | |
|
|
405
465
|
| **[dsh-power-ticket-check](https://github.com/PerryLink/dsh-power-ticket-check)** | |
|
|
@@ -411,7 +471,7 @@ This project is part of the DeepSeek Harness plugin family from [PerryLink](http
|
|
|
411
471
|
| **[dsh-review-reply-check](https://github.com/PerryLink/dsh-review-reply-check)** | |
|
|
412
472
|
| **[dsh-rulefile-check](https://github.com/PerryLink/dsh-rulefile-check)** | |
|
|
413
473
|
| **[dsh-safety-brief-check](https://github.com/PerryLink/dsh-safety-brief-check)** | |
|
|
414
|
-
| **[dsh-score](https://github.com/PerryLink/dsh-score)** |
|
|
474
|
+
| **[dsh-score](https://github.com/PerryLink/dsh-score)** | 🧊 已冻结 — 见仓库 README |
|
|
415
475
|
| **[dsh-session-sync](https://github.com/PerryLink/dsh-session-sync)** | |
|
|
416
476
|
| **[dsh-site-log-check](https://github.com/PerryLink/dsh-site-log-check)** | |
|
|
417
477
|
| **[dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security)** | |
|
|
@@ -423,20 +483,24 @@ This project is part of the DeepSeek Harness plugin family from [PerryLink](http
|
|
|
423
483
|
| **[dsh-tender-extract](https://github.com/PerryLink/dsh-tender-extract)** | |
|
|
424
484
|
| **[dsh-tender-matrix](https://github.com/PerryLink/dsh-tender-matrix)** | |
|
|
425
485
|
| **[dsh-test-drive](https://github.com/PerryLink/dsh-test-drive)** | |
|
|
426
|
-
| **[dsh-ticktick](https://github.com/PerryLink/dsh-ticktick)** |
|
|
486
|
+
| **[dsh-ticktick](https://github.com/PerryLink/dsh-ticktick)** | 🚫 已退役(仓库已归档) |
|
|
427
487
|
| **[dsh-translate](https://github.com/PerryLink/dsh-translate)** | |
|
|
428
488
|
| **[dsh-warranty-calc](https://github.com/PerryLink/dsh-warranty-calc)** | |
|
|
429
|
-
| **[dsh-budget](https://github.com/PerryLink/dsh-budget)** | 🧊
|
|
430
|
-
| **[dsh-claude-move](https://github.com/PerryLink/dsh-claude-move)** | 🧊
|
|
431
|
-
| **[dsh-defend](https://github.com/PerryLink/dsh-defend)** | 🧊
|
|
432
|
-
| **[dsh-draw](https://github.com/PerryLink/dsh-draw)** | 🧊
|
|
433
|
-
| **[dsh-reach](https://github.com/PerryLink/dsh-reach)** | 🧊
|
|
434
|
-
| **[dsh-background-agents](https://github.com/PerryLink/dsh-background-agents)** | 🚫
|
|
435
|
-
| **[dsh-session-pin](https://github.com/PerryLink/dsh-session-pin)** | 🚫
|
|
436
|
-
| **[dsh-team-rooms](https://github.com/PerryLink/dsh-team-rooms)** | 🚫
|
|
489
|
+
| **[dsh-budget](https://github.com/PerryLink/dsh-budget)** | 🧊 已冻结 — 见仓库 README |
|
|
490
|
+
| **[dsh-claude-move](https://github.com/PerryLink/dsh-claude-move)** | 🧊 已冻结 — 见仓库 README |
|
|
491
|
+
| **[dsh-defend](https://github.com/PerryLink/dsh-defend)** | 🧊 已冻结 — 见仓库 README |
|
|
492
|
+
| **[dsh-draw](https://github.com/PerryLink/dsh-draw)** | 🧊 已冻结 — 见仓库 README |
|
|
493
|
+
| **[dsh-reach](https://github.com/PerryLink/dsh-reach)** | 🧊 已冻结 — 见仓库 README |
|
|
494
|
+
| **[dsh-background-agents](https://github.com/PerryLink/dsh-background-agents)** | 🚫 已退役(仓库已归档) |
|
|
495
|
+
| **[dsh-session-pin](https://github.com/PerryLink/dsh-session-pin)** | 🚫 已退役(仓库已归档) |
|
|
496
|
+
| **[dsh-team-rooms](https://github.com/PerryLink/dsh-team-rooms)** | 🚫 已退役(仓库已归档) |
|
|
437
497
|
|
|
438
498
|
</details>
|
|
439
499
|
|
|
440
500
|
## License
|
|
441
501
|
|
|
442
|
-
[Apache License 2.0
|
|
502
|
+
[LICENSE](LICENSE)(Apache License 2.0)© 2026 dsh-permission-rules contributors
|
|
503
|
+
|
|
504
|
+
<p align="center"><sub>Apache-2.0 · 社区插件,与 DeepSeek 无关。</sub></p>
|
|
505
|
+
|
|
506
|
+
<p align="center"><sub>工具链:<a href="https://github.com/PerryLink/dsh-plugin-guide">dsh-plugin-guide</a> · <a href="https://github.com/PerryLink/dsh-standards">dsh-standards</a> · <a href="https://github.com/PerryLink/dsh-plugin-start">dsh-plugin-start</a></sub></p>
|