dsh-perm-gate 0.2.1-beta.3 → 0.2.1-beta.5

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/README.ja.md CHANGED
@@ -12,13 +12,35 @@
12
12
  - [日本語 changelog](./CHANGELOG.ja.md)
13
13
  - [한국어 changelog](./CHANGELOG.ko.md)
14
14
 
15
- > **互換性に関する注記:** v0.2.1-beta.3 は `ja` / `ko` 辞書を同梱しますが、公式 DSH の
15
+ > **互換性に関する注記:** v0.2.1-beta.5 は `ja` / `ko` 辞書を同梱しますが、公式 DSH の
16
16
  > `LocaleRuntime` が公開するのは `zh` / `en` のみです(`LOCALE_IDS = ["zh", "en"]`)。
17
17
  > 素の DSH で `ja` / `ko` を選択すると `locale "<id>" is not registered` になります。
18
18
  > `LOCALE_IDS`(locale-settings.ts)と `LOCALES` ラベル(client/index.ts)を更新した
19
19
  > DSH fork を使って再ビルドしてください。
20
20
 
21
- バージョン **0.2.1-beta.3** — 変更履歴は [日本語 changelog](./CHANGELOG.ja.md) を参照。
21
+ > **▼ DSH バージョン互換性**
22
+ >
23
+ > 2 つの DSH ラインが 2 つの長期ブランチから提供され、それぞれが独立したバージョン
24
+ > 系列、`engines.dsh`、npm dist-tag を持っています
25
+ > ([リリースレイアウト](./RELEASING.md)):
26
+ >
27
+ > | DSH バージョン | ブランチ | バージョン | npm タグ |
28
+ > | --- | --- | --- | --- |
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` | `0.2.x` | `@latest` |
31
+ >
32
+ > `@deepseek-ai/dsh-client-runtime` は `0.1.2-alpha.1` で**削除**されました ——
33
+ > 単なる移動ではありません。`legacy` ラインは引き続きこれを通じて
34
+ > `ctx.slots` にアクセスします;`main` は
35
+ > `@deepseek-ai/dsh-client-ui-renderer/client` から同じ宣言を取得します。
36
+ > 2 つのバージョン依存シームは、バージョンチェックではなく機能プロブで処理
37
+ > されます:(1)設定登録は `register` を使い、両ラインとも存在します
38
+ > (`installSection` は追加であり、置き換えではありません);(2)
39
+ > `effectivePolicy` は両ラインとも user-approval サービスの**プライベート**
40
+ > メソッドであるため、`typeof` プロブで読み取り、欠落時やエラー時には「ポリシー
41
+ > 不明」にフォールバックします。
42
+
43
+ バージョン **0.2.1-beta.5** — 変更履歴は [日本語 changelog](./CHANGELOG.ja.md) を参照。
22
44
 
23
45
  DeepSeek Harness 向けの、単一・自己完結・決定論優先・fail-closed な権限ゲートです。
24
46
 
@@ -55,10 +77,16 @@ DSH の安全まわりのエコシステムでは、この役割が `dsh-permiss
55
77
  loud fail、ソースの内容ハッシュによるコンパイル キャッシュ。
56
78
  - **監査** — すべての判定を `callId` 付きの `{ignorable:true}` イベントとして記録。
57
79
  モデルに見える理由と記録される結果は常に一致します。
58
- - **Permissive ティア** — read-only / full-access / whitelist とは別の**独立した承認
59
- モード**。「自動承認」でもなく、包括的な権限付与でもありません。フロントが露出する
60
- のは**単一スイッチ**(`permissive`)だけで、バックエンドの 3 つの戦略は**組み合わせ
80
+ - **自动审查ティア**(`permissive`)— read-only / full-access / whitelist とは別の**独立した承認
81
+ モード**。汎用の「自動承認」でもなく、包括的な権限付与でもありません。フロントが露出する
82
+ のは**単一スイッチ**(`permissive`)だけで、バックエンドの 4 つの戦略は**組み合わせ
61
83
  可能**でプラグイン設定から制御されます。P0 に対しては依然 fail-closed です。
84
+ 権限ピッカーと設定行はいずれも製品名「自动审查」で表示し、アイコンは描きません。
85
+ - **サンドボックス昇格の自動回答**(`trustEscalation`)— サンドボックス昇格は shell /
86
+ pwsh / edit ツールの**内部**(`tools/pre-execute` 後)から発生するためゲートはそれを
87
+ 見ておらず、ゲートが自動許可した呼び出しでも確認プロンプトが表示されます。この戦略を
88
+ オンにすると、ゲートが許可した呼び出しを `callId` で正確に一致させてここで直接回答
89
+ します。
62
90
 
63
91
  ## インストール
64
92
 
@@ -114,13 +142,19 @@ permissions:
114
142
 
115
143
  完全な例: [examples/permissions.example.yaml](./examples/permissions.example.yaml)
116
144
 
117
- ## Permissive ティア
145
+ ## 自动审查ティア(マシン値 `permissive`)
118
146
 
119
- Permissive は権限ピッカーの中で Read Only / Workspace Write / Full access /
120
- Whitelist と並ぶ**独立した承認ティア**です。「自動承認」ではなく、包括的な権限を
147
+ 自动审查は権限ピッカーの中で 読み取り専用 / ワークスペース内変更 / 完全権限 /
148
+ 許可リストと並ぶ**独立した承認ティア**です。汎用の「自動承認」ではなく、包括的な権限を
121
149
  発行することもありません。人間/LLM のシーム**の前**で判定を狭めたり広めたりする
122
150
  だけで、P0 ハード拒否は単調かつ交渉不能のままです。
123
151
 
152
+ ピッカーの表示名は**ホストが供給する製品名**で、言語別辞書の項目ではありません。DSH 0.1.2 は
153
+ プラグイン提供ティアの `name:` を 2 つの権限サーフェス(一般設定の既定行と入力欄のピッカー)で
154
+ そのまま描画し、自前のローカライズ済みラベルは 3 つの組み込み値にしか与えないため、
155
+ `cordis.patch.yml` は全セッション共通で中国語ラベルを配布します。このティアは**アイコンを
156
+ 描きません** —— ピッカーのグリフは組み込み値にのみ紐づきます。
157
+
124
158
  `cordis.yml` では:
125
159
 
126
160
  ```yaml
@@ -133,6 +167,7 @@ Whitelist と並ぶ**独立した承認ティア**です。「自動承認」で
133
167
  permissiveStrategies: # バックエンド戦略、組み合わせ可
134
168
  trustAutoAllow: true # スコープ内安全操作は自動許可、危険/不明は ask
135
169
  alwaysConfirm: false # すべて ask。許可コントロールに拡張ボタン 2 つ
170
+ trustEscalation: true # ゲートが許可済みの呼び出し自身のサンドボックス昇格は確認不要
136
171
  llmAssist: false # まず LLM が分類、ask/失敗時は人手へ
137
172
  ```
138
173
 
@@ -144,19 +179,42 @@ Whitelist と並ぶ**独立した承認ティア**です。「自動承認」で
144
179
  永続化して再読込)。`llmAssist` は設定済みの実際の LLM
145
180
  (受信先は設定カードで選択:**カスタム API**(`classifierEndpoint` / `classifierModel`。OpenAI 互換 API なら何でも可、Xiaomi MiMo `https://api.xiaomimimo.com/v1` 等のプリセット付き)または**ホストモデルグループ**(DSH の `llm` サービスと現在のモデルグループ、`classifierProvider` / `classifierModel` で上書き可)。**健全性テスト**ボタンで受信 LLM の疎通とレイテンシを確認可能)に
146
181
  `ask` の自動判定を委ね、`ask`/エラー時は人手のシームへフォールバックします —
147
- 常に fail-closed です。`permissive` がオフなら、ゲートの挙動は以前と完全に同じです。
182
+ 常に fail-closed です。`trustEscalation`(ティア有効時に既定オン)はゲートがすでに許可した呼び出し内で
183
+ `sandbox_permissions` 昇格が発生した際にここで回答します。以下参照。`permissive` がオフなら、ゲートの挙動は以前と完全に同じです。
184
+
185
+ ### サンドボックス昇格:なぜ `safe` 判定でもプロンプトが出たか
186
+
187
+ ツール呼び出しは**2 つの独立した承認**を引き起こし得ます。ゲートが持つのが第 1 の承認 —
188
+ `tools/pre-execute` ウォーターフォール上の `ask` です。第 2 はツール内部の `approveEscalation`、
189
+ `tools/execute` 時刻に発生し、モデルが `sandbox_permissions` + `justification` を渡したとき;
190
+ すでに `tools/pre-execute` は決着しているため、ゲートの allow はそこに届きません。LLM が `safe` と
191
+ 判定しゲートが自動許可した呼び出しでも、サンドボックス広げの確認プロンプトが出たままでした。
192
+
193
+ `trustEscalation` はこの隙間を埋めます。ゲートは正面向上許可した呼び出し(ホストの `callId` で
194
+ キー化され、昇格リクエストがこれを繰り返す)を記憶し、昇格をここで `allowed-once` と自答します。
195
+ **すべてが満たされる場合のみ**適用されます:
196
+
197
+ - 自动审查ティアがオンで `trustEscalation` がオン;
198
+ - 呼び出しにゲートが許可した `callId` があり、ツール名が一致;
199
+ - 理由は認識された昇格で `workspace-write` または `danger-full-access` を命名。
200
+
201
+ それ以外は — 認識されない理由、異なる呼び出し、ゲートが ask した/拒否した呼び出し、`approval:
202
+ never` パススルー — は人手に変更なく委譲されるため、将来の DSH 変更でも open ではなく closed
203
+ になります。自動回答はイベントフィードに記録されます
204
+ (`verdict: "escalation-auto"`、`mode: <ターゲット>`)。スイッチをオフにすると広げは
205
+ 人手ゲート化されたまま、他の許可は自動のままとします。
148
206
 
149
207
  ### 選択可能なセッション ティア
150
208
 
151
- `cordis.patch.yml` は DSH の `permission.config.presets` に、Workspace Write と
152
- Full access の間に `permissive` preset(`sandbox: workspace-write`、`approval: ask`、
153
- 名称 **Permissive**)を追加します。DSH の bundle patch はこの map を**全体置換**するため
209
+ `cordis.patch.yml` は DSH の `permission.config.presets` に、ワークスペース内変更と
210
+ 完全権限の間に `permissive` preset(`sandbox: workspace-write`、`approval: ask`、
211
+ 名称 **自动审查**)を追加します。DSH の bundle patch はこの map を**全体置換**するため
154
212
  (キー単位のマージではありません)、組み込み 3 ティア
155
213
  (`read-only` / `workspace-write` / `danger-full-access`、
156
214
  `@deepseek-ai/dsh-base/cordis.patch.yml` 由来)も再記載する必要があり、
157
215
  `test/patch-presets.spec.ts` がそのキー集合を固定しています。したがって
158
216
  セッションの権限ピッカーには「auto-approval」ではなく、**独立して選択できる承認
159
- ティア**として Permissive が並びます。
217
+ ティア**として「自动审查」が並びます。
160
218
 
161
219
  ゲートが動作するのは **`gatePresets` に列挙したティアの中だけ**です(既定 `['permissive']`、
162
220
  このプラグインが追加するティア)。それ以外のティア(Read Only / Workspace Write /
@@ -174,7 +232,7 @@ Full access / `custom`)では、ゲートの判定フローは**一切実行
174
232
 
175
233
  このティアは実行時にも **設定 → プラグイン → Permissive 承認ティア** から調整できます
176
234
  (プラグインのブラウザ側が描画する `settings.plugins.tab` ページ)。1 つのスイッチが
177
- `permissive` を切り替え、3 つのトグルがバックエンドの `permissiveStrategies` を編集
235
+ `permissive` を切り替え、4 つのトグルがバックエンドの `permissiveStrategies` を編集
178
236
  します。host は名前空間を live に読むため、変更は再起動なしで次のツール呼び出しから
179
237
  適用されます。これは独立した承認クラスであり、DSH の「auto-approval」モードでは
180
238
  **ありません**。
@@ -194,7 +252,9 @@ Full access / `custom`)では、ゲートの判定フローは**一切実行
194
252
 
195
253
  人手に回した `ask` は回答が返るまで追跡されます。受動的な `approval/request` オブザーバが閉じた結果を記録し(`allowed-once` → **承認**、`rejected` → **拒否**、`cancelled` → **キャンセル**、`unavailable` → 拒否=承認チャネルなし)、オブザーバが関連付けできない場合(`callId` 欠落・approval サービスなし・上流リスナーの短絡)は `tools/result` が同じ ask をフォールバックとして解決します。承認時には承認後の学習進捗(`n`/しきい値)を表示し、通知バーも 3 つの終態にラベルを付けます。
196
254
 
197
- さらにプリセットの**拒否キーワード黑名単**(dsh-approval-gate の `DEFAULT_DENY_KEYWORDS` を継承:`rm -rf`、`push --force`、`drop table`、`mkfs`、`git reset --hard`、`docker system prune` など)を備え、テキストがキーワードを含む呼び出し(大小文字を区別しない部分一致)は許可リスト / 許可 / LLM より先に拒否します。設定カードでリストとして編集でき(プリセット項目にはタグ付き、ワンクリック復元対応)、未設定・空ならプリセットを適用します——黑名単が静かに無効化されることはありません。Permissive ティアは権限ピッカーに盾アイコンを保持します(メニュー項目と折りたたみトリガーの両方)。
255
+ さらにプリセットの**拒否キーワード黑名単**(dsh-approval-gate の `DEFAULT_DENY_KEYWORDS` を継承:`rm -rf`、`push --force`、`drop table`、`mkfs`、`git reset --hard`、`docker system prune` など)を備え、テキストがキーワードを含む呼び出し(大小文字を区別しない部分一致)は許可リスト / 許可 / LLM より先に拒否します。設定カードでリストとして編集でき(プリセット項目にはタグ付き、ワンクリック復元対応)、未設定・空ならプリセットを適用します——黑名単が静かに無効化されることはありません。
256
+ このティアは権限ピッカーに**アイコンを表示しません** —— ピッカーのグリフは組み込み 3 値にのみ
257
+ 紐づき、プラグイン提供ティアはテキストのみです。
198
258
 
199
259
 
200
260
  ## CLI(スタンドアロン dry-run)
package/README.ko.md CHANGED
@@ -12,13 +12,33 @@
12
12
  - [日本語 changelog](./CHANGELOG.ja.md)
13
13
  - [한국어 changelog](./CHANGELOG.ko.md)
14
14
 
15
- > **호환성 안내:** v0.2.1-beta.3은 `ja` / `ko` 사전을 포함하지만, 공식 DSH의 `LocaleRuntime`은
15
+ > **호환성 안내:** v0.2.1-beta.5은 `ja` / `ko` 사전을 포함하지만, 공식 DSH의 `LocaleRuntime`은
16
16
  > `zh` / `en`만 노출합니다(`LOCALE_IDS = ["zh", "en"]`). 기본 DSH에서 `ja` / `ko`를
17
17
  > 선택하면 `locale "<id>" is not registered` 오류가 발생합니다. `LOCALE_IDS`
18
18
  > (locale-settings.ts)와 `LOCALES` 라벨(client/index.ts)을 갱신한 DSH fork를 사용해
19
19
  > 다시 빌드하세요.
20
20
 
21
- 버전 **0.2.1-beta.3** — 변경 내역은 [한국어 changelog](./CHANGELOG.ko.md)를 참고하세요.
21
+ > **▼ DSH 버전 호환성**
22
+ >
23
+ > 두 DSH 라인 각각이 장기 유지되는 두 브랜치를 통해 제공되며, 각자 고유한
24
+ > 버전 시리즈, `engines.dsh`, npm dist-tag 을 가집니다
25
+ > ([릴아웃](./RELEASING.md)):
26
+ >
27
+ > | DSH 버전 | 브랜치 | 버전 | npm 태그 |
28
+ > | --- | --- | --- | --- |
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` | `0.2.x` | `@latest` |
31
+ >
32
+ > `@deepseek-ai/dsh-client-runtime`은 `0.1.2-alpha.1`에서 **제거**되었습니다 —
33
+ > 단순히 이동한 것이 아닙니다. `legacy` 라인은 여전히 이를 통해 `ctx.slots`에
34
+ > 접근합니다. `main`은 `@deepseek-ai/dsh-client-ui-renderer/client`에서 같은
35
+ > 선언을 가져옵니다. 두 버전 민감 시ーム은 버전 체크 대신 기능 프로브로 처리합니다:
36
+ > (1) 설정 등록은 `register`를 사용하며, 두 라인 모두에 존재합니다
37
+ > (`installSection`은 대체가 아닌 추가 사항); (2) `effectivePolicy`는 두 라인
38
+ > 모두에서 user-approval 서비스의 **개인** 메소드이므로 `typeof` 프로브를 통해
39
+ > 읽으며, 누락되거나 예외 발생 시 "정책_unknown"으로 후퇴합니다.
40
+
41
+ 버전 **0.2.1-beta.5** — 변경 내역은 [한국어 changelog](./CHANGELOG.ko.md)를 참고하세요.
22
42
 
23
43
  DeepSeek Harness용 단일·자족적·결정론 우선·fail-closed 권한 게이트입니다.
24
44
 
@@ -55,10 +75,15 @@ DSH 안전 생태계에서는 이 역할이 `dsh-permission-rules` / `dsh-auto-m
55
75
  소스 콘텐츠 해시 기반 컴파일 캐시.
56
76
  - **감사** — 모든 판정을 `callId`와 함께 `{ignorable:true}` 이벤트로 기록합니다.
57
77
  모델에 보이는 이유와 기록된 결과는 항상 일치합니다.
58
- - **Permissive 티어** — read-only / full-access / whitelist와 구별되는 **독립 승인
59
- 모드**. "자동 승인"도 아니고 포괄적 권한 부여도 아닙니다. 프론트는 **단일 스위치**
60
- (`permissive`)만 노출하고, 백엔드의 세 가지 전략은 **조합 가능**하며 플러그인
78
+ - **自动审查 티어**(`permissive`) — read-only / full-access / whitelist와 구별되는 **독립 승인
79
+ 모드**. 범용 "자동 승인"도 아니고 포괄적 권한 부여도 아닙니다. 프론트는 **단일 스위치**
80
+ (`permissive`)만 노출하고, 백엔드의 네 가지 전략은 **조합 가능**하며 플러그인
61
81
  설정으로 제어됩니다. P0에 대해서는 여전히 fail-closed입니다.
82
+ 권한 선택기와 설정 행 모두 제품명 「自动审查」로 표시하며 아이콘은 그리지 않습니다.
83
+ - **샌드박스 승격 자동 응답** (`trustEscalation`) — 샌드박스 승격은 shell / pwsh /
84
+ edit 도구의 **내부**(`tools/pre-execute` 이후)에서 발생하므로 게이트가 이를 볼 수
85
+ 없고, 게이트가 자동 허용한 호출에도 확인 프롬프트가 나타납니다. 이 전략을 켜면 게이트가
86
+ `callId`로 이미 허용한 호출을 정확히 매칭하여 여기서 직접 응답합니다.
62
87
 
63
88
  ## 설치
64
89
 
@@ -114,13 +139,19 @@ permissions:
114
139
 
115
140
  전체 예시: [examples/permissions.example.yaml](./examples/permissions.example.yaml)
116
141
 
117
- ## Permissive 티어
142
+ ## 自动审查 티어(머신 값 `permissive`)
118
143
 
119
- Permissive는 권한 선택기에서 Read Only / Workspace Write / Full access / Whitelist와
120
- 나란한 **독립 승인 티어**입니다. "자동 승인"이 아니며 포괄적 권한을 발행하지도 않습니다.
144
+ 自动审查는 권한 선택기에서 읽기 전용 / 워크스페이스 내 수정 / 완전 권한 / 허용 목록과
145
+ 나란한 **독립 승인 티어**입니다. 범용 "자동 승인"이 아니며 포괄적 권한을 발행하지도 않습니다.
121
146
  사람/LLM 심 **이전에** 판정을 좁히거나 넓힐 뿐이고, P0 하드 거부는 단조롭고 협상
122
147
  불가능하게 유지됩니다.
123
148
 
149
+ 선택기의 표시 이름은 **호스트가 공급하는 제품명**이며 언어별 사전 항목이 아닙니다. DSH 0.1.2는
150
+ 플러그인 티어의 `name:`을 두 권한 화면(일반 설정 기본 행과 입력창 선택기)에 그대로 렌더링하고
151
+ 자체 지역화 라벨은 세 가지 내장 값에만 부여하므로, `cordis.patch.yml`이 모든 세션에 중국어
152
+ 라벨을 배포합니다. 이 티어는 **아이콘을 그리지 않습니다** —— 선택기의 글리프는 내장 값에만
153
+ 연결됩니다.
154
+
124
155
  `cordis.yml`에서:
125
156
 
126
157
  ```yaml
@@ -133,10 +164,11 @@ Permissive는 권한 선택기에서 Read Only / Workspace Write / Full access /
133
164
  permissiveStrategies: # 백엔드 전략, 조합 가능
134
165
  trustAutoAllow: true # 범위 내 안전 작업 자동 허용, 위험/미확인은 ask
135
166
  alwaysConfirm: false # 매번 ask. 허용 컨트롤에 확장 버튼 2개
167
+ trustEscalation: true # 게이트가 허용한 호출 자체의 샌드박스 승격은 확인 불필요
136
168
  llmAssist: false # 먼저 LLM이 분류, ask/실패 시 사람에게
137
169
  ```
138
170
 
139
- `trustAutoAllow`는 중간 티어의 기준선입니다(rule-allow는 자동 통과). `alwaysConfirm`은
171
+ `trustAutoAllow`은 중간 티어의 기준선입니다(rule-allow는 자동 통과). `alwaysConfirm`은
140
172
  모든 경계에서 승인 패널을 띄우며, 그「허용 컨트롤」에 두 개의 확장 버튼을 추가합니다 —
141
173
  **이 세션에서 해당 유형 반복 허용**(`approveRepeat`, 유계 세션 허용)과 **모든 발생
142
174
  허용**(`approveAllowEverywhere`, 명령어를 `permissions.yaml`의 allow 허용 목록에
@@ -145,19 +177,44 @@ Permissive는 권한 선택기에서 Read Only / Workspace Write / Full access /
145
177
  프리셋 포함) 또는 **호스트 모델 그룹**(DSH의 `llm` 서비스와 현재 모델 그룹, `classifierProvider` /
146
178
  `classifierModel`로 재정의 가능). **상태 테스트** 버튼으로 수신 LLM의 연결과 지연 시간을 확인할 수 있음)에 `ask` 자동 판정을 맡기고,
147
179
  `ask`/오류 시 사람의 승인 심으로 폴백합니다 — 항상 fail-closed입니다.
180
+ `trustEscalation`(티어 켜짐时 기본 켬)은 게이트가 이미 허용한 호출 내부에서
181
+ `sandbox_permissions` 승격이 발생할 때 여기서 응답합니다. 아래 참조.
148
182
  `permissive`가 꺼져 있으면 게이트는 이전과 완전히 동일하게 동작합니다.
149
183
 
184
+ ### 샌드박스 승격: 왜 `safe` 판정에도 프롬프트가 떴나
185
+
186
+ 툴 호출은 **두 개의 독립된 승인**을 일으킬 수 있습니다. 게이트가 맡는 것이 첫 번째 —
187
+ `tools/pre-execute` 워터폴의 `ask`입니다. 두 번째는 툴 내부의 `approveEscalation`,
188
+ `tools/execute` 시점, 모델이 `sandbox_permissions` + `justification`을 건넸을 때
189
+ 발생 — 이미 `tools/pre-execute`는 끝났으므로 게이트의 allow는 여기에 닿지 않습니다.
190
+ LLM이 `safe`로 판정하고 게이트가 자동 허용한 호출조차 샌드박스 확장을 승인하라는
191
+ 프롬프트가 떴습니다.
192
+
193
+ `trustEscalation`은 이 간극을 메웁니다. 게이트가 정面向上 허용한 호출(호스트의
194
+ `callId`로 키화, 승격 요청이 이를 반복)을 기억하고 승격을 여기서 `allowed-once`로
195
+ 자응답합니다. **모든 조건이 충족될 때만** 적용됩니다:
196
+
197
+ - 自动审查 티어가 켜져 있고 `trustEscalation`이 켜져 있음;
198
+ - 호출에 게이트가 허용한 `callId`가 있고, 툴 이름이 일치;
199
+ - 원인이 알려진 승격이며 `workspace-write` 또는 `danger-full-access`를 명시.
200
+
201
+ 그 외의 모든 경우 — 알려지지 않은 원인, 다른 호출, 게이트가 ask/deny한 호출, `approval:
202
+ never` 패스스루 — 는 사람에 그대로 위임되므로 향후 DSH 변경이 open이 아닌 closed로
203
+ 실패합니다. 자동 응답은 이벤트 피드에 기록됩니다
204
+ (`verdict: "escalation-auto"`, `mode: <대상>`). 스위치를 끄면 샌드박스 확장은
205
+ 사람 게이트로 유지되고 다른 허용은 자동 상태를 유지합니다.
206
+
150
207
  ### 선택 가능한 세션 티어
151
208
 
152
- `cordis.patch.yml`은 DSH의 `permission.config.presets`에 Workspace Write와
153
- Full access 사이의 `permissive` preset(`sandbox: workspace-write`, `approval: ask`,
154
- 이름 **Permissive**)을 추가합니다. DSH의 bundle patch는 이 map을 **전체 교체**하므로
209
+ `cordis.patch.yml`은 DSH의 `permission.config.presets`에 워크스페이스 내 수정과
210
+ 완전 권한 사이의 `permissive` preset(`sandbox: workspace-write`, `approval: ask`,
211
+ 이름 **自动审查**)을 추가합니다. DSH의 bundle patch는 이 map을 **전체 교체**하므로
155
212
  (키 단위 병합이 아닙니다) 내장 3개 티어
156
213
  (`read-only` / `workspace-write` / `danger-full-access`,
157
214
  `@deepseek-ai/dsh-base/cordis.patch.yml` 기준)도 다시 기재해야 하며,
158
215
  `test/patch-presets.spec.ts`가 그 키 집합을 고정합니다. 따라서 세션 권한
159
- 선택기에는 "auto-approval"이 아니라 **독립적으로 선택 가능한 승인 티어**인 Permissive가
160
- 놓입니다.
216
+ 선택기에는 "auto-approval"이 아니라 **독립적으로 선택 가능한 승인 티어**인
217
+ 「自动审查」가 놓입니다.
161
218
 
162
219
  게이트가 동작하는 범위는 **`gatePresets`에 나열한 티어 안뿐**입니다(기본 `['permissive']`,
163
220
  이 플러그인이 추가하는 티어). 그 밖의 티어(Read Only / Workspace Write / Full access /
@@ -174,7 +231,7 @@ P0 하드 거부도, 거부 키워드 차단도, 감사 이벤트 기록도 하
174
231
 
175
232
  이 티어는 실행 중에도 **설정 → 플러그인 → Permissive 승인 티어**에서 조정할 수 있습니다
176
233
  (플러그인 브라우저 절반이 렌더링하는 `settings.plugins.tab` 페이지). 스위치 하나가
177
- `permissive`를 토글하고, 토글 세 개가 백엔드 `permissiveStrategies`를 편집합니다.
234
+ `permissive`를 토글하고, 네 개가 백엔드 `permissiveStrategies`를 편집합니다.
178
235
  host는 네임스페이스를 live로 읽으므로 변경은 재시작 없이 다음 도구 호출부터 적용됩니다.
179
236
  이것은 독립적인 승인 클래스이며 DSH의 "auto-approval" 모드가 **아닙니다**.
180
237
 
@@ -198,7 +255,9 @@ host는 네임스페이스를 live로 읽으므로 변경은 재시작 없이
198
255
  키워드를 포함하는 호출(대소문자 구분 없는 부분 일치)은 허용 목록/권한/LLM보다 먼저 거부됩니다. 설정
199
256
  카드에서 목록으로 편집할 수 있고(프리셋 항목에는 태그 표시, 원클릭 복원 지원) 미설정·빈 목록 시 프리셋이
200
257
  적용됩니다——블랙리스트가 조용히 꺼지지 않습니다.
201
- Permissive 티어는 권한 선택기에서 방패 아이콘을 유지합니다(메뉴 항목과 축소 트리거 모두).
258
+ 블랙리스트가 조용히 꺼지는 일은 없습니다.
259
+ 이 티어는 권한 선택기에 **아이콘을 표시하지 않습니다** —— 선택기의 글리프는 내장 세 값에만
260
+ 연결되고, 플러그인 티어는 텍스트만입니다.
202
261
 
203
262
 
204
263
  ## CLI(독립 실행 dry-run)
package/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
  - [日本語 changelog](./CHANGELOG.ja.md)
13
13
  - [한국어 changelog](./CHANGELOG.ko.md)
14
14
 
15
- > **Compatibility note:** v0.2.1-beta.3 ships `ja` / `ko` dictionaries, but official DSH exposes
15
+ > **Compatibility note:** v0.2.1-beta.5 ships `ja` / `ko` dictionaries, but official DSH exposes
16
16
  > only `zh` / `en` through `LocaleRuntime` (`LOCALE_IDS = ["zh", "en"]`). On stock DSH,
17
17
  > selecting `ja` / `ko` fails with `locale "<id>" is not registered`. Use a DSH fork that
18
18
  > updates `LOCALE_IDS` (locale-settings.ts) and `LOCALES` labels (client/index.ts), then
@@ -20,21 +20,24 @@
20
20
 
21
21
  > **▼ DSH version compatibility**
22
22
  >
23
- > | DSH version | Load | Settings registration | Host gate | Client half |
24
- > | --- | --- | --- | --- | --- |
25
- > | 0.1.0-rc.7 ~ 0.1.1-rc.x | ✅ | `ctx.settings.register(ns, schema, { base })` | ✅ `tools/pre-execute` identical | ✅ type-only imports |
26
- > | 0.1.2-alpha.2+ / 0.1.2-rc.1 | ✅ | `register` still present (`installSection` added) | ✅ `tools/pre-execute` identical | ✅ type-only imports |
23
+ > Two DSH lines are served from two long-lived branches, each with its own version
24
+ > series, `engines.dsh`, and npm dist-tag ([release layout](./RELEASING.md)):
27
25
  >
28
- > One artifact covers both. Two version-sensitive seams are handled by capability
29
- > probes rather than version checks: (1) settings registration uses `register`,
30
- > which exists in every supported version (`installSection` is a 0.1.2 addition,
31
- > not a replacement); (2) `effectivePolicy` is a **private** method of the
32
- > user-approval service in **both** versions, so it is read behind a `typeof`
33
- > probe and degrades to “policy unknown” when absent or throwing. The client
34
- > bundle value-imports nothing from `@deepseek-ai/*`, so the 0.1.2
35
- > `dsh-client-runtime` → `dsh-client-store` rename cannot break it.
26
+ > | DSH version | Branch | Version | npm tag |
27
+ > | --- | --- | --- | --- |
28
+ > | 0.1.0-rc.7 ~ 0.1.1-rc.x | `legacy` | `1.x` | `@legacy` |
29
+ > | 0.1.2-alpha.1+ (incl. 0.1.5-rc.2) | `main` | `0.2.x` | `@latest` |
30
+ >
31
+ > `@deepseek-ai/dsh-client-runtime` was **removed** at `0.1.2-alpha.1` — it did not
32
+ > merely move. The `legacy` line still reaches `ctx.slots` through it; `main` gets
33
+ > the same declaration from `@deepseek-ai/dsh-client-ui-renderer/client`. Two
34
+ > version-sensitive seams are handled by capability probes rather than version
35
+ > checks: (1) settings registration uses `register`, which exists on both lines
36
+ > (`installSection` is an addition, not a replacement); (2) `effectivePolicy` is a
37
+ > **private** method of the user-approval service on both, so it is read behind a
38
+ > `typeof` probe and degrades to “policy unknown” when absent or throwing.
36
39
 
37
- Version **0.2.1-beta.3** — see the [Changelog](./CHANGELOG.md).
40
+ Version **0.2.1-beta.5** — see the [Changelog](./CHANGELOG.md).
38
41
 
39
42
  A single, self-sufficient, deterministic-first, fail-closed permission gate for DeepSeek Harness.
40
43
 
@@ -69,10 +72,15 @@ cross-plugin version coupling.
69
72
  malformed rules, and source-hash compile caching.
70
73
  - **Audit** — every decision is logged as an `{ignorable:true}` event with its `callId`; the
71
74
  model-visible reason matches the recorded outcome.
72
- - **Permissive tier** — an **independent approval mode** (separate from read-only, full-access
73
- and whitelist tiers) that is neither "auto-approve" nor blanket trust. Front-end exposes a
74
- **single switch** (`permissive`); the three backend strategies are **combinable** and driven
75
- by plugin settings — still fail-closed against P0.
75
+ - **自动审查 tier** (`permissive`) — an **independent approval mode** (separate from read-only,
76
+ full-access and whitelist tiers) that is neither "auto-approve" nor blanket trust. Front-end
77
+ exposes a **single switch** (`permissive`); the four backend strategies are **combinable** and
78
+ driven by plugin settings — still fail-closed against P0. The permission picker and the
79
+ settings row both show it under the product label 自动审查, with no icon.
80
+ - **Sandbox-escalation auto-answer** (`trustEscalation`) — a sandbox escalation is asked from
81
+ *inside* the shell / pwsh / edit tool body, after `tools/pre-execute`, so the gate never saw
82
+ it and a call it auto-allowed still prompted you to approve the widening. With this strategy
83
+ on, the exact call the gate cleared (matched by `callId`) is answered here instead.
76
84
  - **Risk-graded `llmAssist`** — a custom OpenAI-compatible LLM grades each `ask` as
77
85
  `safe` / `risky:<category>`; hard categories (deletion, credential, remote, system, bulk)
78
86
  **always ask**, neutral enters verdict learning, and every failure stays fail-closed.
@@ -141,12 +149,18 @@ permissions:
141
149
  A command entry `word#flag` matches the command word (`word`) with the modifier `recursive` or
142
150
  `force` — so `rm#recursive` matches `rm -rf`, `env rm -rf`, and `sh -c "rm -rf /"`.
143
151
 
144
- ## Permissive mode
152
+ ## The 自动审查 tier (machine value `permissive`)
153
+
154
+ 自动审查 is an **independent approval tier** in the DSH permission picker, parallel to
155
+ Read Only / Workspace Write / Full access / Whitelist. It is **not** generic "auto-approval" and
156
+ never mints blanket authority: it only narrows or widens the seam *before* the human/LLM step
157
+ while P0 hard-deny stays monotonic and non-negotiable.
145
158
 
146
- Permissive is an **independent approval tier** in the DSH permission picker, parallel to
147
- Read Only / Workspace Write / Full access / Whitelist. It is **not** "auto-approval" and never
148
- mints blanket authority: it only narrows or widens the seam *before* the human/LLM step while
149
- P0 hard-deny stays monotonic and non-negotiable.
159
+ The picker label is a **host-supplied product string**, not a per-locale dictionary entry: DSH
160
+ 0.1.2 renders a plugin tier's `name:` verbatim on both permission surfaces (the General-settings
161
+ default row and the composer picker) and only supplies its own localized labels for the three
162
+ built-in values, so `cordis.patch.yml` ships the Chinese label for every session. The tier draws
163
+ **no icon** — the composer renders glyphs only for the built-in values.
150
164
 
151
165
  In `cordis.yml`:
152
166
 
@@ -161,6 +175,7 @@ In `cordis.yml`:
161
175
  trustAutoAllow: true # in-scope safe ops auto-allow; dangerous/unknown ask
162
176
  alwaysConfirm: false # every crossing asks; allow-controls add repeat-allow / wl-migrate buttons
163
177
  llmAssist: false # LLM classify first, human fallback on ask/failure
178
+ trustEscalation: true # a cleared call's own sandbox escalation needs no prompt
164
179
  ```
165
180
 
166
181
  `trustAutoAllow` is the baseline middle tier (rule-allow auto-passes). `alwaysConfirm` surfaces
@@ -169,8 +184,33 @@ the approval panel for every crossing; its "allow controls" add two extended but
169
184
  (which persists the command word into the `permissions.yaml` allow whitelist via
170
185
  `approveAllowEverywhere`). `llmAssist` consults a real, configurable LLM (`classifierEndpoint` /
171
186
  `classifierModel`, any OpenAI-compatible API) to auto-decide an `ask`, and falls back to the
172
- human seam on `ask`/error — always fail-closed. When `permissive` is off, the gate behaves
173
- exactly as before.
187
+ human seam on `ask`/error — always fail-closed. `trustEscalation` (on by default while the tier
188
+ is on) answers a `sandbox_permissions` escalation raised from inside a call the gate already
189
+ allowed; see below. When `permissive` is off, the gate behaves exactly as before.
190
+
191
+ ### Sandbox escalation: why a `safe` verdict still prompted
192
+
193
+ A tool call can raise **two independent approvals**. The gate owns the first — its own `ask`, on
194
+ the `tools/pre-execute` waterfall. The second comes from `approveEscalation` **inside the tool
195
+ body**, at `tools/execute` time, whenever the model passed `sandbox_permissions` +
196
+ `justification`; by then `tools/pre-execute` has already settled, so the gate's allow never
197
+ reaches it. A call the LLM graded `safe` and the gate auto-allowed therefore still showed a
198
+ prompt asking you to approve the sandbox widening.
199
+
200
+ `trustEscalation` closes that gap. The gate remembers every call it positively allowed (keyed by
201
+ the host's `callId`, which the escalation request repeats) and answers the escalation
202
+ `allowed-once` itself. It applies only when *all* hold:
203
+
204
+ - the 自动审查 tier is on and `trustEscalation` is on;
205
+ - the request carries a `callId` the gate cleared, with a matching tool name;
206
+ - the reason is a recognized escalation naming `workspace-write` or `danger-full-access`.
207
+
208
+ Everything else — an unrecognized reason, a different call, a call the gate asked or denied, the
209
+ `approval: never` passthrough — delegates to the human unchanged, so a future DSH wording change
210
+ fails closed rather than open. The auto-answer is recorded on the event feed
211
+ (`verdict: "escalation-auto"`, `mode: <target>`). Turn the switch off to keep widening
212
+ human-gated while other allows stay automatic.
213
+
174
214
 
175
215
  ### Risk-graded llmAssist, verdict learning, and the event feed
176
216
 
@@ -220,18 +260,18 @@ channel existed), with `tools/result` settling the same ask as a fallback when t
220
260
  correlate it. Approvals report the post-approval learning progress (`n`/threshold), and the notice
221
261
  strip labels all three terminal states.
222
262
 
223
- The Permissive tier keeps its shield icon in the permission picker — on both the
224
- menu item and the collapsed picker trigger.
263
+ The tier draws no icon in the permission picker: the composer's glyphs are keyed to the three
264
+ built-in values, so a plugin-contributed tier is text-only on every surface.
225
265
 
226
266
  ### A selectable session tier
227
267
 
228
268
  `cordis.patch.yml` adds a `permissive` preset (`sandbox: workspace-write`, `approval: ask`, name
229
- **Permissive**) between Workspace Write and Full access. The DSH bundle patch replaces the whole
269
+ **自动审查**) between Workspace Write and Full access. The DSH bundle patch replaces the whole
230
270
  `permission.config.presets` map rather than merging per key, so the file also restates the three
231
271
  built-ins (`read-only` / `workspace-write` / `danger-full-access`, from
232
272
  `@deepseek-ai/dsh-base/cordis.patch.yml`); `test/patch-presets.spec.ts` pins that key set. So the
233
- session permission picker offers Permissive as an independent selectable approval tier, not an
234
- "auto-approval" mode.
273
+ session permission picker offers 自动审查 as an independent selectable approval tier, not a
274
+ generic "auto-approval" mode.
235
275
 
236
276
  The gate is active **only in the tiers listed in `gatePresets`** (default `['permissive']`, the
237
277
  tier this plugin adds). In every other tier — Read Only, Workspace Write, Full access,
@@ -246,11 +286,11 @@ session's effective approval policy is `never`.
246
286
 
247
287
  ### Configurable in the UI
248
288
 
249
- The tier is also adjustable at runtime from **Settings → Plugins → Permissive approval tier**
289
+ The tier is also adjustable at runtime from **Settings → Plugins → 自动审查**
250
290
  (a `settings.plugins.tab` page rendered by the plugin's browser client): one switch toggles
251
- `permissive`, and three toggles edit the backend `permissiveStrategies`. The host reads the
291
+ `permissive`, and four toggles edit the backend `permissiveStrategies`. The host reads the
252
292
  namespace live, so a change applies to the next tool call without a restart. This is an
253
- independent approval class, NOT the DSH "auto-approval" mode.
293
+ independent approval class, NOT a generic "auto-approval" mode.
254
294
 
255
295
  ## CLI
256
296