dsh-auto-review 0.4.0
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 +91 -0
- package/LICENSE +201 -0
- package/README.es.md +226 -0
- package/README.hi.md +226 -0
- package/README.md +226 -0
- package/README.pt.md +226 -0
- package/README.zh.md +226 -0
- package/cordis.patch.yml +27 -0
- package/lib/client.js +494 -0
- package/lib/client.js.map +1 -0
- package/lib/events-CFl6CHZi.js +344 -0
- package/lib/index.js +5305 -0
- package/lib/invariant.js +223 -0
- package/lib/types/client/ReviewPanel.d.ts +29 -0
- package/lib/types/client/ReviewPanel.d.ts.map +1 -0
- package/lib/types/client/ReviewPanel.js +63 -0
- package/lib/types/client/ReviewPanel.js.map +1 -0
- package/lib/types/client/index.d.ts +31 -0
- package/lib/types/client/index.d.ts.map +1 -0
- package/lib/types/client/index.js +51 -0
- package/lib/types/client/index.js.map +1 -0
- package/lib/types/client/locales.d.ts +49 -0
- package/lib/types/client/locales.d.ts.map +1 -0
- package/lib/types/client/locales.js +82 -0
- package/lib/types/client/locales.js.map +1 -0
- package/lib/types/client/present.d.ts +25 -0
- package/lib/types/client/present.d.ts.map +1 -0
- package/lib/types/client/present.js +36 -0
- package/lib/types/client/present.js.map +1 -0
- package/lib/types/client/styles.d.ts +9 -0
- package/lib/types/client/styles.d.ts.map +1 -0
- package/lib/types/client/styles.js +130 -0
- package/lib/types/client/styles.js.map +1 -0
- package/lib/types/config.d.ts +200 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/config.js +154 -0
- package/lib/types/config.js.map +1 -0
- package/lib/types/events.d.ts +347 -0
- package/lib/types/events.d.ts.map +1 -0
- package/lib/types/events.js +369 -0
- package/lib/types/events.js.map +1 -0
- package/lib/types/index.d.ts +26 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +26 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/invariant.d.ts +28 -0
- package/lib/types/invariant.d.ts.map +1 -0
- package/lib/types/invariant.js +306 -0
- package/lib/types/invariant.js.map +1 -0
- package/lib/types/messages.d.ts +38 -0
- package/lib/types/messages.d.ts.map +1 -0
- package/lib/types/messages.js +65 -0
- package/lib/types/messages.js.map +1 -0
- package/lib/types/projection-types.d.ts +61 -0
- package/lib/types/projection-types.d.ts.map +1 -0
- package/lib/types/projection-types.js +8 -0
- package/lib/types/projection-types.js.map +1 -0
- package/lib/types/projection.d.ts +93 -0
- package/lib/types/projection.d.ts.map +1 -0
- package/lib/types/projection.js +197 -0
- package/lib/types/projection.js.map +1 -0
- package/lib/types/review.d.ts +141 -0
- package/lib/types/review.d.ts.map +1 -0
- package/lib/types/review.js +389 -0
- package/lib/types/review.js.map +1 -0
- package/lib/types/runtime.d.ts +160 -0
- package/lib/types/runtime.d.ts.map +1 -0
- package/lib/types/runtime.js +486 -0
- package/lib/types/runtime.js.map +1 -0
- package/package.json +132 -0
- package/src/client/ReviewPanel.tsx +164 -0
- package/src/client/index.ts +72 -0
- package/src/client/locales.ts +87 -0
- package/src/client/present.ts +58 -0
- package/src/client/styles.ts +131 -0
- package/src/config.ts +346 -0
- package/src/events.ts +553 -0
- package/src/index.ts +28 -0
- package/src/invariant.ts +326 -0
- package/src/messages.ts +91 -0
- package/src/projection-types.ts +61 -0
- package/src/projection.ts +224 -0
- package/src/review.ts +428 -0
- package/src/runtime.ts +562 -0
package/README.pt.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
<!-- links de idioma -->
|
|
2
|
+
[English](README.md) · [中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
|
|
3
|
+
|
|
4
|
+
<div align="center">
|
|
5
|
+
|
|
6
|
+
# 🤖 dsh-auto-review
|
|
7
|
+
|
|
8
|
+
**Aprovação automática por segundo modelo para o DeepSeek Harness** — o padrão `approvals_reviewer=auto_review` do Codex / *auto mode* do Claude Code, implementado como um plugin Cordis puro.
|
|
9
|
+
|
|
10
|
+
Quando uma ação do agente cruza o limite do sandbox, um **subagente revisor somente leitura** decide allow/deny — com um motivo — para que humanos não aprovem nada enquanto nada inseguro passa despercebido.
|
|
11
|
+
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://www.npmjs.com/package/@deepseek-ai/dsh)
|
|
14
|
+
[](.github/workflows/ci.yml)
|
|
15
|
+
[](src)
|
|
16
|
+
[](cordis.patch.yml)
|
|
17
|
+
[](https://github.com/PerryLink/dsh-auto-review)
|
|
18
|
+
|
|
19
|
+
**Zero operações humanas.** A solicitação vai ao revisor de IA, o veredicto é allow/deny + motivo + nível de risco, e toda decisão pode ser reconstruída a partir do log da sessão: `approval/asked` → `autoReview/verdict` (ou `autoReview/rejection` para desativações duras) → `approval/decided`.
|
|
20
|
+
|
|
21
|
+
<img src="docs/demo-auto-review.gif" alt="demo do dsh-auto-review" width="720"/>
|
|
22
|
+
|
|
23
|
+
*Uma execução real de evidência (servidor real, chave de API real, duas rodadas de modelo reais): o revisor de IA **permite** uma escrita escalada dentro do workspace (risco baixo, 5,2 s) e depois **nega** uma exclusão recursiva fora do workspace (risco alto, 8,9 s) — o motivo da negação é devolvido ao modelo, visível na transcrição.*
|
|
24
|
+
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
## Por que um segundo modelo em vez de regras?
|
|
28
|
+
|
|
29
|
+
Aprovadores automáticos baseados em padrões decidem antes do despacho, sem evidência. O `dsh-auto-review` entrega a decisão a um **subagente revisor** que lê o workspace real (com sua face de ferramentas somente leitura), os argumentos da chamada já apresentados (valores sensíveis redigidos), o motivo da solicitação e suas regras de risco — e devolve um veredicto estruturado. Um veredicto de negação devolve seu **motivo ao modelo chamador**, para que o agente aprenda o porquê em vez de tentar de novo às cegas.
|
|
30
|
+
|
|
31
|
+
## ✨ Recursos
|
|
32
|
+
|
|
33
|
+
| | |
|
|
34
|
+
|---|---|
|
|
35
|
+
| 🔌 **Seam oficial** | Um answerer no waterfall `approval/request`. Solicitações que não são dele são delegadas via `next()` — o fluxo de aprovação humana nunca é interrompido. |
|
|
36
|
+
| 🧠 **Veredicto de segundo modelo** | Subagente fork de uso único com lista de permissões somente leitura (`read`/`glob`/`grep`) e schema de veredicto estruturado `{ decision, reason, riskLevel }`. |
|
|
37
|
+
| 🛡️ **Fail closed** | Falha, timeout ou schema inválido do revisor nunca abre a porta: aplica-se `fallbackPolicy`, padrão `rejected`. |
|
|
38
|
+
| 🧩 **Roteamento por configuração** | Políticas por ferramenta (`ai`/`human`/`never`) + regras de risco com regex, tudo alterável pelo cordis.yml. |
|
|
39
|
+
| 💬 **Motivos de negação chegam ao modelo** | O motivo do revisor é injetado no resultado da ferramenta negada (vinculado por callId), para o agente se adaptar. Rejeições do fallback fail-closed e desativações duras da política `never` também injetam textos auditáveis (marcadores `[auto-review]` / `[auto-review-fallback]` / `[auto-review-never]`). |
|
|
40
|
+
| 📜 **Trilha de auditoria completa** | Eventos de sessão `autoReview/verdict` + `autoReview/rejection` (identidade do revisor, veredicto, motivo, risco, duração) + um companion de invariantes que exige *model-visible ⟺ logged*. |
|
|
41
|
+
| 🔁 **Sem recursão** | Solicitações do próprio revisor são reconhecidas por identidade e delegadas; `maxDepth` + a lista de permissões mantêm o revisor sem delegar. |
|
|
42
|
+
| 🧯 **Disjuntor de rejeição** | 3 negações consecutivas (ou 6 dentro dos últimos 10 veredictos) em um turno disparam o disjuntor: solicitações posteriores delegam, rejeitam ou abortam o turno — sem laços infinitos de negação. |
|
|
43
|
+
| 🎚️ **Política por nível de risco** | Um veredicto `allow` cujo risco excede `riskPolicy.maxAutoAllow` nunca resolve a solicitação: ele delega a um humano ou nega. |
|
|
44
|
+
| ✋ **Sobrescrita humana de uso único** | `/auto-review approve [n]` autoriza UMA nova tentativa de uma negação recente; a próxima revisão da mesma ferramenta carrega essa autorização como contexto do revisor (o revisor ainda decide). |
|
|
45
|
+
| 📜 **Contexto do revisor** | Transcrição compacta opcional (mensagens recentes e resultados de ferramentas, limitada) + uma política de decisão `reviewerPolicyText` em Markdown estilo Codex. |
|
|
46
|
+
| ⌨️ **Comando de sessão** | `/auto-review on|off|status|approve [n]` com uma sobrescrita durável por sessão que sobrevive à restauração e estatísticas cumulativas da sessão. |
|
|
47
|
+
| 🖥️ **Painel de revisão web** | Um painel no cabeçalho da sessão (GUI web) mostra o interruptor (com botões liga/desliga), ambos os orçamentos por turno, estatísticas cumulativas, o disparo do disjuntor, veredictos recentes e botões de aprovação de uso único — impulsionado pela projeção de sessão `autoReview`. |
|
|
48
|
+
|
|
49
|
+
## Como funciona
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
waterfall approval/request (cadeia de answerers)
|
|
53
|
+
│
|
|
54
|
+
┌───────────────────────┴──────────────────────┐
|
|
55
|
+
│ answerer dsh-auto-review │
|
|
56
|
+
│ · sessão ativada? · política = ai? │ não ── next() ──▶ answerer humano (UI)
|
|
57
|
+
│ · regras de risco → toolsPolicy → padrão │
|
|
58
|
+
└───────────────────────┬──────────────────────┘
|
|
59
|
+
│ sim
|
|
60
|
+
▼
|
|
61
|
+
┌───────────────────────────────────┐
|
|
62
|
+
│ subagente revisor (fork, uso único)│
|
|
63
|
+
│ · toolFilter: read/glob/grep │
|
|
64
|
+
│ · outputSchema: {decision, │
|
|
65
|
+
│ reason, riskLevel} │
|
|
66
|
+
│ · timeout + abort de req.signal │
|
|
67
|
+
└───────────────┬───────────────────┘
|
|
68
|
+
│ veredicto / falha (fallback fail-closed)
|
|
69
|
+
▼
|
|
70
|
+
allow → allowed-once deny → rejected + motivo injetado no
|
|
71
|
+
resultado da ferramenta negada
|
|
72
|
+
│ never → rejected + feedback [auto-review-never]
|
|
73
|
+
│ (desativação dura, sem revisor)
|
|
74
|
+
▼
|
|
75
|
+
auditoria: approval/asked → autoReview/verdict | autoReview/rejection
|
|
76
|
+
→ approval/decided (eventos de sessão, log-only, verificados por invariantes)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Ordem de composição.** O respondente executa na sua posição de registro no waterfall: se um respondente humano da UI estiver composto ANTES da linha `auto-review`, humanos respondem primeiro e o revisor só vê o que é delegado rio abaixo. Verifique com `dsh --profile <name> --dump-config` e coloque a linha `auto-review` antes das linhas de respondentes humanos quando quiser que ferramentas de política ai sejam roteadas primeiro ao revisor.
|
|
80
|
+
|
|
81
|
+
## 🚀 Início rápido
|
|
82
|
+
|
|
83
|
+
Quatro canais de instalação; o plugin é um **bundle** (`"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`).
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
# 1. npm (artefato publicado, sem etapa de build)
|
|
87
|
+
dsh plugin --profile web add dsh-auto-review
|
|
88
|
+
dsh --profile web # reiniciar
|
|
89
|
+
|
|
90
|
+
# 2. tarball npm (artefatos compilados, instalação offline)
|
|
91
|
+
pnpm pack # → dsh-auto-review-<version>.tgz
|
|
92
|
+
dsh plugin --profile web add ./dsh-auto-review-<version>.tgz
|
|
93
|
+
dsh --profile web # reiniciar
|
|
94
|
+
|
|
95
|
+
# 3. fonte git (fixe o commit; o `prepare` autocontido compila)
|
|
96
|
+
# pnpm ≥ 10 bloqueia builds de ciclo de vida: adicione primeiro a chave
|
|
97
|
+
# allowBuilds impressa ao pnpm-workspace.yaml do perfil.
|
|
98
|
+
dsh plugin --profile web add "github:PerryLink/dsh-auto-review#<commit>"
|
|
99
|
+
|
|
100
|
+
# 4. link local (desenvolvimento)
|
|
101
|
+
dsh plugin --profile web add link:/path/to/dsh-auto-review
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Verifique:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
dsh --profile web --dump-config | grep -A4 'id: auto-review'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
De fábrica, o patch enviado submete `bash` e `write` à revisão de IA; todas as demais ferramentas (incluindo `edit` — modificação no local) são delegadas à cadeia humana. Adicione `edit: ai` explicitamente se você aceitar edições no local sem um humano no circuito.
|
|
111
|
+
|
|
112
|
+
## ⚙️ Configuração
|
|
113
|
+
|
|
114
|
+
Todos os ajustes são campos `Config` de Schemastery (alteráveis pelo cordis.yml). Uma sobrescrita direcionada por `id` **substitui a linha de config inteira** — repita toda chave de que precisar.
|
|
115
|
+
|
|
116
|
+
| Chave | Padrão | Significado |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `enableByDefault` | `true` | As sessões iniciam com auto-review ativado; `/auto-review on\|off` grava uma sobrescrita durável com prioridade |
|
|
119
|
+
| `toolsPolicy.default` | `human` | Política para ferramentas não listadas (delegar ao answerer humano) |
|
|
120
|
+
| `toolsPolicy.overrides` | `{}` | Política por ferramenta: `ai` (o revisor decide), `human` (forçar humano), `never` (rejeição determinística) |
|
|
121
|
+
| `riskRules` | `[]` | `{pattern, policy, field?}` casado (primeira ocorrência vence) antes da tabela de ferramentas; `field` seleciona `reason` (padrão), `toolName` ou `arguments` (os argumentos de chamada apresentados redigidos) |
|
|
122
|
+
| `reviewerProvider` | `fork` | Provider de subagente do revisor (backend fork em processo) |
|
|
123
|
+
| `reviewerModel` | *(herdar)* | Id do modelo do revisor; sem valor herda a rota do agente da sessão |
|
|
124
|
+
| `reviewerTimeoutMs` | `60000` | Prazo do veredicto; ao expirar aplica-se a política de fallback |
|
|
125
|
+
| `reviewerTools` | `[read, glob, grep]` | Lista de permissões de ferramentas do filho revisor (deve ser não vazia) — todo o resto é invisível lá |
|
|
126
|
+
| `fallbackPolicy` | `rejected` | Falha do revisor: `rejected` (fail closed), `delegate` (continua a cadeia), `allow-once` (concede — ver Segurança). Renomeado de `allow-readonly` na 0.2.0; a grafia antiga falha em voz alta |
|
|
127
|
+
| `maxReviewsPerTurn` | `10` | Orçamento real de veredictos de IA por turno aberto; esgotado, delega-se a humanos |
|
|
128
|
+
| `maxFailuresPerTurn` | `10` | Orçamento de falhas do revisor por turno aberto (timeout/indisponível/schema, não cancelamentos); esgotado, as solicitações são delegadas em vez de pagar outro timeout completo. O padrão é `maxReviewsPerTurn` |
|
|
129
|
+
| `reasonMaxChars` | `2000` | Limite para motivos do revisor, o motivo da solicitação e a prévia de argumentos redigida |
|
|
130
|
+
| `reviewerGuidance` | *(nenhuma)* | Orientação opcional anexada ao prompt do revisor (consultiva, não regra rígida) |
|
|
131
|
+
| `reviewerPolicyText` | *(nenhuma)* | Política de decisão em Markdown injetada no prompt do revisor (estilo Codex; modelo em `fixtures/config/policy-template.md`) |
|
|
132
|
+
| `denyGuidance` | *(texto anti-burla)* | Orientação anexada a todo motivo de negação injetado |
|
|
133
|
+
| `contextBudget` | `{turns: 0, maxChars: 4000}` | Orçamento de transcrição compacta para o prompt do revisor; `turns: 0` desativa |
|
|
134
|
+
| `riskPolicy` | `{maxAutoAllow: high, onHighRisk: delegate}` | Veredictos `allow` acima de `maxAutoAllow` delegam (`delegate`) ou negam (`deny`) |
|
|
135
|
+
| `circuitBreaker` | `{consecutiveDenies: 3, windowDenies: 6, windowSize: 10, action: delegate}` | Disjuntor de rejeição; dispara com 3 negações consecutivas ou 6 dos últimos 10 veredictos do turno; `action`: `delegate` / `reject` / `abort-turn` |
|
|
136
|
+
| `overrideTtlMs` | `300000` | Por quanto tempo uma sobrescrita de `/auto-review approve` permanece utilizável |
|
|
137
|
+
| `language` | `en` | Idioma da interface da saída do comando `/auto-review` (`en` \| `zh`) |
|
|
138
|
+
|
|
139
|
+
Exemplo (forma completa comentada: `fixtures/config/config-full.yaml`):
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
- insert:
|
|
143
|
+
- id: auto-review
|
|
144
|
+
name: dsh-auto-review
|
|
145
|
+
config:
|
|
146
|
+
toolsPolicy:
|
|
147
|
+
overrides: { bash: ai, write: ai }
|
|
148
|
+
riskRules:
|
|
149
|
+
- pattern: '(?i)(rm\s+(-[a-z]+\s+)*/|git\s+push\s+--force)'
|
|
150
|
+
policy: never
|
|
151
|
+
- pattern: 'write'
|
|
152
|
+
policy: never
|
|
153
|
+
field: toolName
|
|
154
|
+
reviewerTimeoutMs: 30000
|
|
155
|
+
fallbackPolicy: delegate
|
|
156
|
+
riskPolicy: { maxAutoAllow: medium, onHighRisk: delegate }
|
|
157
|
+
circuitBreaker: { consecutiveDenies: 3, windowDenies: 6, windowSize: 10, action: delegate }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## ⌨️ Comando de sessão
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
/auto-review on|off|status|approve [n]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`on`/`off` anexam a sobrescrita durável `autoReview/state` (o fold sobrevive a reinícios/restauração — a reprodução É o estado) e injetam um aviso de troca visível ao modelo (registrado como evento `user/message`). `status` mostra o estado efetivo, ambos os orçamentos por turno (veredictos de IA e falhas do revisor), um disjuntor disparado quando houver um ativo no turno e as estatísticas cumulativas da sessão (permissões/negações/fallbacks/desativações duras, duração média, veredictos recentes). `approve [n]` registra uma `autoReview/override` de uso único para a n-ésima negação mais recente (1 = a mais recente): a próxima revisão da mesma ferramenta dentro de `overrideTtlMs` carrega a autorização como contexto do revisor — o revisor ainda decide, e a sobrescrita é consumida por essa revisão independentemente de seu resultado.
|
|
167
|
+
|
|
168
|
+
## 🖥️ Painel de revisão web
|
|
169
|
+
|
|
170
|
+
Na GUI web (perfil web), o pacote contribui uma ação no cabeçalho da sessão (**AI Review**) que abre um painel com o estado da auto-revisão da sessão: o interruptor com botões liga/desliga (executam `/auto-review on|off`), ambos os orçamentos por turno, estatísticas cumulativas (incluindo desativações duras), o disparo do disjuntor, os veredictos recentes e botões de **aprovação** de uso único para negações recentes (executam `/auto-review approve [n]`).
|
|
171
|
+
|
|
172
|
+
Como é ligado:
|
|
173
|
+
|
|
174
|
+
- O host registra uma **projeção de sessão** `autoReview` (dobrada a partir dos eventos log-only `autoReview/*`) e a serve pelo canal de projeção de sessão.
|
|
175
|
+
- A metade navegador é um **módulo cliente** (auto-descoberto pela declaração `dsh.client`) registrado no assento `conversation.session.header.actions`.
|
|
176
|
+
- Nenhuma linha de patch adicional é necessária: o painel carrega sempre que o plugin estiver instalado em um perfil cuja compilação web oferece a capacidade de projeção de sessão (o perfil web oferece). Sem essa capacidade o painel se declara indisponível; o respondente não é afetado.
|
|
177
|
+
|
|
178
|
+
O painel lê apenas valores de projeção completos — nunca recebe o fluxo bruto de eventos de sessão.
|
|
179
|
+
|
|
180
|
+
## 🔒 Segurança
|
|
181
|
+
|
|
182
|
+
- O revisor roda com uma **face de ferramentas somente leitura** (lista de permissões `toolFilter`). Ele não pode escrever, editar, executar shell, acessar a rede nem delegar (`maxDepth` = sua própria profundidade). Seu log de sessão persiste e é auditável.
|
|
183
|
+
- **Argumentos sensíveis são redigidos** (casamento 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 é por chave, não por conteúdo — não submeta à revisão de IA ferramentas cujos valores você não possa mostrar a um modelo.
|
|
184
|
+
- **Fail closed por padrão.** Todo caminho anômalo (provider ausente, lacunas de capacidade, início rejeitado, timeout, stopReason não `completed`, veredicto ausente/malformado, falha de correlação de auditoria) resolve-se pela `fallbackPolicy`, padrão `rejected` — e a rejeição devolve um motivo auditável ao modelo em vez do texto genérico "user rejected". `allow-once` concede incondicionalmente — existe apenas para implantações não assistidas cujo administrador aceita esse risco.
|
|
185
|
+
- **Desativações duras se explicam sozinhas.** Uma ferramenta ou regra de risco `never` rejeita de forma determinística E registra um evento log-only `autoReview/rejection` com a regra/entrada que casou, e injeta um texto com o marcador `[auto-review-never]` no resultado da ferramenta negada — o modelo aprende que a ação está desativada em vez de tentá-la de novo (verificado por invariantes: marcador ⟺ evento).
|
|
186
|
+
- **Disjuntor de rejeição.** Uma sequência de negações em um turno dispara o disjuntor (`consecutiveDenies` / `windowDenies` dentro de `windowSize`), registrado como evento log-only `autoReview/circuit`; solicitações posteriores seguem sua `action` (`delegate` / `reject` / `abort-turn`). `abort-turn` injeta um aviso visível ao modelo e cancela o agente.
|
|
187
|
+
- **O contexto do revisor é transcrição já apresentada.** `contextBudget` alimenta o revisor com conteúdo de sessão já apresentado (mensagens, resultados de ferramentas). Com o modelo de revisor padrão na mesma rota, esse conteúdo permanece dentro de um único provider; configure `reviewerModel` para um provider diferente somente se você aceitar apresentar essa transcrição a ele.
|
|
188
|
+
- **`never` é de mão única nesta camada.** Uma ferramenta ou regra de risco `never` rejeita antes de a cadeia humana ver a solicitação — é um cadeado, não um valor padrão.
|
|
189
|
+
- **O revisor é um modelo.** Seus veredictos são política consultiva, não um kernel de segurança. Prefira regras `human`/`never` para operações irreversíveis.
|
|
190
|
+
|
|
191
|
+
## ⚠️ Limitações conhecidas
|
|
192
|
+
|
|
193
|
+
- O revisor precisa de uma rota LLM operante (herdada do agente da sessão por padrão); sem ela, cada revisão cai no `fallbackPolicy` — nunca uma concessão silenciosa.
|
|
194
|
+
- Os nomes de `reviewerTools` devem existir como ferramentas globais do perfil; um nome desconhecido faz o filho revisor falhar em voz alta no ponto mais cedo e cair no fallback.
|
|
195
|
+
- Regras de risco casam o `reason` da solicitação, o `toolName` ou os `arguments` de chamada redigidos conforme seu `field`; outras condições pertencem a `toolsPolicy.overrides`.
|
|
196
|
+
- A sobrescrita `/auto-review approve` autoriza a próxima revisão da mesma ferramenta, não a chamada histórica exata; uma ação diferente na mesma ferramenta a consome.
|
|
197
|
+
- Os eventos de veredicto são log-only; o painel de revisão web dedicado lê a projeção dobrada `autoReview` (o fluxo bruto de eventos nunca chega aos plugins do navegador).
|
|
198
|
+
- `autoReview/state` e `autoReview/verdict` são gravados com o marcador de envelope `ignorable: true`, então qualquer build do harness carrega o log — leitores que não conhecem os tipos fora do repositório simplesmente pulam esses eventos em vez de recusar a sessão. (Hosts rc.6 aceitam e ignoram o marcador, mantendo exatamente o comportamento anterior; sessões escritas por versões anteriores à 0.1.1 podem ser reparadas com `scripts/repair-session-logs.mjs` do `dsh-permission-rules`.)
|
|
199
|
+
- O canal git precisa apenas da chave `allowBuilds` que o CLI `dsh` imprime para o próprio `dsh-auto-review`. O repositório traz seu próprio `pnpm-workspace.yaml` com `allowBuilds: { esbuild: true }` para que o ambiente de prepare isolado não falhe no postinstall do esbuild (validação inofensiva do binário de plataforma); `typescript` + `tsdown` são `dependencies` regulares para que esse ambiente sempre tenha as ferramentas de build.
|
|
200
|
+
- O companion de invariantes opcional (`dsh-auto-review/invariant`) precisa do serviço `invariants` (composições agent-spine como headless/ACP); o perfil web simples não o fornece, por isso a linha é publicada comentada no patch do bundle.
|
|
201
|
+
|
|
202
|
+
## 🏷️ Tópicos do GitHub
|
|
203
|
+
|
|
204
|
+
Recomendados ao publicar: `dsh` · `dsh-plugin` · `deepseek-harness` · `deepseek` · `cordis` · `ai-safety` · `approval` · `sandbox` · `subagent` · `llm`
|
|
205
|
+
|
|
206
|
+
## 🔗 Trabalho relacionado
|
|
207
|
+
|
|
208
|
+
- [Andy8647/dsh-auto-approval](https://github.com/Andy8647/dsh-auto-approval) — classificador binário allow/deny no waterfall `tools/pre-execute` com auditoria em arquivo de log. O `dsh-auto-review` difere de propósito: cadeia de **answerers** oficial, sempre delega o que não possui, segundo modelo somente leitura com veredicto estruturado, motivos de negação devolvidos ao modelo, auditoria no log de sessão.
|
|
209
|
+
- [ACP automation bridge](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/acp/acp) — decisões de máquina de uso único para seus próprios agentes ACP. O `dsh-auto-review` é orientado a sessões e políticas de ferramentas do harness interativo; nunca infere concessões duradouras.
|
|
210
|
+
|
|
211
|
+
## 🧑💻 Desenvolvimento
|
|
212
|
+
|
|
213
|
+
```sh
|
|
214
|
+
pnpm install # node ^22.19 || >=24
|
|
215
|
+
pnpm run typecheck # tsc, src + testes
|
|
216
|
+
pnpm test # vitest: 135 testes, 8 suítes
|
|
217
|
+
pnpm run build # declarações tsc + bundles tsdown (lib/)
|
|
218
|
+
pnpm run verify:self-contained
|
|
219
|
+
pnpm pack # artefato de publicação
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Estrutura do repositório (estrutura plugin-template): `src/index.ts` (contrato do plugin) · `src/config.ts` (schema Schemastery + resolução) · `src/runtime.ts` (answerer, comando, injeção do motivo de negação) · `src/review.ts` (orquestração do revisor, prompt, redação) · `src/events.ts` (vocabulário de eventos de sessão + folds) · `src/projection.ts` + `src/projection-types.ts` (a projeção de sessão `autoReview`) · `src/invariant.ts` (companion de invariantes) · `src/client/` (metade navegador: painel de revisão, locales, estilos) · `test/` · `fixtures/`.
|
|
223
|
+
|
|
224
|
+
## 📄 Licença
|
|
225
|
+
|
|
226
|
+
[Apache License 2.0](LICENSE)
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
<!-- 语言链接 -->
|
|
2
|
+
[English](README.md) · [中文](README.zh.md) · [Español](README.es.md) · [Português](README.pt.md) · [हिन्दी](README.hi.md)
|
|
3
|
+
|
|
4
|
+
<div align="center">
|
|
5
|
+
|
|
6
|
+
# 🤖 dsh-auto-review
|
|
7
|
+
|
|
8
|
+
**DeepSeek Harness 的第二模型 AI 自动审批** —— 以纯 Cordis 插件实现 Codex `approvals_reviewer=auto_review` / Claude Code *auto mode* 模式。
|
|
9
|
+
|
|
10
|
+
当 agent 的动作越过沙箱边界时,一个**只读审查子代理**给出 allow/deny 裁决与理由:人类无需操作,而不安全的操作也绝不会静默放行。
|
|
11
|
+
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
[](https://www.npmjs.com/package/@deepseek-ai/dsh)
|
|
14
|
+
[](.github/workflows/ci.yml)
|
|
15
|
+
[](src)
|
|
16
|
+
[](cordis.patch.yml)
|
|
17
|
+
[](https://github.com/PerryLink/dsh-auto-review)
|
|
18
|
+
|
|
19
|
+
**人类零操作。** 请求交给 AI 审查代理,裁决 = allow/deny + 理由 + 风险等级,且每个决策都能从会话日志完整重建:`approval/asked` → `autoReview/verdict`(硬禁用为 `autoReview/rejection`)→ `approval/decided`。
|
|
20
|
+
|
|
21
|
+
<img src="docs/demo-auto-review.gif" alt="dsh-auto-review 演示" width="720"/>
|
|
22
|
+
|
|
23
|
+
*一次真实证据链(真实服务器、真实 API key、两轮真实模型):AI 审查代理**放行**工作区内的升级写入(risk low,5.2s),随后**拒绝**工作区外的递归删除(risk high,8.9s)——拒绝理由回喂模型,直接显示在转录中。*
|
|
24
|
+
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
## 为什么用第二个模型而不是规则?
|
|
28
|
+
|
|
29
|
+
基于规则的自动审批在派发前就做出二态判定,没有证据。`dsh-auto-review` 把决策交给**审查子代理**:它通过只读工具面读取真实工作区、已流式呈现的工具调用参数(敏感值已脱敏)、请求方 reason 与你的风险规则,再返回结构化裁决。deny 裁决把**理由回喂调用模型**,agent 能学到原因而不是盲目重试。
|
|
30
|
+
|
|
31
|
+
## ✨ 特性
|
|
32
|
+
|
|
33
|
+
| | |
|
|
34
|
+
|---|---|
|
|
35
|
+
| 🔌 **官方接缝** | `approval/request` waterfall 上的 answerer;不接管的请求一律 `next()` 委托——人类审批流程绝不被短路。 |
|
|
36
|
+
| 🧠 **第二模型裁决** | 一次性 fork 子代理,只读工具白名单(`read`/`glob`/`grep`)+ 结构化裁决 schema `{ decision, reason, riskLevel }`。 |
|
|
37
|
+
| 🛡️ **fail closed** | 审查代理崩溃、超时、schema 不符都绝不放行:按 `fallbackPolicy` 回退,默认 `rejected`。 |
|
|
38
|
+
| 🧩 **配置驱动路由** | 每工具策略(`ai`/`human`/`never`)+ 正则风险规则,全部可在 cordis.yml 中修改。 |
|
|
39
|
+
| 💬 **拒绝理由到达模型** | 审查理由经 callId 注入被拒工具结果,agent 据此调整。fail-closed 回退拒绝与 `never` 策略硬禁用同样注入可审计文本(`[auto-review]` / `[auto-review-fallback]` / `[auto-review-never]` 标记)。 |
|
|
40
|
+
| 📜 **完整审计链** | `autoReview/verdict` + `autoReview/rejection` 会话事件(审查代理身份/裁决/理由/风险/耗时)+ invariant 伴生强制「模型可见 ⟺ 已记录」。 |
|
|
41
|
+
| 🔁 **防递归** | 审查代理自身的审批请求按身份识别并委托;`maxDepth` + 工具白名单保证其无法再委派。 |
|
|
42
|
+
| 🧯 **拒绝熔断器** | 单个回合内连续 3 次拒绝(或最近 10 次裁决中 6 次)即触发熔断器:后续请求委托、拒绝或中止回合——不再有无尽拒绝循环。 |
|
|
43
|
+
| 🎚️ **风险等级策略** | 风险超过 `riskPolicy.maxAutoAllow` 的 `allow` 裁决绝不定案:改为委托人类或拒绝。 |
|
|
44
|
+
| ✋ **一次性人工覆盖** | `/auto-review approve [n]` 授权对最近一次拒绝的**一次**重试;下一次同工具审查把该授权作为审查上下文携带(最终仍由审查代理决定)。 |
|
|
45
|
+
| 📜 **审查上下文** | 可选的紧凑转录(近期消息与工具结果,有界)+ Codex 风格 Markdown `reviewerPolicyText` 裁决策略。 |
|
|
46
|
+
| ⌨️ **会话级命令** | `/auto-review on|off|status|approve [n]`,带跨恢复生效的 durable 会话级覆盖与会话累计统计。 |
|
|
47
|
+
| 🖥️ **Web 审查面板** | 会话头部面板(Web GUI)展示开关(带开启/关闭按钮)、两项每回合预算、累计统计、熔断器触发、最近裁决与一次性批准按钮——由 `autoReview` 会话投影驱动。 |
|
|
48
|
+
|
|
49
|
+
## 工作原理
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
approval/request waterfall(answerer 链)
|
|
53
|
+
│
|
|
54
|
+
┌───────────────────────┴──────────────────────┐
|
|
55
|
+
│ dsh-auto-review answerer │
|
|
56
|
+
│ · 会话已启用? · 策略 = ai? │ 否 ── next() ──▶ 人类 answerer(UI)
|
|
57
|
+
│ · 风险规则 → toolsPolicy → 默认值 │
|
|
58
|
+
└───────────────────────┬──────────────────────┘
|
|
59
|
+
│ 是
|
|
60
|
+
▼
|
|
61
|
+
┌───────────────────────────────────┐
|
|
62
|
+
│ 审查子代理(fork,一次性) │
|
|
63
|
+
│ · toolFilter:read/glob/grep │
|
|
64
|
+
│ · outputSchema:{decision, │
|
|
65
|
+
│ reason, riskLevel} │
|
|
66
|
+
│ · 超时 + req.signal 中止 │
|
|
67
|
+
└───────────────┬───────────────────┘
|
|
68
|
+
│ 裁决 / 失败(fail-closed 回退)
|
|
69
|
+
▼
|
|
70
|
+
allow → allowed-once deny → rejected,理由注入被拒工具结果
|
|
71
|
+
(经 callId 关联)
|
|
72
|
+
│ never → rejected + [auto-review-never] 反馈
|
|
73
|
+
│ (硬禁用,不启动审查代理)
|
|
74
|
+
▼
|
|
75
|
+
审计:approval/asked → autoReview/verdict | autoReview/rejection
|
|
76
|
+
→ approval/decided(会话事件,log-only,invariant 校验)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**组合顺序。** answerer 在其注册位置参与 waterfall:若人类 UI answerer 组合在 `auto-review` 行之前,则人类先行应答,审查代理只处理下游委托过来的请求。请用 `dsh --profile <name> --dump-config` 核验;若希望 ai 策略工具优先路由到审查代理,把 `auto-review` 行放在人类 answerer 行之前。
|
|
80
|
+
|
|
81
|
+
## 🚀 快速开始
|
|
82
|
+
|
|
83
|
+
四种安装通道;本插件是 **bundle** 形态(`"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`)。
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
# 1. npm(已发布产物,无需构建)
|
|
87
|
+
dsh plugin --profile web add dsh-auto-review
|
|
88
|
+
dsh --profile web # 重启生效
|
|
89
|
+
|
|
90
|
+
# 2. npm tarball(构建产物,离线安装)
|
|
91
|
+
pnpm pack # → dsh-auto-review-<version>.tgz
|
|
92
|
+
dsh plugin --profile web add ./dsh-auto-review-<version>.tgz
|
|
93
|
+
dsh --profile web # 重启生效
|
|
94
|
+
|
|
95
|
+
# 3. git 源(钉住 commit;自包含 prepare 负责构建)
|
|
96
|
+
# pnpm ≥ 10 默认阻止生命周期构建:先把提示的 allowBuilds 键
|
|
97
|
+
# 加入 profile 的 pnpm-workspace.yaml。
|
|
98
|
+
dsh plugin --profile web add "github:PerryLink/dsh-auto-review#<commit>"
|
|
99
|
+
|
|
100
|
+
# 4. 本地 link(开发调试)
|
|
101
|
+
dsh plugin --profile web add link:/path/to/dsh-auto-review
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
验证:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
dsh --profile web --dump-config | grep -A4 'id: auto-review'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
开箱配置对 `bash`、`write` 走 AI 裁决;其余工具(包括 `edit` —— 就地修改)委托人类链。若接受无人工介入的就地编辑,请显式添加 `edit: ai`。
|
|
111
|
+
|
|
112
|
+
## ⚙️ 配置
|
|
113
|
+
|
|
114
|
+
所有可调参数都是 Schemastery `Config` 字段(cordis.yml 可改)。按 `id` 定向覆盖时**整行 config 被替换**——需要保留的键必须全部重述。
|
|
115
|
+
|
|
116
|
+
| 键 | 默认 | 含义 |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `enableByDefault` | `true` | 会话初始是否启用;`/auto-review on\|off` 写入的 durable 覆盖优先于它 |
|
|
119
|
+
| `toolsPolicy.default` | `human` | 未列出工具的策略(委托人类 answerer) |
|
|
120
|
+
| `toolsPolicy.overrides` | `{}` | 每工具策略:`ai`(AI 裁决)、`human`(强制人类)、`never`(确定性拒绝) |
|
|
121
|
+
| `riskRules` | `[]` | `{pattern, policy, field?}` 在工具表**之前**按顺序匹配(首个命中生效);`field` 选择 `reason`(默认)、`toolName` 或 `arguments`(脱敏后的呈现调用参数) |
|
|
122
|
+
| `reviewerProvider` | `fork` | 审查代理的 subagent provider(进程内 fork 后端) |
|
|
123
|
+
| `reviewerModel` | *(继承)* | 审查模型 id;不设则继承会话 agent 的模型路由 |
|
|
124
|
+
| `reviewerTimeoutMs` | `60000` | 裁决截止时间;超时走回退策略 |
|
|
125
|
+
| `reviewerTools` | `[read, glob, grep]` | 审查子代理的工具白名单(必须非空)——其余工具在其中不可见 |
|
|
126
|
+
| `fallbackPolicy` | `rejected` | 审查失败处理:`rejected`(fail closed)、`delegate`(继续沿链)、`allow-once`(放行——见安全边界)。0.2.0 由 `allow-readonly` 更名而来;旧拼写会响亮失败 |
|
|
127
|
+
| `maxReviewsPerTurn` | `10` | 每个开放回合的真实 AI 裁决预算;耗尽后请求委托人类 |
|
|
128
|
+
| `maxFailuresPerTurn` | `10` | 每个开放回合的审查失败预算(超时/不可用/schema 不符,不含取消);耗尽后请求改为委托,而不再等待另一次完整超时。默认取 `maxReviewsPerTurn` |
|
|
129
|
+
| `reasonMaxChars` | `2000` | 审查理由、请求 reason 与脱敏参数预览的长度上限 |
|
|
130
|
+
| `reviewerGuidance` | *(无)* | 追加进审查 prompt 的可选指导语(建议性,非硬规则) |
|
|
131
|
+
| `reviewerPolicyText` | *(无)* | 注入审查 prompt 的 Markdown 裁决策略(Codex 风格;模板见 `fixtures/config/policy-template.md`) |
|
|
132
|
+
| `denyGuidance` | *(防规避文本)* | 追加到每一段注入拒绝理由之后的指导语 |
|
|
133
|
+
| `contextBudget` | `{turns: 0, maxChars: 4000}` | 审查 prompt 的紧凑转录预算;`turns: 0` 禁用 |
|
|
134
|
+
| `riskPolicy` | `{maxAutoAllow: high, onHighRisk: delegate}` | 高于 `maxAutoAllow` 的 `allow` 裁决委托(`delegate`)或拒绝(`deny`) |
|
|
135
|
+
| `circuitBreaker` | `{consecutiveDenies: 3, windowDenies: 6, windowSize: 10, action: delegate}` | 拒绝熔断器;连续 3 次拒绝或最近 10 次裁决中 6 次即触发;`action`:`delegate` / `reject` / `abort-turn` |
|
|
136
|
+
| `overrideTtlMs` | `300000` | `/auto-review approve` 覆盖保持可用的时长 |
|
|
137
|
+
| `language` | `en` | `/auto-review` 命令输出的界面语言(`en` \| `zh`) |
|
|
138
|
+
|
|
139
|
+
示例(完整注释版见 `fixtures/config/config-full.yaml`):
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
- insert:
|
|
143
|
+
- id: auto-review
|
|
144
|
+
name: dsh-auto-review
|
|
145
|
+
config:
|
|
146
|
+
toolsPolicy:
|
|
147
|
+
overrides: { bash: ai, write: ai }
|
|
148
|
+
riskRules:
|
|
149
|
+
- pattern: '(?i)(rm\s+(-[a-z]+\s+)*/|git\s+push\s+--force)'
|
|
150
|
+
policy: never
|
|
151
|
+
- pattern: 'write'
|
|
152
|
+
policy: never
|
|
153
|
+
field: toolName
|
|
154
|
+
reviewerTimeoutMs: 30000
|
|
155
|
+
fallbackPolicy: delegate
|
|
156
|
+
riskPolicy: { maxAutoAllow: medium, onHighRisk: delegate }
|
|
157
|
+
circuitBreaker: { consecutiveDenies: 3, windowDenies: 6, windowSize: 10, action: delegate }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## ⌨️ 会话级命令
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
/auto-review on|off|status|approve [n]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`on`/`off` 追加 durable 的 `autoReview/state` 覆盖事件(fold 跨重启/恢复生效——重放即状态),并注入模型可见的切换通知(记录为 `user/message` 事件)。`status` 显示当前生效状态、两项回合预算(AI 裁决与审查失败)、当前回合已触发的熔断器(如有)以及会话的累计统计(放行/拒绝/失败/硬禁用拒绝、平均耗时、最近裁决)。`approve [n]` 针对第 n 近的拒绝(1 = 最近一次)记录一次性 `autoReview/override`:在 `overrideTtlMs` 内的下一次同工具审查携带该授权作为审查上下文——最终仍由审查代理决定,且无论该审查结果如何,此覆盖都会被消耗。
|
|
167
|
+
|
|
168
|
+
## 🖥️ Web 审查面板
|
|
169
|
+
|
|
170
|
+
在 Web GUI(web profile)中,本包贡献一个会话头部按钮(**AI 审查**),打开面板显示本会话的自动审查状态:开关(带开启/关闭按钮,执行 `/auto-review on|off`)、两项每回合预算、累计统计(含硬禁用拒绝)、熔断器触发、最近裁决,以及针对近期拒绝的一次性**批准**按钮(执行 `/auto-review approve [n]`)。
|
|
171
|
+
|
|
172
|
+
接线方式:
|
|
173
|
+
|
|
174
|
+
- 宿主注册一个 `autoReview` **会话投影**(由 log-only 的 `autoReview/*` 事件折叠而来),经会话投影通道送达浏览器。
|
|
175
|
+
- 浏览器半是一个 **client module**(由 `dsh.client` 声明自动发现),注册在 `conversation.session.header.actions` 席位。
|
|
176
|
+
- 无需额外 patch 行:只要插件安装在 web 构建提供会话投影能力的 profile(web profile 即如此)中,面板即自动加载;缺少该能力时面板显示不可用,answerer 不受影响。
|
|
177
|
+
|
|
178
|
+
面板只读取投影整值——浏览器插件永远不会收到原始会话事件流。
|
|
179
|
+
|
|
180
|
+
## 🔒 安全边界
|
|
181
|
+
|
|
182
|
+
- 审查代理运行在**只读工具面**(`toolFilter` 白名单)内:不能写、改、执行 shell、访问网络、再委派(`maxDepth` = 自身深度)。其会话日志同样落盘可审计。
|
|
183
|
+
- **敏感参数先脱敏**(按键名匹配:`token`、`password`、`api_key`、`Authorization`、凭据、私钥等)再进入审查 prompt;插件绝不执行被审参数。脱敏是键名级而非内容级——参数值不能接受展示给模型的工具,不要纳入 AI 审查。
|
|
184
|
+
- **默认 fail closed。** 所有异常路径(provider 缺失、能力缺口、启动被拒、超时、非 `completed` 停止原因、裁决缺失/不合规、审计关联失败)都走 `fallbackPolicy`,默认 `rejected`——且该拒绝把一段可审计的理由回喂模型,而不是通用的 “user rejected” 文本。`allow-once` 是无条件放行——仅供接受该风险的无人值守部署使用。
|
|
185
|
+
- **硬禁用会自我解释。** `never` 工具或风险规则确定性拒绝,并记录 log-only 的 `autoReview/rejection` 事件(含命中的规则/表项),再向被拒工具结果注入 `[auto-review-never]` 标记文本——模型明白该动作已被硬禁用,而不是反复重试(invariant 校验:标记 ⟺ 事件)。
|
|
186
|
+
- **拒绝熔断器。** 单个回合内的一连串拒绝(`consecutiveDenies` / `windowSize` 内的 `windowDenies`)触发熔断器,记录为 log-only 的 `autoReview/circuit` 事件;后续请求遵循其 `action`(`delegate` / `reject` / `abort-turn`)。`abort-turn` 注入模型可见的警告并取消 agent。
|
|
187
|
+
- **审查上下文是已呈现的转录。** `contextBudget` 把已呈现的会话内容(消息、工具结果)喂给审查代理。默认同路由审查模型下该内容始终留在同一 provider 内;只有当你接受将这份转录呈现给另一个 provider 时,才把 `reviewerModel` 配置为不同 provider。
|
|
188
|
+
- **`never` 在本层是单向的。** `never` 工具或风险规则在人类链看到请求之前即拒绝——是锁定旋钮,不是默认值。
|
|
189
|
+
- **审查代理也是模型。** 其裁决是建议性策略,不是安全内核。不可逆操作请配 `human`/`never` 规则。
|
|
190
|
+
|
|
191
|
+
## ⚠️ 已知局限
|
|
192
|
+
|
|
193
|
+
- 审查代理需要可用的 LLM 路由(默认继承会话 agent 的 provider/model);没有路由时每次审查按 `fallbackPolicy` 回退——绝不静默放行。
|
|
194
|
+
- `reviewerTools` 中的名字必须是 profile 中真实存在的全局工具;未知名字会在最早点响亮失败并回退。
|
|
195
|
+
- 风险规则按各自的 `field` 匹配请求 `reason`、`toolName` 或脱敏后的调用 `arguments`;其他条件请用 `toolsPolicy.overrides`。
|
|
196
|
+
- `/auto-review approve` 覆盖授权的是下一次同工具审查,而非那次精确的历史调用;同一工具上的另一动作也会消耗它。
|
|
197
|
+
- 裁决事件是 log-only;专属 Web 审查面板读取折叠后的 `autoReview` 投影(原始事件流不会到达浏览器插件)。
|
|
198
|
+
- `autoReview/state` 与 `autoReview/verdict` 均以信封 `ignorable: true` 标记写入,任何 harness 构建都能加载日志——不认识这些仓库外类型的读取器只会跳过相应记录而不是拒绝整个会话。(rc.6 宿主会接受并忽略该标记,行为与打标前完全一致;0.1.1 之前版本写入的会话可用 `dsh-permission-rules` 的 `scripts/repair-session-logs.mjs` 一次性修复。)
|
|
199
|
+
- git 通道只需要 `dsh` CLI 打印的那一条 `allowBuilds` 键(针对 `dsh-auto-review` 本体)。仓库自带 `pnpm-workspace.yaml` 并声明 `allowBuilds: { esbuild: true }`,使隔离的 prepare 环境不会因 esbuild 的(无害的平台二进制校验)postinstall 而失败;`typescript` + `tsdown` 是常规 `dependencies`,保证该环境始终有构建工具。
|
|
200
|
+
- 可选 invariant 伴生(`dsh-auto-review/invariant`)需要 `invariants` 服务(agent-spine 组合,如 headless/ACP);普通 web profile 不提供该服务,因此该行在 bundle patch 中以注释形式发布。
|
|
201
|
+
|
|
202
|
+
## 🏷️ GitHub 话题
|
|
203
|
+
|
|
204
|
+
发布仓库时建议添加:`dsh` · `dsh-plugin` · `deepseek-harness` · `deepseek` · `cordis` · `ai-safety` · `approval` · `sandbox` · `subagent` · `llm`
|
|
205
|
+
|
|
206
|
+
## 🔗 相关项目
|
|
207
|
+
|
|
208
|
+
- [Andy8647/dsh-auto-approval](https://github.com/Andy8647/dsh-auto-approval) —— `tools/pre-execute` waterfall 上的二态 allow/deny 分类器,审计走文件日志。`dsh-auto-review` 刻意差异化:官方 **answerer** 链、不拥有的请求一律委托、只读第二模型结构化裁决、拒绝理由回喂模型、会话日志级审计。
|
|
209
|
+
- [ACP automation bridge](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/acp/acp) —— 为其自有 ACP agent 提供一次性机器决策。`dsh-auto-review` 面向交互式 harness 的会话与工具策略作用域,绝不推断持久授权。
|
|
210
|
+
|
|
211
|
+
## 🧑💻 开发
|
|
212
|
+
|
|
213
|
+
```sh
|
|
214
|
+
pnpm install # node ^22.19 || >=24
|
|
215
|
+
pnpm run typecheck # tsc,src + 测试
|
|
216
|
+
pnpm test # vitest:135 个测试、8 个套件
|
|
217
|
+
pnpm run build # tsc 声明 + tsdown 打包(lib/)
|
|
218
|
+
pnpm run verify:self-contained
|
|
219
|
+
pnpm pack # 发布产物
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
仓库结构(plugin-template 结构):`src/index.ts`(插件契约)· `src/config.ts`(Schemastery schema + 解析)· `src/runtime.ts`(answerer、命令、拒绝理由注入)· `src/review.ts`(审查代理编排、prompt、脱敏)· `src/events.ts`(会话事件词汇 + fold)· `src/projection.ts` + `src/projection-types.ts`(`autoReview` 会话投影)· `src/invariant.ts`(invariant 伴生)· `src/client/`(浏览器半:审查面板、locales、样式)· `test/` · `fixtures/`。
|
|
223
|
+
|
|
224
|
+
## 📄 License
|
|
225
|
+
|
|
226
|
+
[Apache License 2.0](LICENSE)
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# dsh-auto-review bundle patch: mount the auto-review answerer. `name` is the
|
|
2
|
+
# package name, resolved through the profile's node_modules. An id-targeted
|
|
3
|
+
# override replaces the whole config row — restate every key when overriding.
|
|
4
|
+
#
|
|
5
|
+
# The Web GUI review panel needs NO extra row: the package's `dsh.client`
|
|
6
|
+
# declaration auto-registers its browser half (a session-header action), and
|
|
7
|
+
# the host half registers an `autoReview` session projection whenever the
|
|
8
|
+
# profile provides the session-projection capability (the web profile does).
|
|
9
|
+
- insert:
|
|
10
|
+
- id: auto-review
|
|
11
|
+
name: dsh-auto-review
|
|
12
|
+
config:
|
|
13
|
+
toolsPolicy:
|
|
14
|
+
# Tools NOT listed fall back to the schema default `human`
|
|
15
|
+
# (delegate to the human answerer — the chain is never short-circuited).
|
|
16
|
+
# `edit` (in-place modification) is deliberately NOT AI-reviewed by
|
|
17
|
+
# default: add it here explicitly if you accept in-place edits without
|
|
18
|
+
# a human in the loop.
|
|
19
|
+
overrides:
|
|
20
|
+
bash: ai
|
|
21
|
+
write: ai
|
|
22
|
+
# OPTIONAL invariant companion — uncomment and add to YOUR profile patch
|
|
23
|
+
# layer only in compositions that provide the `invariants` service
|
|
24
|
+
# (agent-spine apps such as headless/ACP). The plain web profile has no
|
|
25
|
+
# invariants service, so this row would sit PENDING there and fail boot:
|
|
26
|
+
# - id: auto-review-invariant
|
|
27
|
+
# name: dsh-auto-review/invariant
|