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.hi.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 स्वतः-समीक्षा** — Codex का `approvals_reviewer=auto_review` / Claude Code का *auto mode* पैटर्न, एक शुद्ध Cordis प्लगइन के रूप में।
|
|
9
|
+
|
|
10
|
+
जब एजेंट की कोई क्रिया sandbox की सीमा पार करती है, तो एक **केवल-पढ़ने वाला समीक्षक सबएजेंट** 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 कुंजी, दो वास्तविक मॉडल राउंड): AI समीक्षक workspace के अंदर escalated लेखन को **अनुमति** देता है (कम जोखिम, 5.2 s), फिर workspace के बाहर recursive विलोपन को **अस्वीकार** करता है (उच्च जोखिम, 8.9 s) — अस्वीकृति का कारण मॉडल को वापस दिया जाता है और ट्रांसक्रिप्ट में दिखाई देता है।*
|
|
24
|
+
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
## नियमों के बजाय दूसरा मॉडल क्यों?
|
|
28
|
+
|
|
29
|
+
पैटर्न-आधारित स्वतः-स्वीकर्ता dispatch से पहले, बिना साक्ष्य के फ़ैसला करते हैं। `dsh-auto-review` निर्णय एक **समीक्षक सबएजेंट** को सौंपता है जो वास्तविक workspace (अपने केवल-पढ़ने वाले टूल-सेट से), पहले से प्रस्तुत टूल-कॉल आर्गुमेंट (संवेदनशील मान हटाकर), अनुरोध का कारण और आपके जोखिम नियम पढ़ता है — फिर एक संरचित फ़ैसला लौटाता है। अस्वीकृति का **कारण कॉल करने वाले मॉडल को वापस** दिया जाता है, ताकि एजेंट अंधाधुंध दोबारा कोशिश करने के बजाय कारण सीखे।
|
|
30
|
+
|
|
31
|
+
## ✨ विशेषताएँ
|
|
32
|
+
|
|
33
|
+
| | |
|
|
34
|
+
|---|---|
|
|
35
|
+
| 🔌 **आधिकारिक seam** | `approval/request` waterfall पर एक answerer। जो अनुरोध उसके नहीं हैं वे `next()` से आगे भेजे जाते हैं — मानव स्वीकृति प्रवाह कभी नहीं रोका जाता। |
|
|
36
|
+
| 🧠 **द्वितीय-मॉडल फ़ैसला** | एक बार का fork सबएजेंट, केवल-पढ़ने वाली टूल अनुमति-सूची (`read`/`glob`/`grep`) और संरचित फ़ैसला schema `{ decision, reason, riskLevel }`। |
|
|
37
|
+
| 🛡️ **Fail closed** | समीक्षक का क्रैश, टाइमआउट या गलत schema कभी द्वार नहीं खोलता: `fallbackPolicy` लागू होती है, डिफ़ॉल्ट `rejected`। |
|
|
38
|
+
| 🧩 **कॉन्फ़िग-चालित रूटिंग** | प्रति-टूल नीतियाँ (`ai`/`human`/`never`) + regex जोखिम नियम, सब cordis.yml से बदले जा सकते हैं। |
|
|
39
|
+
| 💬 **अस्वीकृति के कारण मॉडल तक पहुँचते हैं** | समीक्षक का कारण अस्वीकृत टूल के परिणाम में (callId से जुड़ा) डाला जाता है, ताकि एजेंट खुद को ढाल सके। Fail-closed fallback अस्वीकृतियाँ और `never` नीति की हार्ड-डिसेबल अस्वीकृतियाँ भी ऑडिट-योग्य पाठ डालती हैं (`[auto-review]` / `[auto-review-fallback]` / `[auto-review-never]` मार्कर)। |
|
|
40
|
+
| 📜 **पूर्ण ऑडिट शृंखला** | `autoReview/verdict` + `autoReview/rejection` सत्र-ईवेंट (समीक्षक की पहचान, फ़ैसला, कारण, जोखिम, अवधि) + एक invariant companion जो *model-visible ⟺ logged* लागू करता है। |
|
|
41
|
+
| 🔁 **कोई पुनरावृत्ति नहीं** | समीक्षक के अपने अनुरोध पहचान से पहचाने जाते हैं और आगे भेजे जाते हैं; `maxDepth` + अनुमति-सूची समीक्षक को आगे delegation से रोकते हैं। |
|
|
42
|
+
| 🧯 **अस्वीकृति circuit breaker** | एक टर्न में 3 लगातार अस्वीकृतियाँ (या पिछले 10 फ़ैसलों में 6) breaker को ट्रिप कर देती हैं: बाद के अनुरोध सौंपे जाते हैं, अस्वीकार होते हैं या टर्न निरस्त होता है — अस्वीकृति का कोई अंतहीन चक्र नहीं। |
|
|
43
|
+
| 🎚️ **जोखिम-स्तर नीति** | एक `allow` फ़ैसला जिसका जोखिम `riskPolicy.maxAutoAllow` से ऊपर है, अनुरोध को कभी निपटाता नहीं: वह मानव को सौंपता है या अस्वीकार करता है। |
|
|
44
|
+
| ✋ **एक-बार मानव ओवरराइड** | `/auto-review approve [n]` हाल की एक अस्वीकृति के लिए एक बार पुनः-प्रयास अधिकृत करता है; अगली उसी-टूल समीक्षा उस अधिकार को समीक्षक संदर्भ के रूप में ले जाती है (समीक्षक फिर भी फ़ैसला करता है)। |
|
|
45
|
+
| 📜 **समीक्षक संदर्भ** | वैकल्पिक संक्षिप्त ट्रांसक्रिप्ट (हाल के संदेश और टूल परिणाम, सीमित) + एक Codex-शैली Markdown `reviewerPolicyText` निर्णय-नीति। |
|
|
46
|
+
| ⌨️ **सत्र कमांड** | `/auto-review on|off|status|approve [n]` — टिकाऊ प्रति-सत्र ओवरराइड जो restore के बाद भी बना रहता है और संचयी सत्र आँकड़े। |
|
|
47
|
+
| 🖥️ **वेब समीक्षा पैनल** | सत्र-शीर्षक पैनल (वेब GUI) स्विच (ऑन/ऑफ बटन के साथ), दोनों प्रति-टर्न बजट, संचयी आँकड़े, circuit ट्रिप, हाल के फ़ैसले और एक-बार अनुमोदन बटन दिखाता है — `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 abort │
|
|
67
|
+
└───────────────┬───────────────────┘
|
|
68
|
+
│ फ़ैसला / विफलता (fail-closed fallback)
|
|
69
|
+
▼
|
|
70
|
+
allow → allowed-once deny → rejected + कारण अस्वीकृत टूल के
|
|
71
|
+
परिणाम में डाला जाता है
|
|
72
|
+
│ never → rejected + [auto-review-never] फ़ीडबैक
|
|
73
|
+
│ (हार्ड-डिसेबल, समीक्षक नहीं चलता)
|
|
74
|
+
▼
|
|
75
|
+
ऑडिट: approval/asked → autoReview/verdict | autoReview/rejection
|
|
76
|
+
→ approval/decided (सत्र-ईवेंट, log-only, invariant-जाँचित)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**संरचना क्रम।** उत्तरदाता waterfall में अपनी पंजीकरण-स्थिति पर चलता है: यदि कोई मानव UI उत्तरदाता `auto-review` पंक्ति से पहले संयोजित है, तो मानव पहले उत्तर देते हैं और समीक्षक केवल वही देखता है जो आगे सौंपा जाता है। `dsh --profile <name> --dump-config` से सत्यापित करें; यदि ai-नीति उपकरण पहले समीक्षक के पास जाने चाहिए, तो `auto-review` पंक्ति को मानव उत्तरदाता पंक्तियों से पहले रखें।
|
|
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 पिन करें; self-contained `prepare` बिल्ड करता है)
|
|
96
|
+
# pnpm ≥ 10 lifecycle बिल्ड रोकता है: पहले प्रिंट हुई allowBuilds कुंजी को
|
|
97
|
+
# प्रोफ़ाइल के 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 सक्रिय होकर शुरू होते हैं; `/auto-review on\|off` एक टिकाऊ ओवरराइड लिखता है जो इससे ऊपर होता है |
|
|
119
|
+
| `toolsPolicy.default` | `human` | सूची से बाहर के टूल की नीति (मानव answerer को सौंपना) |
|
|
120
|
+
| `toolsPolicy.overrides` | `{}` | प्रति-टूल नीति: `ai` (समीक्षक तय करे), `human` (मानव अनिवार्य), `never` (निश्चित अस्वीकृति) |
|
|
121
|
+
| `riskRules` | `[]` | `{pattern, policy, field?}` — टूल-तालिका से **पहले** मिलान (पहला मिलान जीतता है); `field` `reason` (डिफ़ॉल्ट), `toolName`, या `arguments` (प्रस्तुत redacted कॉल आर्गुमेंट) चुनता है |
|
|
122
|
+
| `reviewerProvider` | `fork` | समीक्षक के लिए सबएजेंट provider (इन-प्रोसेस fork बैकएंड) |
|
|
123
|
+
| `reviewerModel` | *(विरासत)* | समीक्षक मॉडल id; खाली रहने पर सत्र एजेंट की रूट विरासत में मिलती है |
|
|
124
|
+
| `reviewerTimeoutMs` | `60000` | फ़ैसले की समय-सीमा; समाप्त होने पर fallback नीति लागू |
|
|
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` | समीक्षक के कारणों, अनुरोध के कारण और redacted आर्गुमेंट पूर्वावलोकन की सीमा |
|
|
130
|
+
| `reviewerGuidance` | *(कोई नहीं)* | समीक्षक prompt में जोड़ा जाने वाला वैकल्पिक मार्गदर्शन (सलाह, कठोर नियम नहीं) |
|
|
131
|
+
| `reviewerPolicyText` | *(कोई नहीं)* | समीक्षक prompt में डाली जाने वाली Markdown निर्णय-नीति (Codex-शैली; टेम्पलेट `fixtures/config/policy-template.md` पर) |
|
|
132
|
+
| `denyGuidance` | *(circumvention-विरोधी पाठ)* | हर डाले गए अस्वीकृति कारण के अंत में जोड़ा जाने वाला मार्गदर्शन |
|
|
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}` | अस्वीकृति circuit breaker; 3 लगातार अस्वीकृतियों या टर्न के पिछले 10 फ़ैसलों में से 6 पर ट्रिप होता है; `action`: `delegate` / `reject` / `abort-turn` |
|
|
136
|
+
| `overrideTtlMs` | `300000` | `/auto-review approve` ओवरराइड कितनी देर उपयोग-योग्य रहता है |
|
|
137
|
+
| `language` | `en` | `/auto-review` कमांड आउटपुट की UI भाषा (`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` टिकाऊ `autoReview/state` ओवरराइड जोड़ते हैं (fold पुनः आरंभ/restore के बाद भी बना रहता है — रीप्ले ही स्थिति है) और मॉडल को दिखने वाला स्विच-नोटिस डालते हैं (`user/message` ईवेंट के रूप में दर्ज)। `status` प्रभावी स्थिति, दोनों प्रति-टर्न बजट (AI फ़ैसले और समीक्षक विफलताएँ), टर्न में सक्रिय होने पर ट्रिप हुआ circuit breaker, और सत्र के संचयी आँकड़े (अनुमति/अस्वीकृति/fallback/हार्ड-डिसेबल अस्वीकृति, औसत अवधि, हाल के फ़ैसले) दिखाता है। `approve [n]` n-वीं सबसे हाल की अस्वीकृति (1 = सबसे हाल) के लिए एक बार उपयोग होने वाला `autoReview/override` दर्ज करता है: `overrideTtlMs` के भीतर अगली उसी-टूल समीक्षा उस अधिकार को समीक्षक संदर्भ के रूप में ले जाती है — समीक्षक फिर भी फ़ैसला करता है, और ओवरराइड उस समीक्षा द्वारा उपभोग हो जाता है चाहे उसका परिणाम कुछ भी हो।
|
|
167
|
+
|
|
168
|
+
## 🖥️ वेब समीक्षा पैनल
|
|
169
|
+
|
|
170
|
+
वेब GUI (वेब प्रोफ़ाइल) में, पैकेज एक सत्र-शीर्षक क्रिया (**AI Review**) देता है जो सत्र की ऑटो-समीक्षा स्थिति वाला पैनल खोलती है: ऑन/ऑफ बटन वाला स्विच (ये `/auto-review on|off` चलाते हैं), दोनों प्रति-टर्न बजट, संचयी आँकड़े (हार्ड-डिसेबल अस्वीकृतियों सहित), circuit ट्रिप, हाल के फ़ैसले, और हाल की अस्वीकृतियों के लिए एक-बार **अनुमोदन** बटन (ये `/auto-review approve [n]` चलाते हैं)।
|
|
171
|
+
|
|
172
|
+
वायरिंग:
|
|
173
|
+
|
|
174
|
+
- होस्ट एक `autoReview` **सत्र प्रोजेक्शन** पंजीकृत करता है (log-only `autoReview/*` ईवेंट से मुड़ा हुआ) और उसे सत्र-प्रोजेक्शन चैनल से परोसता है।
|
|
175
|
+
- ब्राउज़र आधा एक **client module** है (`dsh.client` घोषणा से स्वतः खोजा गया) जो `conversation.session.header.actions` सीट पर पंजीकृत होता है।
|
|
176
|
+
- कोई अतिरिक्त patch पंक्ति नहीं चाहिए: पैनल तब लोड होता है जब प्लगइन ऐसे प्रोफ़ाइल में स्थापित हो जिसकी वेब बिल्ड सत्र-प्रोजेक्शन क्षमता देती है (वेब प्रोफ़ाइल देती है)। उस क्षमता के बिना पैनल स्वयं को अनुपलब्ध बताता है; उत्तरदाता अप्रभावित रहता है।
|
|
177
|
+
|
|
178
|
+
पैनल केवल संपूर्ण प्रोजेक्शन मान पढ़ता है — ब्राउज़र प्लगइन को कच्ची सत्र-ईवेंट धारा कभी नहीं मिलती।
|
|
179
|
+
|
|
180
|
+
## 🔒 सुरक्षा
|
|
181
|
+
|
|
182
|
+
- समीक्षक **केवल-पढ़ने वाले टूल-सेट** (`toolFilter` अनुमति-सूची) में चलता है। वह लिख, बदल, shell चला, नेटवर्क छू या आगे delegation नहीं कर सकता (`maxDepth` = उसकी अपनी गहराई)। उसका सत्र लॉग स्थायी और ऑडिट-योग्य है।
|
|
183
|
+
- **संवेदनशील आर्गुमेंट पहले हटाए जाते हैं** (कुंजी-नाम मिलान: `token`, `password`, `api_key`, `Authorization`, क्रेडेंशियल, निजी कुंजियाँ …) फिर समीक्षक prompt में जाते हैं; प्लगइन समीक्षित आर्गुमेंट कभी निष्पादित नहीं करता। यह कुंजी-आधारित redaction है, सामग्री-आधारित नहीं — जिन टूल के मान मॉडल को दिखाना जोखिम भरा हो, उन्हें AI समीक्षा में न डालें।
|
|
184
|
+
- **डिफ़ॉल्ट रूप से fail closed।** हर असामान्य रास्ता (provider गायब, क्षमता-अंतराल, start अस्वीकृत, टाइमआउट, गैर-`completed` stopReason, फ़ैसला गायब/विकृत, ऑडिट-सहसंबंध विफलता) `fallbackPolicy` से हल होता है, डिफ़ॉल्ट `rejected` — और अस्वीकृति सामान्य "user rejected" पाठ के बजाय एक ऑडिट-योग्य कारण मॉडल को वापस देती है। `allow-once` बिना शर्त अनुमति देता है — केवल उन अप्रबंधित परिनियोजनों के लिए जिनका व्यवस्थापक यह जोखिम स्वीकार करता है।
|
|
185
|
+
- **हार्ड-डिसेबल खुद को समझाते हैं।** `never` टूल या जोखिम नियम निश्चित रूप से अस्वीकार करता है और मिली हुई नियम/तालिका-प्रविष्टि के साथ एक log-only `autoReview/rejection` ईवेंट दर्ज करता है, फिर अस्वीकृत टूल के परिणाम में `[auto-review-never]` मार्कर पाठ डालता है — मॉडल दोबारा कोशिश करने के बजाय सीख लेता है कि क्रिया हार्ड-डिसेबल है (invariant-जाँचित: मार्कर ⟺ ईवेंट)।
|
|
186
|
+
- **अस्वीकृति circuit breaker।** एक टर्न में अस्वीकृतियों का सिलसिला breaker को ट्रिप कर देता है (`windowSize` के भीतर `consecutiveDenies` / `windowDenies`), log-only `autoReview/circuit` ईवेंट के रूप में दर्ज; बाद के अनुरोध उसके `action` (`delegate` / `reject` / `abort-turn`) का पालन करते हैं। `abort-turn` मॉडल को दिखने वाली चेतावनी डालता है और एजेंट रद्द करता है।
|
|
187
|
+
- **समीक्षक संदर्भ प्रस्तुत ट्रांसक्रिप्ट है।** `contextBudget` पहले से प्रस्तुत सत्र सामग्री (संदेश, टूल परिणाम) समीक्षक को देता है। डिफ़ॉल्ट समान-रूट समीक्षक मॉडल के साथ वह सामग्री एक ही provider के भीतर रहती है; `reviewerModel` को किसी भिन्न provider पर तभी सेट करें जब आप उस ट्रांसक्रिप्ट को उसके सामने प्रस्तुत करना स्वीकार करते हों।
|
|
188
|
+
- **`never` इस परत पर एकतरफ़ा है।** `never` टूल या जोखिम नियम मानव शृंखला के अनुरोध देखने से पहले ही अस्वीकार कर देता है — यह ताला है, डिफ़ॉल्ट नहीं।
|
|
189
|
+
- **समीक्षक भी एक मॉडल है।** उसके फ़ैसले सलाहकार नीति हैं, सुरक्षा कर्नेल नहीं। अपरिवर्तनीय कार्यों के लिए `human`/`never` नियम रखें।
|
|
190
|
+
|
|
191
|
+
## ⚠️ ज्ञात सीमाएँ
|
|
192
|
+
|
|
193
|
+
- समीक्षक को एक कार्यशील LLM रूट चाहिए (डिफ़ॉल्ट में सत्र एजेंट से विरासत); उसके बिना हर समीक्षा `fallbackPolicy` पर गिरती है — कभी भी मौन अनुमति नहीं।
|
|
194
|
+
- `reviewerTools` के नाम प्रोफ़ाइल में वास्तविक वैश्विक टूल होने चाहिए; अज्ञात नाम समीक्षक बच्चे को सबसे पहले बिंदु पर ज़ोर से विफल करता है और fallback पर गिरता है।
|
|
195
|
+
- जोखिम नियम अपने `field` के अनुसार अनुरोध के `reason`, `toolName` या redacted कॉल `arguments` से मिलते हैं; बाकी शर्तें `toolsPolicy.overrides` में रखें।
|
|
196
|
+
- `/auto-review approve` ओवरराइड अगली उसी-टूल समीक्षा को अधिकृत करता है, सटीक ऐतिहासिक कॉल को नहीं; उसी टूल पर कोई भिन्न क्रिया उसे उपभोग कर लेती है।
|
|
197
|
+
- फ़ैसला ईवेंट log-only हैं; समर्पित वेब समीक्षा पैनल मुड़ा हुआ `autoReview` प्रोजेक्शन पढ़ता है (कच्ची ईवेंट धारा ब्राउज़र प्लगइन तक कभी नहीं पहुँचती)।
|
|
198
|
+
- `autoReview/state` और `autoReview/verdict` एन्वेलप के `ignorable: true` मार्कर के साथ लिखे जाते हैं, इसलिए कोई भी harness बिल्ड लॉग लोड कर लेता है — जो पाठक इन आउट-ऑफ-रेपो प्रकारों को नहीं जानते वे सत्र अस्वीकार करने के बजाय केवल उन रिकॉर्ड्स को छोड़ देते हैं। (rc.6 होस्ट मार्कर को स्वीकार कर अनदेखा करते हैं, पहले जैसा ही व्यवहार बना रहता है; 0.1.1 से पहले के संस्करणों द्वारा लिखे सत्र `dsh-permission-rules` के `scripts/repair-session-logs.mjs` से एक बार मरम्मत किए जा सकते हैं।)
|
|
199
|
+
- git चैनल को केवल वही एक `allowBuilds` कुंजी चाहिए जो `dsh` CLI स्वयं `dsh-auto-review` के लिए प्रिंट करता है। रेपो अपना `pnpm-workspace.yaml` लेकर आता है जिसमें `allowBuilds: { esbuild: true }` है, ताकि अलग-थलग prepare वातावरण esbuild के (हानिरहित प्लेटफ़ॉर्म-बाइनरी सत्यापन) postinstall पर विफल न हो; `typescript` + `tsdown` नियमित `dependencies` हैं ताकि उस वातावरण में बिल्ड टूल हमेशा मौजूद रहें।
|
|
200
|
+
- वैकल्पिक invariant companion (`dsh-auto-review/invariant`) को `invariants` सेवा चाहिए (agent-spine संयोजन जैसे headless/ACP); सामान्य web प्रोफ़ाइल उसे नहीं देती, इसलिए वह पंक्ति bundle पैच में टिप्पणी रूप में जाती है।
|
|
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 एजेंटों के लिए एक बार के मशीन निर्णय। `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, redaction) · `src/events.ts` (सत्र-ईवेंट शब्दावली + folds) · `src/projection.ts` + `src/projection-types.ts` (`autoReview` सत्र प्रोजेक्शन) · `src/invariant.ts` (invariant companion) · `src/client/` (ब्राउज़र आधा: समीक्षा पैनल, locales, स्टाइल) · `test/` · `fixtures/`।
|
|
223
|
+
|
|
224
|
+
## 📄 लाइसेंस
|
|
225
|
+
|
|
226
|
+
[Apache License 2.0](LICENSE)
|
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
<!-- language links -->
|
|
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
|
+
**Second-model AI approval for DeepSeek Harness** — the Codex `approvals_reviewer=auto_review` / Claude Code *auto mode* pattern, built as a pure Cordis plugin.
|
|
9
|
+
|
|
10
|
+
When an agent's action crosses the sandbox boundary, a **read-only reviewer subagent** decides allow/deny — with a reason — so humans approve nothing while nothing unsafe slips through.
|
|
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 human operations.** The request goes to the AI reviewer, the verdict is allow/deny + reason + risk level, and every decision is reconstructable from the session log: `approval/asked` → `autoReview/verdict` (or `autoReview/rejection` for hard disables) → `approval/decided`.
|
|
20
|
+
|
|
21
|
+
<img src="docs/demo-auto-review.gif" alt="dsh-auto-review demo" width="720"/>
|
|
22
|
+
|
|
23
|
+
*One real evidence run (real server, real API key, two real model rounds): the AI reviewer **allows** an escalated workspace write (risk low, 5.2 s), then **denies** a recursive out-of-workspace delete (risk high, 8.9 s) — the deny reason is fed back to the model, visible in the transcript.*
|
|
24
|
+
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
## Why a second model instead of rules?
|
|
28
|
+
|
|
29
|
+
Pattern-based auto-approvers decide before dispatch, with no evidence. `dsh-auto-review` gives the decision to a **reviewer subagent** that reads the actual workspace (through its read-only tool face), the already-streamed tool-call arguments (sensitive values redacted), the request reason, and your risk rules — then returns a structured verdict. A deny verdict feeds its **reason back to the calling model**, so the agent learns why instead of retrying blindly.
|
|
30
|
+
|
|
31
|
+
## ✨ Features
|
|
32
|
+
|
|
33
|
+
| | |
|
|
34
|
+
|---|---|
|
|
35
|
+
| 🔌 **Official seam** | An answerer on the `approval/request` waterfall. Requests it does not own are delegated via `next()` — the human approval flow is never short-circuited. |
|
|
36
|
+
| 🧠 **Second-model verdict** | One-shot fork subagent with a read-only tool allow-list (`read`/`glob`/`grep`) and a structured verdict schema `{ decision, reason, riskLevel }`. |
|
|
37
|
+
| 🛡️ **Fail closed** | Reviewer crash, timeout, or schema mismatch never opens the gate: `fallbackPolicy` applies, default `rejected`. |
|
|
38
|
+
| 🧩 **Config-driven routing** | Per-tool policies (`ai`/`human`/`never`) + regex risk rules, all changeable from cordis.yml. |
|
|
39
|
+
| 💬 **Deny reasons reach the model** | The reviewer's reason is injected into the denied tool result (callId-linked), so the agent adapts. Fail-closed fallback rejections and `never`-policy hard disables inject auditable failure texts too (`[auto-review]` / `[auto-review-fallback]` / `[auto-review-never]` markers). |
|
|
40
|
+
| 📜 **Full audit trail** | `autoReview/verdict` + `autoReview/rejection` session events (reviewer identity, verdict, reason, risk, duration) + an invariant companion enforcing *model-visible ⟺ logged*. |
|
|
41
|
+
| 🔁 **No recursion** | Reviewer asks are recognized by identity and delegated; `maxDepth` + the tool allow-list keep the reviewer non-delegating. |
|
|
42
|
+
| 🧯 **Rejection circuit breaker** | 3 consecutive denials (or 6 within the last 10 verdicts) in one turn trip the breaker: later requests delegate, reject, or abort the turn — no endless denial loops. |
|
|
43
|
+
| 🎚️ **Risk-level policy** | An `allow` verdict whose risk exceeds `riskPolicy.maxAutoAllow` never settles the request: it delegates to a human or denies. |
|
|
44
|
+
| ✋ **One-shot human override** | `/auto-review approve [n]` authorizes ONE retry of a recent denial; the next same-tool review carries that authorization as reviewer context (the reviewer still decides). |
|
|
45
|
+
| 📜 **Reviewer context** | Optional compact transcript (recent messages and tool results, bounded) + a Codex-style Markdown `reviewerPolicyText` ruling policy. |
|
|
46
|
+
| ⌨️ **Session command** | `/auto-review on|off|status|approve [n]` with a durable per-session override that survives restore and cumulative session statistics. |
|
|
47
|
+
| 🖥️ **Web review panel** | A session-header panel (Web GUI) shows the switch (with on/off buttons), both per-turn budgets, cumulative statistics, the circuit trip, recent verdicts, and one-shot approve buttons — driven by the `autoReview` session projection. |
|
|
48
|
+
|
|
49
|
+
## How it works
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
approval/request waterfall (answerer chain)
|
|
53
|
+
│
|
|
54
|
+
┌───────────────────────┴──────────────────────┐
|
|
55
|
+
│ dsh-auto-review answerer │
|
|
56
|
+
│ · session enabled? · policy = ai? │ no ── next() ──▶ human answerer (UI)
|
|
57
|
+
│ · risk rules → toolsPolicy → default │
|
|
58
|
+
└───────────────────────┬──────────────────────┘
|
|
59
|
+
│ yes
|
|
60
|
+
▼
|
|
61
|
+
┌───────────────────────────────────┐
|
|
62
|
+
│ reviewer subagent (fork, one-shot)│
|
|
63
|
+
│ · toolFilter: read/glob/grep │
|
|
64
|
+
│ · outputSchema: {decision, │
|
|
65
|
+
│ reason, riskLevel} │
|
|
66
|
+
│ · timeout + req.signal abort │
|
|
67
|
+
└───────────────┬───────────────────┘
|
|
68
|
+
│ verdict / failure (fail-closed fallback)
|
|
69
|
+
▼
|
|
70
|
+
allow → allowed-once deny → rejected + reason injected into the
|
|
71
|
+
denied tool result (callId-linked)
|
|
72
|
+
│ never → rejected + [auto-review-never] feedback
|
|
73
|
+
│ (hard disable, no reviewer runs)
|
|
74
|
+
▼
|
|
75
|
+
audit: approval/asked → autoReview/verdict | autoReview/rejection
|
|
76
|
+
→ approval/decided (session events, log-only, invariant-checked)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Composition order.** The answerer runs at its registration position in the waterfall: if a human UI answerer is composed BEFORE the `auto-review` row, humans answer first and the reviewer only sees what is delegated downstream. Verify with `dsh --profile <name> --dump-config` and place the `auto-review` row before your human answerer rows when you want ai-policy tools routed to the reviewer first.
|
|
80
|
+
|
|
81
|
+
## 🚀 Quick start
|
|
82
|
+
|
|
83
|
+
Three install channels; the plugin is a **bundle** (`"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`).
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
# 1. npm (published artifact, no build step)
|
|
87
|
+
dsh plugin --profile web add dsh-auto-review
|
|
88
|
+
dsh --profile web # restart
|
|
89
|
+
|
|
90
|
+
# 2. npm tarball (built artifacts, offline install)
|
|
91
|
+
pnpm pack # → dsh-auto-review-<version>.tgz
|
|
92
|
+
dsh plugin --profile web add ./dsh-auto-review-<version>.tgz
|
|
93
|
+
dsh --profile web # restart
|
|
94
|
+
|
|
95
|
+
# 3. git source (pin the commit; self-contained `prepare` builds it)
|
|
96
|
+
# pnpm ≥ 10 blocks lifecycle builds: add the printed allowBuilds key
|
|
97
|
+
# to the profile's pnpm-workspace.yaml first.
|
|
98
|
+
dsh plugin --profile web add "github:PerryLink/dsh-auto-review#<commit>"
|
|
99
|
+
|
|
100
|
+
# 4. local link (development)
|
|
101
|
+
dsh plugin --profile web add link:/path/to/dsh-auto-review
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Verify:
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
dsh --profile web --dump-config | grep -A4 'id: auto-review'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Out of the box the shipped patch AI-reviews `bash` and `write`; every other tool (including `edit` — in-place modification) delegates to the human chain. Add `edit: ai` explicitly if you accept in-place edits without a human in the loop.
|
|
111
|
+
|
|
112
|
+
## ⚙️ Configuration
|
|
113
|
+
|
|
114
|
+
All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id-targeted override **replaces the whole config row** — restate every key you need.
|
|
115
|
+
|
|
116
|
+
| Key | Default | Meaning |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `enableByDefault` | `true` | Sessions start with auto-review enabled; `/auto-review on\|off` writes a durable override that beats this |
|
|
119
|
+
| `toolsPolicy.default` | `human` | Policy for unlisted tools (delegate to the human answerer) |
|
|
120
|
+
| `toolsPolicy.overrides` | `{}` | Per-tool policy: `ai` (reviewer decides), `human` (force human), `never` (deterministic reject) |
|
|
121
|
+
| `riskRules` | `[]` | `{pattern, policy, field?}` matched (first match wins) before the tool table; `field` selects `reason` (default), `toolName`, or `arguments` (the redacted presented call arguments) |
|
|
122
|
+
| `reviewerProvider` | `fork` | Subagent provider for the reviewer (in-process fork backend) |
|
|
123
|
+
| `reviewerModel` | *(inherit)* | Reviewer model id; unset inherits the session agent's route |
|
|
124
|
+
| `reviewerTimeoutMs` | `60000` | Verdict deadline; on expiry the fallback policy applies |
|
|
125
|
+
| `reviewerTools` | `[read, glob, grep]` | The reviewer child's tool allow-list (must be non-empty) — everything else is invisible there |
|
|
126
|
+
| `fallbackPolicy` | `rejected` | Reviewer failure: `rejected` (fail closed), `delegate` (continue the chain), `allow-once` (grant — see Security). Renamed from `allow-readonly` in 0.2.0; the old spelling fails loudly |
|
|
127
|
+
| `maxReviewsPerTurn` | `10` | Real AI-verdict budget per open turn; beyond it, requests delegate to humans |
|
|
128
|
+
| `maxFailuresPerTurn` | `10` | Reviewer-failure budget per open turn (timeout/unavailable/schema, not cancellations); beyond it, requests delegate instead of paying another full timeout. Defaults to `maxReviewsPerTurn` |
|
|
129
|
+
| `reasonMaxChars` | `2000` | Cap for reviewer reasons, the request reason, and the redacted argument preview |
|
|
130
|
+
| `reviewerGuidance` | *(none)* | Optional advisory guidance appended to the reviewer prompt |
|
|
131
|
+
| `reviewerPolicyText` | *(none)* | Markdown ruling policy injected into the reviewer prompt (Codex-style; template at `fixtures/config/policy-template.md`) |
|
|
132
|
+
| `denyGuidance` | *(anti-circumvention text)* | Guidance appended to every injected deny reason |
|
|
133
|
+
| `contextBudget` | `{turns: 0, maxChars: 4000}` | Compact transcript budget for the reviewer prompt; `turns: 0` disables |
|
|
134
|
+
| `riskPolicy` | `{maxAutoAllow: high, onHighRisk: delegate}` | `allow` verdicts above `maxAutoAllow` delegate (`delegate`) or deny (`deny`) |
|
|
135
|
+
| `circuitBreaker` | `{consecutiveDenies: 3, windowDenies: 6, windowSize: 10, action: delegate}` | Rejection circuit breaker; trips on 3 consecutive denies or 6 of the last 10 verdicts in a turn; `action`: `delegate` / `reject` / `abort-turn` |
|
|
136
|
+
| `overrideTtlMs` | `300000` | How long a `/auto-review approve` override stays usable |
|
|
137
|
+
| `language` | `en` | UI language of the `/auto-review` command output (`en` \| `zh`) |
|
|
138
|
+
|
|
139
|
+
Example (annotated full form: `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
|
+
## ⌨️ Session command
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
/auto-review on|off|status|approve [n]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`on`/`off` append the durable `autoReview/state` override (the fold survives restart/resume — replay IS the state) and inject a switch notice the model sees (logged as a `user/message` event). `status` reports the effective state, both per-turn budgets (AI verdicts and reviewer failures), a tripped circuit breaker when one is active, and the session's cumulative statistics (allows/denies/fallbacks/never rejects, mean duration, recent verdicts). `approve [n]` records a single-use `autoReview/override` for the n-th most recent denial (1 = most recent): the next same-tool review within `overrideTtlMs` carries the authorization as reviewer context — the reviewer still decides, and the override is consumed by that review regardless of its outcome.
|
|
167
|
+
|
|
168
|
+
## 🖥️ Web review panel
|
|
169
|
+
|
|
170
|
+
In the Web GUI (web profile), the package contributes a session-header action (**AI Review**) that opens a panel with the session's auto-review state: the switch with on/off buttons (they execute `/auto-review on|off`), both per-turn budgets, cumulative statistics (including hard-disable rejections), the circuit trip, the recent verdicts, and one-shot **approve** buttons for recent denials (they execute `/auto-review approve [n]`).
|
|
171
|
+
|
|
172
|
+
How it is wired:
|
|
173
|
+
|
|
174
|
+
- The host registers an `autoReview` **session projection** (folded from the log-only `autoReview/*` events) and serves it through the session-projection channel.
|
|
175
|
+
- The browser half is a **client module** (auto-discovered from the `dsh.client` declaration) registered on the `conversation.session.header.actions` seat.
|
|
176
|
+
- No extra patch rows are needed: the panel loads whenever the plugin is installed in a profile whose web build provides the session-projection capability (the web profile does). Without that capability the panel reports itself unavailable; the answerer is unaffected.
|
|
177
|
+
|
|
178
|
+
The panel reads only whole projection values — it never receives the raw session event stream.
|
|
179
|
+
|
|
180
|
+
## 🔒 Security
|
|
181
|
+
|
|
182
|
+
- The reviewer runs in a **read-only tool face** (`toolFilter` allow-list). It cannot write, edit, run bash, fetch the network, or delegate (`maxDepth` = its own depth). Its session log is persisted and auditable.
|
|
183
|
+
- **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.
|
|
184
|
+
- **Fail closed by default.** 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 instead of the generic "user rejected" text. `allow-once` grants unconditionally — it exists only for unattended deployments whose admin accepts that risk.
|
|
185
|
+
- **Hard disables explain themselves.** A `never` tool or risk rule rejects deterministically AND records a log-only `autoReview/rejection` event with the matched rule/table entry, then injects a `[auto-review-never]` marker text into the denied tool result — the model learns the action is hard-disabled instead of retrying it (invariant-checked: marker ⟺ event).
|
|
186
|
+
- **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`). `abort-turn` injects a model-visible warning and cancels the agent.
|
|
187
|
+
- **Reviewer context is presented transcript.** `contextBudget` feeds already-presented session content (messages, tool results) to the reviewer. With the default same-route reviewer model that content stays inside one provider; configure `reviewerModel` to a different provider only if you accept presenting that transcript to it.
|
|
188
|
+
- **`never` is one-way at this layer.** A `never` tool or risk rule rejects before the human chain sees the request — a lockdown knob, not a default.
|
|
189
|
+
- **The reviewer is a model.** Its verdicts are advisory policy, not a security kernel. Prefer `human`/`never` rules for irreversible operations.
|
|
190
|
+
|
|
191
|
+
## ⚠️ Known limitations
|
|
192
|
+
|
|
193
|
+
- The reviewer needs a working LLM route (inherited from the session agent by default); without one every review falls back per `fallbackPolicy` — never a silent grant.
|
|
194
|
+
- `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.
|
|
195
|
+
- Risk rules match the request `reason`, the `toolName`, or the redacted call `arguments` per their `field`; other conditions belong in `toolsPolicy.overrides`.
|
|
196
|
+
- The `/auto-review approve` override authorizes the next same-tool review, not the exact historical call; a different action on the same tool consumes it.
|
|
197
|
+
- The verdict events are log-only; the dedicated Web review panel reads the folded `autoReview` projection (the raw event stream never reaches browser plugins).
|
|
198
|
+
- `autoReview/state` and `autoReview/verdict` are appended with the envelope's `ignorable: true` marker, so any harness build loads the log — readers that do not know the out-of-repo types simply skip those records instead of refusing the session. (rc.6 hosts accept and ignore the marker, keeping the exact pre-marker behavior; sessions written by pre-0.1.1 versions can be repaired with `scripts/repair-session-logs.mjs` from `dsh-permission-rules`.)
|
|
199
|
+
- The git channel needs the single `allowBuilds` key the `dsh` CLI prints for `dsh-auto-review` itself. The repo ships its own `pnpm-workspace.yaml` with `allowBuilds: { esbuild: true }` so the isolated prepare environment does not fail on esbuild's (harmless platform-binary validation) postinstall; `typescript` + `tsdown` are regular `dependencies` so that environment always has the build tools.
|
|
200
|
+
- The optional invariant companion (`dsh-auto-review/invariant`) needs the `invariants` service (agent-spine compositions such as headless/ACP); the plain web profile does not provide it, so the row ships commented out in the bundle patch.
|
|
201
|
+
|
|
202
|
+
## 🏷️ GitHub topics
|
|
203
|
+
|
|
204
|
+
Recommended when you publish: `dsh` · `dsh-plugin` · `deepseek-harness` · `deepseek` · `cordis` · `ai-safety` · `approval` · `sandbox` · `subagent` · `llm`
|
|
205
|
+
|
|
206
|
+
## 🔗 Related work
|
|
207
|
+
|
|
208
|
+
- [Andy8647/dsh-auto-approval](https://github.com/Andy8647/dsh-auto-approval) — two-state allow/deny classifier on the `tools/pre-execute` waterfall with file-log audit. `dsh-auto-review` deliberately differs: official **answerer** chain, always delegates what it does not own, read-only second model with a structured verdict, deny reasons fed back to the model, session-log audit.
|
|
209
|
+
- [ACP automation bridge](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/acp/acp) — one-shot machine decisions for its own ACP-owned agents. `dsh-auto-review` is session- and tool-policy-scoped for the interactive harness; it never infers durable grants.
|
|
210
|
+
|
|
211
|
+
## 🧑💻 Development
|
|
212
|
+
|
|
213
|
+
```sh
|
|
214
|
+
pnpm install # node ^22.19 || >=24
|
|
215
|
+
pnpm run typecheck # tsc, src + tests
|
|
216
|
+
pnpm test # vitest: 135 tests, 8 suites
|
|
217
|
+
pnpm run build # tsc declarations + tsdown bundles (lib/, incl. the client bundle)
|
|
218
|
+
pnpm run verify:self-contained
|
|
219
|
+
pnpm pack # publish artifact
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Repository layout (plugin-template structure): `src/index.ts` (plugin contract) · `src/config.ts` (Schemastery schema + resolution) · `src/runtime.ts` (answerer, command, deny-reason injection) · `src/review.ts` (reviewer orchestration, prompt, sanitization) · `src/events.ts` (session-event vocabulary + folds) · `src/projection.ts` + `src/projection-types.ts` (the `autoReview` session projection) · `src/invariant.ts` (invariant companion) · `src/client/` (browser half: review panel, locales, styles) · `test/` · `fixtures/`.
|
|
223
|
+
|
|
224
|
+
## 📄 License
|
|
225
|
+
|
|
226
|
+
[Apache License 2.0](LICENSE)
|