dsh-perm-gate 2.1.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.ja.md +108 -0
  2. package/CHANGELOG.ko.md +104 -0
  3. package/CHANGELOG.md +347 -0
  4. package/INSTALL.ja.md +84 -8
  5. package/INSTALL.ko.md +80 -9
  6. package/INSTALL.md +83 -8
  7. package/INSTALL.zh.md +70 -7
  8. package/README.ja.md +130 -16
  9. package/README.ko.md +128 -17
  10. package/README.md +179 -25
  11. package/README.zh.md +121 -12
  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 +37 -3
  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 +22 -0
  26. package/examples/permissions.example.yaml +16 -1
  27. package/lib/agent-identity.d.ts +43 -0
  28. package/lib/agent-identity.js +95 -0
  29. package/lib/allowlist.d.ts +27 -0
  30. package/lib/allowlist.js +103 -1
  31. package/lib/cli.js +11 -14
  32. package/lib/client.js +598 -6
  33. package/lib/client.js.map +1 -1
  34. package/lib/command-dispatcher.d.ts +22 -0
  35. package/lib/command-dispatcher.js +97 -0
  36. package/lib/command-semantics.d.ts +62 -0
  37. package/lib/command-semantics.js +6 -0
  38. package/lib/compiler.d.ts +50 -0
  39. package/lib/compiler.js +122 -0
  40. package/lib/config.d.ts +161 -7
  41. package/lib/config.js +78 -11
  42. package/lib/dry-run.d.ts +87 -0
  43. package/lib/dry-run.js +110 -0
  44. package/lib/engine.js +61 -4
  45. package/lib/evaluate.d.ts +9 -0
  46. package/lib/evaluate.js +264 -1
  47. package/lib/events.d.ts +69 -2
  48. package/lib/events.js +123 -0
  49. package/lib/index.d.ts +1 -1
  50. package/lib/index.js +320 -11
  51. package/lib/network-lifecycle.d.ts +107 -0
  52. package/lib/network-lifecycle.js +180 -0
  53. package/lib/network.d.ts +109 -0
  54. package/lib/network.js +196 -0
  55. package/lib/parsers/git.d.ts +43 -0
  56. package/lib/parsers/git.js +404 -0
  57. package/lib/parsers/shell-cmds.d.ts +32 -0
  58. package/lib/parsers/shell-cmds.js +293 -0
  59. package/lib/preset.d.ts +13 -0
  60. package/lib/preset.js +17 -0
  61. package/lib/proxy.d.ts +160 -0
  62. package/lib/proxy.js +529 -0
  63. package/lib/risk.d.ts +17 -3
  64. package/lib/risk.js +19 -6
  65. package/lib/rule-chain.d.ts +39 -0
  66. package/lib/rule-chain.js +213 -0
  67. package/lib/rule-dims.d.ts +174 -0
  68. package/lib/rule-dims.js +230 -0
  69. package/lib/rule.d.ts +60 -0
  70. package/lib/rule.js +69 -7
  71. package/lib/rules-view.d.ts +52 -0
  72. package/lib/rules-view.js +126 -0
  73. package/lib/runtime.d.ts +208 -7
  74. package/lib/runtime.js +433 -27
  75. package/lib/session-sweep.d.ts +45 -0
  76. package/lib/session-sweep.js +153 -0
  77. package/lib/shadow.d.ts +34 -0
  78. package/lib/shadow.js +143 -0
  79. package/lib/shell.d.ts +14 -0
  80. package/lib/shell.js +17 -0
  81. package/lib/watch.d.ts +42 -0
  82. package/lib/watch.js +170 -0
  83. package/package.json +26 -3
  84. package/scripts/patch-permission-glyph.mjs +392 -0
package/INSTALL.ja.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.0.0**。判定チェーン、ルールファイル形式、自动审查
15
+ `dsh-perm-gate` バージョン **2.6.1**。判定チェーン、ルールファイル形式、自动审查
16
16
  ティアについては [日本語 README](./README.ja.md) を参照してください。
17
17
 
18
18
  ## 必要条件
@@ -23,19 +23,20 @@
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
+ 2 つの長期ブランチが 2 つの 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 の公開方法については、
38
+ DSH は `engines.dsh` を強制しないため、tag と ref は選択メカニズムであり、互換性
39
+ ゲートそのものではありません。ラインと tag の公開レイアウトについては
39
40
  [RELEASING.md](./RELEASING.md) を参照してください。
40
41
 
41
42
  ## 公式 CLI でインストール
@@ -72,6 +73,11 @@ profile の `cordis.yml` にプラグインを追加します:
72
73
  defaultAction: ask # allow | ask | deny
73
74
  ```
74
75
 
76
+ 2.6.0 から、ルール本体は `dsh-perm-gate-rules` settings 名前空間に保存され、変更の
77
+ たびにゲートがその場で再コンパイルされます。上記の YAML ファイルは任意になりました。
78
+ 名前空間が未設定の間だけ読み込まれ、プラグインが最初にルールを書き込む際(許可リスト
79
+ の承認、または設定 UI での編集)にファイルのルールが自動的に取り込まれます。
80
+
75
81
  まずは [examples/permissions.example.yaml](./examples/permissions.example.yaml)
76
82
  から始め、profile を再読込してください。
77
83
 
@@ -87,6 +93,68 @@ dsh plugin --profile web update dsh-perm-gate
87
93
  dsh profile reload --profile web
88
94
  ```
89
95
 
96
+ ## **DSH** アップグレード後:入力欄アイコンのパッチを再適用
97
+
98
+ 「自动审查」と「自动审查(高权限)」の 2 つのティアにアイコンが付くのは、
99
+ `scripts/patch-permission-glyph.mjs` が **DSH ホストパッケージ内の閉じた Map** に
100
+ それらを追加したからにすぎません ——「自动审查」は `workspace-write` の盾+鉛筆を、
101
+ 「自动审查(高权限)」は `danger-full-access` の盾+感嘆符をコピーしており、それぞれが
102
+ 実際に共有するファイルサンドボックスのグリフになります。DSH はプラグイン提供ティアに
103
+ **設計上アイコンを与えません** —— その Map 自身のコメントが *"host-configured names
104
+ outside the design set get none"* と述べています。プラグインが影響できる option
105
+ オブジェクトは `{value, name, description}` しか運ばないため、代わりに使えるプラグイン側の
106
+ シームは存在しません。
107
+
108
+ スクリプトは取得元のキーを**解決**します(`["<key>",` を先に、次にホストが使う定数別名 ——
109
+ 0.1.5 の `danger-full-access` は `[FULL_ACCESS,`)。DSH はこの設計セットを一度変更して
110
+ います —— 0.1.2 には `permissive` のグリフがあり、0.1.5 には `read-only` /
111
+ `workspace-write` / `danger-full-access` しかありません。解決できないキーは、Map が実際に
112
+ 持つキーと一緒に報告されるため、ティアの付け替えは `GLYPH_TARGETS` の 1 行で済みます。
113
+
114
+ このパッチは**ホスト**のファイルを書き換えるので、**DSH のアップグレードや再インストールで
115
+ 失われます**。*本プラグイン*のアップグレードでは失われません。アイコンは元々プラグインの
116
+ ものではなく、プラグイン自身の寄与(`cordis.patch.yml` の `name:` / `description:`)は
117
+ パッケージに同梱されています。
118
+
119
+ ```sh
120
+ npx dsh-perm-gate-patch-glyph # パッチを適用
121
+ npx dsh-perm-gate-patch-glyph --check # 確認のみ。グリフが失われていれば終了コード 1
122
+ dsh profile reload --profile web
123
+ ```
124
+
125
+ スクリプトは**このパッケージに同梱**されています —— `scripts/patch-permission-glyph.mjs`
126
+ としても、`dsh-perm-gate-patch-glyph` bin としても —— ソースの checkout は不要です。
127
+ **意図的に `postinstall` には接続していません**:これはホストパッケージを書き換えるもので、
128
+ プラグインが許可なく自分の harness を書き換えてよい理由はありません。適用の有無にかかわらず
129
+ DSH の動作に影響はなく、ティア自体はそのまま機能します。
130
+
131
+ このスクリプトは冪等(2 回目は no-op)で、バックアップは 1 度だけ取り、2 つのグリフは
132
+ 両方適用するか両方とも適用しないか(解決できない取得元キーは拒否であり、部分適用では
133
+ ありません)のいずれかで、壊れたスライスを書き込もうとしません —— 結果に対して
134
+ `node --check` を実行し、失敗すればバックアップを復元します —— したがって DSH
135
+ アップグレードのたびに無条件で再実行して安全です。呼び出し元の profile スコープを先に、
136
+ CLI インストールを次に探すため、nvm のバージョン変更やインストール symlink の貼り替えでも
137
+ 壊れません。マシンに複数の DSH インストールがある場合、**パッチを当てなかった**方は出力に
138
+ 列挙されます —— 目の前の UI を提供しているのはそのうち 1 つだけなので、必要ならそのパスを
139
+ 引数で明示してください。
140
+
141
+ **プラグインを再インストールしてもアイコンは戻りません。**
142
+ `dsh plugin --profile web add …` は profile ディレクトリ内の pnpm に引数を転送し、
143
+ profile 自身の `node_modules` しか書き換えません(`-w` = `--workspace-root` ですが、
144
+ この profile の workspace は `packages: ['.']` そのものなので関係ありません)。
145
+ アイコンは DSH インストール側にあります。標準的なインストールでは、以下の 3 つの
146
+ パスは 3 つのコピーではなく **1 つの物理ファイル**です:
147
+
148
+ | パス | 実体 |
149
+ |------|------|
150
+ | `dirname(node)/node_modules/@deepseek-ai/dsh` | DSH インストール先(symlink のことがある) |
151
+ | `<profile>/node_modules/@deepseek-ai/dsh-client-ui-conversation` | そこへの**ジャンクション** |
152
+ | `<dsh>/node_modules/@deepseek-ai/dsh-client-ui-conversation/lib/client.js` | パッチ対象のファイル |
153
+
154
+ 見るべき症状:ティアは動作しゲートも効いたままですが、入力欄のドロップダウンの行に
155
+ アイコンがなく、折りたたまれたトリガーは他のティアがアイコン+文字なのに対して
156
+ 文字だけになります。
157
+
90
158
  ## 分割プラグインからの移行
91
159
 
92
160
  `dsh-perm-gate` は、これまで `dsh-permission-rules` / `dsh-auto-mode` /
@@ -144,6 +212,14 @@ DSH の bundle patch は `permission.config.presets` を key 単位でマージ
144
212
  します。profile を再読込して `cordis.patch.yml` を再適用し、後から読み込まれる
145
213
  プラグインが `presets` を上書きしていないか確認してください。
146
214
 
215
+ **「自动审查」ティアの入力欄アイコンが消えた。**
216
+ DSH のアップグレードまたは再インストールが、パッチを当てたホスト bundle を置き換え
217
+ ました。プラグインを再インストールしても戻りません。
218
+ `npx dsh-perm-gate-patch-glyph` を実行して再読込してください。取得元キーが無いと
219
+ 報告された場合は DSH がグリフ表を再度変更しています —— エラーが現在のキー一覧を
220
+ 示すので、`GLYPH_TARGETS` の該当ティアを付け替えてください。
221
+ ティア自体は影響を受けません —— パッチなしでもラベルとゲートは動作します。
222
+
147
223
  **ルールファイルがあるのに `--list` が `ruleCount: 0` を返す。**
148
224
  `rulesFile` はプラグイン ディレクトリではなく Harness プロセスの CWD から解決されます。
149
225
  絶対パスを使うか、シェルの CWD を確認してください。不正なドキュメントは読み込み時に
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.0.0**. 결정 체인, 규칙 파일 형식, 自动审查 티어는
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
 
@@ -88,6 +94,64 @@ dsh plugin --profile web update dsh-perm-gate
88
94
  dsh profile reload --profile web
89
95
  ```
90
96
 
97
+ ## **DSH** 업그레이드 후: 입력창 아이콘 패치 재적용
98
+
99
+ 「自动审查」와「自动审查(高权限)」두 티어에 아이콘이 붙는 것은
100
+ `scripts/patch-permission-glyph.mjs`가 **DSH 호스트 패키지 안의 닫힌 Map**에 두 항목을
101
+ 추가했기 때문입니다 ——「自动审查」는 `workspace-write`의 방패+연필을,
102
+ 「自动审查(高权限)」는 `danger-full-access`의 방패+느낌표를 복사해 각자가 실제로 공유하는
103
+ 파일 샌드박스의 글리프를 갖습니다. DSH는 플러그인이 제공한 티어에 **설계상 아이콘을 주지
104
+ 않습니다** —— 그 Map 자체의 주석이 *"host-configured names outside the design set get
105
+ none"*이라고 말합니다. 플러그인이 영향을 줄 수 있는 option 객체는
106
+ `{value, name, description}`만 나르므로, 대신 쓸 수 있는 플러그인 측 이음새가 없습니다.
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
+
114
+ 이 패치는 **호스트** 파일을 고치므로 **DSH 업그레이드나 재설치에서 사라집니다**.
115
+ *이 플러그인*을 업그레이드할 때는 사라지지 않습니다. 아이콘은 애초에 플러그인 소유가
116
+ 아니었고, 플러그인 자신의 기여(`cordis.patch.yml`의 `name:` / `description:`)는
117
+ 패키지에 함께 실려 나갑니다.
118
+
119
+ ```sh
120
+ npx dsh-perm-gate-patch-glyph # 패치 적용
121
+ npx dsh-perm-gate-patch-glyph --check # 확인만. 글리프가 사라졌으면 종료 코드 1
122
+ dsh profile reload --profile web
123
+ ```
124
+
125
+ 스크립트는 **이 패키지에 함께 실려 나갑니다** —— `scripts/patch-permission-glyph.mjs`로도,
126
+ `dsh-perm-gate-patch-glyph` bin으로도 —— 소스 checkout이 필요 없습니다.
127
+ **의도적으로 `postinstall`에 연결하지 않았습니다**: 이 스크립트는 호스트 패키지를 고치며,
128
+ 플러그인이 허락 없이 자신이 설치된 harness를 다시 쓸 이유는 없습니다. 적용 여부와 무관하게
129
+ DSH 동작에는 영향이 없고 티어 자체는 그대로 기능합니다.
130
+
131
+ 이 스크립트는 멱등이며(두 번째 실행은 no-op), 백업은 한 번만 뜨고, 두 글리프를 모두
132
+ 적용하거나 모두 적용하지 않으며(해석할 수 없는 원본 키는 거부이지 부분 적용이 아닙니다),
133
+ 잘못 잘린 조각을 쓰지 않습니다 —— 결과에 `node --check`를 돌려 실패하면 백업을 복원합니다
134
+ —— 따라서 DSH 업그레이드 때마다 무조건 다시 실행해도 안전합니다. 호출자의 profile
135
+ 스코프를 먼저, CLI 설치를 다음으로 탐색하므로 nvm 버전 변경이나 설치 symlink 재지정에도
136
+ 깨지지 않습니다. 머신에 DSH 설치가 여러 개면 **패치하지 않은** 쪽이 출력에 나열됩니다 ——
137
+ 눈앞의 UI를 제공하는 것은 그중 하나뿐이므로, 필요하면 그 경로를 인수로 명시하세요.
138
+
139
+ **플러그인을 재설치해도 아이콘은 돌아오지 않습니다.**
140
+ `dsh plugin --profile web add …`는 profile 디렉터리 안의 pnpm으로 인자를 넘기고
141
+ profile 자신의 `node_modules`만 씁니다(`-w` = `--workspace-root`인데, 이 profile의
142
+ workspace는 `packages: ['.']` 그 자체이므로 달라지는 것이 없습니다). 아이콘은 DSH
143
+ 설치 쪽에 있습니다. 표준 설치에서 아래 세 경로는 사본 세 개가 아니라
144
+ **하나의 물리 파일**입니다:
145
+
146
+ | 경로 | 실체 |
147
+ |------|------|
148
+ | `dirname(node)/node_modules/@deepseek-ai/dsh` | DSH 설치 위치(symlink일 수 있음) |
149
+ | `<profile>/node_modules/@deepseek-ai/dsh-client-ui-conversation` | 그곳을 가리키는 **정션(junction)** |
150
+ | `<dsh>/node_modules/@deepseek-ai/dsh-client-ui-conversation/lib/client.js` | 패치 대상 파일 |
151
+
152
+ 관찰할 증상: 티어는 여전히 동작하고 게이트도 그대로지만, 입력창 드롭다운의 그 행에
153
+ 아이콘이 없고 접힌 트리거가 다른 티어의 아이콘+텍스트와 달리 텍스트만 표시됩니다.
154
+
91
155
  ## 분리된 플러그인에서 이전하기
92
156
 
93
157
  `dsh-perm-gate`는 `dsh-permission-rules`, `dsh-auto-mode`, `dsh-auto-review`,
@@ -143,6 +207,13 @@ DSH 번들 패치는 `permission.config.presets`를 key 단위로 병합하지
143
207
  합니다. profile을 다시 불러와 `cordis.patch.yml`을 재적용하고, 더 늦게 로드되는
144
208
  플러그인이 `presets`를 덮어쓰지 않는지 확인하세요.
145
209
 
210
+ **「自动审查」티어의 입력창 아이콘이 사라졌습니다.**
211
+ DSH 업그레이드나 재설치가 패치해 둔 호스트 번들을 교체했습니다. 플러그인을
212
+ 재설치해도 되돌아오지 않습니다. `npx dsh-perm-gate-patch-glyph`를 실행하고
213
+ 다시 불러오세요. 원본 키가 없다고 보고되면 DSH가 글리프 표를 다시 바꾼 것입니다 ——
214
+ 오류가 현재 키 목록을 알려 주므로 `GLYPH_TARGETS`에서 해당 티어를 다시 지정하세요.
215
+ 티어 자체는 영향받지 않습니다 —— 패치가 없어도 라벨과 게이트는 정상 동작합니다.
216
+
146
217
  **규칙 파일이 있는데 `--list`가 `ruleCount: 0`을 표시합니다.**
147
218
  `rulesFile`은 플러그인 디렉터리가 아니라 Harness 프로세스의 CWD에서 해석됩니다.
148
219
  절대 경로를 쓰거나 셸의 CWD를 확인하세요. 잘못된 문서는 로드 시 loud-fail하며
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.0.0**. 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
 
@@ -88,6 +96,65 @@ Then re-apply the profile so the patch file is re-read:
88
96
  dsh profile reload --profile web
89
97
  ```
90
98
 
99
+ ## After a **DSH** upgrade: re-apply the composer glyph patch
100
+
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`.
116
+
117
+ That patch edits a **host** file, so a DSH upgrade or reinstall erases it. Upgrading
118
+ *this plugin* does not: the plugin never owned the glyph, and its own contribution
119
+ (`name:` / `description:` in `cordis.patch.yml`) ships inside the package.
120
+
121
+ ```sh
122
+ npx dsh-perm-gate-patch-glyph # apply the patch
123
+ npx dsh-perm-gate-patch-glyph --check # report only; exits 1 if the glyph is gone
124
+ dsh profile reload --profile web
125
+ ```
126
+
127
+ The script **ships inside this package** — as `scripts/patch-permission-glyph.mjs` and as
128
+ the `dsh-perm-gate-patch-glyph` bin — so no source checkout is needed. It is deliberately
129
+ **not** wired to `postinstall`: it edits a host package, and a plugin must not rewrite its
130
+ harness uninvited. Running DSH is unaffected either way; the tier works with or without it.
131
+
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.
141
+
142
+ **Reinstalling the plugin does not restore the glyph.** `dsh plugin --profile web
143
+ add …` forwards to pnpm inside the profile directory and writes the profile's own
144
+ `node_modules` only; `-w` (`--workspace-root`, and this profile's workspace is just
145
+ `packages: ['.']`) changes nothing about that. The glyph lives in the DSH install.
146
+ On a stock install these are not three copies but **one physical file**:
147
+
148
+ | Path | What it is |
149
+ |------|------------|
150
+ | `dirname(node)/node_modules/@deepseek-ai/dsh` | the DSH install (may be a symlink) |
151
+ | `<profile>/node_modules/@deepseek-ai/dsh-client-ui-conversation` | a **junction** into it |
152
+ | `<dsh>/node_modules/@deepseek-ai/dsh-client-ui-conversation/lib/client.js` | the patched file |
153
+
154
+ Symptom to look for: the tier still works and still gates correctly, but its row in
155
+ the composer dropdown has no icon and the collapsed trigger renders plain text
156
+ where the other tiers render glyph + text.
157
+
91
158
  ## Migrate from the split plugins
92
159
 
93
160
  `dsh-perm-gate` merges the gate, the approval seam and the (optional) classifier
@@ -145,6 +212,14 @@ The DSH bundle patch replaces the whole `permission.config.presets` map instead
145
212
  merging per key. Reload the profile so `cordis.patch.yml` is re-applied, and make
146
213
  sure no later plugin overwrites `presets`.
147
214
 
215
+ **A 自动审查 tier lost its icon in the composer.**
216
+ A DSH upgrade or reinstall replaced the host bundle the glyphs were patched into;
217
+ re-running the plugin install will not bring it back. Run
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.
222
+
148
223
  **`--list` reports `ruleCount: 0` although my rules file exists.**
149
224
  `rulesFile` is resolved against the process CWD of the harness, not the plugin
150
225
  directory. Prefer an absolute path or confirm the shell CWD. A malformed document
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.0.0**。裁决链、规则文件格式与自动审查档位请见
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
 
@@ -85,6 +90,58 @@ dsh plugin --profile web update dsh-perm-gate
85
90
  dsh profile reload --profile web
86
91
  ```
87
92
 
93
+ ## **DSH** 升级后:重打输入区图标补丁
94
+
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` 一行。
107
+
108
+ 该补丁改的是**宿主**文件,因此 **DSH 升级或重装会把它抹掉**。升级*本插件*不会:
109
+ 图标从来不属于插件,而插件自己的贡献(`cordis.patch.yml` 里的 `name:` /
110
+ `description:`)随包发布。
111
+
112
+ ```sh
113
+ npx dsh-perm-gate-patch-glyph # 应用补丁
114
+ npx dsh-perm-gate-patch-glyph --check # 只检查;图标已丢失时退出码为 1
115
+ dsh profile reload --profile web
116
+ ```
117
+
118
+ 脚本**随本包分发** —— 既是 `scripts/patch-permission-glyph.mjs`,也是一个
119
+ `dsh-perm-gate-patch-glyph` bin —— 所以不需要源码 checkout。它**故意没有**挂在
120
+ `postinstall` 上:它改的是宿主包,插件不该未经许可改写自己所在的 harness。有没有它
121
+ 都不影响 DSH 运行,档位本身照常工作。
122
+
123
+ 脚本是幂等的(重复执行是 no-op),只备份一次,两个图标要么都打要么都不打(源键解析不到
124
+ 即拒绝,不会打出半个补丁),且拒绝写坏切片 —— 它会对结果跑 `node --check`,失败即还原
125
+ 备份 —— 所以每次 DSH 升级后无条件重跑都是安全的。它先探测调用方自己的 profile 作用域,
126
+ 再看 CLI 安装目录,因此 nvm 换版本或安装软链重指都不会让它失效;当机器上存在多份 DSH
127
+ 安装时,**没有**被打补丁的那些会列在输出里 —— 因为真正服务你面前界面的只有其中一份,
128
+ 需要时把那个路径作为参数显式传入。
129
+
130
+ **重装插件并不会恢复图标。**`dsh plugin --profile web add …` 只是把参数转发给
131
+ profile 目录里的 pnpm,只写 profile 自己的 `node_modules`;`-w`
132
+ (`--workspace-root`,而本 profile 的 workspace 就是 `packages: ['.']`)对此没有
133
+ 任何改变。图标住在 DSH 安装里。在标准安装上,下面三条路径不是三份副本,而是
134
+ **同一个物理文件**:
135
+
136
+ | 路径 | 实际是什么 |
137
+ |------|-----------|
138
+ | `dirname(node)/node_modules/@deepseek-ai/dsh` | DSH 安装位(可能是软链) |
139
+ | `<profile>/node_modules/@deepseek-ai/dsh-client-ui-conversation` | 指向它的**目录联接(junction)** |
140
+ | `<dsh>/node_modules/@deepseek-ai/dsh-client-ui-conversation/lib/client.js` | 被补丁的那个文件 |
141
+
142
+ 要观察的现象:档位依然工作、门禁依然生效,但它在输入区下拉里那一行没有图标,
143
+ 收起后的触发器显示纯文字,而同排其他档位是图标+文字。
144
+
88
145
  ## 从分裂的插件迁移
89
146
 
90
147
  `dsh-perm-gate` 把原先散落在 `dsh-permission-rules`、`dsh-auto-mode`、
@@ -138,6 +195,12 @@ DSH 的 bundle patch 是整体替换 `permission.config.presets`,而非逐 key
138
195
  请重载 profile 让 `cordis.patch.yml` 重新生效,并确认没有更晚加载的插件覆盖了
139
196
  `presets`。
140
197
 
198
+ **某个「自动审查」档位在输入区丢了图标。**
199
+ DSH 升级或重装替换了被打了补丁的宿主 bundle;重装插件不会把它带回来。执行
200
+ `npx dsh-perm-gate-patch-glyph` 后重载即可。若报错说某个源键不存在,说明宿主又改了
201
+ 图标表 —— 报错会列出表里现有的键,按提示改 `GLYPH_TARGETS` 即可。档位本身不受影响 ——
202
+ 没有补丁,它的标签与门禁照常工作。
203
+
141
204
  **规则文件存在但 `--list` 显示 `ruleCount: 0`。**
142
205
  `rulesFile` 按 harness 进程的 CWD 解析,而不是插件目录。建议使用绝对路径,
143
206
  或确认 shell 的 CWD。格式错误的文档在加载时 loud fail,绝不会静默失效。