dsh-auto-review 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.es.md +182 -162
  3. package/README.hi.md +182 -162
  4. package/README.md +134 -136
  5. package/README.pt.md +182 -162
  6. package/README.zh.md +175 -177
  7. package/bin/dsh-eval.mjs +0 -0
  8. package/lib/client.js +2 -1
  9. package/lib/client.js.map +1 -1
  10. package/lib/eval-cli.js +5 -2
  11. package/lib/{events-CFl6CHZi.js → events-CLaRirOo.js} +45 -1
  12. package/lib/index.js +334 -70
  13. package/lib/invariant.js +1 -1
  14. package/lib/types/audit.d.ts +48 -0
  15. package/lib/types/audit.d.ts.map +1 -0
  16. package/lib/types/audit.js +62 -0
  17. package/lib/types/audit.js.map +1 -0
  18. package/lib/types/client/ReviewPanel.d.ts +1 -1
  19. package/lib/types/client/index.d.ts +4 -4
  20. package/lib/types/client/index.d.ts.map +1 -1
  21. package/lib/types/client/index.js +2 -1
  22. package/lib/types/client/index.js.map +1 -1
  23. package/lib/types/client/present.d.ts +1 -1
  24. package/lib/types/config.d.ts +10 -1
  25. package/lib/types/config.d.ts.map +1 -1
  26. package/lib/types/config.js +5 -0
  27. package/lib/types/config.js.map +1 -1
  28. package/lib/types/eval/assert.d.ts +2 -2
  29. package/lib/types/eval/index.d.ts +6 -6
  30. package/lib/types/eval/report.d.ts +1 -1
  31. package/lib/types/eval/review.d.ts +2 -2
  32. package/lib/types/eval/runner.d.ts +5 -5
  33. package/lib/types/events.d.ts +37 -1
  34. package/lib/types/events.d.ts.map +1 -1
  35. package/lib/types/events.js +44 -0
  36. package/lib/types/events.js.map +1 -1
  37. package/lib/types/index.d.ts +8 -8
  38. package/lib/types/messages.d.ts +1 -0
  39. package/lib/types/messages.d.ts.map +1 -1
  40. package/lib/types/messages.js +5 -0
  41. package/lib/types/messages.js.map +1 -1
  42. package/lib/types/projection.d.ts +1 -1
  43. package/lib/types/review.d.ts +3 -3
  44. package/lib/types/runtime.d.ts +44 -3
  45. package/lib/types/runtime.d.ts.map +1 -1
  46. package/lib/types/runtime.js +311 -71
  47. package/lib/types/runtime.js.map +1 -1
  48. package/package.json +57 -48
  49. package/src/audit.ts +66 -0
  50. package/src/client/index.ts +21 -1
  51. package/src/config.ts +14 -0
  52. package/src/events.ts +48 -0
  53. package/src/messages.ts +6 -0
  54. package/src/runtime.ts +377 -70
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to `dsh-auto-review` are documented here. The repo is pre-release; versions follow the DeepSeek Harness `0.1.0-rc.x` target runtime and bump on every behavior change.
4
4
 
5
+ ## [0.5.2] — 2026-08-19
6
+
7
+ ### Fixed
8
+
9
+ - The circuit breaker's deferred abort-turn `setTimeout(…, 0)` is now tracked by the runtime and cleared through a teardown effect when the plugin fiber unloads — an unload inside the macro-task window can no longer fire a stale `agent.cancel` against a disposed composition.
10
+
11
+ ## [0.5.1] — 2026-08-17
12
+
13
+ ### Fixed
14
+
15
+ - **rc session-corruption fix (the #918 report).** On hosts whose `Session.append` predates the `ignorable` envelope-marker surface (every released rc line through `0.1.0-rc.7` silently drops the options bag — the stamping fix exists on harness master only), `autoReview/*` audit events used to land in the session log WITHOUT the marker — stricter hosts then refused to resume those sessions (`SessionFormatUnsupportedError`). The runtime now detects such hosts BEFORE polluting a log (installed-peer pre-check, then a probe of the first appended envelope's return value), disables session-log audit with a one-time warning, and degrades to an in-memory audit mirror: marker-free deny/fallback/circuit feedback, in-memory budgets, circuit breaker, `/auto-review on|off` override and `approve` feed. Marker-aware hosts (a future release that stamps the marker, or any unresolvable version that probes clean) keep the full event-based audit unchanged. `allowUnmarkedAudit: true` opts back into the old behavior on unmarked hosts (deliberately dangerous), and already-polluted logs can be repaired with `scripts/repair-session-logs.mjs` from `dsh-permission-rules` (its default target set now covers `autoReview/state`, `autoReview/verdict`, `autoReview/circuit`, `autoReview/override`, `autoReview/rejection`).
16
+ - `/auto-review status` reports the disabled-audit notice on unmarked hosts.
17
+ - The browser half pins the api-remotes `commands` Remote namespace shape locally (the ambient namespace merge is fragile across strict package-manager copies on rc.7).
18
+
19
+ ### Changed
20
+
21
+ - Peers and dev/test pins bumped `0.1.0-rc.6` → `0.1.0-rc.7` (npm `latest` moved); the full gate passes against the rc.7 peers, and `dshWorkshop.dshVersions` now lists both.
22
+
23
+ ### Added
24
+
25
+ - New `src/audit.ts` host-capability module (`isMarkedAuditEvent`, `isUnmarkedHostVersion`, `peerSessionVersion`) shared by every audit path; unit-tested in `test/audit.spec.ts`, and the full degraded path is covered by `test/audit-degradation.spec.ts` (unmarked-host default safety, in-memory breaker/override/approve, the unversioned-host probe).
26
+
5
27
  ## [0.5.0] — 2026-08-16
6
28
 
7
29
  ### Added
package/README.es.md CHANGED
@@ -1,144 +1,104 @@
1
- <!-- enlaces de idioma -->
2
- [English](README.md) · [中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
3
-
4
1
  <div align="center">
5
2
 
6
3
  # 🤖 dsh-auto-review
7
4
 
8
- **Aprobación automática por segundo modelo para DeepSeek Harness** — el patrón `approvals_reviewer=auto_review` de Codex / *auto mode* de Claude Code, implementado como un plugin puro de Cordis.
5
+ **Aprobación con IA de segundo modelo para DeepSeek Harness: un subagente revisor de solo lectura decide permitir/denegar en la cadena de aprobación, con cierre en fallo por defecto.**
9
6
 
10
- Cuando una acción del agente cruza el límite del sandbox, un **subagente revisor de solo lectura** decide allow/deny — con un motivo — para que los humanos no aprueben nada mientras nada inseguro se cuela.
7
+ *Cuando una acción cruza el límite del sandbox, un segundo modelo lee la evidencia y devuelve un veredicto con su razón — para que los humanos no aprueben nada y nada inseguro se cuele.*
11
8
 
12
- [![license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
13
- [![dsh](https://img.shields.io/badge/dsh-0.1.0--rc.6-4c51bf.svg)](https://www.npmjs.com/package/@deepseek-ai/dsh)
9
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
+ [![DSH plugin](https://img.shields.io/badge/dsh-plugin-✅-green)](https://github.com/topics/dsh-plugin)
11
+ [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
12
+ [![CI](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-auto-review/ci.yml?branch=main&label=CI)](https://github.com/PerryLink/dsh-auto-review/actions)
13
+ [![Version](https://img.shields.io/github/v/tag/PerryLink/dsh-auto-review?label=version)](https://github.com/PerryLink/dsh-auto-review/releases)
14
14
  [![npm version](https://img.shields.io/npm/v/dsh-auto-review)](https://www.npmjs.com/package/dsh-auto-review)
15
15
  [![npm downloads](https://img.shields.io/npm/dm/dsh-auto-review)](https://www.npmjs.com/package/dsh-auto-review)
16
- [![tests](https://img.shields.io/github/actions/workflow/status/PerryLink/dsh-auto-review/ci.yml?label=tests&logo=githubactions)](.github/workflows/ci.yml)
17
- [![typescript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg)](src)
18
- [![type](https://img.shields.io/badge/type-cordis%20bundle-8a5cf6.svg)](cordis.patch.yml)
19
- [![repo](https://img.shields.io/badge/repo-PerryLink%2Fdsh--auto--review-181717.svg)](https://github.com/PerryLink/dsh-auto-review)
20
-
21
- **Cero operaciones humanas.** La petición va al revisor de IA, el veredicto es allow/deny + motivo + nivel de riesgo, y cada decisión se puede reconstruir desde el registro de sesión: `approval/asked` → `autoReview/verdict` (o `autoReview/rejection` para desactivaciones duras) → `approval/decided`.
22
16
 
23
- <img src="docs/demo-auto-review.gif" alt="demo de dsh-auto-review" width="720"/>
24
-
25
- *Una ejecución real de evidencia (servidor real, clave de API real, dos rondas de modelo reales): el revisor de IA **permite** una escritura con escalado dentro del workspace (riesgo bajo, 5,2 s) y luego **deniega** un borrado recursivo fuera del workspace (riesgo alto, 8,9 s) — el motivo de la denegación se devuelve al modelo, visible en la transcripción.*
17
+ [English](README.md) · [简体中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
26
18
 
27
19
  </div>
28
20
 
29
- ## ¿Por qué un segundo modelo en lugar de reglas?
21
+ ---
30
22
 
31
- Los auto-aprobadores basados en patrones deciden antes del despacho, sin evidencia. `dsh-auto-review` entrega la decisión a un **subagente revisor** que lee el workspace real (con su cara de herramientas de solo lectura), los argumentos de la llamada ya presentados (valores sensibles redactados), el motivo de la petición y tus reglas de riesgo — y devuelve un veredicto estructurado. Un veredicto de denegación devuelve su **motivo al modelo que llama**, para que el agente aprenda el porqué en lugar de reintentar a ciegas.
23
+ ## Compatibilidad
32
24
 
33
- ## ✨ Características
34
-
35
- | | |
25
+ | Superficie | Estado |
36
26
  |---|---|
37
- | 🔌 **Seam oficial** | Un answerer en el waterfall `approval/request`. Las peticiones que no le pertenecen se delegan con `next()` — el flujo de aprobación humana nunca se corta. |
38
- | 🧠 **Veredicto de segundo modelo** | Subagente fork de un solo uso con lista blanca de herramientas de solo lectura (`read`/`glob`/`grep`) y esquema de veredicto estructurado `{ decision, reason, riskLevel }`. |
39
- | 🛡️ **Fail closed** | Un fallo, timeout o esquema inválido del revisor nunca abre la puerta: se aplica `fallbackPolicy`, por defecto `rejected`. |
40
- | 🧩 **Enrutado por configuración** | Políticas por herramienta (`ai`/`human`/`never`) + reglas de riesgo con regex, todo cambiable desde cordis.yml. |
41
- | 💬 **Los motivos de denegación llegan al modelo** | El motivo del revisor se inyecta en el resultado de la herramienta denegada (vinculado por callId), para que el agente se adapte. Las denegaciones del fallback fail-closed y las desactivaciones duras de la política `never` también inyectan textos auditables (marcadores `[auto-review]` / `[auto-review-fallback]` / `[auto-review-never]`). |
42
- | 📜 **Auditoría completa** | Eventos de sesión `autoReview/verdict` + `autoReview/rejection` (identidad del revisor, veredicto, motivo, riesgo, duración) + un companion de invariantes que exige *model-visible ⟺ logged*. |
43
- | 🔁 **Sin recursión** | Las peticiones del propio revisor se reconocen por identidad y se delegan; `maxDepth` + la lista blanca mantienen al revisor sin delegar. |
44
- | 🧯 **Disyuntor de rechazos** | 3 denegaciones consecutivas (o 6 dentro de los últimos 10 veredictos) en un turno disparan el disyuntor: las peticiones posteriores delegan, rechazan o abortan el turno — sin bucles de denegación interminables. |
45
- | 🎚️ **Política por nivel de riesgo** | Un veredicto `allow` cuyo riesgo supera `riskPolicy.maxAutoAllow` nunca resuelve la petición: la delega a un humano o la deniega. |
46
- | ✋ **Anulación humana de un solo uso** | `/auto-review approve [n]` autoriza UN reintento de una denegación reciente; la siguiente revisión de la misma herramienta lleva esa autorización como contexto del revisor (el revisor sigue decidiendo). |
47
- | 📜 **Contexto del revisor** | Transcripción compacta opcional (mensajes recientes y resultados de herramientas, acotada) + una política de decisión `reviewerPolicyText` en Markdown estilo Codex. |
48
- | ⌨️ **Comando de sesión** | `/auto-review on|off|status|approve [n]` con una anulación duradera por sesión que sobrevive a la restauración y estadísticas acumuladas de sesión. |
49
- | 🖥️ **Panel de revisión web** | Un panel en la cabecera de sesión (GUI web) muestra el interruptor (con botones de encendido/apagado), ambos presupuestos por turno, estadísticas acumuladas, el disparo del disyuntor, veredictos recientes y botones de aprobación de un solo uso — impulsado por la proyección de sesión `autoReview`. |
27
+ | Harness | DeepSeek Harness `0.1.0-rc.7` (peers fijados a `0.1.0-rc.7`) |
28
+ | Node | `^22.19.0 \|\| >=24.0.0` |
29
+ | Plataformas | Todas (answerer de host; panel web opcional mediante la capacidad de proyección de sesión) |
30
+ | Modelo | Cualquiera (el revisor hereda la ruta del agente de sesión; `reviewerModel` la reemplaza) |
50
31
 
51
- ## Cómo funciona
32
+ ## Qué obtienes
52
33
 
53
- ```text
54
- waterfall approval/request (cadena de answerers)
55
- │
56
- ┌───────────────────────┴──────────────────────┐
57
- │ answerer dsh-auto-review │
58
- │ · ¿sesión activada? · ¿política = ai? │ no ── next() ──▶ answerer humano (UI)
59
- │ · reglas de riesgo → toolsPolicy → defecto │
60
- └───────────────────────┬──────────────────────┘
61
- │ sí
62
- ▼
63
- ┌───────────────────────────────────┐
64
- │ subagente revisor (fork, un uso) │
65
- │ · toolFilter: read/glob/grep │
66
- │ · outputSchema: {decision, │
67
- │ reason, riskLevel} │
68
- │ · timeout + abort de req.signal │
69
- └───────────────┬───────────────────┘
70
- │ veredicto / fallo (fallback fail-closed)
71
- ▼
72
- allow → allowed-once deny → rejected + motivo inyectado en el
73
- resultado de la herramienta denegada
74
- │ never → rejected + feedback [auto-review-never]
75
- │ (desactivación dura, sin revisor)
76
- ▼
77
- auditoría: approval/asked → autoReview/verdict | autoReview/rejection
78
- → approval/decided (eventos de sesión, log-only, verificados por invariantes)
79
- ```
80
-
81
- **Orden de composición.** El contestador se ejecuta en su posición de registro dentro del waterfall: si un contestador humano de la UI está compuesto ANTES de la fila `auto-review`, los humanos responden primero y el revisor solo ve lo que se delega aguas abajo. Verifícalo con `dsh --profile <name> --dump-config` y coloca la fila `auto-review` antes de tus filas de contestadores humanos si quieres que las herramientas con política ai se enruten primero al revisor.
34
+ `dsh-auto-review` pone un segundo modelo en la cadena de answerers de `approval/request`:
82
35
 
83
- ## 🚀 Inicio rápido
36
+ 1. **Costura oficial** — un answerer que solo reclama las solicitudes que le pertenecen (política `ai`) y delega todo lo demás con `next()`; el flujo de aprobación humana nunca se cortocircuita.
37
+ 2. **Subagente revisor de solo lectura** — un fork de un solo uso con una lista blanca de herramientas `read`/`glob`/`grep` devuelve un veredicto estructurado `{ decision, reason, riskLevel }`. Las solicitudes del revisor se reconocen por identidad y se delegan; `maxDepth` + la lista blanca mantienen al revisor sin delegar.
38
+ 3. **Cierre en fallo** — un fallo, un timeout o un desajuste de esquema del revisor se resuelve con `fallbackPolicy` (por defecto `rejected`); un veredicto de denegación devuelve su razón al modelo que llama.
39
+ 4. **Enrutamiento por configuración** — políticas por herramienta (`ai`/`human`/`never`) más reglas de riesgo con regex, todo modificable desde cordis.yml.
40
+ 5. **Las razones de denegación llegan al modelo** — la razón del revisor se inyecta en el resultado de la herramienta denegada (vinculada por callId); los rechazos por fallback y por política `never` también inyectan marcadores auditables (`[auto-review]` / `[auto-review-fallback]` / `[auto-review-never]`).
41
+ 6. **Rastro de auditoría completo** — eventos de sesión solo-registro `autoReview/verdict` + `autoReview/rejection` (sobre `ignorable: true`) más un compañero invariant opcional que impone marcador ⟺ evento.
42
+ 7. **Controles de seguridad** — un disyuntor de rechazos (3 denegaciones consecutivas, o 6 de los últimos 10 veredictos, por turno), una política por nivel de riesgo, una anulación de un solo uso `/auto-review approve`, y una desactivación dura de política `never` que se explica a sí misma al modelo.
43
+ 8. **Contexto opcional del revisor** — una transcripción compacta acotada (`contextBudget`) más una política de decisión en Markdown estilo Codex (`reviewerPolicyText`).
84
44
 
85
- Cuatro canales de instalación; el plugin es un **bundle** (`"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`).
45
+ Cada decisión se reconstruye desde el registro de sesión: `approval/asked` → `autoReview/verdict` (o `autoReview/rejection`) → `approval/decided`.
86
46
 
87
- ```sh
88
- # 1. npm (artefacto publicado, sin paso de build)
89
- dsh plugin --profile web add dsh-auto-review
90
- dsh --profile web # reiniciar
47
+ ## ¿Por qué un segundo modelo en lugar de reglas?
91
48
 
92
- # 2. tarball de npm (artefactos compilados, instalación offline)
93
- pnpm pack # → dsh-auto-review-<version>.tgz
94
- dsh plugin --profile web add ./dsh-auto-review-<version>.tgz
95
- dsh --profile web # reiniciar
49
+ Los auto-aprobadores basados en patrones deciden antes del despacho, sin evidencia. `dsh-auto-review` entrega la decisión a un **subagente revisor** que lee el espacio de trabajo real (a través de su interfaz de herramientas de solo lectura), los argumentos de la llamada a herramienta ya transmitidos (valores sensibles redactados), la razón de la solicitud y tus reglas de riesgo — y devuelve un veredicto estructurado. Un veredicto de denegación devuelve su **razón al modelo que llama**, de modo que el agente aprende por qué en lugar de reintentar a ciegas.
96
50
 
97
- # 3. fuente git (fija el commit; el `prepare` autocontenido lo compila)
98
- # pnpm ≥ 10 bloquea los builds de ciclo de vida: añade primero la clave
99
- # allowBuilds impresa al pnpm-workspace.yaml del perfil.
100
- dsh plugin --profile web add "github:PerryLink/dsh-auto-review#<commit>"
51
+ ## Inicio rápido
101
52
 
102
- # 4. enlace local (desarrollo)
103
- dsh plugin --profile web add link:/path/to/dsh-auto-review
104
- ```
53
+ ```sh
54
+ # 1. instala el bundle en tu perfil
55
+ dsh plugin --profile web add "github:PerryLink/dsh-auto-review#main"
105
56
 
106
- Verifica:
57
+ # o desde npm (versiones publicadas)
58
+ dsh plugin --profile web add dsh-auto-review
107
59
 
108
- ```sh
60
+ # 2. reinicia y verifica la fila
109
61
  dsh --profile web --dump-config | grep -A4 'id: auto-review'
110
62
  ```
111
63
 
112
- De serie, el patch enviado somete `bash` y `write` a revisión de IA; el resto de herramientas (incluido `edit` — modificación in situ) se delega a la cadena humana. Añade `edit: ai` explícitamente si aceptas ediciones in situ sin un humano en el bucle.
64
+ De fábrica, el parche incluido revisa con IA `bash` y `write`; todas las demás herramientas (incluido `edit` — modificación in situ) delegan a la cadena humana. Añade `edit: ai` explícitamente si aceptas ediciones in situ sin un humano en el bucle.
113
65
 
114
- ## ⚙️ Configuración
66
+ ## Instalación y desinstalación
115
67
 
116
- Todos los parámetros son campos `Config` de Schemastery (cambiables desde cordis.yml). Una anulación dirigida por `id` **reemplaza toda la fila de config** — repite toda clave que necesites.
68
+ - **Canal git** (último `main`): `dsh plugin --profile web add "github:PerryLink/dsh-auto-review#main"` — la compilación aislada de `prepare` necesita la única clave `allowBuilds: { esbuild: true }` que imprime el CLI de `dsh` para `dsh-auto-review`.
69
+ - **Canal npm** (versiones publicadas): `dsh plugin --profile web add dsh-auto-review`.
70
+ - **Canal tarball**: `pnpm pack` en este repo y luego `dsh plugin --profile web add ./dsh-auto-review-<version>.tgz`.
71
+ - **Desinstalación**: `dsh plugin --profile web remove dsh-auto-review` (o elimina la fila del parche de perfil).
117
72
 
118
- | Clave | Defecto | Significado |
73
+ ## Configuración
74
+
75
+ Todas las opciones son campos Schemastery `Config` (modificables desde cordis.yml). Una anulación dirigida por id reemplaza toda la fila — repite cada clave que necesites.
76
+
77
+ | Clave | Por defecto | Significado |
119
78
  |---|---|---|
120
- | `enableByDefault` | `true` | Las sesiones arrancan con auto-review activado; `/auto-review on\|off` escribe una anulación duradera con prioridad |
121
- | `toolsPolicy.default` | `human` | Política para herramientas no listadas (delegar al answerer humano) |
122
- | `toolsPolicy.overrides` | `{}` | Política por herramienta: `ai` (decide el revisor), `human` (forzar humano), `never` (rechazo determinista) |
123
- | `riskRules` | `[]` | `{pattern, policy, field?}` emparejado (gana la primera coincidencia) antes de la tabla de herramientas; `field` selecciona `reason` (por defecto), `toolName` o `arguments` (los argumentos de llamada presentados redactados) |
124
- | `reviewerProvider` | `fork` | Provider de subagente para el revisor (backend fork en proceso) |
125
- | `reviewerModel` | *(heredar)* | Id del modelo del revisor; sin valor hereda la ruta del agente de sesión |
79
+ | `enableByDefault` | `true` | Las sesiones arrancan con auto-review activo; `/auto-review on\|off` escribe una anulación duradera que gana a esto |
80
+ | `toolsPolicy.default` | `human` | Política para herramientas no listadas (delega al answerer humano) |
81
+ | `toolsPolicy.overrides` | `{}` | Política por herramienta: `ai` / `human` / `never` |
82
+ | `riskRules` | `[]` | `{pattern, policy, field?}` emparejado antes de la tabla de herramientas; `field` elige `reason` (por defecto), `toolName` o `arguments` |
83
+ | `reviewerProvider` | `fork` | Proveedor de subagente para el revisor (backend fork en proceso) |
84
+ | `reviewerModel` | *(heredado)* | Id del modelo revisor; si no se define, hereda la ruta del agente de sesión |
126
85
  | `reviewerTimeoutMs` | `60000` | Plazo del veredicto; al vencer se aplica la política de fallback |
127
- | `reviewerTools` | `[read, glob, grep]` | Lista blanca de herramientas del hijo revisor (no debe estar vacía) — todo lo demás es invisible allí |
128
- | `fallbackPolicy` | `rejected` | Ante fallo del revisor: `rejected` (fail closed), `delegate` (continúa la cadena), `allow-once` (concede — ver Seguridad). Renombrado desde `allow-readonly` en 0.2.0; la grafía antigua falla en voz alta |
129
- | `maxReviewsPerTurn` | `10` | Presupuesto real de veredictos de IA por turno abierto; agotado, se delega a humanos |
130
- | `maxFailuresPerTurn` | `10` | Presupuesto de fallos del revisor por turno abierto (timeout/no disponible/schema, no cancelaciones); agotado, las peticiones se delegan en lugar de pagar otro timeout completo. Por defecto, `maxReviewsPerTurn` |
131
- | `reasonMaxChars` | `2000` | Tope para los motivos del revisor, el motivo de la petición y la vista previa de argumentos redactada |
132
- | `reviewerGuidance` | *(ninguna)* | Guía opcional añadida al prompt del revisor (consultiva, no regla dura) |
133
- | `reviewerPolicyText` | *(ninguna)* | Política de decisión en Markdown inyectada en el prompt del revisor (estilo Codex; plantilla en `fixtures/config/policy-template.md`) |
134
- | `denyGuidance` | *(texto anti-elusión)* | Guía añadida a cada motivo de denegación inyectado |
86
+ | `reviewerTools` | `[read, glob, grep]` | Lista blanca de herramientas del hijo revisor (debe ser no vacía) |
87
+ | `fallbackPolicy` | `rejected` | Ante fallo del revisor: `rejected` (cierre en fallo) / `delegate` / `allow-once` |
88
+ | `maxReviewsPerTurn` | `10` | Presupuesto de veredictos de IA reales por turno abierto; superado, las solicitudes delegan |
89
+ | `maxFailuresPerTurn` | `10` | Presupuesto de fallos del revisor por turno abierto |
90
+ | `reasonMaxChars` | `2000` | Límite para las razones del revisor y la vista previa de argumentos redactados |
91
+ | `reviewerGuidance` | *(ninguna)* | Orientación opcional añadida al prompt del revisor |
92
+ | `reviewerPolicyText` | *(ninguna)* | Política de decisión en Markdown inyectada en el prompt del revisor (estilo Codex) |
93
+ | `denyGuidance` | *(texto anti-elusión)* | Orientación añadida a cada razón de denegación inyectada |
135
94
  | `contextBudget` | `{turns: 0, maxChars: 4000}` | Presupuesto de transcripción compacta para el prompt del revisor; `turns: 0` lo desactiva |
136
- | `riskPolicy` | `{maxAutoAllow: high, onHighRisk: delegate}` | Los veredictos `allow` por encima de `maxAutoAllow` delegan (`delegate`) o deniegan (`deny`) |
137
- | `circuitBreaker` | `{consecutiveDenies: 3, windowDenies: 6, windowSize: 10, action: delegate}` | Disyuntor de rechazos; se dispara con 3 denegaciones consecutivas o 6 de los últimos 10 veredictos del turno; `action`: `delegate` / `reject` / `abort-turn` |
138
- | `overrideTtlMs` | `300000` | Cuánto tiempo una anulación `/auto-review approve` sigue siendo utilizable |
139
- | `language` | `en` | Idioma de la interfaz de la salida del comando `/auto-review` (`en` \| `zh`) |
95
+ | `riskPolicy` | `{maxAutoAllow: high, onHighRisk: delegate}` | Los veredictos `allow` por encima de `maxAutoAllow` delegan o deniegan |
96
+ | `circuitBreaker` | `{consecutiveDenies: 3, windowDenies: 6, windowSize: 10, action: delegate}` | Disyuntor de rechazos |
97
+ | `overrideTtlMs` | `300000` | Cuánto dura una anulación de `/auto-review approve` |
98
+ | `language` | `en` | Idioma de la UI de la salida del comando `/auto-review` (`en` \| `zh`) |
99
+ | `allowUnmarkedAudit` | `false` | Fuerza la auditoría del registro de sesión en hosts que descartan el marcador `ignorable` (peligroso: los eventos sin marcar hacen las sesiones irrecuperables en otros hosts); por defecto se detecta y se degrada |
140
100
 
141
- Ejemplo (forma completa comentada: `fixtures/config/config-full.yaml`):
101
+ Ejemplo (forma completa anotada: `fixtures/config/config-full.yaml`):
142
102
 
143
103
  ```yaml
144
104
  - insert:
@@ -159,32 +119,76 @@ Ejemplo (forma completa comentada: `fixtures/config/config-full.yaml`):
159
119
  circuitBreaker: { consecutiveDenies: 3, windowDenies: 6, windowSize: 10, action: delegate }
160
120
  ```
161
121
 
162
- ## ⌨️ Comando de sesión
122
+ ## Herramientas y superficies
123
+
124
+ | Superficie | Tipo | Notas |
125
+ |---|---|---|
126
+ | `auto-review` | answerer | Answerer de la cascada `approval/request` — reclama solicitudes de política `ai`, delega el resto con `next()` |
127
+ | `/auto-review` | comando | `on\|off\|status\|approve [n]` — anulación durable por sesión, presupuestos y estadísticas acumuladas |
128
+ | Inyección de razón de denegación | listener | `tools/post-execute` — razones de veredicto / fallback / `never` devueltas al resultado de la herramienta denegada |
129
+ | `autoReview` | proyección de sesión | Plegada desde los eventos solo-registro `autoReview/*` |
130
+ | Panel web de revisión | cliente | Acción en la cabecera de sesión: interruptor, presupuestos, estadísticas, veredictos recientes, aprobación de un solo uso |
131
+ | `dsh-eval` | CLI | Motor de evaluación de agentes basado en YAML (`bin/dsh-eval.mjs`) |
132
+ | Compañero invariant | invariant | `dsh-auto-review/invariant` (opcional; necesita el servicio `invariants`) |
133
+
134
+ ## Comando de sesión
163
135
 
164
136
  ```
165
137
  /auto-review on|off|status|approve [n]
166
138
  ```
167
139
 
168
- `on`/`off` añaden la anulación duradera `autoReview/state` (el fold sobrevive a reinicios/restauración — la reproducción ES el estado) e inyectan un aviso de cambio visible para el modelo (registrado como evento `user/message`). `status` muestra el estado efectivo, ambos presupuestos por turno (veredictos de IA y fallos del revisor), un disyuntor disparado cuando hay uno activo en el turno y las estadísticas acumuladas de la sesión (permisos/denegaciones/fallos/desactivaciones duras, duración media, veredictos recientes). `approve [n]` registra una `autoReview/override` de un solo uso para la n-ésima denegación más reciente (1 = la más reciente): la siguiente revisión de la misma herramienta dentro de `overrideTtlMs` lleva la autorización como contexto del revisor — el revisor sigue decidiendo, y la anulación se consume con esa revisión independientemente de su resultado.
140
+ `on`/`off` añaden la anulación durable `autoReview/state` (el plegado sobrevive al reinicio/reanudación — la repetición ES el estado) e inyectan un aviso de cambio que el modelo ve (registrado como un evento `user/message`). `status` informa del estado efectivo, de ambos presupuestos por turno (veredictos de IA y fallos del revisor), de un disyuntor disparado cuando hay uno activo, y de las estadísticas acumuladas de la sesión (permisiones/denegaciones/fallbacks/rechazos `never`, duración media, veredictos recientes). `approve [n]` registra una anulación `autoReview/override` de un solo uso para la n-ésima denegación más reciente (1 = la más reciente): la siguiente revisión de la misma herramienta dentro de `overrideTtlMs` lleva la autorización como contexto del revisor — el revisor sigue decidiendo, y la anulación se consume con esa revisión independientemente de su resultado.
141
+
142
+ ## Panel web de revisión
143
+
144
+ En la GUI web (perfil web), el paquete contribuye una acción en la cabecera de sesión (**AI Review**) que abre un panel con el estado de auto-review de la sesión: el interruptor con botones on/off (que ejecutan `/auto-review on|off`), ambos presupuestos por turno, estadísticas acumuladas (incluidos los rechazos por desactivación dura), el disparo del disyuntor, los veredictos recientes y botones **approve** de un solo uso para las denegaciones recientes (que ejecutan `/auto-review approve [n]`).
169
145
 
170
- ## 🖥️ Panel de revisión web
146
+ Cómo está conectado:
171
147
 
172
- En la GUI web (perfil web), el paquete aporta una acción en la cabecera de sesión (**AI Review**) que abre un panel con el estado de auto-revisión de la sesión: el interruptor con botones de encendido/apagado (ejecutan `/auto-review on|off`), ambos presupuestos por turno, estadísticas acumuladas (incluidas las desactivaciones duras), el disparo del disyuntor, los veredictos recientes y botones de **aprobación** de un solo uso para denegaciones recientes (ejecutan `/auto-review approve [n]`).
148
+ - El host registra una **proyección de sesión** `autoReview` (plegada desde los eventos solo-registro `autoReview/*`) y la sirve a través del canal de proyección de sesión.
149
+ - La mitad del navegador es un **módulo cliente** (auto-descubierto desde la declaración `dsh.client`) registrado en el asiento `conversation.session.header.actions`.
150
+ - No se necesitan filas de parche adicionales: el panel se carga siempre que el plugin esté instalado en un perfil cuya compilación web proporcione la capacidad de proyección de sesión (el perfil web lo hace). Sin esa capacidad, el panel se declara no disponible; el answerer no se ve afectado.
173
151
 
174
- Cómo está cableado:
152
+ El panel lee solo valores completos de proyección — nunca recibe el flujo crudo de eventos de sesión.
175
153
 
176
- - El host registra una **proyección de sesión** `autoReview` (plegada desde los eventos log-only `autoReview/*`) y la sirve a través del canal de proyección de sesión.
177
- - La mitad navegador es un **módulo cliente** (auto-descubierto desde la declaración `dsh.client`) registrado en el asiento `conversation.session.header.actions`.
178
- - No hacen falta filas de patch adicionales: el panel carga siempre que el plugin esté instalado en un perfil cuya compilación web ofrece la capacidad de proyección de sesión (el perfil web lo hace). Sin esa capacidad el panel se declara no disponible; el contestador no se ve afectado.
154
+ ## Cómo funciona
155
+
156
+ ```text
157
+ approval/request waterfall (answerer chain)
158
+ │
159
+ ┌───────────────────────┴──────────────────────┐
160
+ │ dsh-auto-review answerer │
161
+ │ · session enabled? · policy = ai? │ no ── next() ──▶ human answerer (UI)
162
+ │ · risk rules → toolsPolicy → default │
163
+ └───────────────────────┬──────────────────────┘
164
+ │ yes
165
+ ▼
166
+ ┌───────────────────────────────────┐
167
+ │ reviewer subagent (fork, one-shot)│
168
+ │ · toolFilter: read/glob/grep │
169
+ │ · outputSchema: {decision, │
170
+ │ reason, riskLevel} │
171
+ │ · timeout + req.signal abort │
172
+ └───────────────┬───────────────────┘
173
+ │ verdict / failure (fail-closed fallback)
174
+ ▼
175
+ allow → allowed-once deny → rejected + reason injected into the
176
+ denied tool result (callId-linked)
177
+ │ never → rejected + [auto-review-never] feedback
178
+ │ (hard disable, no reviewer runs)
179
+ ▼
180
+ audit: approval/asked → autoReview/verdict | autoReview/rejection
181
+ → approval/decided (session events, log-only, invariant-checked)
182
+ ```
179
183
 
180
- El panel solo lee valores de proyección completos — nunca recibe el flujo crudo de eventos de sesión.
184
+ **Orden de composición.** El answerer se ejecuta en su posición de registro en la cascada: si un answerer de UI humana se compone ANTES de la fila `auto-review`, los humanos responden primero y el revisor solo ve lo que se delega aguas abajo. Verifícalo con `dsh --profile <name> --dump-config` y coloca la fila `auto-review` antes de tus filas de answerer humano cuando quieras que las herramientas de política ai se enruten primero al revisor.
181
185
 
182
- ## 🧪 dsh-eval — motor de evaluación de agentes
186
+ ## dsh-eval — motor de evaluación de agentes
183
187
 
184
- Más allá del revisor de aprobación, `dsh-auto-review` incluye `dsh-eval`: una plataforma de evaluación de agentes dirigida por YAML que ejecuta sesiones DSH headless reales (un agente aislado + un workspace de scratch por caso, la persona oficial Minimal como prompt de sistema base), recoge la traza de llamadas a herramientas del registro de eventos de la sesión y evalúa aserciones estructuradas más una revisión opcional de segundo modelo — el mismo seam de revisor que el answerer de aprobación.
188
+ Más allá del revisor de aprobación, `dsh-auto-review` incluye `dsh-eval`: una plataforma de evaluación de agentes basada en YAML que ejecuta sesiones DSH headless reales (un agente aislado + espacio de trabajo temporal por caso, la persona oficial Minimal como prompt de sistema de base), recoge el rastro de llamadas a herramientas del registro de eventos de sesión y evalúa aserciones estructuradas más una revisión opcional de segundo modelo — la misma costura de revisor que el answerer de aprobación.
185
189
 
186
190
  ```yaml
187
- # eval/cases/demo.yaml (resumido)
191
+ # eval/cases/demo.yaml (abreviado)
188
192
  suite:
189
193
  name: my-suite
190
194
  cases:
@@ -198,12 +202,6 @@ suite:
198
202
  expect:
199
203
  toolCalls: [{ tool: glob, arguments: { contains: { pattern: "src" } } }]
200
204
  results: [{ tool: glob, contains: "index.ts" }]
201
- - id: review-write
202
- input: Read src/config.ts, write the default reviewerTimeoutMs into scratch/answer.txt…
203
- expect:
204
- output: { contains: "60000" }
205
- review:
206
- statement: The agent read the default reviewerTimeoutMs and wrote it to the file.
207
205
  ```
208
206
 
209
207
  Ejecútalo (una clave de API de DeepSeek debe estar en el entorno):
@@ -212,62 +210,84 @@ Ejecútalo (una clave de API de DeepSeek debe estar en el entorno):
212
210
  dsh-eval eval/cases --model deepseek-v4-flash --timeout-ms 240000 --out .eval-reports
213
211
  ```
214
212
 
215
- Puerta de CI: el proceso sale con 0 solo cuando todos los casos de todas las suites han pasado — intégralo en un paso de GitHub Action y las evaluaciones fallidas harán fallar el build. Cada caso deja un JSONL de sesión reproducible y un JSON de traza junto a `report.md`/`report.json`; los resultados de las aserciones, el uso de tokens y el veredicto de la revisión se escriben todos en los archivos de reporte. El motor nunca sustituye valores por defecto de modelo o timeout hardcodeados, aborta limpiamente con SIGINT/SIGTERM y limita el pool de workers a la concurrencia configurada.
213
+ Puerta de CI: el proceso sale con 0 solo cuando todos los casos de todas las suites han pasado — colócalo en un paso de GitHub Action y las evaluaciones que fallen harán fallar la compilación. Cada caso deja un JSONL de sesión reproducible y un JSON de rastro junto a `report.md`/`report.json`; los resultados de las aserciones, el uso de tokens y el veredicto de revisión se escriben todos en los archivos de informe.
216
214
 
217
- A diferencia de [codex-research](https://github.com/openai/codex/tree/main/codex-rs/research) (investigación de agentes de automatización de navegador), `dsh-eval` apunta a la evaluación de agentes a nivel de harness: aserciones sobre la traza de llamadas a herramientas contra el registro de eventos de la sesión, revisión de segundo modelo como capa de aserción suplementaria y sesiones headless aisladas por caso — sin pila de navegador ni Selenium.
215
+ ## Permisos y datos
218
216
 
219
- ## 🔒 Seguridad
217
+ - **Permisos**: el manifiesto del workshop declara `session:append`, `approval:answer`, `subagent:spawn`, `command:register` y `tools:observe`.
218
+ - **Datos**: nada se guarda en disco; el búfer circular de informes está en memoria y acotado. Sin peticiones de red propias.
219
+ - **Registro de sesión**: los eventos `autoReview/*` llevan identidad del revisor, veredicto, razón, riesgo y duración — añadidos con el marcador de sobre `ignorable: true` para que cualquier compilación cargue el registro. Los hosts cuyo `Session.append` es anterior al marcador (todas las líneas rc publicadas hasta `0.1.0-rc.7` — ninguna versión lo estampa aún) se detectan antes del primer append (precomprobación de la versión del peer y luego sondeo del sobre devuelto) y la auditoría se degrada a un espejo en memoria con comentarios sin marcador, de modo que las sesiones siguen siendo cargables en todas partes.
220
220
 
221
- - El revisor corre con una **cara de herramientas de solo lectura** (lista blanca `toolFilter`). No puede escribir, editar, ejecutar shell, acceder a la red ni delegar (`maxDepth` = su propia profundidad). Su registro de sesión persiste y es auditable.
222
- - **Los argumentos sensibles se redactan** (coincidencia por nombre de clave: `token`, `password`, `api_key`, `Authorization`, credenciales, claves privadas …) antes de entrar en el prompt del revisor; el plugin nunca ejecuta los argumentos revisados. La redacción es por clave, no por contenido — no sometas a revisión de IA herramientas cuyos valores no puedas mostrar a un modelo.
223
- - **Fail closed por defecto.** Toda ruta anómala (provider ausente, brechas de capacidad, arranque rechazado, timeout, stopReason no `completed`, veredicto ausente/malformado, fallo de correlación de auditoría) se resuelve con `fallbackPolicy`, por defecto `rejected` — y la denegación devuelve un motivo auditable al modelo en lugar del texto genérico "user rejected". `allow-once` concede incondicionalmente — solo existe para despliegues desatendidos cuyo administrador acepta ese riesgo.
224
- - **Las desactivaciones duras se explican solas.** Una herramienta o regla de riesgo `never` rechaza de forma determinista Y registra un evento log-only `autoReview/rejection` con la regla/entrada que coincidió, e inyecta un texto con el marcador `[auto-review-never]` en el resultado de la herramienta denegada — el modelo aprende que la acción está desactivada en lugar de reintentarla (verificado por invariantes: marcador ⟺ evento).
225
- - **Disyuntor de rechazos.** Una racha de denegaciones en un turno dispara el disyuntor (`consecutiveDenies` / `windowDenies` dentro de `windowSize`), registrado como evento log-only `autoReview/circuit`; las peticiones posteriores siguen su `action` (`delegate` / `reject` / `abort-turn`). `abort-turn` inyecta una advertencia visible para el modelo y cancela al agente.
226
- - **El contexto del revisor es transcripción ya presentada.** `contextBudget` alimenta al revisor con contenido de sesión ya presentado (mensajes, resultados de herramientas). Con el modelo de revisor por defecto en la misma ruta, ese contenido permanece dentro de un único provider; configura `reviewerModel` con un provider diferente solo si aceptas presentarle esa transcripción.
227
- - **`never` es unidireccional en esta capa.** Una herramienta o regla de riesgo `never` rechaza antes de que la cadena humana vea la petición — es un candado, no un valor por defecto.
228
- - **El revisor es un modelo.** Sus veredictos son política consultiva, no un kernel de seguridad. Prefiere reglas `human`/`never` para operaciones irreversibles.
221
+ ## Límites de seguridad
229
222
 
230
- ## ⚠️ Limitaciones conocidas
223
+ - **El revisor es un modelo.** Sus veredictos son política consultiva, no un núcleo de seguridad; prefiere reglas `human`/`never` para operaciones irreversibles.
224
+ - **Cierre en fallo.** Cada camino anómalo (proveedor ausente, carencias de capacidad, rechazo al iniciar, timeout, razón de parada no `completed`, veredicto ausente/malformado, fallo de correlación de auditoría) se resuelve con `fallbackPolicy`, por defecto `rejected` — y el rechazo devuelve una razón auditable al modelo. `allow-once` concede incondicionalmente; existe solo para despliegues desatendidos cuyo administrador acepta ese riesgo.
225
+ - **Revisor de solo lectura.** La lista blanca `toolFilter` del revisor (`read`/`glob`/`grep`) no puede escribir, editar, ejecutar bash, acceder a la red ni delegar (`maxDepth` = su propia profundidad). Su registro de sesión se persiste y es auditable.
226
+ - **Los argumentos sensibles se redactan** (coincidencia por nombre de clave: `token`, `password`, `api_key`, `Authorization`, credenciales, claves privadas …) antes de entrar en el prompt del revisor; el plugin nunca ejecuta los argumentos revisados. La redacción se basa en claves, no en contenido — no revises con IA herramientas cuyos valores de argumento no te puedas permitir mostrar a un modelo.
227
+ - **Las desactivaciones duras se explican a sí mismas.** Una herramienta o regla de riesgo `never` rechaza de forma determinista Y registra un evento solo-registro `autoReview/rejection`, y luego inyecta un marcador `[auto-review-never]` en el resultado de la herramienta denegada — el modelo aprende que la acción está duramente desactivada en lugar de reintentarla (verificado por invariant: marcador ⟺ evento).
228
+ - **Disyuntor de rechazos.** Una racha de denegaciones en un turno dispara el disyuntor (`consecutiveDenies` / `windowDenies` dentro de `windowSize`), registrada como un evento solo-registro `autoReview/circuit`; las solicitudes posteriores siguen su `action` (`delegate` / `reject` / `abort-turn`).
229
+ - **El contexto del revisor es transcripción ya presentada.** `contextBudget` alimenta al revisor con contenido de sesión ya presentado. Con el modelo revisor de la misma ruta por defecto, ese contenido permanece dentro de un proveedor; configura `reviewerModel` a un proveedor diferente solo si aceptas presentarle esa transcripción.
230
+ - **`never` es unidireccional en esta capa.** Una herramienta o regla de riesgo `never` rechaza antes de que la cadena humana vea la solicitud — un control de bloqueo, no un valor por defecto.
231
231
 
232
- - El revisor necesita una ruta LLM operativa (heredada del agente de sesión por defecto); sin ella, cada revisión cae al `fallbackPolicy` — nunca una concesión silenciosa.
233
- - Los nombres de `reviewerTools` deben existir como herramientas globales del perfil; un nombre desconocido hace fallar al hijo revisor en voz alta en el punto más temprano y cae al fallback.
234
- - Las reglas de riesgo emparejan el `reason` de la petición, el `toolName` o los `arguments` redactados de la llamada según su `field`; las demás condiciones van en `toolsPolicy.overrides`.
235
- - La anulación `/auto-review approve` autoriza la siguiente revisión de la misma herramienta, no la llamada histórica exacta; una acción distinta sobre la misma herramienta la consume.
236
- - Los eventos de veredicto son log-only; el panel de revisión web dedicado lee la proyección plegada `autoReview` (el flujo crudo de eventos nunca llega a los plugins del navegador).
237
- - `autoReview/state` y `autoReview/verdict` se escriben con el marcador de envoltura `ignorable: true`, de modo que cualquier build del harness carga el registro: los lectores que no conocen los tipos fuera del repositorio simplemente omiten esos eventos en lugar de rechazar la sesión. (Los hosts rc.6 aceptan e ignoran el marcador, conservando exactamente el comportamiento anterior; las sesiones escritas por versiones anteriores a 0.1.1 pueden repararse con `scripts/repair-session-logs.mjs` de `dsh-permission-rules`.)
238
- - El canal git solo necesita la clave `allowBuilds` que imprime el CLI `dsh` para `dsh-auto-review`. El repo trae su propio `pnpm-workspace.yaml` con `allowBuilds: { esbuild: true }` para que el entorno de prepare aislado no falle por el postinstall de esbuild (validación inofensiva del binario de plataforma); `typescript` + `tsdown` son `dependencies` regulares para que ese entorno siempre tenga las herramientas de build.
239
- - El companion de invariantes opcional (`dsh-auto-review/invariant`) necesita el servicio `invariants` (composiciones agent-spine como headless/ACP); el perfil web simple no lo proporciona, por eso la fila se publica comentada en el patch del bundle.
232
+ ## Limitaciones conocidas
240
233
 
241
- ## 🏷️ Topics de GitHub
234
+ - El revisor necesita una ruta LLM funcional (heredada por defecto); sin ella, cada revisión cae según `fallbackPolicy` — nunca una concesión silenciosa.
235
+ - Los nombres de `reviewerTools` deben existir como herramientas globales en el perfil; un nombre desconocido hace fallar al hijo revisor en voz alta en el punto más temprano y cae en fallback.
236
+ - Las reglas de riesgo emparejan el `reason` de la solicitud, el `toolName` o los `arguments` redactados de la llamada según su `field`; otras condiciones van en `toolsPolicy.overrides`.
237
+ - La anulación `/auto-review approve` autoriza la siguiente revisión de la misma herramienta, no la llamada histórica exacta; una acción diferente sobre la misma herramienta la consume.
238
+ - Los eventos de veredicto son solo-registro; el panel web de revisión lee la proyección `autoReview` plegada (el flujo crudo de eventos nunca llega a los plugins del navegador).
239
+ - `autoReview/state` y `autoReview/verdict` se añaden con el marcador de sobre `ignorable: true` en hosts que lo respetan, de modo que cualquier compilación del harness carga el registro — los lectores que no conocen los tipos fuera del repo simplemente omiten esos registros. En hosts rc publicados (rc.1–rc.7) el runtime detecta el marcador descartado y nunca escribe estos eventos (el espejo en memoria mantiene el comando, los presupuestos, el disyuntor y `approve` durante la sesión); las sesiones ya contaminadas por versiones anteriores a 0.5.1 pueden repararse con `scripts/repair-session-logs.mjs` de `dsh-permission-rules` (su conjunto de tipos por defecto cubre los cinco eventos `autoReview/*`).
240
+ - El canal git necesita la única clave `allowBuilds` que el CLI de `dsh` imprime para el propio `dsh-auto-review`. El repo incluye su propio `pnpm-workspace.yaml` con `allowBuilds: { esbuild: true }`; `typescript` + `tsdown` son `dependencies` regulares.
241
+ - El compañero invariant opcional necesita el servicio `invariants` (composiciones agent-spine como headless/ACP); el perfil web plano no lo proporciona, por lo que la fila se incluye comentada en el parche del bundle.
242
242
 
243
- Recomendados al publicar: `dsh` · `dsh-plugin` · `deepseek-harness` · `deepseek` · `cordis` · `ai-safety` · `approval` · `sandbox` · `subagent` · `llm`
243
+ ## Trabajo relacionado
244
244
 
245
- ## 🔗 Trabajo relacionado
245
+ - [Andy8647/dsh-auto-approval](https://github.com/Andy8647/dsh-auto-approval) — clasificador allow/deny de dos estados en la cascada `tools/pre-execute` con auditoría en archivo de registro. `dsh-auto-review` difiere deliberadamente: cadena de **answerer** oficial, siempre delega lo que no le pertenece, segundo modelo de solo lectura con un veredicto estructurado, razones de denegación devueltas al modelo, auditoría en el registro de sesión.
246
+ - [ACP automation bridge](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/acp/acp) — decisiones de máquina de un solo uso para sus propios agentes de ACP. `dsh-auto-review` está limitado a sesión y política de herramientas para el harness interactivo; nunca infiere concesiones durables.
246
247
 
247
- - [Andy8647/dsh-auto-approval](https://github.com/Andy8647/dsh-auto-approval) — clasificador binario allow/deny en el waterfall `tools/pre-execute` con auditoría en archivo de log. `dsh-auto-review` difiere a propósito: cadena de **answerers** oficial, siempre delega lo que no posee, segundo modelo de solo lectura con veredicto estructurado, motivos de denegación devueltos al modelo, auditoría en el registro de sesión.
248
- - [ACP automation bridge](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/acp/acp) — decisiones de máquina de un solo uso para sus propios agentes ACP. `dsh-auto-review` está orientado a sesiones y políticas de herramientas del harness interactivo; nunca infiere concesiones duraderas.
249
-
250
- ## 🧑‍💻 Desarrollo
248
+ ## Desarrollo
251
249
 
252
250
  ```sh
253
251
  pnpm install # node ^22.19 || >=24
254
- pnpm run typecheck # tsc, src + tests
255
- pnpm test # vitest: 190 tests, 14 files
256
- pnpm run build # declaraciones tsc + bundles tsdown (lib/)
252
+ pnpm run typecheck # tsc: src + tests contra el checkout local del harness
253
+ pnpm test # vitest: 190 tests, 14 archivos
254
+ pnpm run build # declaraciones tsc + bundles tsdown (lib/, incluido el bundle de cliente)
257
255
  pnpm run verify:self-contained
258
- pnpm pack # artefacto de publicación
256
+ pnpm pack # el tarball publicado
259
257
  ```
260
258
 
261
- Estructura del repositorio (estructura plugin-template): `src/index.ts` (contrato del plugin) · `src/config.ts` (esquema Schemastery + resolución) · `src/runtime.ts` (answerer, comando, inyección del motivo de denegación) · `src/review.ts` (orquestación del revisor, prompt, redacción) · `src/events.ts` (vocabulario de eventos de sesión + folds) · `src/projection.ts` + `src/projection-types.ts` (la proyección de sesión `autoReview`) · `src/invariant.ts` (companion de invariantes) · `src/eval/` (el motor dsh-eval: DSL, runner, assertions, trace, review, reports, CLI) · `eval/` (composición de evaluación incluida + demo suite) · `bin/dsh-eval.mjs` (lanzador CLI) · `src/client/` (mitad navegador: panel de revisión, locales, estilos) · `test/` · `fixtures/`.
259
+ Estructura del repositorio: `src/index.ts` (contrato del plugin) · `src/config.ts` (esquema Schemastery + resolución) · `src/runtime.ts` (answerer, comando, inyección de razón de denegación) · `src/review.ts` (orquestación del revisor, prompt, saneamiento) · `src/events.ts` (vocabulario de eventos de sesión + pliegues) · `src/projection.ts` + `src/projection-types.ts` (la proyección de sesión `autoReview`) · `src/invariant.ts` (compañero invariant) · `src/eval/` (el motor dsh-eval) · `eval/` (composición de evaluación incluida) · `bin/dsh-eval.mjs` (lanzador CLI) · `src/client/` (mitad del navegador) · `test/` · `fixtures/`.
260
+
261
+ ## Temas
262
262
 
263
- ## 👥 Contribuidores
263
+ `deepseek-harness`, `dsh`, `dsh-plugin`, `cordis`, `approval`, `auto-review`, `second-model`, `ai-safety`, `sandbox`, `subagent`
264
264
 
265
- Gracias a todos los que han contribuido a `dsh-auto-review`:
265
+ ## Contribuidores
266
266
 
267
- - [PerryLink](https://github.com/PerryLink) — autor y mantenedor: answerer de aprobación, subagente revisor, política de riesgo y disyuntor, panel de revisión por proyección de sesión, companion de invariantes, documentación, CI/CD y lanzamientos.
267
+ - [@PerryLink](https://github.com/PerryLink) — creador y mantenedor: el answerer de aprobación, el subagente revisor, la política de riesgo y el disyuntor, el panel de revisión por proyección de sesión, el compañero invariant, dsh-eval y la documentación en cinco idiomas.
268
268
 
269
- ¿Quieres ayudar? Revisa las [plantillas de issues](.github/ISSUE_TEMPLATE/), la [política de seguridad](SECURITY.md) y [AGENTS.md](AGENTS.md) con las convenciones del repositorio — los PR son bienvenidos en inglés o chino.
269
+ ## Familia de plugins DSH de PerryLink
270
270
 
271
- ## 📄 Licencia
271
+ Este proyecto es uno de los plugins de DeepSeek Harness mantenidos por [PerryLink](https://github.com/PerryLink). Si este te ayuda, probablemente los demás también lo harán:
272
272
 
273
- [Apache License 2.0](LICENSE)
273
+ | Plugin | En una línea |
274
+ |---|---|
275
+ | [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | Panel de tiempo de ejecución MCP de solo lectura: comando /mcp + pestaña Settings con estado, herramientas y errores |
276
+ | [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | Guardián de disciplina de ingeniería: interrogatorio de requisitos, puertas de pruebas, revisión adversaria |
277
+ | [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | Agentes hijos en segundo plano durables con barra lateral de UI web, mensajería e interrupción |
278
+ | [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | Diagnósticos, formato, autocompletado, acciones de código y renombrado LSP sobre servidores de lenguaje |
279
+ | [dsh-output-styles](https://github.com/PerryLink/dsh-output-styles) | Cambio de estilo en tiempo de ejecución equivalente a outputStyles de Claude Code |
280
+ | [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | Equivalente a /rewind de Claude Code: instantáneas, bifurcaciones de sesión, restauración de un solo uso |
281
+ | [dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules) | Reglas de permisos declarativas allow/deny/ask estilo Claude Code con auditoría |
282
+ | **[dsh-auto-review](https://github.com/PerryLink/dsh-auto-review)** | Auto-revisión de segundo modelo en la cadena de aprobación, con cierre en fallo por defecto |
283
+ | [dsh-memento](https://github.com/PerryLink/dsh-memento) | Memoria entre sesiones controlada por aprobación: costura ctx.memory + SQLite + herramienta de memoria |
284
+ | [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | Paquete de habilidades de auditoría de seguridad: escaneo de secretos, revisión de dependencias y cadena de suministro |
285
+ | [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | Fija sesiones en la barra lateral web con orden durable |
286
+ | [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Historial de entrada estilo terminal para el compositor web: flechas, búsqueda Ctrl+R |
287
+ | [dsh-github](https://github.com/PerryLink/dsh-github) | Integración de PR/issues de GitHub para DSH, cada escritura controlada por aprobación |
288
+ | [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Base de conocimiento de desarrollo de plugins como habilidad de agente bajo demanda |
289
+ | [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migra sesiones, memoria, habilidades y CLAUDE.md de Claude Code a DSH |
290
+
291
+ ## Licencia
292
+
293
+ [Apache License 2.0](LICENSE) © 2026 dsh-auto-review contributors