dsh-permission-rules 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,37 @@
2
2
 
3
3
  All notable changes to dsh-permission-rules are recorded here, newest first.
4
4
 
5
+ ## v0.4.1 — 2026-08-15
6
+
7
+ ### Audit safety on every host (fixes [#2](https://github.com/PerryLink/dsh-permission-rules/issues/2))
8
+
9
+ - Hosts whose `Session.append` predates the `ignorable` envelope marker (the `0.1.0-rc.6` line) silently drop the marker, writing audit events that make sessions unresumable on stricter harness builds (`SessionFormatUnsupportedError`). The runtime now detects such hosts BEFORE the first append (peer-version pre-check) and re-checks after the first append (probe of the returned envelope), then degrades gracefully: session-log audit is disabled with a one-time warning so session logs stay loadable everywhere.
10
+ - New `allowUnmarkedAudit` config (default `false`): set `true` to opt back into the in-session audit trail on pre-marker hosts (accepting that those sessions may need `scripts/repair-session-logs.mjs` before loading on a newer harness). `/rules decisions` explains the disabled audit on degraded hosts.
11
+ - `events.ts` no longer claims rc.6 hosts are harmless ("no failure either way") — the failure mode is documented accurately, and `isMarkedAuditEvent`/`isUnmarkedHostVersion` ship as exported capability helpers.
12
+ - Thanks to [@22xuan](https://github.com/22xuan) for the detailed report and the upstream harness discussion; credited in the README Acknowledgments.
13
+
14
+ ### Engineering
15
+
16
+ - 139 tests across 9 suites: new `audit-support.spec.ts` covers the version-line classification, the envelope probe, the pre-append degradation, the opt-in, and the `/rules decisions` notice. Five-language READMEs (config table, Known limitations, Acknowledgments), AGENTS.md, CHANGELOG, and VERIFICATION updated.
17
+
18
+ ## v0.4.0 — 2026-08-15
19
+
20
+ ### Hot reload and workspace identity
21
+
22
+ - **Mid-session rule-file creation is adopted automatically.** Expected-but-absent rule files (the project file when it is not in effect, a fallback deleted after mount) are now watched through their deepest existing ancestor directory (chokidar cannot reliably watch a missing path whose parent is also missing), so creating `.dsh/rules.yaml` — or recreating it after a fallback took over — takes effect without a manual `/rules reload`. Under `searchUp`, only the immediate cwd-level candidate is watched; deeper ancestors still need a reload.
23
+ - The per-workspace cache key is now the resolved cwd, case-folded on Windows: differently-spelled paths to the same workspace share one cache entry and one watcher set instead of doubling both.
24
+
25
+ ### Commands and observability
26
+
27
+ - `/rules test` accepts `--platform <name>` (one of the closed platform list): the `when.platform` match dimension is now dry-testable on any host, completing the flag coverage of every match dimension.
28
+ - `/rules` lists each rule with its own source file in multi-file chains (`searchUp`), via a localized `src:` attribution token; `/rules list` is an explicit alias for the bare listing.
29
+ - All five output languages carry the new `testBadPlatform` message, the updated usage strings, and the `src` token.
30
+
31
+ ### Engineering
32
+
33
+ - 133 tests across 8 suites (new coverage: creation-adoption watch paths, fallback recreation, cache-key dedup, `--platform`, `list`, source attribution); coverage gate held. Five-language READMEs, both rules-format references, AGENTS.md, and the `/rules` command hint updated.
34
+ - The test harness now mounts with `watch: false` by default (only the chokidar-mocked watch suite opts in): real watchers on temp workspaces tripped a Node 24 + Windows libuv assertion (`src\win\fs-event.c`) when dirs were removed mid-test — the pre-existing cause of the red windows-latest/Node 24 matrix cells since v0.3.0.
35
+
5
36
  ## v0.3.0 — 2026-08-14
6
37
 
7
38
  ### Rules vocabulary
package/README.es.md CHANGED
@@ -53,10 +53,10 @@ Un segundo modelo responde *"¿es segura ESTA llamada?"* con criterio, pero cues
53
53
  - ✅ **Metadatos de reglas** — `enabled: false`, `description`, `tags`; `/rules` advierte sobre reglas eclipsadas por un catch-all anterior
54
54
  - ✅ **Seguro para el waterfall** — `allow`/paso siempre llaman a `next()`; solo `deny`/`ask` cortocircuitan
55
55
  - ✅ **Seam de aprobación oficial** — `ask` fluye por `ctx.approval`; nunca reimplementado, nunca eludido
56
- - ✅ **Auditoría completa** — los eventos `permissionRules/decision` llevan la acción de la regla, el cwd del workspace Y el resultado final de cada llamada; `/rules decisions` reproduce el rastro en la sesión
56
+ - ✅ **Auditoría completa** — los eventos `permissionRules/decision` llevan la acción de la regla, el cwd del workspace Y el resultado final de cada llamada; `/rules decisions` reproduce el rastro en la sesión; los hosts anteriores al marcador de envoltura de auditoría degradan a auditoría desactivada con un aviso único en lugar de escribir registros irrecuperables (`allowUnmarkedAudit` la reactiva)
57
57
  - ✅ **Despliegue en simulación** — `enforce: false` audita lo que la política *haría* (acción hipotética + resultado real posterior, marcado `dryRun`) mientras deja pasar todas las llamadas; prueba segura de políticas en producción
58
- - ✅ **Prueba en seco** — `/rules test <tool> <json-args>` evalúa las reglas activas sin ejecutar nada, con sobrescrituras `--cwd`, `--env` y `--agent` para cada dimensión
59
- - ✅ **Recarga en caliente** — vigilancia Chokidar con debounce; una edición rota conserva las reglas previas, nunca falla
58
+ - ✅ **Prueba en seco** — `/rules test <tool> <json-args>` evalúa las reglas activas sin ejecutar nada, con sobrescrituras `--cwd`, `--env`, `--agent` y `--platform` para cada dimensión
59
+ - ✅ **Recarga en caliente** — vigilancia Chokidar con debounce; una edición rota conserva las reglas previas, nunca falla; un archivo de reglas creado a mitad de sesión (el del proyecto o el fallback) se adopta automáticamente, sin recarga manual
60
60
  - ✅ **Fallo ruidoso** — YAML inválido, acciones/campos desconocidos, globs/regex incorrectos, patrones propensos a backtracking o > `maxRules` hacen fallar la carga
61
61
  - ✅ **Ruta caliente acotada** — matchers precompilados, O(reglas × patrones), limitado por `maxRules`; el grado de backtracking de glob limitado por `maxGlobStars`
62
62
 
@@ -68,7 +68,7 @@ dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"
68
68
 
69
69
  # o desde un tarball empaquetado (artefactos compilados, sin permiso de build)
70
70
  pnpm pack
71
- dsh plugin --profile web add ./dsh-permission-rules-0.3.0.tgz
71
+ dsh plugin --profile web add ./dsh-permission-rules-0.4.1.tgz
72
72
 
73
73
  # 2. reinicia
74
74
  dsh --profile web
@@ -114,17 +114,19 @@ Todos los ajustes son campos `Config` de Schemastery (modificables desde cordis.
114
114
  | `searchUp` | `false` | Recorre los directorios padre desde el cwd de la sesión y combina cada archivo de reglas encontrado, el más cercano primero |
115
115
  | `maxGlobStars` | `2` | Límite duro de cuantificadores `*`/`**` sin límite por patrón glob (cota del grado de backtracking) |
116
116
  | `enforce` | `true` | `false` = modo simulación: los aciertos deny/ask solo se registran en auditoría con un marcador `dryRun` (acción hipotética + resultado real posterior) y todas las llamadas pasan — prueba una política antes de aplicarla |
117
+ | `allowUnmarkedAudit` | `false` | Los hosts cuyo `Session.append` es anterior al marcador `ignorable` (la línea `0.1.0-rc.6`) escriben eventos de auditoría sin marcar, haciendo las sesiones irrecuperables en builds más estrictos: el plugin los detecta y desactiva la auditoría del registro de sesión con un aviso único. Ponlo en `true` para reactivar el rastro en la sesión (repara los registros existentes con `scripts/repair-session-logs.mjs`) |
117
118
 
118
119
  ### Comandos de sesión
119
120
 
120
121
  ```
121
122
  /rules lista las reglas activas, sus archivos fuente y cualquier error de la última recarga
123
+ /rules list alias explícito del listado simple
122
124
  /rules reload relee la cadena de archivos de reglas de este workspace
123
125
  /rules decisions [n] muestra las últimas n decisiones de permisos de esta sesión (por defecto 10)
124
126
  /rules test <tool> <json> evalúa en seco las reglas contra una llamada hipotética, p. ej. /rules test bash {"command":"git push origin main"}
125
127
  ```
126
128
 
127
- `/rules test` también acepta banderas iniciales: `--cwd <dir>` evalúa contra otro workspace, `--env CLAVE=VALOR` (repetible) sobrescribe el entorno para `when.env`, y `--agent <selector>` (repetible) suministra candidatos de identidad para la dimensión `agents`.
129
+ `/rules test` también acepta banderas iniciales: `--cwd <dir>` evalúa contra otro workspace, `--env CLAVE=VALOR` (repetible) sobrescribe el entorno para `when.env`, `--agent <selector>` (repetible) suministra candidatos de identidad para la dimensión `agents`, y `--platform <nombre>` sobrescribe la plataforma para `when.platform`. En cadenas de varios archivos (p. ej. `searchUp`), cada línea de regla se atribuye a su propio archivo fuente.
128
130
 
129
131
  La salida de los comandos es solo UI: el modelo aprende las reglas únicamente a través de los resultados de herramienta que producen. `language` elige el idioma de salida. Un JSON Schema del archivo de reglas se distribuye en [docs/rules-format.schema.json](docs/rules-format.schema.json) (conéctalo con `# yaml-language-server: $schema=...` para autocompletado en el editor).
130
132
 
@@ -150,7 +152,7 @@ La salida de los comandos es solo UI: el modelo aprende las reglas únicamente a
150
152
 
151
153
  ## Limitaciones conocidas
152
154
 
153
- - `permissionRules/decision` se añade con el marcador de envoltura `ignorable: true`, de modo que cualquier build del harness carga el registro: los lectores que no conocen el tipo fuera del repositorio simplemente omiten el registro de auditoría en lugar de rechazar la sesión. (Los hosts rc.6 aceptan e ignoran el marcador, conservando exactamente el comportamiento anterior; las sesiones escritas en hosts rc.6 carecen del marcador y pueden necesitar `scripts/repair-session-logs.mjs` antes de cargarse en hosts con semántica required-on-read.)
155
+ - `permissionRules/decision` se añade con el marcador de envoltura `ignorable: true`, de modo que cualquier build del harness carga el registro: los lectores que no conocen el tipo fuera del repositorio simplemente omiten el registro de auditoría en lugar de rechazar la sesión. Los hosts cuyo `Session.append` es anterior al marcador (la línea `0.1.0-rc.6`) lo DESCARTAN silenciosamente: el plugin los detecta en tiempo de ejecución (verificación previa de la versión del peer + una sonda del sobre añadido) y desactiva la auditoría del registro de sesión con un aviso único, para que los registros sigan siendo cargables en cualquier parte. Pon `allowUnmarkedAudit: true` para reactivar el rastro en la sesión; los registros ya escritos sin marcador pueden repararse con `scripts/repair-session-logs.mjs` antes de cargarlos en hosts con semántica required-on-read.
154
156
  - Los candidatos de `paths` son heurísticos: solo las claves de argumentos documentadas alimentan la coincidencia de rutas, y la coincidencia relativa al workspace ignora las mayúsculas ASCII solo cuando `caseInsensitivePaths` está activo.
155
157
  - Los globs son un subconjunto conservador (sin expansión de llaves): escribe dos patrones o usa el modo regex.
156
158
  - El guard de backtracking de regex es estructural, no exhaustivo: los casos de ambigüedad por alternancia sin prefijos literales (p. ej. lookarounds elaborados) son responsabilidad del autor; prefiere el modo glob para archivos no confiables.
@@ -172,7 +174,7 @@ node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
172
174
  pnpm install # node ^22.19 || >=24
173
175
  pnpm run typecheck # tsc, src + tests
174
176
  pnpm run lint # eslint, src + tests + scripts
175
- pnpm test # vitest: 106 tests, 8 suites
177
+ pnpm test # vitest: 139 tests, 9 suites
176
178
  pnpm run test:coverage # puerta de cobertura (90/80/90/90)
177
179
  pnpm run build # declaraciones tsc + bundles tsdown (lib/)
178
180
  pnpm run pack:check # build + pack (el artefacto publicado)
@@ -181,6 +183,10 @@ node scripts/check-readme-sync.mjs # puerta de sincronización de READMEs en ci
181
183
 
182
184
  Consulta [VERIFICATION.md](VERIFICATION.md) para el registro de verificación headless de extremo a extremo (deny bloqueando una herramienta de shell, ask enrutado por el seam de aprobación, `--dump-config`).
183
185
 
186
+ ## Agradecimientos
187
+
188
+ - Gracias a [@22xuan](https://github.com/22xuan) por el detallado informe sobre los hosts rc.6 que descartan silenciosamente el marcador `ignorable` de los eventos de auditoría ([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2)) y por abrir la discusión en el harness upstream — la detección de capacidades del host en tiempo de ejecución y la corrección de la documentación derivan directamente de ese análisis.
189
+
184
190
  ## Licencia
185
191
 
186
192
  [Apache License 2.0](LICENSE) © 2026 dsh-permission-rules contributors
package/README.hi.md CHANGED
@@ -53,10 +53,10 @@ tools/pre-execute waterfall approval/request waterfall (answ
53
53
  - ✅ **नियम मेटाडेटा** — `enabled: false`, `description`, `tags`; `/rules` पहले किसी catch-all से छिपे नियमों की चेतावनी देता है
54
54
  - ✅ **waterfall-सुरक्षित** — `allow`/पास-थ्रू हमेशा `next()` बुलाते हैं; केवल `deny`/`ask` शॉर्ट-सर्किट करते हैं
55
55
  - ✅ **आधिकारिक approval seam** — `ask` `ctx.approval` से होकर जाता है; कभी पुनः-कार्यान्वित नहीं, कभी बायपास नहीं
56
- - ✅ **पूर्ण ऑडिट** — `permissionRules/decision` इवेंट हर कॉल के लिए नियम क्रिया, workspace cwd और अंतिम परिणाम रखते हैं; `/rules decisions` सत्र में रास्ता फिर चलाता है
56
+ - ✅ **पूर्ण ऑडिट** — `permissionRules/decision` इवेंट हर कॉल के लिए नियम क्रिया, workspace cwd और अंतिम परिणाम रखते हैं; `/rules decisions` सत्र में रास्ता फिर चलाता है; ऑडिट एन्वेलप मार्कर से पुराने होस्ट अप्राप्य लॉग लिखने के बजाय एक-बार चेतावनी के साथ ऑडिट-बंद हो जाते हैं (`allowUnmarkedAudit` पुनः चालू करता है)
57
57
  - ✅ **dry-run रोलआउट** — `enforce: false` केवल ऑडिट करता है कि नीति *क्या करती* (काल्पनिक क्रिया + वास्तविक डाउनस्ट्रीम परिणाम, `dryRun` चिह्नित) और हर कॉल को पास करता है; उत्पादन में नई नीति का सुरक्षित परीक्षण
58
- - ✅ **dry-run परीक्षण** — `/rules test <tool> <json-args>` कुछ भी निष्पादित किए बिना सक्रिय नियमों का मूल्यांकन करता है, हर मिलान आयाम के लिए `--cwd`, `--env`, और `--agent` ओवरराइड के साथ
59
- - ✅ **हॉट रीलोड** — debounce सहित Chokidar निगरानी; टूटा हुआ संपादन पिछले नियम रखता है, कभी क्रैश नहीं करता
58
+ - ✅ **dry-run परीक्षण** — `/rules test <tool> <json-args>` कुछ भी निष्पादित किए बिना सक्रिय नियमों का मूल्यांकन करता है, हर मिलान आयाम के लिए `--cwd`, `--env`, `--agent` और `--platform` ओवरराइड के साथ
59
+ - ✅ **हॉट रीलोड** — debounce सहित Chokidar निगरानी; टूटा हुआ संपादन पिछले नियम रखता है, कभी क्रैश नहीं करता; सत्र के बीच बनाई गई नियम फ़ाइल (प्रोजेक्ट की या fallback) स्वतः अपनाई जाती है, मैनुअल रीलोड की आवश्यकता नहीं
60
60
  - ✅ **ज़ोरदार विफलता** — अमान्य YAML, अज्ञात action/फ़ील्ड, ख़राब globs/regex, बैकट्रैकिंग-प्रवण पैटर्न, या `maxRules` से अधिक → लोड विफल
61
61
  - ✅ **सीमित हॉट पथ** — पूर्व-संकलित matchers, O(नियम × पैटर्न), `maxRules` द्वारा सीमित; glob बैकट्रैकिंग डिग्री `maxGlobStars` द्वारा सीमित
62
62
 
@@ -68,7 +68,7 @@ dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"
68
68
 
69
69
  # या पैक किए गए tarball से (बिल्ट आर्टिफ़ैक्ट, build अनुमति की ज़रूरत नहीं)
70
70
  pnpm pack
71
- dsh plugin --profile web add ./dsh-permission-rules-0.3.0.tgz
71
+ dsh plugin --profile web add ./dsh-permission-rules-0.4.1.tgz
72
72
 
73
73
  # 2. पुनः आरंभ करें
74
74
  dsh --profile web
@@ -114,17 +114,19 @@ dsh --profile web --dump-config | grep -A4 'id: permission-rules' # पंक
114
114
  | `searchUp` | `false` | सत्र cwd से पैरेंट निर्देशिकाओं पर चलकर हर मिली नियम फ़ाइल मिलाता है, निकटतम पहले |
115
115
  | `maxGlobStars` | `2` | प्रति glob पैटर्न असीमित `*`/`**` क्वांटिफ़ायर की कठोर सीमा (बैकट्रैकिंग-डिग्री सीमा) |
116
116
  | `enforce` | `true` | `false` = dry-run मोड: deny/ask मिलान केवल ऑडिट में `dryRun` चिह्न के साथ दर्ज होते हैं (काल्पनिक क्रिया + वास्तविक डाउनस्ट्रीम परिणाम) और हर कॉल पास होती है — लागू करने से पहले नीति का परीक्षण करें |
117
+ | `allowUnmarkedAudit` | `false` | जिन होस्ट का `Session.append` `ignorable` मार्कर से पुराना है (`0.1.0-rc.6` शृंखला) वे बिना-चिह्न ऑडिट इवेंट लिखते हैं, जिससे सत्र कठोर बिल्ड पर अप्राप्य हो जाते हैं: प्लगइन ऐसे होस्ट का पता लगाकर एक-बार चेतावनी के साथ सत्र-लॉग ऑडिट बंद कर देता है। सत्र में रास्ता वापस चाहिए तो `true` सेट करें (मौजूदा लॉग `scripts/repair-session-logs.mjs` से मरम्मत करें) |
117
118
 
118
119
  ### सेशन कमांड
119
120
 
120
121
  ```
121
122
  /rules सक्रिय नियम, उनकी स्रोत फ़ाइलें और अंतिम रीलोड त्रुटि दिखाता है
123
+ /rules list सामान्य सूची का स्पष्ट उपनाम
122
124
  /rules reload इस workspace की नियम-फ़ाइल शृंखला दोबारा पढ़ता है
123
125
  /rules decisions [n] इस सत्र की अंतिम n अनुमति निर्णय दिखाता है (डिफ़ॉल्ट 10)
124
126
  /rules test <tool> <json> काल्पनिक कॉल के विरुद्ध नियमों का dry-मूल्यांकन, जैसे /rules test bash {"command":"git push origin main"}
125
127
  ```
126
128
 
127
- `/rules test` शुरुआती फ़्लैग भी स्वीकार करता है: `--cwd <dir>` दूसरे workspace के विरुद्ध मूल्यांकन करता है, `--env KEY=मान` (दोहराने योग्य) `when.env` के लिए होस्ट env ओवरराइड करता है, और `--agent <चयनकर्ता>` (दोहराने योग्य) `agents` आयाम के लिए पहचान उम्मीदवार देता है।
129
+ `/rules test` शुरुआती फ़्लैग भी स्वीकार करता है: `--cwd <dir>` दूसरे workspace के विरुद्ध मूल्यांकन करता है, `--env KEY=मान` (दोहराने योग्य) `when.env` के लिए होस्ट env ओवरराइड करता है, `--agent <चयनकर्ता>` (दोहराने योग्य) `agents` आयाम के लिए पहचान उम्मीदवार देता है, और `--platform <नाम>` `when.platform` के लिए होस्ट प्लेटफ़ॉर्म ओवरराइड करता है। बहु-फ़ाइल शृंखलाओं (जैसे `searchUp`) में हर नियम पंक्ति अपनी स्रोत फ़ाइल के साथ चिह्नित होती है।
128
130
 
129
131
  कमांड आउटपुट केवल UI के लिए है — मॉडल नियमों को केवल उनके उत्पन्न टूल परिणामों से ही सीखता है। `language` आउटपुट भाषा चुनता है। नियम फ़ाइल का JSON Schema [docs/rules-format.schema.json](docs/rules-format.schema.json) पर साथ आता है (संपादक पूर्णता के लिए `# yaml-language-server: $schema=...` से जोड़ें)।
130
132
 
@@ -150,7 +152,7 @@ dsh --profile web --dump-config | grep -A4 'id: permission-rules' # पंक
150
152
 
151
153
  ## ज्ञात सीमाएँ
152
154
 
153
- - `permissionRules/decision` एन्वेलप के `ignorable: true` मार्कर के साथ जोड़ा जाता है, इसलिए कोई भी harness बिल्ड लॉग लोड कर लेता है — जो पाठक इस आउट-ऑफ-रेपो प्रकार को नहीं जानते वे सत्र अस्वीकार करने के बजाय केवल ऑडिट रिकॉर्ड छोड़ देते हैं। (rc.6 होस्ट मार्कर को स्वीकार कर अनदेखा करते हैं, पहले जैसा ही व्यवहार बना रहता है; rc.6 होस्ट पर लिखे सत्रों में मार्कर नहीं होता और required-on-read शब्दार्थ वाले होस्ट पर लोड से पहले `scripts/repair-session-logs.mjs` की ज़रूरत पड़ सकती है।)
155
+ - `permissionRules/decision` एन्वेलप के `ignorable: true` मार्कर के साथ जोड़ा जाता है, इसलिए कोई भी harness बिल्ड लॉग लोड कर लेता है — जो पाठक इस आउट-ऑफ-रेपो प्रकार को नहीं जानते वे सत्र अस्वीकार करने के बजाय केवल ऑडिट रिकॉर्ड छोड़ देते हैं। मार्कर से पुराने होस्ट (`0.1.0-rc.6` शृंखला) इसे चुपचाप गिरा देते हैं: प्लगइन रनटाइम पर उन्हें पहचानता है (peer संस्करण पूर्व-जाँच + जोड़े गए एन्वेलप की जाँच) और एक-बार चेतावनी के साथ सत्र-लॉग ऑडिट बंद कर देता है, ताकि लॉग हर जगह लोड होते रहें। सत्र में रास्ता वापस चाहिए तो `allowUnmarkedAudit: true` सेट करें; बिना-चिह्न लिखे गए लॉग required-on-read शब्दार्थ वाले होस्ट पर लोड से पहले `scripts/repair-session-logs.mjs` से मरम्मत किए जा सकते हैं।
154
156
  - `paths` उम्मीदवार ह्यूरिस्टिक हैं: केवल दस्तावेज़ित आर्गुमेंट-कुंजियाँ पथ मिलान में आती हैं, और workspace-सापेक्ष मिलान केवल तभी ASCII-केस-असंवेदनशील होता है जब `caseInsensitivePaths` चालू हो।
155
157
  - globs एक रूढ़िवादी उपसमुच्चय हैं (brace विस्तार नहीं) — दो पैटर्न लिखें या regex मोड इस्तेमाल करें।
156
158
  - regex बैकट्रैकिंग गार्ड संरचनात्मक है, संपूर्ण नहीं: शाब्दिक उपसर्ग के बिना विकल्प-अस्पष्टता के मामले (जैसे कृत्रिम lookarounds) लेखक की ज़िम्मेदारी हैं; अविश्वसनीय फ़ाइलों के लिए glob मोड पसंद करें।
@@ -172,7 +174,7 @@ node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
172
174
  pnpm install # node ^22.19 || >=24
173
175
  pnpm run typecheck # tsc, src + tests
174
176
  pnpm run lint # eslint, src + tests + scripts
175
- pnpm test # vitest: 106 tests, 8 suites
177
+ pnpm test # vitest: 139 tests, 9 suites
176
178
  pnpm run test:coverage # कवरेज द्वार (90/80/90/90)
177
179
  pnpm run build # tsc डिक्लेरेशन + tsdown bundles (lib/)
178
180
  pnpm run pack:check # build + pack (प्रकाशित आर्टिफ़ैक्ट)
@@ -181,6 +183,10 @@ node scripts/check-readme-sync.mjs # पाँच-भाषा README सिं
181
183
 
182
184
  headless एंड-टू-एंड सत्यापन रिकॉर्ड (deny द्वारा shell टूल रोकना, ask का approval seam से गुज़रना, `--dump-config`) [VERIFICATION.md](VERIFICATION.md) में देखें।
183
185
 
186
+ ## आभार
187
+
188
+ - [@22xuan](https://github.com/22xuan) को धन्यवाद — rc.6 होस्ट द्वारा ऑडिट इवेंट के `ignorable` मार्कर को चुपचाप गिराने की विस्तृत रिपोर्ट ([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2)) और अपस्ट्रीम harness चर्चा खोलने के लिए — रनटाइम होस्ट-क्षमता पहचान और दस्तावेज़ सुधार सीधे उसी विश्लेषण से निकले हैं।
189
+
184
190
  ## लाइसेंस
185
191
 
186
192
  [Apache License 2.0](LICENSE) © 2026 dsh-permission-rules contributors
package/README.md CHANGED
@@ -53,10 +53,10 @@ A second model answers *"is THIS call okay?"* with judgment, but costs a round-t
53
53
  - ✅ **Rule metadata** — `enabled: false`, `description`, `tags`; `/rules` warns about rules shadowed by an earlier catch-all
54
54
  - ✅ **Waterfall-safe** — `allow`/passthrough always call `next()`; only `deny`/`ask` short-circuit
55
55
  - ✅ **Official approval seam** — `ask` flows through `ctx.approval`; never re-implemented, never bypassed
56
- - ✅ **Full audit** — `permissionRules/decision` events carry the rule action, the workspace cwd, AND the final outcome for every call; `/rules decisions` replays the trail in-session
56
+ - ✅ **Full audit** — `permissionRules/decision` events carry the rule action, the workspace cwd, AND the final outcome for every call; `/rules decisions` replays the trail in-session; hosts that predate the audit envelope marker degrade to audit-off with a one-time warning instead of writing unresumable logs (`allowUnmarkedAudit` opts back in)
57
57
  - ✅ **Dry-run rollout** — `enforce: false` audits what the policy *would* do (would-be action + real downstream outcome, `dryRun`-marked) while passing every call through; safe policy trialing in production
58
- - ✅ **Dry-run testing** — `/rules test <tool> <json-args>` evaluates the active rules without executing anything, with `--cwd`, `--env`, and `--agent` overrides for every match dimension
59
- - ✅ **Hot reload** — Chokidar watch with debounce; a broken edit keeps the previous rules, never crashes
58
+ - ✅ **Dry-run testing** — `/rules test <tool> <json-args>` evaluates the active rules without executing anything, with `--cwd`, `--env`, `--agent`, and `--platform` overrides for every match dimension
59
+ - ✅ **Hot reload** — Chokidar watch with debounce; a broken edit keeps the previous rules, never crashes; a rule file created mid-session (the project file or the fallback) is adopted automatically, no manual reload
60
60
  - ✅ **Fail loud** — invalid YAML, unknown actions/fields, bad globs/regexes, backtracking-prone patterns, or > `maxRules` fail the load
61
61
  - ✅ **Bounded hot path** — precompiled matchers, O(rules × patterns), capped by `maxRules`; glob backtracking degree capped by `maxGlobStars`
62
62
 
@@ -68,7 +68,7 @@ dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"
68
68
 
69
69
  # or from a packed tarball (built artifacts, no build permission needed)
70
70
  pnpm pack
71
- dsh plugin --profile web add ./dsh-permission-rules-0.3.0.tgz
71
+ dsh plugin --profile web add ./dsh-permission-rules-0.4.1.tgz
72
72
 
73
73
  # 2. restart
74
74
  dsh --profile web
@@ -114,17 +114,19 @@ All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id
114
114
  | `searchUp` | `false` | Walk parent directories from the session cwd and merge every found rule file, nearest first |
115
115
  | `maxGlobStars` | `2` | Hard cap on unbounded `*`/`**` quantifiers per glob pattern (backtracking-degree bound) |
116
116
  | `enforce` | `true` | `false` = dry-run mode: deny/ask hits are audit-logged with a `dryRun` marker (would-be action + real downstream outcome) and every call passes through — trial a policy before enforcing it |
117
+ | `allowUnmarkedAudit` | `false` | Hosts whose `Session.append` predates the `ignorable` marker (the `0.1.0-rc.6` line) write audit events unmarked, making sessions unresumable on stricter builds: the plugin detects them and disables session-log audit with a one-time warning. Set `true` to opt back into the in-session trail (repair existing logs with `scripts/repair-session-logs.mjs`) |
117
118
 
118
119
  ### Session commands
119
120
 
120
121
  ```
121
122
  /rules list the active rules, their source files, and any last-reload error
123
+ /rules list explicit alias for the bare listing
122
124
  /rules reload re-read the rule-file chain for this workspace
123
125
  /rules decisions [n] show the last n permission decisions of this session (default 10)
124
126
  /rules test <tool> <json> dry-evaluate the rules against a hypothetical call, e.g. /rules test bash {"command":"git push origin main"}
125
127
  ```
126
128
 
127
- `/rules test` also accepts leading flags: `--cwd <dir>` evaluates against another workspace, `--env KEY=VALUE` (repeatable) overrides host env for `when.env`, and `--agent <selector>` (repeatable) supplies identity candidates for the `agents` dimension.
129
+ `/rules test` also accepts leading flags: `--cwd <dir>` evaluates against another workspace, `--env KEY=VALUE` (repeatable) overrides host env for `when.env`, `--agent <selector>` (repeatable) supplies identity candidates for the `agents` dimension, and `--platform <name>` overrides the host platform for `when.platform`. In multi-file chains (e.g. `searchUp`), every listed rule line is attributed to its own source file.
128
130
 
129
131
  Command output is UI-only — the model learns the rules only through the tool results they produce. `language` picks the output language. A JSON Schema for the rule file ships at [docs/rules-format.schema.json](docs/rules-format.schema.json) (wire it up with `# yaml-language-server: $schema=...` for editor completion).
130
132
 
@@ -150,7 +152,7 @@ Command output is UI-only — the model learns the rules only through the tool r
150
152
 
151
153
  ## Known limitations
152
154
 
153
- - `permissionRules/decision` is appended with the envelope's `ignorable: true` marker, so any harness build loads the log — readers that do not know the out-of-repo type simply skip the audit record instead of refusing the session. (rc.6 hosts accept and ignore the marker, keeping the exact pre-marker behavior; sessions written on rc.6 hosts lack the marker and may need `scripts/repair-session-logs.mjs` before loading on hosts with required-on-read semantics.)
155
+ - `permissionRules/decision` is appended with the envelope's `ignorable: true` marker, so any harness build loads the log — readers that do not know the out-of-repo type simply skip the audit record instead of refusing the session. Hosts whose `Session.append` predates the marker (the `0.1.0-rc.6` line) silently DROP it: the plugin detects them at runtime (peer-version pre-check + a probe of the appended envelope) and disables session-log audit with a one-time warning, so session logs stay loadable everywhere. Set `allowUnmarkedAudit: true` to opt back into the in-session trail; logs already written without the marker can be repaired with `scripts/repair-session-logs.mjs` before loading on hosts with required-on-read semantics.
154
156
  - `paths` candidates are heuristic: only the documented argument keys feed path matching, and workspace-relative matching is ASCII-case-insensitive only when `caseInsensitivePaths` is on.
155
157
  - Globs are a conservative subset (no brace expansion) — write two patterns, or use regex mode.
156
158
  - The regex backtracking guard is structural, not exhaustive: alternation-ambiguity cases without literal prefixes (e.g. crafted lookarounds) are the author's responsibility; prefer glob mode for untrusted files.
@@ -172,7 +174,7 @@ node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
172
174
  pnpm install # node ^22.19 || >=24
173
175
  pnpm run typecheck # tsc, src + tests
174
176
  pnpm run lint # eslint, src + tests + scripts
175
- pnpm test # vitest: 106 tests, 8 suites
177
+ pnpm test # vitest: 139 tests, 9 suites
176
178
  pnpm run test:coverage # coverage gate (90/80/90/90)
177
179
  pnpm run build # tsc declarations + tsdown bundles (lib/)
178
180
  pnpm run pack:check # build + pack (the published artifact)
@@ -181,6 +183,10 @@ node scripts/check-readme-sync.mjs # five-language README sync gate (also in CI
181
183
 
182
184
  See [VERIFICATION.md](VERIFICATION.md) for the headless end-to-end verification record (deny blocking a shell tool, ask routing through the approval seam, `--dump-config`).
183
185
 
186
+ ## Acknowledgments
187
+
188
+ - Thanks to [@22xuan](https://github.com/22xuan) for 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 for filing the upstream harness discussion — the runtime host-capability detection and the documentation correction drew directly from that analysis.
189
+
184
190
  ## License
185
191
 
186
192
  [Apache License 2.0](LICENSE) © 2026 dsh-permission-rules contributors
package/README.pt.md CHANGED
@@ -53,10 +53,10 @@ Um segundo modelo responde *"ESTA chamada é segura?"* com julgamento, mas custa
53
53
  - ✅ **Metadados de regras** — `enabled: false`, `description`, `tags`; `/rules` avisa sobre regras encobertas por um catch-all anterior
54
54
  - ✅ **Seguro para o waterfall** — `allow`/passagem sempre chamam `next()`; somente `deny`/`ask` curto-circuitam
55
55
  - ✅ **Seam de aprovação oficial** — `ask` flui por `ctx.approval`; nunca reimplementado, nunca contornado
56
- - ✅ **Auditoria completa** — os eventos `permissionRules/decision` carregam a ação da regra, o cwd do workspace E o resultado final de cada chamada; `/rules decisions` reproduz o rastro na sessão
56
+ - ✅ **Auditoria completa** — os eventos `permissionRules/decision` carregam a ação da regra, o cwd do workspace E o resultado final de cada chamada; `/rules decisions` reproduz o rastro na sessão; hosts anteriores ao marcador de envelope de auditoria degradam para auditoria desativada com um aviso único em vez de gravar registros irrecuperáveis (`allowUnmarkedAudit` reativa)
57
57
  - ✅ **Implantação em simulação** — `enforce: false` audita o que a política *faria* (ação hipotética + resultado real posterior, marcado com `dryRun`) enquanto deixa todas as chamadas passarem; teste seguro de políticas em produção
58
- - ✅ **Teste em seco** — `/rules test <tool> <json-args>` avalia as regras ativas sem executar nada, com sobrescritas `--cwd`, `--env` e `--agent` para cada dimensão
59
- - ✅ **Recarga a quente** — vigilância Chokidar com debounce; uma edição quebrada mantém as regras anteriores, nunca quebra
58
+ - ✅ **Teste em seco** — `/rules test <tool> <json-args>` avalia as regras ativas sem executar nada, com sobrescritas `--cwd`, `--env`, `--agent` e `--platform` para cada dimensão
59
+ - ✅ **Recarga a quente** — vigilância Chokidar com debounce; uma edição quebrada mantém as regras anteriores, nunca quebra; um arquivo de regras criado no meio da sessão (o do projeto ou o fallback) é adotado automaticamente, sem recarga manual
60
60
  - ✅ **Falha ruidosa** — YAML inválido, ações/campos desconhecidos, globs/regex ruins, padrões propensos a backtracking ou > `maxRules` fazem a carga falhar
61
61
  - ✅ **Caminho quente limitado** — matchers pré-compilados, O(regras × padrões), limitado por `maxRules`; o grau de backtracking de glob limitado por `maxGlobStars`
62
62
 
@@ -68,7 +68,7 @@ dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"
68
68
 
69
69
  # ou a partir de um tarball empacotado (artefatos compilados, sem permissão de build)
70
70
  pnpm pack
71
- dsh plugin --profile web add ./dsh-permission-rules-0.3.0.tgz
71
+ dsh plugin --profile web add ./dsh-permission-rules-0.4.1.tgz
72
72
 
73
73
  # 2. reinicie
74
74
  dsh --profile web
@@ -114,17 +114,19 @@ Todos os ajustes são campos `Config` do Schemastery (alteráveis no cordis.yml)
114
114
  | `searchUp` | `false` | Percorre os diretórios pais a partir do cwd da sessão e combina cada arquivo de regras encontrado, o mais próximo primeiro |
115
115
  | `maxGlobStars` | `2` | Limite rígido de quantificadores `*`/`**` ilimitados por padrão glob (cota do grau de backtracking) |
116
116
  | `enforce` | `true` | `false` = modo simulação: acertos deny/ask são apenas registrados na auditoria com um marcador `dryRun` (ação hipotética + resultado real posterior) e todas as chamadas passam — teste uma política antes de aplicá-la |
117
+ | `allowUnmarkedAudit` | `false` | Hosts cujo `Session.append` é anterior ao marcador `ignorable` (a linha `0.1.0-rc.6`) gravam eventos de auditoria sem marcação, tornando as sessões irrecuperáveis em builds mais rígidos: o plugin os detecta e desativa a auditoria do registro da sessão com um aviso único. Defina `true` para reativar o rastro na sessão (repare registros existentes com `scripts/repair-session-logs.mjs`) |
117
118
 
118
119
  ### Comandos de sessão
119
120
 
120
121
  ```
121
122
  /rules lista as regras ativas, seus arquivos de origem e qualquer erro da última recarga
123
+ /rules list alias explícito da listagem simples
122
124
  /rules reload relê a cadeia de arquivos de regras deste workspace
123
125
  /rules decisions [n] mostra as últimas n decisões de permissão desta sessão (padrão 10)
124
126
  /rules test <tool> <json> avalia em seco as regras contra uma chamada hipotética, ex.: /rules test bash {"command":"git push origin main"}
125
127
  ```
126
128
 
127
- `/rules test` também aceita sinalizadores iniciais: `--cwd <dir>` avalia contra outro workspace, `--env CHAVE=VALOR` (repetível) sobrescreve o ambiente para `when.env`, e `--agent <seletor>` (repetível) fornece candidatos de identidade para a dimensão `agents`.
129
+ `/rules test` também aceita sinalizadores iniciais: `--cwd <dir>` avalia contra outro workspace, `--env CHAVE=VALOR` (repetível) sobrescreve o ambiente para `when.env`, `--agent <seletor>` (repetível) fornece candidatos de identidade para a dimensão `agents`, e `--platform <nome>` sobrescreve a plataforma para `when.platform`. Em cadeias de vários arquivos (ex.: `searchUp`), cada linha de regra é atribuída ao seu próprio arquivo de origem.
128
130
 
129
131
  A saída dos comandos é somente UI — o modelo aprende as regras apenas pelos resultados de ferramenta que elas produzem. `language` escolhe o idioma da saída. Um JSON Schema do arquivo de regras é distribuído em [docs/rules-format.schema.json](docs/rules-format.schema.json) (conecte-o com `# yaml-language-server: $schema=...` para autocompletar no editor).
130
132
 
@@ -150,7 +152,7 @@ A saída dos comandos é somente UI — o modelo aprende as regras apenas pelos
150
152
 
151
153
  ## Limitações conhecidas
152
154
 
153
- - `permissionRules/decision` é anexado com o marcador de envelope `ignorable: true`, então qualquer build do harness carrega o log — leitores que não conhecem o tipo fora do repositório simplesmente pulam o registro de auditoria em vez de recusar a sessão. (Hosts rc.6 aceitam e ignoram o marcador, mantendo exatamente o comportamento anterior; sessões gravadas em hosts rc.6 não têm o marcador e podem precisar de `scripts/repair-session-logs.mjs` antes de carregar em hosts com semântica required-on-read.)
155
+ - `permissionRules/decision` é anexado com o marcador de envelope `ignorable: true`, então qualquer build do harness carrega o log — leitores que não conhecem o tipo fora do repositório simplesmente pulam o registro de auditoria em vez de recusar a sessão. Hosts cujo `Session.append` é anterior ao marcador (a linha `0.1.0-rc.6`) o DESCARTAM silenciosamente: o plugin os detecta em tempo de execução (verificação prévia da versão do peer + sonda do envelope anexado) e desativa a auditoria do registro da sessão com um aviso único, mantendo os registros carregáveis em qualquer lugar. Defina `allowUnmarkedAudit: true` para reativar o rastro na sessão; registros já gravados sem o marcador podem ser reparados com `scripts/repair-session-logs.mjs` antes de carregar em hosts com semântica required-on-read.
154
156
  - Os candidatos de `paths` são heurísticos: apenas as chaves de argumentos documentadas alimentam a correspondência de caminhos, e a correspondência relativa ao workspace ignora maiúsculas ASCII somente quando `caseInsensitivePaths` está ativo.
155
157
  - Os globs são um subconjunto conservador (sem expansão de chaves) — escreva dois padrões ou use o modo regex.
156
158
  - O guard de backtracking de regex é estrutural, não exaustivo: casos de ambiguidade por alternância sem prefixos literais (ex.: lookarounds elaborados) são responsabilidade do autor; prefira o modo glob para arquivos não confiáveis.
@@ -172,7 +174,7 @@ node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
172
174
  pnpm install # node ^22.19 || >=24
173
175
  pnpm run typecheck # tsc, src + tests
174
176
  pnpm run lint # eslint, src + tests + scripts
175
- pnpm test # vitest: 106 tests, 8 suites
177
+ pnpm test # vitest: 139 tests, 9 suites
176
178
  pnpm run test:coverage # portão de cobertura (90/80/90/90)
177
179
  pnpm run build # declarações tsc + bundles tsdown (lib/)
178
180
  pnpm run pack:check # build + pack (o artefato publicado)
@@ -181,6 +183,10 @@ node scripts/check-readme-sync.mjs # portão de sincronização dos READMEs em
181
183
 
182
184
  Veja [VERIFICATION.md](VERIFICATION.md) para o registro de verificação headless de ponta a ponta (deny bloqueando uma ferramenta de shell, ask roteado pelo seam de aprovação, `--dump-config`).
183
185
 
186
+ ## Agradecimentos
187
+
188
+ - Agradecemos a [@22xuan](https://github.com/22xuan) pelo relatório detalhado sobre hosts rc.6 descartando silenciosamente o marcador `ignorable` dos eventos de auditoria ([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2)) e por abrir a discussão no harness upstream — a detecção de capacidade do host em tempo de execução e a correção da documentação derivam diretamente dessa análise.
189
+
184
190
  ## Licença
185
191
 
186
192
  [Apache License 2.0](LICENSE) © 2026 dsh-permission-rules contributors
package/README.zh.md CHANGED
@@ -53,10 +53,10 @@ tools/pre-execute waterfall approval/request waterfall(ans
53
53
  - ✅ **规则元数据** — `enabled: false`、`description`、`tags`;`/rules` 会告警被前面通配规则遮蔽的规则
54
54
  - ✅ **waterfall 安全** — `allow`/透传一律 `next()`;只有 `deny`/`ask` 短路
55
55
  - ✅ **官方审批 seam** — `ask` 走 `ctx.approval`;不重复实现、绝不绕过
56
- - ✅ **完整审计** — `permissionRules/decision` 事件记录规则动作、工作区 cwd 与最终裁决;`/rules decisions` 可在会话内回放审计轨迹
56
+ - ✅ **完整审计** — `permissionRules/decision` 事件记录规则动作、工作区 cwd 与最终裁决;`/rules decisions` 可在会话内回放审计轨迹;早于审计信封标记的宿主自动降级为关闭审计并一次性警告,绝不写出无法恢复的日志(`allowUnmarkedAudit` 可重新开启)
57
57
  - ✅ **干跑上线** — `enforce: false` 只审计策略「本会做什么」(记录本会动作 + 下游真实结果,带 `dryRun` 标记),所有调用照常透传;可在生产环境安全试跑新策略
58
- - ✅ **干跑测试** — `/rules test <工具> <json-参数>` 不执行任何东西地评估规则命中,支持 `--cwd`、`--env`、`--agent` 覆盖每个匹配维度
59
- - ✅ **热更新** — Chokidar 监视 + 去抖;改坏了保留旧规则,绝不崩溃
58
+ - ✅ **干跑测试** — `/rules test <工具> <json-参数>` 不执行任何东西地评估规则命中,支持 `--cwd`、`--env`、`--agent`、`--platform` 覆盖每个匹配维度
59
+ - ✅ **热更新** — Chokidar 监视 + 去抖;改坏了保留旧规则,绝不崩溃;会话中途创建的规则文件(项目文件或 fallback)自动生效,无需手动重载
60
60
  - ✅ **响亮失败** — 非法 YAML、未知字段/action、坏 glob/正则、易回溯灾难的模式、超过 `maxRules` 都使加载失败
61
61
  - ✅ **热路径有界** — 预编译匹配器,O(规则数 × 模式数),`maxRules` 封顶;glob 回溯度由 `maxGlobStars` 封顶
62
62
 
@@ -68,7 +68,7 @@ dsh plugin --profile web add "github:PerryLink/dsh-permission-rules#main"
68
68
 
69
69
  # 或从打包好的 tarball 安装(预构建产物,无需构建许可)
70
70
  pnpm pack
71
- dsh plugin --profile web add ./dsh-permission-rules-0.3.0.tgz
71
+ dsh plugin --profile web add ./dsh-permission-rules-0.4.1.tgz
72
72
 
73
73
  # 2. 重启
74
74
  dsh --profile web
@@ -114,17 +114,19 @@ dsh --profile web --dump-config | grep -A4 'id: permission-rules' # 验证挂
114
114
  | `searchUp` | `false` | 从会话 cwd 向上逐级查找并合并规则文件,最近的优先 |
115
115
  | `maxGlobStars` | `2` | 每个 glob 模式的无界 `*`/`**` 量词数硬上界(回溯度封顶) |
116
116
  | `enforce` | `true` | `false` = 干跑模式:deny/ask 命中只写审计(带 `dryRun` 标记,记录本会动作与下游真实结果),所有调用照常透传——先试跑策略再强制执行 |
117
+ | `allowUnmarkedAudit` | `false` | 早于 `ignorable` 信封标记的宿主(`0.1.0-rc.6` 系列)会写出无标记审计事件,使会话在更严格构建上无法恢复:插件会探测到此类宿主并停用会话日志审计(一次性警告)。设 `true` 重新开启会话内轨迹(已有日志用 `scripts/repair-session-logs.mjs` 修复) |
117
118
 
118
119
  ### 会话命令
119
120
 
120
121
  ```
121
122
  /rules 列出当前生效规则、来源文件与最近一次重载错误
123
+ /rules list 裸列出的显式别名
122
124
  /rules reload 重读本工作区的规则文件链
123
125
  /rules decisions [n] 显示本会话最近 n 条权限裁决(默认 10)
124
126
  /rules test <工具> <json> 对假设调用干跑评估,如 /rules test bash {"command":"git push origin main"}
125
127
  ```
126
128
 
127
- `/rules test` 还支持前置标志:`--cwd <目录>` 换一个工作区评估,`--env 键=值`(可重复)覆盖宿主环境变量以测试 `when.env`,`--agent <选择器>`(可重复)为 `agents` 维度提供身份候选。
129
+ `/rules test` 还支持前置标志:`--cwd <目录>` 换一个工作区评估,`--env 键=值`(可重复)覆盖宿主环境变量以测试 `when.env`,`--agent <选择器>`(可重复)为 `agents` 维度提供身份候选,`--platform <平台名>` 覆盖宿主平台以测试 `when.platform`。多文件链(如 `searchUp`)下,每条规则行都会标注它自己的来源文件。
128
130
 
129
131
  命令输出只进 UI——模型只通过规则产生的工具结果感知规则。`language` 选择输出语言。规则文件的 JSON Schema 随包发布在 [docs/rules-format.schema.json](docs/rules-format.schema.json)(用 `# yaml-language-server: $schema=...` 启用编辑器补全)。
130
132
 
@@ -150,7 +152,7 @@ dsh --profile web --dump-config | grep -A4 'id: permission-rules' # 验证挂
150
152
 
151
153
  ## 已知局限
152
154
 
153
- - `permissionRules/decision` 以信封 `ignorable: true` 标记写入,任何 harness 构建都能加载日志——不认识该仓库外类型的第一方读取器会跳过这条审计记录而不是拒绝整个会话。(rc.6 宿主会接受并忽略该标记,行为与打标前完全一致;rc.6 宿主写出的日志没有该标记,在 required-on-read 语义的宿主上加载前可能需要 `scripts/repair-session-logs.mjs`。)
155
+ - `permissionRules/decision` 以信封 `ignorable: true` 标记写入,任何 harness 构建都能加载日志——不认识该仓库外类型的第一方读取器会跳过这条审计记录而不是拒绝整个会话。早于该标记的宿主(`0.1.0-rc.6` 系列)会静默丢弃它:插件在运行时探测(peer 版本预检 + 已写事件信封探针),探测到即停用会话日志审计并一次性警告,确保会话日志在任何构建上都能加载。设 `allowUnmarkedAudit: true` 重新开启会话内轨迹;已写出且缺标记的日志可在 required-on-read 语义的宿主上加载前用 `scripts/repair-session-logs.mjs` 修复。
154
156
  - `paths` 候选是启发式的:只有文档化的参数键进入路径匹配;工作区相对匹配仅在 `caseInsensitivePaths` 开启时忽略 ASCII 大小写。
155
157
  - glob 是保守子集(不支持花括号展开)——写两条模式,或用 regex 模式。
156
158
  - regex 回溯守卫是结构性的而非穷尽的:不含字面量前缀的交替歧义(如精心构造的环视)由作者自负其责;不可信文件请优先用 glob 模式。
@@ -172,7 +174,7 @@ node scripts/repair-session-logs.mjs repair [--home DIR] [--dry-run]
172
174
  pnpm install # node ^22.19 || >=24
173
175
  pnpm run typecheck # tsc,src + tests
174
176
  pnpm run lint # eslint,src + tests + scripts
175
- pnpm test # vitest:106 测试 / 8 套件
177
+ pnpm test # vitest:139 测试 / 9 套件
176
178
  pnpm run test:coverage # 覆盖率门禁(90/80/90/90)
177
179
  pnpm run build # tsc 声明 + tsdown 打包(lib/)
178
180
  pnpm run pack:check # 构建 + pack(发布产物)
@@ -181,6 +183,10 @@ node scripts/check-readme-sync.mjs # 五语 README 同步门禁(CI 同步执
181
183
 
182
184
  headless 端到端验证记录(deny 阻止 shell 工具、ask 走审批 seam、`--dump-config`)见 [VERIFICATION.md](VERIFICATION.md)。
183
185
 
186
+ ## 致谢
187
+
188
+ - 感谢 [@22xuan](https://github.com/22xuan) 关于 rc.6 宿主静默丢弃审计事件 `ignorable` 标记的详尽报告([#2](https://github.com/PerryLink/dsh-permission-rules/issues/2))以及其向上游 harness 提交的讨论——运行时宿主能力探测与文档修正均直接源自该分析。
189
+
184
190
  ## License
185
191
 
186
192
  [Apache License 2.0](LICENSE) © 2026 dsh-permission-rules contributors
package/cordis.patch.yml CHANGED
@@ -14,3 +14,6 @@
14
14
  maxRules: 256
15
15
  patternMode: glob
16
16
  watch: true
17
+ # allowUnmarkedAudit: false # hosts that predate the ignorable marker
18
+ # # degrade to audit-off by default (safe);
19
+ # # set true to keep the in-session trail
@@ -100,9 +100,11 @@ This plugin only produces `ask` decisions; the `ask` goes to the official `ctx.a
100
100
 
101
101
  ## Loading and hot reload
102
102
 
103
- - Lazily discovered per session cwd and cached on the first `tools/pre-execute` (least-recently-used eviction beyond `maxCachedWorkspaces`).
103
+ - Lazily discovered per session cwd and cached on the first `tools/pre-execute` (least-recently-used eviction beyond `maxCachedWorkspaces`); the cache key is the resolved cwd (case-folded on Windows), so differently-spelled paths share one entry.
104
104
  - Invalid YAML, unknown fields/actions, bad globs/regexes, backtracking-prone patterns, and counts over `maxRules` are load-time errors: `badFilePolicy: fail` (default) makes the first tool call in that workspace fail loudly; `ignore-with-warning` warns and degrades to an empty rule set.
105
105
  - An absolute `rulesFile` or a configured `fallbackPath` is validated at plugin mount — missing or invalid fails the mount.
106
106
  - File changes reload through Chokidar with a debounce (`watch`, `watchStabilityThresholdMs`); a failed reload keeps the previous rules and only warns — never crashes. `/rules reload` triggers the same path manually; `/rules decisions` and `/rules test` inspect the trail and dry-run the rules.
107
- - `/rules test` accepts leading flags: `--cwd <dir>` evaluates against another workspace (rule discovery AND path normalization), `--env KEY=VALUE` (repeatable) overrides host env for `when.env`, and `--agent <selector>` (repeatable) supplies identity candidates for the `agents` dimension.
107
+ - Expected-but-absent rule files (the project file when it is not in effect, a fallback after it was deleted) are watched through their deepest existing ancestor directory: creating one mid-session is adopted automatically without a manual reload. Under `searchUp` only the immediate cwd-level candidate is watched — creating a rule file in a deeper ancestor still needs `/rules reload`.
108
+ - `/rules` lists the active rules (with `list` as an explicit alias); in multi-file chains every rule line is attributed to its own source file.
109
+ - `/rules test` accepts leading flags: `--cwd <dir>` evaluates against another workspace (rule discovery AND path normalization), `--env KEY=VALUE` (repeatable) overrides host env for `when.env`, `--agent <selector>` (repeatable) supplies identity candidates for the `agents` dimension, and `--platform <name>` overrides the host platform for `when.platform`.
108
110
  - `enforce: false` puts the plugin in dry-run mode: deny/ask hits are audit-logged with a `dryRun` marker (keeping the would-be action and the real downstream outcome) and every call passes through — use it to trial a new policy in production before enforcing it. `/rules` prints a dry-run notice while the mode is active.
@@ -98,9 +98,11 @@ rules:
98
98
 
99
99
  ## 加载与热更新
100
100
 
101
- - 按会话 cwd 惰性发现,首次 `tools/pre-execute` 时加载并缓存(超出 `maxCachedWorkspaces` 逐出最久未用项)。
101
+ - 按会话 cwd 惰性发现,首次 `tools/pre-execute` 时加载并缓存(超出 `maxCachedWorkspaces` 逐出最久未用项);缓存键为解析后的 cwd(Windows 上折叠大小写),同一目录的不同拼写共享同一条目。
102
102
  - 非法 YAML / 未知字段或 action / 坏 glob 与正则 / 易回溯灾难的模式 / 超 `maxRules` 都是加载期错误:`badFilePolicy: fail`(默认)时首个使用该工作区的工具调用响亮失败;`ignore-with-warning` 时告警并降级为空规则集。
103
103
  - 绝对 `rulesFile` 或配置的 `fallbackPath` 在插件挂载时即校验,缺失/非法直接挂载失败。
104
104
  - 文件变更后经 Chokidar 去抖重读(`watch`、`watchStabilityThresholdMs`);重读失败保留旧规则、只告警,绝不崩溃。`/rules reload` 手动触发同样路径;`/rules decisions` 回放审计轨迹,`/rules test` 对假设调用干跑规则。
105
- - `/rules test` 支持前置标志:`--cwd <目录>` 换一个工作区求值(规则发现与路径归一化都切换);`--env 键=值`(可重复)覆盖宿主环境变量以测试 `when.env`;`--agent <选择器>`(可重复)为 `agents` 维度提供身份候选。
105
+ - 预期存在但缺失的规则文件(未生效的项目文件、被删除后的 fallback)会通过其最近存在祖先目录被监听:会话中途创建即自动采纳,无需手动重载。`searchUp` 下只监听 cwd 层级的候选——更上层祖先新建规则文件仍需 `/rules reload`。
106
+ - `/rules` 列出当前规则(`list` 为显式别名);多文件链中每条规则行标注自己的来源文件。
107
+ - `/rules test` 支持前置标志:`--cwd <目录>` 换一个工作区求值(规则发现与路径归一化都切换);`--env 键=值`(可重复)覆盖宿主环境变量以测试 `when.env`;`--agent <选择器>`(可重复)为 `agents` 维度提供身份候选;`--platform <平台名>` 覆盖宿主平台以测试 `when.platform`。
106
108
  - `enforce: false` 让插件进入干跑模式:deny/ask 命中只写审计(带 `dryRun` 标记,记录「本会做什么」与下游真实结果),所有调用照常透传——用于在生产环境先试跑新策略再强制执行。激活期间 `/rules` 会打印干跑提示。