dsh-perm-gate 2.1.2 → 2.6.2

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 (67) hide show
  1. package/CHANGELOG.ja.md +108 -0
  2. package/CHANGELOG.ko.md +104 -0
  3. package/CHANGELOG.md +239 -0
  4. package/INSTALL.ja.md +41 -21
  5. package/INSTALL.ko.md +37 -19
  6. package/INSTALL.md +46 -23
  7. package/INSTALL.zh.md +33 -17
  8. package/README.ja.md +52 -12
  9. package/README.ko.md +53 -13
  10. package/README.md +68 -10
  11. package/README.zh.md +41 -10
  12. package/assets/allow1.png +0 -0
  13. package/assets/allow2.png +0 -0
  14. package/assets/gateoff.png +0 -0
  15. package/assets/llms.png +0 -0
  16. package/assets/permlist.png +0 -0
  17. package/assets/setting-head.png +0 -0
  18. package/assets/setting-rules.png +0 -0
  19. package/cordis.patch.yml +11 -8
  20. package/docs/baseline-guard.md +56 -0
  21. package/docs/plan-rules-to-settings.md +217 -0
  22. package/docs/rules-format.en.md +294 -0
  23. package/docs/rules-format.md +279 -0
  24. package/docs/ui-gap-analysis-and-branch-permissions.md +338 -0
  25. package/dsh.plugin.json +2 -2
  26. package/examples/permissions.example.yaml +16 -1
  27. package/lib/allowlist.d.ts +27 -0
  28. package/lib/allowlist.js +103 -1
  29. package/lib/cli.js +11 -14
  30. package/lib/client.js +484 -6
  31. package/lib/client.js.map +1 -1
  32. package/lib/command-dispatcher.d.ts +22 -0
  33. package/lib/command-dispatcher.js +97 -0
  34. package/lib/command-semantics.d.ts +62 -0
  35. package/lib/command-semantics.js +6 -0
  36. package/lib/compiler.d.ts +11 -0
  37. package/lib/compiler.js +16 -0
  38. package/lib/config.d.ts +73 -12
  39. package/lib/config.js +56 -14
  40. package/lib/dry-run.d.ts +87 -0
  41. package/lib/dry-run.js +110 -0
  42. package/lib/engine.js +52 -2
  43. package/lib/evaluate.js +76 -2
  44. package/lib/events.d.ts +56 -2
  45. package/lib/events.js +92 -0
  46. package/lib/index.js +106 -26
  47. package/lib/parsers/git.d.ts +43 -0
  48. package/lib/parsers/git.js +404 -0
  49. package/lib/parsers/shell-cmds.d.ts +32 -0
  50. package/lib/parsers/shell-cmds.js +293 -0
  51. package/lib/preset.d.ts +13 -0
  52. package/lib/preset.js +17 -0
  53. package/lib/risk.d.ts +17 -3
  54. package/lib/risk.js +17 -3
  55. package/lib/rule-chain.js +13 -22
  56. package/lib/rule-dims.d.ts +35 -0
  57. package/lib/rule-dims.js +36 -0
  58. package/lib/rule.d.ts +36 -1
  59. package/lib/rule.js +56 -8
  60. package/lib/rules-view.d.ts +52 -0
  61. package/lib/rules-view.js +126 -0
  62. package/lib/runtime.d.ts +121 -7
  63. package/lib/runtime.js +204 -25
  64. package/lib/shell.d.ts +14 -0
  65. package/lib/shell.js +17 -0
  66. package/package.json +19 -2
  67. package/scripts/patch-permission-glyph.mjs +225 -42
package/INSTALL.ko.md CHANGED
@@ -12,7 +12,7 @@
12
12
  - [日本語 changelog](./CHANGELOG.ja.md)
13
13
  - [한국어 changelog](./CHANGELOG.ko.md)
14
14
 
15
- `dsh-perm-gate` 버전 **2.1.2**. 결정 체인, 규칙 파일 형식, 自动审查 티어는
15
+ `dsh-perm-gate` 버전 **2.6.1**. 결정 체인, 규칙 파일 형식, 自动审查 티어는
16
16
  [한국어 README](./README.ko.md)를 참고하세요.
17
17
 
18
18
  ## 요구 사항
@@ -23,20 +23,21 @@
23
23
  - 설치할 profile. 브라우저 절반은 `web` profile용으로만 빌드됩니다
24
24
  (`package.json`의 `dsh.client.platform = "web"`).
25
25
 
26
- ## DSH 버전에 맞는 tag 선택
26
+ ## DSH 버전에 맞는 라인 선택
27
27
 
28
- 단일 빌드는 두 DSH 라인을 모두 커버하므로, 어느 tag를 골라도 작동하는 코드가
29
- 설치됩니다 —— tag를 유지하는 이유는 당신이 고정하는 버전이 각 라인에서 의미 있게
30
- 유지되도록 하기 위함입니다.
28
+ 두 개의 장기 브랜치가 두 DSH 라인을 담당합니다: `main`(2.x)과
29
+ `sync/0.1.5-from-main`(3.x, DSH 0.1.5 패키징 변형 —— `compat/0.1.5`는 같은 코드
30
+ 트리를 가리킵니다).
31
31
 
32
32
  | DSH 버전 | 설치 방법 |
33
33
  |----------|-----------|
34
- | `0.1.2-alpha.1` 이상 (`0.1.5-rc.2` 포함) | `dsh plugin --profile web add dsh-perm-gate` (tag `latest`) |
34
+ | `0.1.2-alpha.1` – `0.1.5-rc.0` | `dsh plugin --profile web add dsh-perm-gate` (tag `latest`, 2.x 라인) |
35
+ | `0.1.5-rc.1` 이상 | `dsh plugin --profile web add github:drscrewdriver/dsh-perm-gate#sync/0.1.5-from-main` (3.x 라인; npm dist-tag 미게시 —— `@latest`는 동일 코드의 2.x 패키징을 설치) |
35
36
  | `0.1.1-rc.2` 이하 | `dsh plugin --profile web add dsh-perm-gate@legacy` |
36
37
 
37
- DSH는 `engines.dsh`를 강제하지 않으므로, tag는 선택 메커니즘이지 호환성 게이트가
38
- 아닙니다. 단일 아티팩트가 두 라인을 커버하는 이유와 tag가 게시되는 방식에 대해서는
39
- [RELEASING.md](./RELEASING.md)를 참고하세요.
38
+ DSH는 `engines.dsh`를 강제하지 않으므로, tag과 ref은 선택 메커니즘이지 호환성
39
+ 게이트가 아닙니다. 라인과 tag 게시 레이아웃은 [RELEASING.md](./RELEASING.md)를
40
+ 참고하세요.
40
41
 
41
42
  ## 공식 CLI로 설치
42
43
 
@@ -73,6 +74,11 @@ profile의 `cordis.yml`에 플러그인을 추가합니다:
73
74
  defaultAction: ask # allow | ask | deny
74
75
  ```
75
76
 
77
+ 2.6.0부터 규칙 본체는 `dsh-perm-gate-rules` settings 네임스페이스에 저장되며, 변경 시
78
+ 마다 게이트가 그 자리에서 다시 컴파일됩니다. 위의 YAML 파일은 선택 사항이 되었습니다.
79
+ 네임스페이스가 설정되지 않은 동안에만 읽히며, 플러그인이 처음으로 규칙을 쓸 때(허용
80
+ 목록 승인 또는 설정 UI에서의 편집) 파일의 규칙이 자동으로 흡수됩니다.
81
+
76
82
  [examples/permissions.example.yaml](./examples/permissions.example.yaml)에서 시작한 뒤
77
83
  profile을 다시 불러오세요.
78
84
 
@@ -90,13 +96,21 @@ dsh profile reload --profile web
90
96
 
91
97
  ## **DSH** 업그레이드 후: 입력창 아이콘 패치 재적용
92
98
 
93
- 「自动审查(高权限)」가 「自动审查」와 같은 방패+눈 아이콘을 보여 주는 것은
94
- `scripts/patch-permission-glyph.mjs`가 **DSH 호스트 패키지 안의 닫힌 Map**에 그 항목을
95
- 추가했기 때문일 뿐입니다. DSH는 플러그인이 제공한 티어에 **설계상 아이콘을 주지
99
+ 「自动审查」와「自动审查(高权限)」두 티어에 아이콘이 붙는 것은
100
+ `scripts/patch-permission-glyph.mjs`가 **DSH 호스트 패키지 안의 닫힌 Map**에 두 항목을
101
+ 추가했기 때문입니다 ——「自动审查」는 `workspace-write`의 방패+연필을,
102
+ 「自动审查(高权限)」는 `danger-full-access`의 방패+느낌표를 복사해 각자가 실제로 공유하는
103
+ 파일 샌드박스의 글리프를 갖습니다. DSH는 플러그인이 제공한 티어에 **설계상 아이콘을 주지
96
104
  않습니다** —— 그 Map 자체의 주석이 *"host-configured names outside the design set get
97
105
  none"*이라고 말합니다. 플러그인이 영향을 줄 수 있는 option 객체는
98
106
  `{value, name, description}`만 나르므로, 대신 쓸 수 있는 플러그인 측 이음새가 없습니다.
99
107
 
108
+ 스크립트는 원본 키를 **해석**합니다(`["<key>",`를 먼저, 다음으로 호스트가 쓰는 상수 별칭 ——
109
+ 0.1.5의 `danger-full-access`는 `[FULL_ACCESS,`). DSH는 이 설계 집합을 이미 한 번 바꿨습니다 ——
110
+ 0.1.2에는 `permissive` 글리프가 있었고 0.1.5에는 `read-only` / `workspace-write` /
111
+ `danger-full-access`만 있습니다. 해석할 수 없는 키는 Map이 실제로 가진 키와 함께 보고되므로
112
+ 티어 교체는 `GLYPH_TARGETS` 한 줄이면 됩니다.
113
+
100
114
  이 패치는 **호스트** 파일을 고치므로 **DSH 업그레이드나 재설치에서 사라집니다**.
101
115
  *이 플러그인*을 업그레이드할 때는 사라지지 않습니다. 아이콘은 애초에 플러그인 소유가
102
116
  아니었고, 플러그인 자신의 기여(`cordis.patch.yml`의 `name:` / `description:`)는
@@ -114,10 +128,13 @@ dsh profile reload --profile web
114
128
  플러그인이 허락 없이 자신이 설치된 harness를 다시 쓸 이유는 없습니다. 적용 여부와 무관하게
115
129
  DSH 동작에는 영향이 없고 티어 자체는 그대로 기능합니다.
116
130
 
117
- 이 스크립트는 멱등이며(두 번째 실행은 no-op), 백업은 한 번만 뜨고, 잘못 잘린 조각을
118
- 쓰지 않습니다 —— 결과에 `node --check`를 돌려 실패하면 백업을 복원합니다 —— 따라서
119
- DSH 업그레이드 때마다 무조건 다시 실행해도 안전합니다. 실행 중인 `node` 바이너리에서
120
- 패키지를 역산하므로 nvm 버전 변경이나 설치 symlink 재지정에도 깨지지 않습니다.
131
+ 이 스크립트는 멱등이며(두 번째 실행은 no-op), 백업은 한 번만 뜨고, 두 글리프를 모두
132
+ 적용하거나 모두 적용하지 않으며(해석할 수 없는 원본 키는 거부이지 부분 적용이 아닙니다),
133
+ 잘못 잘린 조각을 쓰지 않습니다 —— 결과에 `node --check`를 돌려 실패하면 백업을 복원합니다
134
+ —— 따라서 DSH 업그레이드 때마다 무조건 다시 실행해도 안전합니다. 호출자의 profile
135
+ 스코프를 먼저, CLI 설치를 다음으로 탐색하므로 nvm 버전 변경이나 설치 symlink 재지정에도
136
+ 깨지지 않습니다. 머신에 DSH 설치가 여러 개면 **패치하지 않은** 쪽이 출력에 나열됩니다 ——
137
+ 눈앞의 UI를 제공하는 것은 그중 하나뿐이므로, 필요하면 그 경로를 인수로 명시하세요.
121
138
 
122
139
  **플러그인을 재설치해도 아이콘은 돌아오지 않습니다.**
123
140
  `dsh plugin --profile web add …`는 profile 디렉터리 안의 pnpm으로 인자를 넘기고
@@ -190,11 +207,12 @@ DSH 번들 패치는 `permission.config.presets`를 key 단위로 병합하지
190
207
  합니다. profile을 다시 불러와 `cordis.patch.yml`을 재적용하고, 더 늦게 로드되는
191
208
  플러그인이 `presets`를 덮어쓰지 않는지 확인하세요.
192
209
 
193
- **「自动审查(高权限)」의 입력창 아이콘이 사라졌습니다.**
210
+ **「自动审查」티어의 입력창 아이콘이 사라졌습니다.**
194
211
  DSH 업그레이드나 재설치가 패치해 둔 호스트 번들을 교체했습니다. 플러그인을
195
212
  재설치해도 되돌아오지 않습니다. `npx dsh-perm-gate-patch-glyph`를 실행하고
196
- 다시 불러오세요. 티어 자체는 영향받지 않습니다 —— 패치가 없어도 라벨과 게이트는
197
- 정상 동작합니다.
213
+ 다시 불러오세요. 원본 키가 없다고 보고되면 DSH가 글리프 표를 다시 바꾼 것입니다 ——
214
+ 오류가 현재 키 목록을 알려 주므로 `GLYPH_TARGETS`에서 해당 티어를 다시 지정하세요.
215
+ 티어 자체는 영향받지 않습니다 —— 패치가 없어도 라벨과 게이트는 정상 동작합니다.
198
216
 
199
217
  **규칙 파일이 있는데 `--list`가 `ruleCount: 0`을 표시합니다.**
200
218
  `rulesFile`은 플러그인 디렉터리가 아니라 Harness 프로세스의 CWD에서 해석됩니다.
package/INSTALL.md CHANGED
@@ -12,7 +12,7 @@
12
12
  - [日本語 changelog](./CHANGELOG.ja.md)
13
13
  - [한국어 changelog](./CHANGELOG.ko.md)
14
14
 
15
- `dsh-perm-gate` version **2.1.2**. Continue with the [README](./README.md) for the
15
+ `dsh-perm-gate` version **2.6.1**. Continue with the [README](./README.md) for the
16
16
  decision chain, the rules file format and the 自动审查 tier.
17
17
 
18
18
  ## Requirements
@@ -23,19 +23,21 @@ decision chain, the rules file format and the 自动审查 tier.
23
23
  - A profile to install into — the browser half only ships for the `web` profile
24
24
  (`dsh.client.platform = "web"` in `package.json`).
25
25
 
26
- ## Pick the tag for your DSH version
26
+ ## Pick the line for your DSH version
27
27
 
28
- One build serves both DSH lines, so either tag installs working code — the tag
29
- exists so a version you pin stays meaningful per line.
28
+ Two long-lived branches serve two DSH lines: `main` (2.x) and
29
+ `sync/0.1.5-from-main` (3.x, the DSH 0.1.5 packaging variant — `compat/0.1.5`
30
+ points at the same tree).
30
31
 
31
32
  | Your DSH | Install |
32
33
  |----------|---------|
33
- | `0.1.2-alpha.1` or newer (incl. `0.1.5-rc.2`) | `dsh plugin --profile web add dsh-perm-gate` (tag `latest`) |
34
+ | `0.1.2-alpha.1` – `0.1.5-rc.0` | `dsh plugin --profile web add dsh-perm-gate` (tag `latest`, the 2.x line) |
35
+ | `0.1.5-rc.1` or newer | `dsh plugin --profile web add github:drscrewdriver/dsh-perm-gate#sync/0.1.5-from-main` (the 3.x line; no npm dist-tag yet — `@latest` installs the same code with 2.x packaging) |
34
36
  | up to `0.1.1-rc.2` | `dsh plugin --profile web add dsh-perm-gate@legacy` |
35
37
 
36
- DSH does not enforce `engines.dsh`, so the tags are the selection mechanism rather
37
- than a compatibility gate. See [RELEASING.md](./RELEASING.md) for why one artifact
38
- covers both lines and how the tags are published.
38
+ DSH does not enforce `engines.dsh`, so tags and refs are the selection mechanism
39
+ rather than a compatibility gate. See [RELEASING.md](./RELEASING.md) for how the
40
+ lines and tags are laid out.
39
41
 
40
42
  ## Install with the official CLI
41
43
 
@@ -73,6 +75,12 @@ Add the plugin to your profile's `cordis.yml`:
73
75
  gatePresets: [permissive] # tiers where the gate is active at all (default)
74
76
  ```
75
77
 
78
+ Since 2.6.0 the rules themselves are stored in the `dsh-perm-gate-rules` settings
79
+ namespace, and every change recompiles the gate in place. The YAML file above is
80
+ optional: it is only read while the namespace is untouched, and the first rules
81
+ write from the plugin (an allowlist approval, or an edit in the settings UI)
82
+ absorbs the file's rules automatically.
83
+
76
84
  Start from [examples/permissions.example.yaml](./examples/permissions.example.yaml),
77
85
  then reload the profile.
78
86
 
@@ -90,12 +98,21 @@ dsh profile reload --profile web
90
98
 
91
99
  ## After a **DSH** upgrade: re-apply the composer glyph patch
92
100
 
93
- The 自动审查(高权限) tier shows the same shield+eye glyph as 自动审查 only because
94
- `scripts/patch-permission-glyph.mjs` added it to a **closed map inside a DSH host
95
- package**. DSH gives host-configured tiers no glyph by design — the map's own
96
- comment reads *"host-configured names outside the design set get none"* — and the
97
- option objects a plugin can influence carry only `{value, name, description}`, so
98
- there is no plugin-side seam to use instead.
101
+ Both 自动审查 tiers draw an icon only because `scripts/patch-permission-glyph.mjs`
102
+ added them to a **closed map inside a DSH host package**: 自动审查 copies the
103
+ `workspace-write` glyph and 自动审查(高权限) the `danger-full-access` one — the
104
+ built-in tier each shares a file sandbox with. DSH gives host-configured tiers no
105
+ glyph by design — the map's own comment reads *"host-configured names outside the
106
+ design set get none"* — and the option objects a plugin can influence carry only
107
+ `{value, name, description}`, so there is no plugin-side seam to use instead.
108
+
109
+ The script resolves each source key instead of assuming its spelling: `["<key>",`
110
+ first, then the constant alias the bundle may use instead (`[FULL_ACCESS,` for
111
+ `danger-full-access`). DSH has already changed this design set once — 0.1.2 keyed a
112
+ `permissive` glyph, 0.1.5 keeps only `read-only` / `workspace-write` /
113
+ `danger-full-access` — and a source key it cannot resolve is reported together with
114
+ the keys the map does carry, so re-pointing a tier is a one-line edit to
115
+ `GLYPH_TARGETS`.
99
116
 
100
117
  That patch edits a **host** file, so a DSH upgrade or reinstall erases it. Upgrading
101
118
  *this plugin* does not: the plugin never owned the glyph, and its own contribution
@@ -112,11 +129,15 @@ the `dsh-perm-gate-patch-glyph` bin — so no source checkout is needed. It is d
112
129
  **not** wired to `postinstall`: it edits a host package, and a plugin must not rewrite its
113
130
  harness uninvited. Running DSH is unaffected either way; the tier works with or without it.
114
131
 
115
- It is idempotent (a second run is a no-op), backs the bundle up once, and refuses to
116
- write a mis-sliced bundle — it runs `node --check` on the result and restores the
117
- backup if that fails — so it is safe to run unconditionally after every DSH upgrade.
118
- It locates the bundle from the running `node` binary, so an nvm version change or a
119
- re-pointed install symlink does not break it.
132
+ It is idempotent (a second run is a no-op), backs the bundle up once, applies both
133
+ glyphs or neither (a source key it cannot resolve is a refusal, not a half-patch),
134
+ and refuses to write a mis-sliced bundle — it runs `node --check` on the result and
135
+ restores the backup if that fails — so it is safe to run unconditionally after every
136
+ DSH upgrade. It locates the bundle from the caller's profile scope first and the CLI
137
+ install second, so an nvm version change or a re-pointed install symlink does not
138
+ break it — and when the machine carries more than one DSH install, the ones it did
139
+ **not** patch are listed in the output, because only one of them serves the UI in
140
+ front of you. Pass that path explicitly to patch it.
120
141
 
121
142
  **Reinstalling the plugin does not restore the glyph.** `dsh plugin --profile web
122
143
  add …` forwards to pnpm inside the profile directory and writes the profile's own
@@ -191,11 +212,13 @@ The DSH bundle patch replaces the whole `permission.config.presets` map instead
191
212
  merging per key. Reload the profile so `cordis.patch.yml` is re-applied, and make
192
213
  sure no later plugin overwrites `presets`.
193
214
 
194
- **自动审查(高权限) lost its icon in the composer.**
195
- A DSH upgrade or reinstall replaced the host bundle the glyph was patched into;
215
+ **A 自动审查 tier lost its icon in the composer.**
216
+ A DSH upgrade or reinstall replaced the host bundle the glyphs were patched into;
196
217
  re-running the plugin install will not bring it back. Run
197
- `npx dsh-perm-gate-patch-glyph` and reload. The tier itself is
198
- unaffected — its label and its gating keep working without the patch.
218
+ `npx dsh-perm-gate-patch-glyph` and reload. If it reports that a source key is gone,
219
+ DSH changed the glyph map again: the error names the keys the map now carries, so
220
+ re-point the affected tier in `GLYPH_TARGETS`. The tiers themselves are
221
+ unaffected — their labels and their gating keep working without the patch.
199
222
 
200
223
  **`--list` reports `ruleCount: 0` although my rules file exists.**
201
224
  `rulesFile` is resolved against the process CWD of the harness, not the plugin
package/INSTALL.zh.md CHANGED
@@ -12,7 +12,7 @@
12
12
  - [日本語 changelog](./CHANGELOG.ja.md)
13
13
  - [한국어 changelog](./CHANGELOG.ko.md)
14
14
 
15
- `dsh-perm-gate` 版本 **2.1.2**。裁决链、规则文件格式与自动审查档位请见
15
+ `dsh-perm-gate` 版本 **2.6.1**。裁决链、规则文件格式与自动审查档位请见
16
16
  [中文 README](./README.zh.md)。
17
17
 
18
18
  ## 前置条件
@@ -23,18 +23,19 @@
23
23
  - 需要一个目标 profile —— 浏览器端只为 `web` profile 构建(`package.json`
24
24
  里 `dsh.client.platform = "web"`)。
25
25
 
26
- ## 按你的 DSH 版本选择 tag
26
+ ## 按你的 DSH 版本选择安装线
27
27
 
28
- 单一构建同时覆盖两条 DSH 线,所以任一 tag 安装的代码都能工作 —— 保留 tag
29
- 是为了让你锁定的版本在每条线上都有意义。
28
+ 两条长期分支分别服务两条 DSH 线:`main`(2.x)与 `sync/0.1.5-from-main`
29
+ (3.x,DSH 0.1.5 打包变体 —— `compat/0.1.5` 指向同一棵代码树)。
30
30
 
31
31
  | 你的 DSH | 安装方式 |
32
32
  |----------|----------|
33
- | `0.1.2-alpha.1` 或更高(含 `0.1.5-rc.2`) | `dsh plugin --profile web add dsh-perm-gate`(tag `latest`) |
33
+ | `0.1.2-alpha.1` – `0.1.5-rc.0` | `dsh plugin --profile web add dsh-perm-gate`(tag `latest`,2.x 线) |
34
+ | `0.1.5-rc.1` 或更高 | `dsh plugin --profile web add github:drscrewdriver/dsh-perm-gate#sync/0.1.5-from-main`(3.x 线;npm 尚无对应 dist-tag —— `@latest` 安装的是相同代码的 2.x 打包) |
34
35
  | 不高于 `0.1.1-rc.2` | `dsh plugin --profile web add dsh-perm-gate@legacy` |
35
36
 
36
- DSH 不强制 `engines.dsh`,因此 tag 是选择机制而非兼容性关卡。
37
- 详见 [RELEASING.md](./RELEASING.md) 了解为何单一制品覆盖两条线以及 tag 的发布方式。
37
+ DSH 不强制 `engines.dsh`,因此 tag 与 ref 是选择机制而非兼容性关卡。
38
+ 各线与 tag 的发布布局详见 [RELEASING.md](./RELEASING.md)。
38
39
 
39
40
  ## 用官方 CLI 安装
40
41
 
@@ -70,6 +71,10 @@ dsh plugin --profile web add .
70
71
  defaultAction: ask # allow | ask | deny
71
72
  ```
72
73
 
74
+ 自 2.6.0 起,规则本体存储在 `dsh-perm-gate-rules` settings 命名空间中,每次变更都会
75
+ 就地重编译闸门。上面的 YAML 文件变为可选:只有命名空间未被配置时才会读取它,插件
76
+ 发起的首次规则写入(白名单批准或设置界面编辑)会自动收编文件中的规则。
77
+
73
78
  可从 [examples/permissions.example.yaml](./examples/permissions.example.yaml) 起步,
74
79
  然后重载 profile。
75
80
 
@@ -87,11 +92,18 @@ dsh profile reload --profile web
87
92
 
88
93
  ## **DSH** 升级后:重打输入区图标补丁
89
94
 
90
- 「自动审查(高权限)」之所以和「自动审查」一样显示盾+眼图标,只是因为
91
- `scripts/patch-permission-glyph.mjs` 把这一项加进了 **DSH 宿主包里的一张封闭 Map**。
92
- DSH 对插件档位**设计上就不给图标** —— 那张表自己的注释写着 *"host-configured
93
- names outside the design set get none"*;而插件能影响的 option 对象只携带
94
- `{value, name, description}`,所以插件侧没有可用的接缝。
95
+ 两个「自动审查」档位之所以有图标,只是因为 `scripts/patch-permission-glyph.mjs`
96
+ 把它们加进了 **DSH 宿主包里的一张封闭 Map**:「自动审查」复制 `workspace-write` 的
97
+ 盾+铅笔,「自动审查(高权限)」复制 `danger-full-access` 的盾+感叹号 —— 各自对应
98
+ 自己实际共用的文件沙箱。DSH 对插件档位**设计上就不给图标** —— 那张表自己的注释写着
99
+ *"host-configured names outside the design set get none"*;而插件能影响的 option 对象
100
+ 只携带 `{value, name, description}`,所以插件侧没有可用的接缝。
101
+
102
+ 脚本会**解析**源键而不是假定它的写法:先找 `["<key>",`,再找宿主可能改用的常量别名
103
+ (`danger-full-access` 在 0.1.5 里就写作 `[FULL_ACCESS,`)。宿主已经改过一次设计集 ——
104
+ 0.1.2 有 `permissive` 图标,0.1.5 只剩 `read-only` / `workspace-write` /
105
+ `danger-full-access` —— 解析不到的源键会在报错里连同「表里实际有哪些键」一起给出,
106
+ 所以改档位只需改 `GLYPH_TARGETS` 一行。
95
107
 
96
108
  该补丁改的是**宿主**文件,因此 **DSH 升级或重装会把它抹掉**。升级*本插件*不会:
97
109
  图标从来不属于插件,而插件自己的贡献(`cordis.patch.yml` 里的 `name:` /
@@ -108,9 +120,12 @@ dsh profile reload --profile web
108
120
  `postinstall` 上:它改的是宿主包,插件不该未经许可改写自己所在的 harness。有没有它
109
121
  都不影响 DSH 运行,档位本身照常工作。
110
122
 
111
- 脚本是幂等的(重复执行是 no-op),只备份一次,且拒绝写坏切片 —— 它会对结果跑
112
- `node --check`,失败即还原备份 —— 所以每次 DSH 升级后无条件重跑都是安全的。
113
- 它从运行中的 `node` 二进制反推包路径,因此 nvm 换版本或安装软链重指都不会让它失效。
123
+ 脚本是幂等的(重复执行是 no-op),只备份一次,两个图标要么都打要么都不打(源键解析不到
124
+ 即拒绝,不会打出半个补丁),且拒绝写坏切片 —— 它会对结果跑 `node --check`,失败即还原
125
+ 备份 —— 所以每次 DSH 升级后无条件重跑都是安全的。它先探测调用方自己的 profile 作用域,
126
+ 再看 CLI 安装目录,因此 nvm 换版本或安装软链重指都不会让它失效;当机器上存在多份 DSH
127
+ 安装时,**没有**被打补丁的那些会列在输出里 —— 因为真正服务你面前界面的只有其中一份,
128
+ 需要时把那个路径作为参数显式传入。
114
129
 
115
130
  **重装插件并不会恢复图标。**`dsh plugin --profile web add …` 只是把参数转发给
116
131
  profile 目录里的 pnpm,只写 profile 自己的 `node_modules`;`-w`
@@ -180,9 +195,10 @@ DSH 的 bundle patch 是整体替换 `permission.config.presets`,而非逐 key
180
195
  请重载 profile 让 `cordis.patch.yml` 重新生效,并确认没有更晚加载的插件覆盖了
181
196
  `presets`。
182
197
 
183
- **「自动审查(高权限)」在输入区丢了图标。**
198
+ **某个「自动审查」档位在输入区丢了图标。**
184
199
  DSH 升级或重装替换了被打了补丁的宿主 bundle;重装插件不会把它带回来。执行
185
- `npx dsh-perm-gate-patch-glyph` 后重载即可。档位本身不受影响 ——
200
+ `npx dsh-perm-gate-patch-glyph` 后重载即可。若报错说某个源键不存在,说明宿主又改了
201
+ 图标表 —— 报错会列出表里现有的键,按提示改 `GLYPH_TARGETS` 即可。档位本身不受影响 ——
186
202
  没有补丁,它的标签与门禁照常工作。
187
203
 
188
204
  **规则文件存在但 `--list` 显示 `ruleCount: 0`。**
package/README.ja.md CHANGED
@@ -27,7 +27,8 @@
27
27
  > | DSH バージョン | ブランチ | バージョン | npm タグ |
28
28
  > | --- | --- | --- | --- |
29
29
  > | 0.1.0-rc.7 ~ 0.1.1-rc.x | `legacy` | `1.x` | `@legacy` |
30
- > | 0.1.2-alpha.1+(0.1.5-rc.2を含む) | `main` | `2.x` | `@latest` / `@dsh-0.1.2` (`@2.x` は範囲) |
30
+ > | 0.1.2-alpha.1 ~ 0.1.5-rc.0 | `main` | `2.x` | `@latest` / `@dsh-0.1.2` (`@2.x` は範囲) |
31
+ > | 0.1.5-rc.1+ | `sync/0.1.5-from-main`(=`compat/0.1.5`) | `3.x` | GitHub ref インストール(dist-tag 未公開) |
31
32
  >
32
33
  > バージョン系列は **DSH ライン**を追います(`1.x` = DSH ≤ 0.1.1、`2.x` = DSH 0.1.2+)。
33
34
  > メジャー同士が互いを遮断するため、`^1.x` のインストールが `2.x` を解決することは
@@ -45,7 +46,7 @@
45
46
  > メソッドであるため、`typeof` プロブで読み取り、欠落時やエラー時には「ポリシー
46
47
  > 不明」にフォールバックします。
47
48
 
48
- バージョン **2.1.2** — 変更履歴は [日本語 changelog](./CHANGELOG.ja.md) を参照。
49
+ バージョン **2.6.1** — 変更履歴は [日本語 changelog](./CHANGELOG.ja.md) を参照。
49
50
 
50
51
  DeepSeek Harness 向けの、単一・自己完結・決定論優先・fail-closed な権限ゲートです。
51
52
 
@@ -93,6 +94,31 @@ DSH の安全まわりのエコシステムでは、この役割が `dsh-permiss
93
94
  オンにすると、ゲートが許可した呼び出しを `callId` で正確に一致させてここで直接回答
94
95
  します。
95
96
 
97
+ ## スクリーンショット
98
+
99
+ **設定カード — 自动审查ティア**:フロントが露出するのは単一スイッチのみで、バックエンドの
100
+ 4 戦略は組み合わせ可能です。`LlmAssist` はセッションの現在のモデルに追従するか、
101
+ Provider / Model を固定でき、ヘルスチェックと裁決学習を備えます:
102
+
103
+ ![設定カード — 自动审查ティア](assets/setting-head.png)
104
+ ![LlmAssist — Provider / Model / API Key](assets/llms.png)
105
+
106
+ **ゲートが実際に読み込んだルール** — `dsh-perm-gate-rules` 設定名前空間から直接読み出した
107
+ 読み取り専用ビューです。パネルからは変更できません:
108
+
109
+ ![組み込みルール(読み取り専用)](assets/setting-rules.png)
110
+
111
+ **権限承認記録** — このセッションのすべての裁決を新しい順に、モデルが見た理由つきで表示します:
112
+
113
+ ![権限承認記録](assets/permlist.png)
114
+
115
+ **裁決ストリップ** — 自動許可は根拠(読み取り専用ツール、または LLM の `safe` 判定)を明示し、
116
+ ゲートの停止も決して無言では起きません:
117
+
118
+ ![ALLOW ストリップ — 読み取り専用ツール](assets/allow1.png)
119
+ ![ALLOW ストリップ — llm-assist が safe](assets/allow2.png)
120
+ ![GATE OFF ストリップ — ゲート停止](assets/gateoff.png)
121
+
96
122
  ## インストール
97
123
 
98
124
  [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) が導入済みである
@@ -202,7 +228,16 @@ DSH **自身**の通信 —— 組み込みネットワークツールと LLM
202
228
  自动审查は権限ピッカーの中で 読み取り専用 / ワークスペース内変更 / 完全権限 /
203
229
  許可リストと並ぶ**独立した承認ティア**です。汎用の「自動承認」ではなく、包括的な権限を
204
230
  発行することもありません。人間/LLM のシーム**の前**で判定を狭めたり広めたりする
205
- だけで、P0 ハード拒否は単調かつ交渉不能のままです。
231
+ だけで、P0 ハード拒否は**ゲート自身のスコープ内で**単調かつ交渉不能のままです。
232
+
233
+ > **P0 はスコープ付きであり、グローバルではありません。** このゲートはセッションの権限プリセットが
234
+ > `gatePresets`(既定は `permissive` / `permissive-full`)のいずれかである間だけ動作します。それ以外の
235
+ > プリセット —— 読み取り専用 / ワークスペース内変更 / 完全権限 —— では **P0 ハード拒否を含むゲート
236
+ > 全体が停止**し、選択されたティア自身のポリシーがそのセッションを統治します。これは意図的な設計です
237
+ > (設定表の `gatePresets` を参照)が、「P0 は交渉不能」は**ゲートのティア内**で成立するものであり、
238
+ > すべてのティアに跨るものではありません。停止は**沈黙しません**: セッション/プリセットの遷移ごとに
239
+ > `stand-down` イベントを 1 件記録し、ブラウザは入力欄の上に **GATE OFF** の常駐ストリップを表示します。
240
+ > `gatePresets: ['*']` に設定すると P0 は再びグローバルになります。
206
241
 
207
242
  **2 つのバリアントを同梱します。** プリセットの `sandbox` と `approval` は**独立した**ノブであり、
208
243
  両者を結び付けると悪いトレードオフを強いられるためです。
@@ -226,9 +261,10 @@ P0–P4 の全チェーンが動作します。ゲートはプリセットの**
226
261
  `cordis.patch.yml` は全セッション共通で中国語ラベルを配布します。
227
262
 
228
263
  **アイコンは別の話です。** 入力欄のグリフ表は閉じており、その表自身のコメントが規則を述べています:
229
- *host-configured names outside the design set get none*。`permissive` は組み込み値なので
230
- 「自动审查」には元から盾+目のアイコンがあります。「自动审查(高权限)」が同じアイコンを得るのは、
231
- `npx dsh-perm-gate-patch-glyph` がその表に 1 項目を追加したからです。このパッチは
264
+ *host-configured names outside the design set get none*。どちらのティアも組み込み値ではないため、
265
+ アイコンは `npx dsh-perm-gate-patch-glyph` がその表に 2 項目を足すことで初めて付きます ——
266
+ 「自动审查」は `workspace-write` の盾+鉛筆を、「自动审查(高权限)」は `danger-full-access` の
267
+ 盾+感嘆符をコピーし、それぞれが実際に共有するファイルサンドボックスのグリフになります。このパッチは
232
268
  **ホスト**パッケージを書き換えるため、DSH アップグレードのたびに失われます ——
233
269
  [DSH アップグレード後:入力欄アイコンのパッチを再適用](./INSTALL.ja.md) を参照してください。
234
270
 
@@ -296,8 +332,10 @@ never` パススルー — は人手に変更なく委譲されるため、将
296
332
  ゲートが動作するのは **`gatePresets` に列挙したティアの中だけ**です(既定
297
333
  `['permissive', 'permissive-full']`、このプラグインが追加する 2 つのティア)。それ以外のティア(Read Only / Workspace Write /
298
334
  Full access / `custom`)では、ゲートの判定フローは**一切実行されません**——許可も、ask も、
299
- 拒否も、P0 ハード拒否も、拒否キーワードの遮断も、監査イベントの記録も行いません。選択された
300
- ティア自身の方針が呼び出しを決めます。`danger-full-access` の定義は「承認プロンプトなしの
335
+ 拒否も、P0 ハード拒否も、拒否キーワードの遮断も行いません。選択された
336
+ ティア自身の方針が呼び出しを決めます。ただし**沈黙はしません**: セッション/プリセットの遷移ごとに
337
+ `stand-down` イベントを 1 件だけ記録し(判定ではなく通知です)、ブラウザは入力欄の上に
338
+ **GATE OFF** の常駐ストリップを表示します。`danger-full-access` の定義は「承認プロンプトなしの
301
339
  フルアクセス」であり、そこを ask で上書きしても意味がありません(その方針では DSH の承認シームが
302
340
  **どの answerer よりも先に** `rejected` を返し、転送された ask はパネルを一度も表示せず
303
341
  `the user rejected tool "..."` にしかなりません)。ハード拒否で上書きするのも、ユーザーが選んだ
@@ -319,7 +357,8 @@ Full access / `custom`)では、ゲートの判定フローは**一切実行
319
357
  `llmAssist` 有効時、設定された LLM(OpenAI 互換エンドポイントなら任意——`classifierEndpoint` / `classifierModel` / `classifierApiKey` を自分の API に向けてください)が構造化プロトコルで `ask` を 1 件ずつ判定します。**判定はゲートの `tools/pre-execute` ウォーターフォール内、決定がホストへ返る前に行われます**:`safe` はそのまま委譲されるため承認パネルは一切表示されず、本当に判断できない判定だけが人手に回ります。
320
358
 
321
359
  - `safe` → 自動許可(監査ソースは `classifier`)。パネルは表示されません。
322
- - `risky` + **ハードリスクカテゴリ**(`deletion`、`credential`、`remote`、`system`、`bulk`)→ **自動拒否**、パネルなし。ハードリスクは自動許可も学習もされません。
360
+ - `risky` + **ハードリスクカテゴリ**(`deletion`、`credential`、`remote`、`system`、`bulk`)→ **人間への確認(ask)を維持**します。分類器は**決して拒否しません**。拒否は決定論的レイヤー(P0 ハード拒否、拒否キーワードのブラックリスト、明示的な `deny:` ルール)だけに属するため、誤判定されたカテゴリは常に交渉可能で、異議を唱えられないブロックにはなりません。ハードカテゴリが `neutral` と異なる重要な点は一つだけです: **決して学習されない**ため、承認を繰り返しても自動許可に沈殿しません。
361
+ (モデルの判断を拒否の根拠にした結果は実測済みです: 無害な `git commit -F …` が `remote` と判定され、パネルも再試行用の grant もない自動拒否が発生しました。)
323
362
  - `risky:neutral` → `riskLearning` 有効時(設定カード内、既定オフ)、人手で承認され実際に実行された neutral リスクは `tool|カテゴリ` ごとにカウントされ、`riskThreshold`(既定 3)到達かつ新呼び出しの操作指紋(コマンド語+対象の基底名)が確認済みサンプルに一致した場合、**同一操作のみ**自動許可されます。学習沈殿(`riskSediment`、既定オン)を有効にすると、しきい値に達したキーの確認サンプルは**決定論的な許可ルール**になります:指紋の正確一致は LLM を経由せず自動許可——llmAssist オフでも継続し、沈殿ルールは設定カードで確認・管理(終止 / サンプル削除)できます。
324
363
  - タイムアウト(`riskTimeoutMs`、既定 20 秒、1 回リトライ)、通信失敗、プロトコル外出力は元の `ask` を維持します。
325
364
 
@@ -330,9 +369,10 @@ Full access / `custom`)では、ゲートの判定フローは**一切実行
330
369
  人手に回した `ask` は回答が返るまで追跡されます。受動的な `approval/request` オブザーバが閉じた結果を記録し(`allowed-once` → **承認**、`rejected` → **拒否**、`cancelled` → **キャンセル**、`unavailable` → 拒否=承認チャネルなし)、オブザーバが関連付けできない場合(`callId` 欠落・approval サービスなし・上流リスナーの短絡)は `tools/result` が同じ ask をフォールバックとして解決します。承認時には承認後の学習進捗(`n`/しきい値)を表示し、通知バーも 3 つの終態にラベルを付けます。
331
370
 
332
371
  さらにプリセットの**拒否キーワード黑名単**(dsh-approval-gate の `DEFAULT_DENY_KEYWORDS` を継承:`rm -rf`、`push --force`、`drop table`、`mkfs`、`git reset --hard`、`docker system prune` など)を備え、テキストがキーワードを含む呼び出し(大小文字を区別しない部分一致)は許可リスト / 許可 / LLM より先に拒否します。設定カードでリストとして編集でき(プリセット項目にはタグ付き、ワンクリック復元対応)、未設定・空ならプリセットを適用します——黑名単が静かに無効化されることはありません。
333
- 「自动审查」と「自动审查(高权限)」はどちらもピッカーに盾+目のアイコンを描きます —— 前者は
334
- DSH の組み込み表から、後者はインストールガイドに書かれたホストパッチからです。そのパッチが
335
- ない場合、2 つ目のティアはどのサーフェスでもテキストのみになります。ラベルとゲートは影響を
372
+ 「自动审查」と「自动审查(高权限)」はどちらもピッカーにアイコンを描きます —— インストール
373
+ ガイドに書かれたホストパッチが、それぞれが共有するファイルサンドボックスのティア
374
+ (`workspace-write` と `danger-full-access`)からコピーしたものです。そのパッチが
375
+ ない場合、両ティアはどのサーフェスでもテキストのみになります。ラベルとゲートは影響を
336
376
  受けません。
337
377
 
338
378
 
package/README.ko.md CHANGED
@@ -27,7 +27,8 @@
27
27
  > | DSH 버전 | 브랜치 | 버전 | npm 태그 |
28
28
  > | --- | --- | --- | --- |
29
29
  > | 0.1.0-rc.7 ~ 0.1.1-rc.x | `legacy` | `1.x` | `@legacy` |
30
- > | 0.1.2-alpha.1+ (0.1.5-rc.2 포함) | `main` | `2.x` | `@latest` / `@dsh-0.1.2` (`@2.x`는 범위) |
30
+ > | 0.1.2-alpha.1 ~ 0.1.5-rc.0 | `main` | `2.x` | `@latest` / `@dsh-0.1.2` (`@2.x`는 범위) |
31
+ > | 0.1.5-rc.1+ | `sync/0.1.5-from-main` (=`compat/0.1.5`) | `3.x` | GitHub ref 설치 (dist-tag 미게시) |
31
32
  >
32
33
  > 버전 계열은 **DSH 라인**을 따릅니다(`1.x` = DSH ≤ 0.1.1, `2.x` = DSH 0.1.2+). 메이저
33
34
  > 버전이 서로를 차단하므로 `^1.x` 설치가 `2.x`를 해석하는 일은 없고 그 반대도
@@ -43,7 +44,7 @@
43
44
  > 모두에서 user-approval 서비스의 **개인** 메소드이므로 `typeof` 프로브를 통해
44
45
  > 읽으며, 누락되거나 예외 발생 시 "정책_unknown"으로 후퇴합니다.
45
46
 
46
- 버전 **2.1.2** — 변경 내역은 [한국어 changelog](./CHANGELOG.ko.md)를 참고하세요.
47
+ 버전 **2.6.1** — 변경 내역은 [한국어 changelog](./CHANGELOG.ko.md)를 참고하세요.
47
48
 
48
49
  DeepSeek Harness용 단일·자족적·결정론 우선·fail-closed 권한 게이트입니다.
49
50
 
@@ -90,6 +91,31 @@ DSH 안전 생태계에서는 이 역할이 `dsh-permission-rules` / `dsh-auto-m
90
91
  없고, 게이트가 자동 허용한 호출에도 확인 프롬프트가 나타납니다. 이 전략을 켜면 게이트가
91
92
  `callId`로 이미 허용한 호출을 정확히 매칭하여 여기서 직접 응답합니다.
92
93
 
94
+ ## 스크린샷
95
+
96
+ **설정 카드 — 自动审查 티어**: 프론트는 단일 스위치만 노출하고, 백엔드의 네 전략은 조합
97
+ 가능합니다. `LlmAssist`는 세션의 현재 모델을 따르거나 Provider / Model을 고정할 수 있으며,
98
+ 헬스 테스트와 판정 학습을 갖춥니다:
99
+
100
+ ![설정 카드 — 自动审查 티어](assets/setting-head.png)
101
+ ![LlmAssist — Provider / Model / API Key](assets/llms.png)
102
+
103
+ **게이트가 실제로 로드한 규칙** — `dsh-perm-gate-rules` 설정 네임스페이스에서 직접 읽은
104
+ 읽기 전용 뷰입니다. 패널에서는 바꿀 수 없습니다:
105
+
106
+ ![내장 규칙(읽기 전용)](assets/setting-rules.png)
107
+
108
+ **권한 승인 기록** — 이 세션의 모든 판정을 최신순으로, 모델이 본 이유와 함께 표시합니다:
109
+
110
+ ![권한 승인 기록](assets/permlist.png)
111
+
112
+ **판정 스트립** — 자동 허용은 근거(읽기 전용 도구 또는 LLM의 `safe` 판정)를 밝히고,
113
+ 게이트 정지도 결코 조용히 일어나지 않습니다:
114
+
115
+ ![ALLOW 스트립 — 읽기 전용 도구](assets/allow1.png)
116
+ ![ALLOW 스트립 — llm-assist safe](assets/allow2.png)
117
+ ![GATE OFF 스트립 — 게이트 정지](assets/gateoff.png)
118
+
93
119
  ## 설치
94
120
 
95
121
  [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)가 설치되어 있어야
@@ -196,8 +222,17 @@ DSH **자신**의 트래픽 —— 내장 네트워크 도구와 LLM 전송 —
196
222
 
197
223
  自动审查는 권한 선택기에서 읽기 전용 / 워크스페이스 내 수정 / 완전 권한 / 허용 목록과
198
224
  나란한 **독립 승인 티어**입니다. 범용 "자동 승인"이 아니며 포괄적 권한을 발행하지도 않습니다.
199
- 사람/LLM 심 **이전에** 판정을 좁히거나 넓힐 뿐이고, P0 하드 거부는 단조롭고 협상
200
- 불가능하게 유지됩니다.
225
+ 사람/LLM 심 **이전에** 판정을 좁히거나 넓힐 뿐이고, P0 하드 거부는 **게이트 자체 범위 안에서**
226
+ 단조롭고 협상 불가능하게 유지됩니다.
227
+
228
+ > **P0는 범위가 있으며 전역이 아닙니다.** 이 게이트는 세션 권한 프리셋이 `gatePresets`(기본값
229
+ > `permissive` / `permissive-full`) 중 하나일 때만 동작합니다. 그 밖의 프리셋 —— 읽기 전용 /
230
+ > 워크스페이스 내 수정 / 완전 권한 —— 에서는 **P0 하드 거부를 포함한 게이트 전체가 정지**하고,
231
+ > 선택된 티어 자체의 정책이 그 세션을 통치합니다. 의도된 설계이지만(설정 표의 `gatePresets` 참조),
232
+ > "P0는 협상 불가"는 **게이트의 티어 안에서** 성립하는 것이지 모든 티어에 걸친 것이 아닙니다.
233
+ > 정지는 **침묵하지 않습니다**: 세션/프리셋 전환마다 `stand-down` 이벤트 1건을 기록하고 브라우저는
234
+ > 입력창 위에 **GATE OFF** 상시 표시줄을 띄웁니다. `gatePresets: ['*']`로 설정하면 P0는 다시
235
+ > 전역이 됩니다.
201
236
 
202
237
  **두 가지 변형을 함께 제공합니다.** 프리셋의 `sandbox`와 `approval`은 **독립된** 노브이며, 둘을
203
238
  묶으면 나쁜 트레이드오프를 강요받기 때문입니다.
@@ -221,9 +256,10 @@ DSH **자신**의 트래픽 —— 내장 네트워크 도구와 LLM 전송 —
221
256
  라벨을 배포합니다.
222
257
 
223
258
  **아이콘은 다른 이야기입니다.** 입력창의 글리프 표는 닫혀 있고, 그 표 자체의 주석이 규칙을
224
- 말합니다: *host-configured names outside the design set get none*. `permissive`는 내장 값이라
225
- 「自动审查」에는 원래부터 방패+눈 아이콘이 있습니다. 「自动审查(高权限)」가 같은 아이콘을
226
- 갖는 것은 `npx dsh-perm-gate-patch-glyph`가 그 표에 항목 하나를 추가했기 때문입니다.
259
+ 말합니다: *host-configured names outside the design set get none*. 두 티어 모두 내장 값이 아니므로
260
+ 아이콘은 `npx dsh-perm-gate-patch-glyph`가 그 표에 항목 두 개를 넣어야 생깁니다 ——
261
+ 「自动审查」는 `workspace-write`의 방패+연필을, 「自动审查(高权限)」는 `danger-full-access`의
262
+ 방패+느낌표를 복사해 각자가 실제로 공유하는 파일 샌드박스의 글리프를 갖습니다.
227
263
  이 패치는 **호스트** 패키지를 고치므로 DSH 업그레이드마다 사라집니다 ——
228
264
  [DSH 업그레이드 후: 입력창 아이콘 패치 재적용](./INSTALL.ko.md)을 참고하세요.
229
265
 
@@ -294,8 +330,10 @@ never` 패스스루 — 는 사람에 그대로 위임되므로 향후 DSH 변
294
330
  게이트가 동작하는 범위는 **`gatePresets`에 나열한 티어 안뿐**입니다(기본
295
331
  `['permissive', 'permissive-full']`, 이 플러그인이 추가하는 두 티어). 그 밖의 티어(Read Only / Workspace Write / Full access /
296
332
  `custom`)에서는 게이트의 판정 흐름이 **전혀 실행되지 않습니다** — 허용도, ask도, 거부도,
297
- P0 하드 거부도, 거부 키워드 차단도, 감사 이벤트 기록도 하지 않습니다. 선택한 티어의 자체 정책이
298
- 호출을 결정합니다. `danger-full-access`의 정의는 "승인 프롬프트 없는 전체 접근"이며, 이를 ask로
333
+ P0 하드 거부도, 거부 키워드 차단도 하지 않습니다. 선택한 티어의 자체 정책이
334
+ 호출을 결정합니다. 다만 **침묵하지는 않습니다**: 세션/프리셋 전환마다 `stand-down` 이벤트를 1건만
335
+ 기록하고(판정이 아니라 알림입니다), 브라우저는 입력창 위에 **GATE OFF** 상시 표시줄을 띄웁니다.
336
+ `danger-full-access`의 정의는 "승인 프롬프트 없는 전체 접근"이며, 이를 ask로
299
337
  덮어써도 의미가 없습니다(그 정책에서는 DSH 승인 시임이 **어떤 answerer보다도 먼저** `rejected`를
300
338
  반환해 전달된 ask는 패널을 한 번도 띄우지 못하고 `the user rejected tool "..."`만 남습니다).
301
339
  하드 거부로 덮어쓰는 것 역시 사용자가 고른 티어를 조용히 뒤집는 일입니다.
@@ -315,7 +353,8 @@ host는 네임스페이스를 live로 읽으므로 변경은 재시작 없이
315
353
  `llmAssist`가 켜져 있으면 설정된 LLM(OpenAI 호환 엔드포인트라면 무엇이든 — `classifierEndpoint` / `classifierModel` / `classifierApiKey`을 자신의 API로 지정)이 구조화된 프로토콜로 `ask`를 하나씩 판정합니다. **판정은 게이트의 `tools/pre-execute` 워터폴 안에서, 결정이 호스트로 반환되기 전에 이루어집니다**: `safe`는 곧바로 위임되므로 승인 패널이 아예 표시되지 않고, 정말로 판단할 수 없는 판정만 사람에게 전달됩니다.
316
354
 
317
355
  - `safe` → 자동 허용(감사 소스 `classifier`), 패널 없음.
318
- - `risky` + **하드 위험 카테고리**(`deletion`, `credential`, `remote`, `system`, `bulk`) → **자동 거부**, 패널 없음. 하드 위험은 자동 허용도 학습도 되지 않습니다.
356
+ - `risky` + **하드 위험 카테고리**(`deletion`, `credential`, `remote`, `system`, `bulk`) → **사람 확인(ask)을 유지**합니다. 분류기는 **결코 거부하지 않습니다**. 거부는 결정론적 계층(P0 하드 거부, 거부 키워드 블랙리스트, 명시적 `deny:` 규칙)에만 속하므로, 잘못 판정된 카테고리는 언제나 협상 가능하며 이의를 제기할 수 없는 차단이 되지 않습니다. 하드 카테고리가 `neutral`과 다른 중요한 점은 하나뿐입니다: **결코 학습되지 않으므로** 승인을 반복해도 자동 허용으로 침전되지 않습니다.
357
+ (모델의 판단을 거부 근거로 삼은 결과는 실측되었습니다: 무해한 `git commit -F …`가 `remote`로 판정되어 패널도, 재시도용 grant도 없는 자동 거부가 발생했습니다.)
319
358
  - `risky:neutral` → `riskLearning` 활성 시(설정 카드, 기본 꺼짐), 사람이 승인하고 실제 실행된 neutral 위험은 `tool|카테고리` 키로 카운트되며, `riskThreshold`(기본 3) 도달 및 새 호출의 작업 지문(명령어 단어 + 대상 기본 이름)이 확인된 샘플과 일치하면 **동일 작업만** 자동 허용됩니다. 학습 침전(`riskSediment`, 기본 켜짐)을 사용하면 임계값에 도달한 키의 확인 샘플이 **결정론적 허용 규칙**이 됩니다: 지문이 정확히 일치하면 LLM 호출 없이 바로 허용——llmAssist가 꺼져도 유지되며, 침전 규칙은 설정 카드에서 확인·관리(종료 / 샘플 삭제)할 수 있습니다.
320
359
  - 시간 초과(`riskTimeoutMs`, 기본 20초, 1회 재시도), 전송 실패, 프로토콜 외 출력은 원래 `ask`를 유지합니다.
321
360
 
@@ -331,9 +370,10 @@ host는 네임스페이스를 live로 읽으므로 변경은 재시작 없이
331
370
  카드에서 목록으로 편집할 수 있고(프리셋 항목에는 태그 표시, 원클릭 복원 지원) 미설정·빈 목록 시 프리셋이
332
371
  적용됩니다——블랙리스트가 조용히 꺼지지 않습니다.
333
372
  블랙리스트가 조용히 꺼지는 일은 없습니다.
334
- 「自动审查」와 「自动审查(高权限)」는 둘 다 선택기에 방패+눈 아이콘을 그립니다 — 전자는
335
- DSH 내장 표에서, 후자는 설치 안내에 적힌 호스트 패치에서 옵니다. 그 패치가 없으면 두 번째
336
- 티어는 모든 화면에서 텍스트만 표시됩니다. 라벨과 게이트는 영향을 받지 않습니다.
373
+ 「自动审查」와 「自动审查(高权限)」는 둘 다 선택기에 아이콘을 그립니다 — 설치 안내에 적힌
374
+ 호스트 패치가 각자가 공유하는 파일 샌드박스 티어(`workspace-write`와 `danger-full-access`)에서
375
+ 복사한 것입니다. 그 패치가 없으면 두 티어 모두 모든 화면에서 텍스트만 표시됩니다.
376
+ 라벨과 게이트는 영향을 받지 않습니다.
337
377
 
338
378
 
339
379
  ## CLI(독립 실행 dry-run)