dsh-auto-review 0.12.17 → 0.13.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.13.2] - 2026-10-18
4
+
5
+ ### Changed
6
+
7
+ - Add a 1280×720 hero and a 960×540, 4-second terminal GIF rendered from the test run; `screenshots.json` is an object array and `capture.json` records the command.
8
+
9
+ ## [0.13.1] - 2026-10-18
10
+
11
+ ### Fixed
12
+
13
+ - **Risk-rule examples are valid JavaScript regexes, and an invalid pattern names its index.** The READMEs used the PCRE inline flag `(?i)`, which `new RegExp(..., "u")` rejects; examples now spell the case-insensitive character classes out. Config errors read `riskRules[0]: pattern …` instead of an unlocated message (issue #59).
14
+
15
+ ## [0.13.0] - 2026-10-18
16
+
17
+ ### Added
18
+
19
+ - **Reviewer activation on 0.2.1+ (`startActivation`).** The review and eval paths now detect `subagents.startActivation` and use it with `delivery: "caller"`; on hosts that still expose `start()` the old path is unchanged. Because `startActivation` has no `toolFilter`, the new path requires `reviewerPreset` (a read-only Agent Preset) and fails closed without one, rather than giving the reviewer the parent's full tool surface. This closes the functional failure where every AI approval on 0.2.1 was rejected.
20
+
21
+ ### Fixed
22
+
23
+ - `reviewerPreset` added to config/ResolvedConfig and the eval review config.
24
+
25
+ ## [0.12.18] - 2026-10-17
26
+
27
+ ### Fixed
28
+
29
+ - **Windows default no longer silently does nothing (issue #30).** The shipped defaults now cover `pwsh` and `powershell` as `ai`, not only `bash`/`write`.
30
+ - **The context-firewall docs no longer claim the runtime-context snapshot is dropped.** The host re-admits `runtimeContext.project(...)` after `agent/pre-step`; `README` (en/zh/es/pt), `AGENTS.md` and `isolation.ts` now state that the reviewer still sees it. Workspace instruction files and third-party injections remain filtered.
31
+ - Compatibility: `engines.dsh` -> `>=0.2.1-0 <0.3.0`; devDependencies to `0.2.1-rc.2`; add `@deepseek-ai/dsh-working-directory`; remove the deleted `@deepseek-ai/dsh-invariants` peer.
32
+
3
33
  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
34
 
5
35
  ## [0.12.17] - 2026-10-10
package/README-es.md CHANGED
@@ -41,7 +41,7 @@ Aprobación con IA de segundo modelo para DeepSeek Harness: un subagente revisor
41
41
 
42
42
  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.
43
43
 
44
- ![Demostración de terminal de dsh-auto-review: dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.png)
44
+ ![Demostración de terminal de dsh-auto-review: dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-hero.png)
45
45
 
46
46
  ![Animated terminal demo of dsh-auto-review](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.gif)
47
47
 
@@ -113,6 +113,7 @@ Todas las opciones son campos Schemastery `Config` (modificables desde cordis.ym
113
113
  | `toolsPolicy.overrides` | `{}` | Política por herramienta: `ai` / `human` / `never` |
114
114
  | `riskRules` | `[]` | `{pattern, policy, field?}` emparejado antes de la tabla de herramientas; `field` elige `reason` (por defecto), `toolName` o `arguments` |
115
115
  | `reviewerProvider` | `fork` | Proveedor de subagente para el revisor (backend fork en proceso) |
116
+ | `reviewerPreset` | *(none)* | Id del Agent Preset de solo lectura; obligatorio cuando el host solo expone `startActivation` (0.2.1+) |
116
117
  | `reviewerModel` | *(heredado)* | Id del modelo revisor; si no se define, hereda la ruta del agente de sesión |
117
118
  | `reviewerTimeoutMs` | `60000` | Plazo del veredicto; al vencer se aplica la política de fallback |
118
119
  | `reviewerTools` | `[read, glob, grep]` | Lista blanca de herramientas del hijo revisor (debe ser no vacía) |
@@ -142,7 +143,7 @@ Ejemplo (forma completa anotada: `fixtures/config/config-full.yaml`):
142
143
  toolsPolicy:
143
144
  overrides: { bash: ai, write: ai }
144
145
  riskRules:
145
- - pattern: '(?i)(rm\s+(-[a-z]+\s+)*/|git\s+push\s+--force)'
146
+ - pattern: '([Rr][Mm]\s+(-[a-z]+\s+)*/|[Gg][Ii][Tt]\s+push\s+--force)'
146
147
  policy: never
147
148
  - pattern: 'write'
148
149
  policy: never
@@ -353,7 +354,7 @@ El servidor es de solo lectura y determinista: sin red, sin modelo, sin escritur
353
354
  - **El revisor es un modelo.** Sus veredictos son política consultiva, no un núcleo de seguridad; prefiere reglas `human`/`never` para operaciones irreversibles.
354
355
  - **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.
355
356
  - **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.
356
- - **Revisor aislado del contexto.** Los pasos del hijo revisor se filtran en la costura oficial `agent/pre-step`: solo entran su propio prompt y los resultados de sus propias herramientas de solo lectura. Los archivos de instrucciones del espacio de trabajo (`AGENTS.md` / `CLAUDE.md`), la instantánea de contexto de ejecución del harness y cualquier plugin que inyecte contexto se descartan antes de que el bucle los añada, de modo que el texto controlado por el repositorio nunca llega al componente que decide si se permite una llamada. Esto vale con CUALQUIERA de los proveedores de subagente — esos productores inyectan de nuevo en cada sesión de agente, así que lo que los cierra es el filtro y no la elección de proveedor. La lista blanca es por ORIGEN del mensaje, así que un plugin que declare un origen nuevo también se descarta.
357
+ - **Revisor aislado del contexto.** Los pasos del hijo revisor se filtran en la costura oficial `agent/pre-step`: solo entran su propio prompt y los resultados de sus propias herramientas de solo lectura. Los archivos de instrucciones del espacio de trabajo (`AGENTS.md` / `CLAUDE.md`) y los plugins que inyectan contexto se descartan en esa costura; **la instantánea de contexto de ejecución del propio harness se re-admite después de `agent/pre-step`, el firewall no la elimina y el revisor la ve.** Esto vale con CUALQUIERA de los proveedores de subagente — esos productores inyectan de nuevo en cada sesión de agente, así que lo que los cierra es el filtro y no la elección de proveedor. La lista blanca es por ORIGEN del mensaje, así que un plugin que declare un origen nuevo también se descarta.
357
358
  - **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.
358
359
  - **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).
359
360
  - **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`).
@@ -430,7 +431,7 @@ Evidencia estática: `dsh-plugin-doctor` K10–K13 dan `pass` en todas las compr
430
431
 
431
432
  ## PerryLink DSH Plugin Family
432
433
 
433
- Este proyecto es uno de los **33 plugins activamente mantenidos** de DeepSeek Harness de [PerryLink](https://github.com/PerryLink): el registro tiene **42**, de los cuales **6** están congelados y **3** retirados; cada uno conserva su fila abajo, con el motivo en la columna Estado. Si este te ayuda, probablemente los demás también:
434
+ Este proyecto es uno de los **34 plugins activamente mantenidos** de DeepSeek Harness de [PerryLink](https://github.com/PerryLink): el registro tiene **42**, de los cuales **5** están congelados y **3** retirados; cada uno conserva su fila abajo, con el motivo en la columna Estado. Si este te ayuda, probablemente los demás también:
434
435
 
435
436
  | Plugin | En una línea | Estado |
436
437
  |---|---|---|
@@ -458,7 +459,7 @@ Este proyecto es uno de los **33 plugins activamente mantenidos** de DeepSeek Ha
458
459
  | **[dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions)** | LSP diagnostics, formatting, completion, code actions and rename over language servers | |
459
460
  | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | PII masking middleware: anonymize at the model boundary, restore at the display layer | |
460
461
  | **[dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel)** | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors | |
461
- | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | 🧊 CONGELADO — ver el README del repositorio |
462
+ | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | |
462
463
  | **[dsh-observe](https://github.com/PerryLink/dsh-observe)** | OpenTelemetry and Langfuse observability exporter for DeepSeek Harness. | |
463
464
  | **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | Claude Code outputStyles-equivalent runtime style switching | |
464
465
  | **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | Claude Code-style declarative allow/deny/ask permission rules with audit | |
package/README-hi.md CHANGED
@@ -41,7 +41,7 @@ DeepSeek Harness के लिए द्वितीय-मॉडल AI अन
41
41
 
42
42
  जब कोई क्रिया सैंडबॉक्स सीमा पार करती है, तो दूसरा मॉडल साक्ष्य पढ़ता है और कारण सहित निर्णय लौटाता है — ताकि मनुष्य कुछ भी स्वीकृत न करें और कुछ भी असुरक्षित छूट न जाए।
43
43
 
44
- ![dsh-auto-review का टर्मिनल डेमो: dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.png)
44
+ ![dsh-auto-review का टर्मिनल डेमो: dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-hero.png)
45
45
 
46
46
  ![Animated terminal demo of dsh-auto-review](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.gif)
47
47
 
@@ -113,6 +113,7 @@ dsh --profile web --dump-config | grep -A4 'id: auto-review'
113
113
  | `toolsPolicy.overrides` | `{}` | प्रति-टूल नीति: `ai` / `human` / `never` |
114
114
  | `riskRules` | `[]` | टूल तालिका से पहले मिलाया गया `{pattern, policy, field?}`; `field` चुनता है `reason` (डिफ़ॉल्ट), `toolName` या `arguments` |
115
115
  | `reviewerProvider` | `fork` | समीक्षक का उप-एजेंट प्रदाता (इन-प्रोसेस fork बैकएंड) |
116
+ | `reviewerPreset` | *(none)* | केवल-पढ़ने वाला Agent Preset id; जब होस्ट केवल `startActivation` (0.2.1+) देता है तब आवश्यक |
116
117
  | `reviewerModel` | *(विरासत)* | समीक्षक मॉडल id; खाली होने पर सत्र एजेंट का मार्ग लेता है |
117
118
  | `reviewerTimeoutMs` | `60000` | निर्णय की समय-सीमा; समाप्ति पर fallback नीति लागू होती है |
118
119
  | `reviewerTools` | `[read, glob, grep]` | समीक्षक चाइल्ड की टूल अनुमति-सूची (गैर-रिक्त होनी चाहिए) |
@@ -142,7 +143,7 @@ dsh --profile web --dump-config | grep -A4 'id: auto-review'
142
143
  toolsPolicy:
143
144
  overrides: { bash: ai, write: ai }
144
145
  riskRules:
145
- - pattern: '(?i)(rm\s+(-[a-z]+\s+)*/|git\s+push\s+--force)'
146
+ - pattern: '([Rr][Mm]\s+(-[a-z]+\s+)*/|[Gg][Ii][Tt]\s+push\s+--force)'
146
147
  policy: never
147
148
  - pattern: 'write'
148
149
  policy: never
@@ -279,7 +280,7 @@ dsh-eval eval/cases --model deepseek-flash --timeout-ms 240000 --out .eval-repor
279
280
 
280
281
  ## PerryLink DSH Plugin Family
281
282
 
282
- यह प्रोजेक्ट [PerryLink](https://github.com/PerryLink) के DeepSeek Harness प्लगइन परिवार का हिस्सा है — **33 सक्रिय रूप से अनुरक्षित**, कुल सूची **42** है जिसमें **6 फ़्रोज़न** और **3 सेवानिवृत्त** हैं; हर एक की पंक्ति नीचे बनी रहती है, कारण “स्थिति” कॉलम में है। अगर यह उपयोगी लगे, तो अन्य भी मददगार होंगे:
283
+ यह प्रोजेक्ट [PerryLink](https://github.com/PerryLink) के DeepSeek Harness प्लगइन परिवार का हिस्सा है — **34 सक्रिय रूप से अनुरक्षित**, कुल सूची **42** है जिसमें **5 फ़्रोज़न** और **3 सेवानिवृत्त** हैं; हर एक की पंक्ति नीचे बनी रहती है, कारण “स्थिति” कॉलम में है। अगर यह उपयोगी लगे, तो अन्य भी मददगार होंगे:
283
284
 
284
285
  | Plugin | एक पंक्ति में | स्थिति |
285
286
  |---|---|---|
@@ -307,7 +308,7 @@ dsh-eval eval/cases --model deepseek-flash --timeout-ms 240000 --out .eval-repor
307
308
  | **[dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions)** | LSP diagnostics, formatting, completion, code actions and rename over language servers | |
308
309
  | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | PII masking middleware: anonymize at the model boundary, restore at the display layer | |
309
310
  | **[dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel)** | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors | |
310
- | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | 🧊 फ़्रोज़न — रिपॉज़िटरी README देखें |
311
+ | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | |
311
312
  | **[dsh-observe](https://github.com/PerryLink/dsh-observe)** | OpenTelemetry and Langfuse observability exporter for DeepSeek Harness. | |
312
313
  | **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | Claude Code outputStyles-equivalent runtime style switching | |
313
314
  | **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | Claude Code-style declarative allow/deny/ask permission rules with audit | |
package/README-pt.md CHANGED
@@ -41,7 +41,7 @@ Aprovação por IA de segundo modelo para o DeepSeek Harness — um subagente re
41
41
 
42
42
  Quando uma ação cruza a fronteira do sandbox, um segundo modelo lê as evidências e devolve um veredito com a razão — para que humanos não aprovem nada e nada inseguro passe despercebido.
43
43
 
44
- ![Demonstração de terminal do dsh-auto-review: dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.png)
44
+ ![Demonstração de terminal do dsh-auto-review: dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-hero.png)
45
45
 
46
46
  ![Animated terminal demo of dsh-auto-review](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.gif)
47
47
 
@@ -113,6 +113,7 @@ Todos os ajustes são campos Schemastery `Config` (alteráveis no cordis.yml). U
113
113
  | `toolsPolicy.overrides` | `{}` | Política por ferramenta: `ai` / `human` / `never` |
114
114
  | `riskRules` | `[]` | `{pattern, policy, field?}` emparelhado antes da tabela de ferramentas; `field` escolhe `reason` (padrão), `toolName` ou `arguments` |
115
115
  | `reviewerProvider` | `fork` | Provedor de subagente do revisor (backend fork em processo) |
116
+ | `reviewerPreset` | *(none)* | Id do Agent Preset somente leitura; obrigatório quando o host expõe apenas `startActivation` (0.2.1+) |
116
117
  | `reviewerModel` | *(herdado)* | Id do modelo revisor; se vazio, herda a rota do agente da sessão |
117
118
  | `reviewerTimeoutMs` | `60000` | Prazo do veredito; ao expirar, aplica-se a política de fallback |
118
119
  | `reviewerTools` | `[read, glob, grep]` | Lista de permissões de ferramentas do filho revisor (deve ser não vazia) |
@@ -142,7 +143,7 @@ Exemplo (forma completa anotada: `fixtures/config/config-full.yaml`):
142
143
  toolsPolicy:
143
144
  overrides: { bash: ai, write: ai }
144
145
  riskRules:
145
- - pattern: '(?i)(rm\s+(-[a-z]+\s+)*/|git\s+push\s+--force)'
146
+ - pattern: '([Rr][Mm]\s+(-[a-z]+\s+)*/|[Gg][Ii][Tt]\s+push\s+--force)'
146
147
  policy: never
147
148
  - pattern: 'write'
148
149
  policy: never
@@ -353,7 +354,7 @@ O servidor é somente-leitura e determinista: sem rede, sem modelo, sem gravaç
353
354
  - **O revisor é um modelo.** Seus vereditos são política consultiva, não um núcleo de segurança; prefira regras `human`/`never` para operações irreversíveis.
354
355
  - **Falha fechada.** Todo caminho anômalo (provedor ausente, lacunas de capacidade, rejeição ao iniciar, timeout, razão de parada não `completed`, veredito ausente/malformado, falha de correlação de auditoria) se resolve via `fallbackPolicy`, padrão `rejected` — e a rejeição devolve uma razão auditável ao modelo. `allow-once` concede incondicionalmente; existe apenas para implantações desatendidas cujo administrador aceita esse risco.
355
356
  - **Revisor somente leitura.** A lista de permissões `toolFilter` do revisor (`read`/`glob`/`grep`) não pode escrever, editar, executar bash, acessar a rede nem delegar (`maxDepth` = sua própria profundidade). Seu log de sessão é persistido e auditável.
356
- - **Revisor isolado do contexto.** Os passos do filho revisor são filtrados na costura oficial `agent/pre-step`: apenas o seu próprio prompt e os resultados das suas próprias ferramentas somente leitura entram. Arquivos de instruções do workspace (`AGENTS.md` / `CLAUDE.md`), o instantâneo de contexto de execução do harness e qualquer plugin que injete contexto são descartados antes de o laço anexá-los, de modo que texto controlado pelo repositório nunca chega ao componente que decide se uma chamada é permitida. Isso vale sob QUALQUER provedor de subagente — esses produtores injetam de novo em cada sessão de agente, então o que os fecha é o filtro, não a escolha do provedor. A lista de permissões é por ORIGEM da mensagem, então um plugin que declare uma origem nova também é descartado.
357
+ - **Revisor isolado do contexto.** Os passos do filho revisor são filtrados na costura oficial `agent/pre-step`: apenas o seu próprio prompt e os resultados das suas próprias ferramentas somente leitura entram. Arquivos de instruções do workspace (`AGENTS.md` / `CLAUDE.md`) e plugins que injetam contexto são descartados nessa costura; **o instantâneo de contexto de execução do próprio harness é readmitido após `agent/pre-step`, o firewall não o remove e o revisor o vê.** Isso vale sob QUALQUER provedor de subagente — esses produtores injetam de novo em cada sessão de agente, então o que os fecha é o filtro, não a escolha do provedor. A lista de permissões é por ORIGEM da mensagem, então um plugin que declare uma origem nova também é descartado.
357
358
  - **Argumentos sensíveis são redigidos** (correspondência por nome de chave: `token`, `password`, `api_key`, `Authorization`, credenciais, chaves privadas …) antes de entrar no prompt do revisor; o plugin nunca executa os argumentos revisados. A redação é baseada em chave, não em conteúdo — não revise com IA ferramentas cujos valores de argumento você não pode se dar ao luxo de mostrar a um modelo.
358
359
  - **Desativações duras se explicam.** Uma ferramenta ou regra de risco `never` rejeita de forma determinística E registra um evento somente-log `autoReview/rejection`, e então injeta um marcador `[auto-review-never]` no resultado da ferramenta negada — o modelo aprende que a ação está duramente desativada em vez de tentar novamente (verificado por invariant: marcador ⟺ evento).
359
360
  - **Disjuntor de rejeições.** Uma sequência de negações em um turno dispara o disjuntor (`consecutiveDenies` / `windowDenies` dentro de `windowSize`), registrada como um evento somente-log `autoReview/circuit`; solicitações posteriores seguem sua `action` (`delegate` / `reject` / `abort-turn`).
@@ -426,7 +427,7 @@ Evidência estática: `dsh-plugin-doctor` K10–K13 retornam `pass` em todas as
426
427
 
427
428
  ## PerryLink DSH Plugin Family
428
429
 
429
- Este projeto é um dos **33 plugins ativamente mantidos** do DeepSeek Harness da [PerryLink](https://github.com/PerryLink): o registro tem **42**, dos quais **6** estão congelados e **3** aposentados; cada um mantém sua linha abaixo, com o motivo na coluna Status. Se este ajudou você, provavelmente os outros também ajudarão:
430
+ Este projeto é um dos **34 plugins ativamente mantidos** do DeepSeek Harness da [PerryLink](https://github.com/PerryLink): o registro tem **42**, dos quais **5** estão congelados e **3** aposentados; cada um mantém sua linha abaixo, com o motivo na coluna Status. Se este ajudou você, provavelmente os outros também ajudarão:
430
431
 
431
432
  | Plugin | Em uma linha | Status |
432
433
  |---|---|---|
@@ -454,7 +455,7 @@ Este projeto é um dos **33 plugins ativamente mantidos** do DeepSeek Harness da
454
455
  | **[dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions)** | LSP diagnostics, formatting, completion, code actions and rename over language servers | |
455
456
  | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | PII masking middleware: anonymize at the model boundary, restore at the display layer | |
456
457
  | **[dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel)** | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors | |
457
- | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | 🧊 CONGELADO — ver o README do repositório |
458
+ | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | |
458
459
  | **[dsh-observe](https://github.com/PerryLink/dsh-observe)** | OpenTelemetry and Langfuse observability exporter for DeepSeek Harness. | |
459
460
  | **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | Claude Code outputStyles-equivalent runtime style switching | |
460
461
  | **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | Claude Code-style declarative allow/deny/ask permission rules with audit | |
package/README-zh.md CHANGED
@@ -41,7 +41,7 @@ DeepSeek Harness 的第二模型 AI 审批 —— 一个只读审查子代理在
41
41
 
42
42
  当某个动作越过沙箱边界时,第二模型读取证据并给出带有理由的裁决 —— 人类无需批准任何事,同时也没有任何不安全的东西蒙混过关。
43
43
 
44
- ![dsh-auto-review 终端演示:dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.png)
44
+ ![dsh-auto-review 终端演示:dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-hero.png)
45
45
 
46
46
  ![Animated terminal demo of dsh-auto-review](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.gif)
47
47
 
@@ -113,6 +113,7 @@ dsh --profile web --dump-config | grep -A4 'id: auto-review'
113
113
  | `toolsPolicy.overrides` | `{}` | 按工具策略:`ai` / `human` / `never` |
114
114
  | `riskRules` | `[]` | 在工具表之前匹配的 `{pattern, policy, field?}`;`field` 选择 `reason`(默认)、`toolName` 或 `arguments` |
115
115
  | `reviewerProvider` | `fork` | 审查器的子代理 provider(进程内 fork 后端) |
116
+ | `reviewerPreset` | *(none)* | 只读 Agent Preset id;宿主只提供 `startActivation`(0.2.1+)时必填 |
116
117
  | `reviewerModel` | *(继承)* | 审查器模型 id;不设置则继承会话代理的路由 |
117
118
  | `reviewerTimeoutMs` | `60000` | 裁决截止时间;超时后应用 fallback 策略 |
118
119
  | `reviewerTools` | `[read, glob, grep]` | 审查器子代理的工具白名单(必须非空) |
@@ -142,7 +143,7 @@ dsh --profile web --dump-config | grep -A4 'id: auto-review'
142
143
  toolsPolicy:
143
144
  overrides: { bash: ai, write: ai }
144
145
  riskRules:
145
- - pattern: '(?i)(rm\s+(-[a-z]+\s+)*/|git\s+push\s+--force)'
146
+ - pattern: '([Rr][Mm]\s+(-[a-z]+\s+)*/|[Gg][Ii][Tt]\s+push\s+--force)'
146
147
  policy: never
147
148
  - pattern: 'write'
148
149
  policy: never
@@ -353,7 +354,7 @@ Claude Desktop(`claude_desktop_config.json`)配置示例:
353
354
  - **审查器是模型。** 其裁决是建议性策略,不是安全内核;对不可逆操作优先使用 `human`/`never` 规则。
354
355
  - **失败关闭。** 每条异常路径(provider 缺失、能力缺口、启动拒绝、超时、非 `completed` 停止原因、缺失/畸形裁决、审计关联失败)都经由 `fallbackPolicy` 处理,默认 `rejected` —— 且拒绝会向模型反馈一条可审计的理由。`allow-once` 是无条件放行;它只用于接受该风险的无值守部署。
355
356
  - **只读审查器。** 审查器的 `toolFilter` 白名单(`read`/`glob`/`grep`)无法写入、编辑、运行 bash、访问网络或委派(`maxDepth` = 自身深度)。其会话日志被持久化且可审计。
356
- - **上下文隔离的审查器。** 审查器子代理的每一步都在官方 `agent/pre-step` 接缝上被过滤:只有它自己的提示词与它自己的只读工具结果能够进入。工作区指令文件(`AGENTS.md` / `CLAUDE.md`)、宿主运行时上下文快照,以及任何注入上下文的插件,都会在循环追加它们之前被丢弃,因此仓库可控的文本永远不会抵达决定是否放行调用的组件。这在任一 subagent provider 下都成立——这些注入方会向任何新建的 agent 会话重新注入,因此关闭它们的是这道过滤,而不是 provider 的选择。白名单按消息来源判定,所以声明了新来源类型的插件同样会被丢弃。
357
+ - **上下文隔离的审查器。** 审查器子代理的每一步都在官方 `agent/pre-step` 接缝上被过滤:只有它自己的提示词与它自己的只读工具结果能够进入。工作区指令文件(`AGENTS.md` / `CLAUDE.md`)与注入上下文的插件会在该接缝处被丢弃;**宿主自己的运行时上下文快照会在 `agent/pre-step` 之后被循环重新接纳,防火墙无法移除它,因此审查器能看到该快照。**这在任一 subagent provider 下都成立——这些注入方会向任何新建的 agent 会话重新注入,因此关闭它们的是这道过滤,而不是 provider 的选择。白名单按消息来源判定,所以声明了新来源类型的插件同样会被丢弃。
357
358
  - **敏感参数会被脱敏**(按键名匹配:`token`、`password`、`api_key`、`Authorization`、凭据、私钥……)后才进入审查器提示词;该插件绝不会执行被审查的参数。脱敏是按键名而非内容 —— 不要把参数值经不起展示给模型的工具交给 AI 审查。
358
359
  - **硬禁用会自我解释。** `never` 工具或风险规则确定性拒绝,并记录一条仅日志的 `autoReview/rejection` 事件,然后把 `[auto-review-never]` 标记注入被拒绝的工具结果 —— 模型学会该操作已被硬禁用,而不是重试(invariant 校验:标记 ⟺ 事件)。
359
360
  - **拒绝熔断器。** 一轮内连续拒绝会触发熔断(`consecutiveDenies` / 窗口内的 `windowDenies`),记录为仅日志的 `autoReview/circuit` 事件;后续请求按其 `action`(`delegate` / `reject` / `abort-turn`)处理。
@@ -362,7 +363,7 @@ Claude Desktop(`claude_desktop_config.json`)配置示例:
362
363
 
363
364
  ## 已知限制
364
365
 
365
- - **两种不同的暴露面,两种不同的解法——彼此不能互相替代。** *注入式*上下文(工作区指令文件、运行时上下文快照、第三方插件注入)会被重新注入到任何新建的 agent 会话中,因此在 `reviewerProvider: fork` 与 `reviewerProvider: spawn` 下抵达审查器的内容完全相同——同一请求下实测逐字节一致。关闭它的是 `agent/pre-step` 来源过滤,且在两种 provider 下都有效;**仅切换到 `spawn` 并不能阻止工作区指令进入审查器。** 另一方面,`fork` 会用委派会话已完成的回合为子会话播种:那段历史已经是子会话自己的日志,而不是进入某一步的消息,因此过滤无法触及,只有 `spawn` 能避免,两者之间由审查器提示词的“不可信记录”围栏作为缓解。在上述两次追踪中,播种并未产生额外消息,因此其实际影响尚未量化。
366
+ - **两种不同的暴露面,两种不同的解法——彼此不能互相替代。** *注入式*上下文(工作区指令文件、第三方插件注入)会被重新注入到任何新建的 agent 会话中;宿主运行时上下文快照在 pre-step 之后被重新接纳,明确不在防火墙承诺范围内,因此在 `reviewerProvider: fork` 与 `reviewerProvider: spawn` 下抵达审查器的内容完全相同——同一请求下实测逐字节一致。关闭它的是 `agent/pre-step` 来源过滤,且在两种 provider 下都有效;**仅切换到 `spawn` 并不能阻止工作区指令进入审查器。** 另一方面,`fork` 会用委派会话已完成的回合为子会话播种:那段历史已经是子会话自己的日志,而不是进入某一步的消息,因此过滤无法触及,只有 `spawn` 能避免,两者之间由审查器提示词的“不可信记录”围栏作为缓解。在上述两次追踪中,播种并未产生额外消息,因此其实际影响尚未量化。
366
367
  - 审查器需要可用的 LLM 路由(默认继承);没有路由时,每次审查都会按 `fallbackPolicy` 回退 —— 绝不会静默放行。
367
368
  - `reviewerTools` 中的名称必须是 profile 中已存在的全局工具;未知名称会使审查器子代理在最早点大声失败并回退。
368
369
  - 风险规则按各自的 `field` 匹配请求的 `reason`、`toolName` 或脱敏后的调用 `arguments`;其他条件应放入 `toolsPolicy.overrides`。
@@ -421,7 +422,7 @@ pnpm pack # 发布产物
421
422
 
422
423
  ## PerryLink DSH Plugin Family
423
424
 
424
- 本项目是 [PerryLink](https://github.com/PerryLink) 维护的 DeepSeek Harness 插件家族成员:**33 个活跃维护**,名册共 **42** 个,其中 **6 个已冻结**、**3 个已退役**——每一个都在下表保留自己的行,原因见「状态」列。如果它能帮到你,其他的也会:
425
+ 本项目是 [PerryLink](https://github.com/PerryLink) 维护的 DeepSeek Harness 插件家族成员:**34 个活跃维护**,名册共 **42** 个,其中 **5 个已冻结**、**3 个已退役**——每一个都在下表保留自己的行,原因见「状态」列。如果它能帮到你,其他的也会:
425
426
 
426
427
  | Plugin | 一句话 | 状态 |
427
428
  |---|---|---|
@@ -449,7 +450,7 @@ pnpm pack # 发布产物
449
450
  | **[dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions)** | LSP diagnostics, formatting, completion, code actions and rename over language servers | |
450
451
  | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | PII masking middleware: anonymize at the model boundary, restore at the display layer | |
451
452
  | **[dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel)** | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors | |
452
- | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | 🧊 已冻结 — 见仓库 README |
453
+ | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | |
453
454
  | **[dsh-observe](https://github.com/PerryLink/dsh-observe)** | OpenTelemetry and Langfuse observability exporter for DeepSeek Harness. | |
454
455
  | **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | Claude Code outputStyles-equivalent runtime style switching | |
455
456
  | **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | Claude Code-style declarative allow/deny/ask permission rules with audit | |
package/README.md CHANGED
@@ -43,7 +43,7 @@ Second-model AI approval for DeepSeek Harness — a read-only reviewer subagent
43
43
 
44
44
  When an action crosses the sandbox boundary, a second model reads the evidence and returns a verdict with a reason — so humans approve nothing while nothing unsafe slips through.
45
45
 
46
- ![Terminal demo of dsh-auto-review: dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.png)
46
+ ![Terminal demo of dsh-auto-review: dsh-auto-review — standalone MCP path: deterministic deny, then cache replay](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-hero.png)
47
47
 
48
48
  ![Animated terminal demo of dsh-auto-review](https://raw.githubusercontent.com/PerryLink/dsh-auto-review/main/docs/assets/dsh-auto-review-demo.gif)
49
49
 
@@ -116,6 +116,7 @@ All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id
116
116
  | `toolsPolicy.overrides` | `{}` | Per-tool policy: `ai` / `human` / `never` |
117
117
  | `riskRules` | `[]` | `{pattern, policy, field?}` matched before the tool table; `field` selects `reason` (default), `toolName`, or `arguments` |
118
118
  | `reviewerProvider` | `fork` | Subagent provider for the reviewer (in-process fork backend) |
119
+ | `reviewerPreset` | *(none)* | Read-only Agent Preset id; required when the host exposes `startActivation` (0.2.1+) instead of `toolFilter` |
119
120
  | `reviewerModel` | *(inherit)* | Reviewer model id; unset inherits the session agent's route |
120
121
  | `reviewerTimeoutMs` | `60000` | Verdict deadline; on expiry the fallback policy applies |
121
122
  | `reviewerTools` | `[read, glob, grep]` | The reviewer child's tool allow-list (must be non-empty) |
@@ -145,7 +146,7 @@ Example (annotated full form: `fixtures/config/config-full.yaml`):
145
146
  toolsPolicy:
146
147
  overrides: { bash: ai, write: ai }
147
148
  riskRules:
148
- - pattern: '(?i)(rm\s+(-[a-z]+\s+)*/|git\s+push\s+--force)'
149
+ - pattern: '([Rr][Mm]\s+(-[a-z]+\s+)*/|[Gg][Ii][Tt]\s+push\s+--force)'
149
150
  policy: never
150
151
  - pattern: 'write'
151
152
  policy: never
@@ -356,7 +357,7 @@ The server is read-only and deterministic: no network, no model, no writes.
356
357
  - **The reviewer is a model.** Its verdicts are advisory policy, not a security kernel; prefer `human`/`never` rules for irreversible operations.
357
358
  - **Fail closed.** Every abnormal path (provider missing, capability gaps, start rejection, timeout, non-`completed` stop reason, missing/malformed verdict, audit-correlation failure) resolves through `fallbackPolicy`, default `rejected` — and the rejection feeds an auditable reason back to the model. `allow-once` grants unconditionally; it exists only for unattended deployments whose admin accepts that risk.
358
359
  - **Read-only reviewer.** The reviewer's `toolFilter` allow-list (`read`/`glob`/`grep`) cannot write, edit, run bash, fetch the network, or delegate (`maxDepth` = its own depth). Its session log is persisted and auditable.
359
- - **Context-isolated reviewer.** The reviewer child's steps are filtered on the documented `agent/pre-step` seam: only its own prompt and its own read-only tool results enter them. Workspace instruction files (`AGENTS.md` / `CLAUDE.md`), the harness runtime-context snapshot, and any context-injecting plugin are dropped before the loop appends them, so repository-controlled text never reaches the component that decides whether a call is allowed. This holds under EITHER subagent provider — those producers inject fresh into any new agent session, so the filter, not the provider choice, is what closes them. The filter is an allow-list over message SOURCES, so a plugin that declares a new source kind is dropped too.
360
+ - **Context-isolated reviewer.** The reviewer child's steps are filtered on the documented `agent/pre-step` seam: only its own prompt and its own read-only tool results enter them. Workspace instruction files (`AGENTS.md` / `CLAUDE.md`) and context-injecting plugins are dropped from the step this seam controls. **The host's own runtime-context snapshot is re-admitted by the loop after `agent/pre-step`; the firewall does not remove it, so the reviewer sees it.** This holds under EITHER subagent provider. The filter is an allow-list over message SOURCES, so a plugin that declares a new source kind is dropped too.
360
361
  - **Sensitive arguments are redacted** (key-name matching: `token`, `password`, `api_key`, `Authorization`, credentials, private keys …) before entering the reviewer prompt; the plugin never executes the reviewed arguments. Redaction is key-based, not content-based — do not AI-review tools whose argument values you cannot afford to show a model.
361
362
  - **Hard disables explain themselves.** A `never` tool or risk rule rejects deterministically AND records a log-only `autoReview/rejection` event, then injects a `[auto-review-never]` marker into the denied tool result — the model learns the action is hard-disabled instead of retrying it (invariant-checked: marker ⟺ event).
362
363
  - **Rejection circuit breaker.** A run of denials in one turn trips the breaker (`consecutiveDenies` / `windowDenies` inside `windowSize`), recorded as a log-only `autoReview/circuit` event; later requests follow its `action` (`delegate` / `reject` / `abort-turn`).
@@ -365,7 +366,7 @@ The server is read-only and deterministic: no network, no model, no writes.
365
366
 
366
367
  ## Known limitations
367
368
 
368
- - **Two different exposures, two different answers — neither substitutes for the other.** *Injected* context (workspace instruction files, the runtime-context snapshot, third-party plugin injections) is injected fresh into any new agent session, so it reaches the reviewer identically under `reviewerProvider: fork` and `reviewerProvider: spawn` — measured byte-identical across both on the same request. The `agent/pre-step` source filter is what closes it, under either provider; **`spawn` alone does NOT keep workspace instructions out of the reviewer.** Separately, `fork` seeds the child with the delegating session's completed turns: that history is already the child's own log rather than a message entering a step, so the filter cannot touch it and only `spawn` avoids it, with the reviewer prompt's untrusted-transcript fence as the mitigation in between. In the two traces above the seeding produced no additional messages, so its practical impact is unquantified.
369
+ - **Two different exposures, two different answers — neither substitutes for the other.** *Injected* context (workspace instruction files, third-party plugin injections) is injected fresh into any new agent session, so it reaches the reviewer identically under `reviewerProvider: fork` and `reviewerProvider: spawn`; the host runtime-context snapshot is re-admitted after the pre-step seam and is explicitly out of the firewall's claim — measured byte-identical across both on the same request. The `agent/pre-step` source filter closes the workspace/third-party half under either provider; it does **not** remove the host snapshot, which is re-admitted after the seam. **`spawn` alone does NOT keep workspace instructions out of the reviewer.** Separately, `fork` seeds the child with the delegating session's completed turns: that history is already the child's own log rather than a message entering a step, so the filter cannot touch it and only `spawn` avoids it, with the reviewer prompt's untrusted-transcript fence as the mitigation in between. In the two traces above the seeding produced no additional messages, so its practical impact is unquantified.
369
370
  - The reviewer needs a working LLM route (inherited by default); without one every review falls back per `fallbackPolicy` — never a silent grant.
370
371
  - `reviewerTools` names must exist as global tools in the profile; an unknown name fails the reviewer child loudly at the earliest point and falls back.
371
372
  - Risk rules match the request `reason`, the `toolName`, or the redacted call `arguments` per their `field`; other conditions belong in `toolsPolicy.overrides`.
@@ -424,7 +425,7 @@ Static evidence: `dsh-plugin-doctor` K10–K13 report `pass` for every check on
424
425
 
425
426
  ## PerryLink DSH Plugin Family
426
427
 
427
- This project is one of the **33 actively maintained** DeepSeek Harness plugins from [PerryLink](https://github.com/PerryLink) — the roster is **42**, of which **6** are frozen and **3** retired; every one keeps its row below, with the reason in the Status column. If this one helps you, the others likely will too:
428
+ This project is one of the **34 actively maintained** DeepSeek Harness plugins from [PerryLink](https://github.com/PerryLink) — the roster is **42**, of which **5** are frozen and **3** retired; every one keeps its row below, with the reason in the Status column. If this one helps you, the others likely will too:
428
429
 
429
430
  | Plugin | One-liner | Status |
430
431
  |---|---|---|
@@ -452,7 +453,7 @@ This project is one of the **33 actively maintained** DeepSeek Harness plugins f
452
453
  | **[dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions)** | LSP diagnostics, formatting, completion, code actions and rename over language servers | |
453
454
  | **[dsh-mask](https://github.com/PerryLink/dsh-mask)** | PII masking middleware: anonymize at the model boundary, restore at the display layer | |
454
455
  | **[dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel)** | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors | |
455
- | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | 🧊 FROZEN — see the repo README |
456
+ | **[dsh-memento](https://github.com/PerryLink/dsh-memento)** | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool | |
456
457
  | **[dsh-observe](https://github.com/PerryLink/dsh-observe)** | OpenTelemetry and Langfuse observability exporter for DeepSeek Harness. | |
457
458
  | **[dsh-output-styles](https://github.com/PerryLink/dsh-output-styles)** | Claude Code outputStyles-equivalent runtime style switching | |
458
459
  | **[dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules)** | Claude Code-style declarative allow/deny/ask permission rules with audit | |
package/cordis.patch.yml CHANGED
@@ -19,6 +19,8 @@
19
19
  overrides:
20
20
  bash: ai
21
21
  write: ai
22
+ pwsh: ai
23
+ powershell: ai
22
24
  # OPTIONAL invariant companion — uncomment and add to YOUR profile patch
23
25
  # layer only in compositions that provide the `invariants` service
24
26
  # (agent-spine apps such as headless/ACP). The plain web profile has no
package/lib/eval-cli.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as parseSuite, a as EvalEngine, i as writeReports, o as evalReviewConfig, r as renderTerminalSummary, t as exitCodeFor } from "./report-CGzPAnI6.js";
1
+ import { A as parseSuite, a as EvalEngine, i as writeReports, o as evalReviewConfig, r as renderTerminalSummary, t as exitCodeFor } from "./report-Df29db58.js";
2
2
  import { mkdir, readFile, readdir } from "node:fs/promises";
3
3
  import { dirname, isAbsolute, join, resolve } from "node:path";
4
4
  import { existsSync, readFileSync, statSync } from "node:fs";
@@ -46,6 +46,7 @@ z.object({
46
46
  field: FIELD.default("reason")
47
47
  })).default([]),
48
48
  reviewerProvider: z.string().default("fork"),
49
+ reviewerPreset: z.string(),
49
50
  reviewerModel: z.string(),
50
51
  reviewerTimeoutMs: z.number().default(6e4),
51
52
  reviewerTools: z.array(z.string()).default([
@@ -125,12 +126,12 @@ function resolveConfig(config = {}) {
125
126
  "grep"
126
127
  ];
127
128
  if (reviewerTools.length === 0) throw new TypeError("reviewerTools must name at least one tool: an empty allow-list would leave the reviewer with no tool face");
128
- const riskRules = (config.riskRules ?? []).map((rule) => {
129
+ const riskRules = (config.riskRules ?? []).map((rule, index) => {
129
130
  let regex;
130
131
  try {
131
132
  regex = new RegExp(rule.pattern, "u");
132
133
  } catch (error) {
133
- throw new TypeError(`risk rule pattern ${JSON.stringify(rule.pattern)} is not a valid regular expression: ${String(error)}`);
134
+ throw new TypeError(`riskRules[${index}]: pattern ${JSON.stringify(rule.pattern)} is not a valid regular expression: ${String(error)}`);
134
135
  }
135
136
  return {
136
137
  pattern: rule.pattern,
@@ -147,6 +148,7 @@ function resolveConfig(config = {}) {
147
148
  },
148
149
  riskRules,
149
150
  reviewerProvider: config.reviewerProvider ?? "fork",
151
+ reviewerPreset: config.reviewerPreset,
150
152
  reviewerModel: config.reviewerModel,
151
153
  reviewerTimeoutMs: config.reviewerTimeoutMs ?? 6e4,
152
154
  reviewerTools,
package/lib/eval.js CHANGED
@@ -1,2 +1,2 @@
1
- import { A as parseSuite, C as diffLines, D as renderToolCall, E as collectTrace, M as resolveCaseTimeout, O as DslError, S as percentile, T as renderSideBySide, _ as renderArgumentExpectation, a as EvalEngine, b as validateExpectations, c as resolvePromptBaselines, d as EVAL_VERDICT_SCHEMA, f as buildEvalReviewPrompt, g as deepContains, h as argumentsMatchRegexes, i as writeReports, j as resolveCaseModel, k as SuiteSchema, l as sessionHeaderLine, m as runEvalReview, n as renderMarkdownReport, o as evalReviewConfig, p as isEvalReviewFailure, r as renderTerminalSummary, s as renderSessionArtifact, t as exitCodeFor, u as summarizeCaseResult, v as runAssertions, w as hasChanges, x as computeStressMetrics, y as toolNameMatches } from "./report-CGzPAnI6.js";
1
+ import { A as parseSuite, C as diffLines, D as renderToolCall, E as collectTrace, M as resolveCaseTimeout, O as DslError, S as percentile, T as renderSideBySide, _ as renderArgumentExpectation, a as EvalEngine, b as validateExpectations, c as resolvePromptBaselines, d as EVAL_VERDICT_SCHEMA, f as buildEvalReviewPrompt, g as deepContains, h as argumentsMatchRegexes, i as writeReports, j as resolveCaseModel, k as SuiteSchema, l as sessionHeaderLine, m as runEvalReview, n as renderMarkdownReport, o as evalReviewConfig, p as isEvalReviewFailure, r as renderTerminalSummary, s as renderSessionArtifact, t as exitCodeFor, u as summarizeCaseResult, v as runAssertions, w as hasChanges, x as computeStressMetrics, y as toolNameMatches } from "./report-Df29db58.js";
2
2
  export { DslError, EVAL_VERDICT_SCHEMA, EvalEngine, SuiteSchema, argumentsMatchRegexes, buildEvalReviewPrompt, collectTrace, computeStressMetrics, deepContains, diffLines, evalReviewConfig, exitCodeFor, hasChanges, isEvalReviewFailure, parseSuite, percentile, renderArgumentExpectation, renderMarkdownReport, renderSessionArtifact, renderSideBySide, renderTerminalSummary, renderToolCall, resolveCaseModel, resolveCaseTimeout, resolvePromptBaselines, runAssertions, runEvalReview, sessionHeaderLine, summarizeCaseResult, toolNameMatches, validateExpectations, writeReports };
package/lib/index.js CHANGED
@@ -353,6 +353,7 @@ const Config = z.object({
353
353
  field: FIELD.default("reason")
354
354
  })).default([]),
355
355
  reviewerProvider: z.string().default("fork"),
356
+ reviewerPreset: z.string(),
356
357
  reviewerModel: z.string(),
357
358
  reviewerTimeoutMs: z.number().default(6e4),
358
359
  reviewerTools: z.array(z.string()).default([
@@ -449,12 +450,12 @@ function resolveConfig(config = {}) {
449
450
  "grep"
450
451
  ];
451
452
  if (reviewerTools.length === 0) throw new TypeError("reviewerTools must name at least one tool: an empty allow-list would leave the reviewer with no tool face");
452
- const riskRules = (config.riskRules ?? []).map((rule) => {
453
+ const riskRules = (config.riskRules ?? []).map((rule, index) => {
453
454
  let regex;
454
455
  try {
455
456
  regex = new RegExp(rule.pattern, "u");
456
457
  } catch (error) {
457
- throw new TypeError(`risk rule pattern ${JSON.stringify(rule.pattern)} is not a valid regular expression: ${String(error)}`);
458
+ throw new TypeError(`riskRules[${index}]: pattern ${JSON.stringify(rule.pattern)} is not a valid regular expression: ${String(error)}`);
458
459
  }
459
460
  return {
460
461
  pattern: rule.pattern,
@@ -471,6 +472,7 @@ function resolveConfig(config = {}) {
471
472
  },
472
473
  riskRules,
473
474
  reviewerProvider: config.reviewerProvider ?? "fork",
475
+ reviewerPreset: config.reviewerPreset,
474
476
  reviewerModel: config.reviewerModel,
475
477
  reviewerTimeoutMs: config.reviewerTimeoutMs ?? 6e4,
476
478
  reviewerTools,
@@ -512,10 +514,10 @@ function resolveConfig(config = {}) {
512
514
  * - `tool` — the results of the read-only tools the reviewer called; dropping
513
515
  * these would blind the reviewer to its own `read`/`glob`/`grep` output.
514
516
  *
515
- * Everything else is injected context: `plugin` covers the loop's
516
- * runtime-context snapshot and third-party injections, and out-of-repo
517
- * producers (the workspace instruction loader among them) declare their own
518
- * merge-extended `kind`. All of it is dropped.
517
+ * Everything else is injected context: `plugin` covers third-party injections,
518
+ * and out-of-repo producers (the workspace instruction loader among them)
519
+ * declare their own merge-extended `kind`. The loop's runtime-context snapshot
520
+ * is re-admitted after this seam and is NOT removed here.
519
521
  */
520
522
  const REVIEWER_MESSAGE_SOURCES = /* @__PURE__ */ new Set(["user", "tool"]);
521
523
  /**
@@ -6433,18 +6435,40 @@ async function runReview(ctx, config, request, reviewerSessions, override) {
6433
6435
  ...model !== void 0 ? { model } : {}
6434
6436
  });
6435
6437
  try {
6436
- run = await ctx.subagents.start(provider, {
6437
- label: `auto-review: ${request.toolName}`,
6438
- prompt,
6439
- parent: request.agent,
6440
- signal: controller.signal,
6441
- toolFilter: { allow: config.reviewerTools },
6442
- outputSchema: VERDICT_SCHEMA,
6443
- maxDepth: (request.agent.session.header.delegationDepth ?? 0) + 1,
6444
- ...config.reviewerModel !== void 0 ? { agentOptions: { model: config.reviewerModel } } : {}
6445
- });
6446
- reviewerSessionId = run.id;
6447
- reviewerSessions.add(run.id);
6438
+ const activationService = ctx.subagents;
6439
+ if (typeof activationService.startActivation === "function") {
6440
+ if (config.reviewerPreset === void 0) return failure("unavailable", "this host uses subagents.startActivation; set reviewerPreset to a read-only Agent Preset (reviewerProvider fork cannot scope tools here)");
6441
+ const activation = await activationService.startActivation({
6442
+ provider,
6443
+ label: `auto-review: ${request.toolName}`,
6444
+ request: {
6445
+ prompt,
6446
+ parent: request.agent,
6447
+ outputSchema: VERDICT_SCHEMA,
6448
+ maxDepth: (request.agent.session.header.delegationDepth ?? 0) + 1,
6449
+ agentPreset: config.reviewerPreset,
6450
+ ...config.reviewerModel !== void 0 ? { agentOptions: { model: config.reviewerModel } } : {}
6451
+ },
6452
+ signal: controller.signal,
6453
+ delivery: "caller"
6454
+ });
6455
+ run = activation;
6456
+ reviewerSessionId = activation.childId;
6457
+ } else {
6458
+ run = await ctx.subagents.start(provider, {
6459
+ label: `auto-review: ${request.toolName}`,
6460
+ prompt,
6461
+ parent: request.agent,
6462
+ signal: controller.signal,
6463
+ toolFilter: { allow: config.reviewerTools },
6464
+ outputSchema: VERDICT_SCHEMA,
6465
+ maxDepth: (request.agent.session.header.delegationDepth ?? 0) + 1,
6466
+ ...config.reviewerModel !== void 0 ? { agentOptions: { model: config.reviewerModel } } : {}
6467
+ });
6468
+ reviewerSessionId = run.id;
6469
+ }
6470
+ if (run === void 0 || reviewerSessionId === void 0) return failure("unavailable", "reviewer did not publish a session id");
6471
+ reviewerSessions.add(reviewerSessionId);
6448
6472
  model = config.reviewerModel;
6449
6473
  const result = await run.result;
6450
6474
  if (timedOut) return failure("timeout", `reviewer exceeded ${config.reviewerTimeoutMs} ms`);
package/lib/mcp.js CHANGED
@@ -229,6 +229,7 @@ z.object({
229
229
  field: FIELD.default("reason")
230
230
  })).default([]),
231
231
  reviewerProvider: z.string().default("fork"),
232
+ reviewerPreset: z.string(),
232
233
  reviewerModel: z.string(),
233
234
  reviewerTimeoutMs: z.number().default(6e4),
234
235
  reviewerTools: z.array(z.string()).default([
@@ -308,12 +309,12 @@ function resolveConfig(config = {}) {
308
309
  "grep"
309
310
  ];
310
311
  if (reviewerTools.length === 0) throw new TypeError("reviewerTools must name at least one tool: an empty allow-list would leave the reviewer with no tool face");
311
- const riskRules = (config.riskRules ?? []).map((rule) => {
312
+ const riskRules = (config.riskRules ?? []).map((rule, index) => {
312
313
  let regex;
313
314
  try {
314
315
  regex = new RegExp(rule.pattern, "u");
315
316
  } catch (error) {
316
- throw new TypeError(`risk rule pattern ${JSON.stringify(rule.pattern)} is not a valid regular expression: ${String(error)}`);
317
+ throw new TypeError(`riskRules[${index}]: pattern ${JSON.stringify(rule.pattern)} is not a valid regular expression: ${String(error)}`);
317
318
  }
318
319
  return {
319
320
  pattern: rule.pattern,
@@ -330,6 +331,7 @@ function resolveConfig(config = {}) {
330
331
  },
331
332
  riskRules,
332
333
  reviewerProvider: config.reviewerProvider ?? "fork",
334
+ reviewerPreset: config.reviewerPreset,
333
335
  reviewerModel: config.reviewerModel,
334
336
  reviewerTimeoutMs: config.reviewerTimeoutMs ?? 6e4,
335
337
  reviewerTools,
@@ -13283,17 +13283,39 @@ async function runEvalReview(ctx, config, parent, caze, trace, signal) {
13283
13283
  ...reviewerModel !== void 0 ? { model: reviewerModel } : {}
13284
13284
  });
13285
13285
  try {
13286
- run = await ctx.subagents.start(provider, {
13287
- label: `eval-review: ${caze.id}`,
13288
- prompt,
13289
- parent,
13290
- signal: controller.signal,
13291
- toolFilter: { allow: config.reviewerTools },
13292
- outputSchema: EVAL_VERDICT_SCHEMA,
13293
- maxDepth: (parent.session.header.delegationDepth ?? 0) + 1,
13294
- ...reviewerModel !== void 0 ? { agentOptions: { model: reviewerModel } } : {}
13295
- });
13296
- reviewerSessionId = run.id;
13286
+ const activationService = ctx.subagents;
13287
+ if (typeof activationService.startActivation === "function") {
13288
+ if (config.reviewerPreset === void 0) return failure("unavailable", "this host uses subagents.startActivation; set reviewerPreset to a read-only Agent Preset");
13289
+ const activation = await activationService.startActivation({
13290
+ provider,
13291
+ label: `eval-review: ${caze.id}`,
13292
+ request: {
13293
+ prompt,
13294
+ parent,
13295
+ outputSchema: EVAL_VERDICT_SCHEMA,
13296
+ maxDepth: (parent.session.header.delegationDepth ?? 0) + 1,
13297
+ agentPreset: config.reviewerPreset,
13298
+ ...reviewerModel !== void 0 ? { agentOptions: { model: reviewerModel } } : {}
13299
+ },
13300
+ signal: controller.signal,
13301
+ delivery: "caller"
13302
+ });
13303
+ run = activation;
13304
+ reviewerSessionId = activation.childId;
13305
+ } else {
13306
+ run = await ctx.subagents.start(provider, {
13307
+ label: `eval-review: ${caze.id}`,
13308
+ prompt,
13309
+ parent,
13310
+ signal: controller.signal,
13311
+ toolFilter: { allow: config.reviewerTools },
13312
+ outputSchema: EVAL_VERDICT_SCHEMA,
13313
+ maxDepth: (parent.session.header.delegationDepth ?? 0) + 1,
13314
+ ...reviewerModel !== void 0 ? { agentOptions: { model: reviewerModel } } : {}
13315
+ });
13316
+ reviewerSessionId = run.id;
13317
+ }
13318
+ if (run === void 0 || reviewerSessionId === void 0) return failure("unavailable", "reviewer did not publish a session id");
13297
13319
  const result = await run.result;
13298
13320
  if (timedOut) return failure("timeout", `reviewer exceeded ${config.reviewerTimeoutMs} ms`);
13299
13321
  if (signal.aborted) return failure("cancelled", "the eval run was cancelled while the reviewer ran");
@@ -13351,6 +13373,7 @@ function evalReviewConfig(config) {
13351
13373
  reviewerProvider: config.reviewerProvider,
13352
13374
  reviewerModel: config.reviewerModel,
13353
13375
  reviewerTimeoutMs: config.reviewerTimeoutMs,
13376
+ reviewerPreset: config.reviewerPreset,
13354
13377
  reviewerTools: config.reviewerTools
13355
13378
  };
13356
13379
  }
@@ -122,6 +122,8 @@ export interface Config {
122
122
  riskRules?: RiskRuleConfig[];
123
123
  /** Subagent provider name for the reviewer (default `fork`, the in-process fork backend). */
124
124
  reviewerProvider?: string;
125
+ /** Reviewer Agent Preset id; required when the host only exposes startActivation. */
126
+ reviewerPreset?: string;
125
127
  /** Reviewer model id; when unset the reviewer inherits the session agent's route. */
126
128
  reviewerModel?: string;
127
129
  /** Verdict deadline in milliseconds. Default 60000. */
@@ -195,6 +197,7 @@ export interface ResolvedConfig {
195
197
  readonly toolsPolicy: ToolsPolicyConfig;
196
198
  readonly riskRules: readonly ResolvedRiskRule[];
197
199
  readonly reviewerProvider: string;
200
+ readonly reviewerPreset?: string | undefined;
198
201
  readonly reviewerModel: string | undefined;
199
202
  readonly reviewerTimeoutMs: number;
200
203
  readonly reviewerTools: readonly string[];