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.
Files changed (84) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/LICENSE +201 -0
  3. package/README.es.md +226 -0
  4. package/README.hi.md +226 -0
  5. package/README.md +226 -0
  6. package/README.pt.md +226 -0
  7. package/README.zh.md +226 -0
  8. package/cordis.patch.yml +27 -0
  9. package/lib/client.js +494 -0
  10. package/lib/client.js.map +1 -0
  11. package/lib/events-CFl6CHZi.js +344 -0
  12. package/lib/index.js +5305 -0
  13. package/lib/invariant.js +223 -0
  14. package/lib/types/client/ReviewPanel.d.ts +29 -0
  15. package/lib/types/client/ReviewPanel.d.ts.map +1 -0
  16. package/lib/types/client/ReviewPanel.js +63 -0
  17. package/lib/types/client/ReviewPanel.js.map +1 -0
  18. package/lib/types/client/index.d.ts +31 -0
  19. package/lib/types/client/index.d.ts.map +1 -0
  20. package/lib/types/client/index.js +51 -0
  21. package/lib/types/client/index.js.map +1 -0
  22. package/lib/types/client/locales.d.ts +49 -0
  23. package/lib/types/client/locales.d.ts.map +1 -0
  24. package/lib/types/client/locales.js +82 -0
  25. package/lib/types/client/locales.js.map +1 -0
  26. package/lib/types/client/present.d.ts +25 -0
  27. package/lib/types/client/present.d.ts.map +1 -0
  28. package/lib/types/client/present.js +36 -0
  29. package/lib/types/client/present.js.map +1 -0
  30. package/lib/types/client/styles.d.ts +9 -0
  31. package/lib/types/client/styles.d.ts.map +1 -0
  32. package/lib/types/client/styles.js +130 -0
  33. package/lib/types/client/styles.js.map +1 -0
  34. package/lib/types/config.d.ts +200 -0
  35. package/lib/types/config.d.ts.map +1 -0
  36. package/lib/types/config.js +154 -0
  37. package/lib/types/config.js.map +1 -0
  38. package/lib/types/events.d.ts +347 -0
  39. package/lib/types/events.d.ts.map +1 -0
  40. package/lib/types/events.js +369 -0
  41. package/lib/types/events.js.map +1 -0
  42. package/lib/types/index.d.ts +26 -0
  43. package/lib/types/index.d.ts.map +1 -0
  44. package/lib/types/index.js +26 -0
  45. package/lib/types/index.js.map +1 -0
  46. package/lib/types/invariant.d.ts +28 -0
  47. package/lib/types/invariant.d.ts.map +1 -0
  48. package/lib/types/invariant.js +306 -0
  49. package/lib/types/invariant.js.map +1 -0
  50. package/lib/types/messages.d.ts +38 -0
  51. package/lib/types/messages.d.ts.map +1 -0
  52. package/lib/types/messages.js +65 -0
  53. package/lib/types/messages.js.map +1 -0
  54. package/lib/types/projection-types.d.ts +61 -0
  55. package/lib/types/projection-types.d.ts.map +1 -0
  56. package/lib/types/projection-types.js +8 -0
  57. package/lib/types/projection-types.js.map +1 -0
  58. package/lib/types/projection.d.ts +93 -0
  59. package/lib/types/projection.d.ts.map +1 -0
  60. package/lib/types/projection.js +197 -0
  61. package/lib/types/projection.js.map +1 -0
  62. package/lib/types/review.d.ts +141 -0
  63. package/lib/types/review.d.ts.map +1 -0
  64. package/lib/types/review.js +389 -0
  65. package/lib/types/review.js.map +1 -0
  66. package/lib/types/runtime.d.ts +160 -0
  67. package/lib/types/runtime.d.ts.map +1 -0
  68. package/lib/types/runtime.js +486 -0
  69. package/lib/types/runtime.js.map +1 -0
  70. package/package.json +132 -0
  71. package/src/client/ReviewPanel.tsx +164 -0
  72. package/src/client/index.ts +72 -0
  73. package/src/client/locales.ts +87 -0
  74. package/src/client/present.ts +58 -0
  75. package/src/client/styles.ts +131 -0
  76. package/src/config.ts +346 -0
  77. package/src/events.ts +553 -0
  78. package/src/index.ts +28 -0
  79. package/src/invariant.ts +326 -0
  80. package/src/messages.ts +91 -0
  81. package/src/projection-types.ts +61 -0
  82. package/src/projection.ts +224 -0
  83. package/src/review.ts +428 -0
  84. package/src/runtime.ts +562 -0
@@ -0,0 +1,486 @@
1
+ /**
2
+ * Runtime of `dsh-auto-review`: the `approval/request` answerer (claim when
3
+ * the session and tool policy say `ai`, otherwise strictly `next()`), the
4
+ * reviewer verdict handling with fail-closed fallback, the risk-policy
5
+ * escalation, the rejection circuit breaker, the deny-reason injection into
6
+ * the denied tool result, and the `/auto-review` session command. Every
7
+ * registration is an effect (ctx.on / commands.register).
8
+ * @module dsh-auto-review/runtime
9
+ */
10
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
11
+ import { resolveConfig, riskExceeds } from "./config.js";
12
+ import { messages } from "./messages.js";
13
+ import { makeAutoReviewProjection } from "./projection.js";
14
+ import { activeOverride, autoReviewFailuresInOpenTurn, autoReviewsInOpenTurn, circuitInOpenTurn, circuitResultText, consecutiveDeniesInOpenTurn, correlateApprovalId, deniesInRecentVerdicts, denyResultText, effectiveAutoReviewState, fallbackResultText, lastDeniedVerdicts, neverResultText, reviewStats, } from "./events.js";
15
+ import { isReviewFailure, newCircuitId, newRejectionId, newVerdictId, runReview, sanitizedArgumentsText, truncate } from "./review.js";
16
+ export const name = 'auto-review';
17
+ export const inject = ['approval', 'subagents', 'commands', 'tools'];
18
+ /** How long an injected feedback text stays available for its tool result (bounded cleanup). */
19
+ const FEEDBACK_TTL_MS = 5 * 60_000;
20
+ /** Closed-union backstop for the fallback-policy switch. */
21
+ function assertNever(value, label) {
22
+ throw new TypeError(`unknown ${label}: ${String(value)}`);
23
+ }
24
+ /**
25
+ * Answerer policy resolution for one request: the first matching risk rule
26
+ * (security invariants win over tool defaults), then the exact tool override,
27
+ * then the table default. Each rule matches its configured field: the
28
+ * request reason, the tool name, or the redacted presented call arguments.
29
+ * @param config - the resolved config.
30
+ * @param request - the pending approval request.
31
+ * @param argumentsText - the sanitized call-arguments JSON, when the log has it.
32
+ * @returns the policy this request resolves to, with its provenance.
33
+ */
34
+ function policyFor(config, request, argumentsText) {
35
+ for (const rule of config.riskRules) {
36
+ const subject = rule.field === 'reason'
37
+ ? request.reason ?? ''
38
+ : rule.field === 'toolName'
39
+ ? request.toolName
40
+ : argumentsText ?? '';
41
+ if (rule.regex.test(subject))
42
+ return { policy: rule.policy, source: `risk rule /${rule.pattern}/ (${rule.field})` };
43
+ }
44
+ const override = config.toolsPolicy.overrides[request.toolName];
45
+ if (override !== undefined)
46
+ return { policy: override, source: `toolsPolicy.overrides.${request.toolName}` };
47
+ return { policy: config.toolsPolicy.default, source: 'toolsPolicy.default' };
48
+ }
49
+ /**
50
+ * Answerer state and behavior. One instance per plugin mount; disposals are
51
+ * owned by the ctx.on / commands.register effects in {@link apply}.
52
+ */
53
+ export class AutoReviewRuntime {
54
+ ctx;
55
+ config;
56
+ /** Live reviewer child sessions — their approval asks never re-enter AI review. */
57
+ reviewerSessions = new Set();
58
+ /** Feedback texts keyed by call id, consumed (and deleted) by the post-execute listener. */
59
+ feedback = new Map();
60
+ constructor(ctx, config) {
61
+ this.ctx = ctx;
62
+ this.config = config;
63
+ }
64
+ /**
65
+ * The `approval/request` answerer. Claims a request ONLY when auto-review
66
+ * is enabled for the session AND the policy for this tool/reason is `ai`
67
+ * AND both per-turn budgets remain AND the rejection circuit breaker is
68
+ * not tripped; everything else delegates via `next()` (or deterministically
69
+ * rejects for `never`). The reviewer's own asks are always delegated
70
+ * (anti-recursion).
71
+ * @param request - the pending decision.
72
+ * @param next - the downstream answerer chain.
73
+ * @returns the closed approval outcome.
74
+ */
75
+ answer(request, next) {
76
+ // Anti-recursion: a reviewer child's own approval asks go to the human chain.
77
+ if (this.reviewerSessions.has(request.agent.id))
78
+ return next();
79
+ const session = request.agent.session;
80
+ const enabled = effectiveAutoReviewState(session.events) ?? this.config.enableByDefault;
81
+ if (!enabled)
82
+ return next();
83
+ const needsArguments = this.config.riskRules.some(rule => rule.field === 'arguments');
84
+ const argumentsText = needsArguments && request.callId !== undefined
85
+ ? sanitizedArgumentsText(session.events, request.callId)
86
+ : undefined;
87
+ const { policy, source } = policyFor(this.config, request, argumentsText);
88
+ if (policy === 'never')
89
+ return this.neverReject(request, source);
90
+ if (policy !== 'ai')
91
+ return next();
92
+ // Separate budgets: real AI verdicts vs reviewer failures. A broken
93
+ // reviewer burns the failure budget (then delegates) without eating the
94
+ // AI-decision budget, and vice versa.
95
+ if (autoReviewsInOpenTurn(session.events) >= this.config.maxReviewsPerTurn)
96
+ return next();
97
+ if (autoReviewFailuresInOpenTurn(session.events) >= this.config.maxFailuresPerTurn)
98
+ return next();
99
+ const circuit = circuitInOpenTurn(session.events);
100
+ if (circuit !== undefined)
101
+ return this.circuitSettle(request, circuit, next);
102
+ const approvalId = correlateApprovalId(session.events, request.toolName, request.callId);
103
+ if (approvalId === undefined) {
104
+ // The audit chain cannot be completed (verdict → approval/asked); treat
105
+ // as an internal unavailability, never as a grant.
106
+ return this.finish(request, undefined, {
107
+ fallback: 'unavailable',
108
+ error: 'cannot correlate the pending approval/asked audit event',
109
+ }, next);
110
+ }
111
+ const overrideId = activeOverride(session.events, request.toolName, this.config.overrideTtlMs, Date.now());
112
+ const override = overrideId === undefined
113
+ ? undefined
114
+ : { reviewId: overrideId, toolName: request.toolName };
115
+ return this.review(request, approvalId, next, override);
116
+ }
117
+ /**
118
+ * Settle a `never`-policy request deterministically: record the log-only
119
+ * `autoReview/rejection` audit event, and feed a model-visible
120
+ * `[auto-review-never]` marker text (plus the deny guidance) into the
121
+ * denied call's tool result — without it the model only sees the generic
122
+ * rejection and keeps retrying a hard-disabled action. No reviewer runs
123
+ * and no budget is consumed.
124
+ * @param request - the hard-disabled decision.
125
+ * @param source - the matched risk rule or policy table entry.
126
+ * @returns the closed rejection.
127
+ */
128
+ neverReject(request, source) {
129
+ const rejectionId = newRejectionId();
130
+ const reason = truncate(source, this.config.reasonMaxChars);
131
+ const approvalId = correlateApprovalId(request.agent.session.events, request.toolName, request.callId);
132
+ request.agent.session.append('autoReview/rejection', {
133
+ rejectionId,
134
+ ...approvalId !== undefined ? { approvalId } : {},
135
+ toolName: request.toolName,
136
+ ...request.callId !== undefined ? { callId: request.callId } : {},
137
+ reason,
138
+ outcome: 'rejected',
139
+ }, { ignorable: true });
140
+ this.recordFeedback(request.callId, `${neverResultText(rejectionId, request.toolName, reason)}\n${this.config.denyGuidance}`);
141
+ return Promise.resolve('rejected');
142
+ }
143
+ /**
144
+ * Run the reviewer for one claimed request, register the child for
145
+ * anti-recursion, apply the risk policy, record the verdict, trip the
146
+ * circuit breaker on denials, and settle the answerer chain.
147
+ * @param request - the pending decision.
148
+ * @param approvalId - the correlated `approval/asked` id.
149
+ * @param next - the downstream chain (used by risk-policy delegation).
150
+ * @param override - a pending human one-shot override, when one applies.
151
+ * @returns the closed approval outcome.
152
+ */
153
+ async review(request, approvalId, next, override) {
154
+ const started = Date.now();
155
+ const resolution = await runReview(this.ctx, this.config, request, this.reviewerSessions, override);
156
+ const durationMs = Date.now() - started;
157
+ if (isReviewFailure(resolution)) {
158
+ return this.finish(request, approvalId, resolution, next, durationMs);
159
+ }
160
+ const reviewId = newVerdictId();
161
+ const overridden = resolution.decision === 'allow'
162
+ && resolution.riskLevel !== undefined
163
+ && riskExceeds(resolution.riskLevel, this.config.riskPolicy.maxAutoAllow);
164
+ const outcome = overridden
165
+ ? this.config.riskPolicy.onHighRisk === 'deny' ? 'rejected' : undefined
166
+ : resolution.decision === 'allow' ? 'allowed-once' : 'rejected';
167
+ request.agent.session.append('autoReview/verdict', {
168
+ reviewId,
169
+ approvalId,
170
+ toolName: request.toolName,
171
+ ...request.callId !== undefined ? { callId: request.callId } : {},
172
+ provider: this.config.reviewerProvider,
173
+ ...resolution.model !== undefined ? { model: resolution.model } : {},
174
+ ...resolution.reviewerSessionId !== undefined ? { reviewerSessionId: resolution.reviewerSessionId } : {},
175
+ durationMs,
176
+ decision: resolution.decision,
177
+ reason: resolution.reason,
178
+ ...resolution.riskLevel !== undefined ? { riskLevel: resolution.riskLevel } : {},
179
+ ...overridden ? { escalation: 'risk-policy' } : {},
180
+ ...outcome !== undefined ? { outcome } : {},
181
+ }, { ignorable: true });
182
+ if (outcome === undefined)
183
+ return next();
184
+ if (resolution.decision === 'deny') {
185
+ this.recordDenyReason(request.callId, request.toolName, reviewId, resolution.reason);
186
+ this.checkCircuit(request);
187
+ return 'rejected';
188
+ }
189
+ if (overridden) {
190
+ // The reviewer allowed, but the risk policy denied: feed the override
191
+ // back to the model and count it toward the rejection circuit breaker.
192
+ this.recordDenyReason(request.callId, request.toolName, reviewId, `${resolution.reason} (risk ${resolution.riskLevel} exceeds the configured maxAutoAllow ${this.config.riskPolicy.maxAutoAllow}; the allow verdict was overridden)`);
193
+ this.checkCircuit(request);
194
+ return 'rejected';
195
+ }
196
+ return 'allowed-once';
197
+ }
198
+ /**
199
+ * Append the fallback verdict event and apply the configured fallback
200
+ * policy. A user cancellation settles `cancelled` regardless of policy;
201
+ * otherwise `rejected` (fail closed), `allow-once`, or `delegate`
202
+ * (continue the chain) per config.
203
+ */
204
+ finish(request, approvalId, failure, next, durationMs = 0) {
205
+ const outcome = this.fallbackOutcome(failure);
206
+ if (approvalId !== undefined) {
207
+ const reviewId = newVerdictId();
208
+ request.agent.session.append('autoReview/verdict', {
209
+ reviewId,
210
+ approvalId,
211
+ toolName: request.toolName,
212
+ ...request.callId !== undefined ? { callId: request.callId } : {},
213
+ provider: this.config.reviewerProvider,
214
+ ...failure.model !== undefined ? { model: failure.model } : {},
215
+ ...failure.reviewerSessionId !== undefined ? { reviewerSessionId: failure.reviewerSessionId } : {},
216
+ durationMs,
217
+ fallback: failure.fallback,
218
+ error: failure.error,
219
+ ...outcome !== undefined ? { outcome } : {},
220
+ }, { ignorable: true });
221
+ this.ctx.logger.warn(`auto-review fallback (${failure.fallback}) for ${request.toolName}: ${failure.error}`);
222
+ // A fail-closed rejection is as model-visible as a reviewer deny: the
223
+ // agent learns WHY it was rejected (and that the reviewer failed)
224
+ // instead of retrying the same escalation blindly.
225
+ if (outcome === 'rejected') {
226
+ this.recordFallbackFeedback(request.callId, reviewId, failure.fallback, failure.error);
227
+ }
228
+ }
229
+ if (outcome === undefined)
230
+ return next();
231
+ return Promise.resolve(outcome);
232
+ }
233
+ /**
234
+ * Map one reviewer failure to the approval outcome the answerer settles
235
+ * with: `cancelled` when the user aborted the request; otherwise the
236
+ * configured fallback policy.
237
+ * @param failure - the review failure.
238
+ * @returns the outcome, or undefined when the chain must continue.
239
+ */
240
+ fallbackOutcome(failure) {
241
+ if (failure.fallback === 'cancelled')
242
+ return 'cancelled';
243
+ switch (this.config.fallbackPolicy) {
244
+ case 'rejected': return 'rejected';
245
+ case 'allow-once': return 'allowed-once';
246
+ case 'delegate': return undefined;
247
+ default: return assertNever(this.config.fallbackPolicy, 'fallback policy');
248
+ }
249
+ }
250
+ /**
251
+ * Settle one request while the rejection circuit breaker is tripped:
252
+ * `delegate` continues the chain; `reject` (and `abort-turn`, whose abort
253
+ * already happened at trip time) rejects with an auditable marker.
254
+ * @param request - the pending decision.
255
+ * @param circuit - the turn's recorded circuit trip.
256
+ * @param next - the downstream chain.
257
+ * @returns the closed approval outcome.
258
+ */
259
+ circuitSettle(request, circuit, next) {
260
+ if (circuit.action === 'delegate')
261
+ return next();
262
+ const explanation = `rejection circuit breaker tripped (${circuit.trip.kind}: ${circuit.trip.count} denials)`;
263
+ this.recordFeedback(request.callId, circuitResultText(circuit.circuitId, request.toolName, explanation));
264
+ return Promise.resolve('rejected');
265
+ }
266
+ /**
267
+ * Trip the rejection circuit breaker after a denial, at most once per
268
+ * turn. `abort-turn` also injects a model-visible warning and cancels the
269
+ * agent (deferred a macrotask so the service's `approval/decided` append
270
+ * commits first — the pair must stay turn-enclosed).
271
+ * @param request - the request whose denial may trip the breaker.
272
+ */
273
+ checkCircuit(request) {
274
+ const session = request.agent.session;
275
+ if (circuitInOpenTurn(session.events) !== undefined)
276
+ return;
277
+ const { consecutiveDenies, windowDenies, windowSize, action } = this.config.circuitBreaker;
278
+ const consecutive = consecutiveDeniesInOpenTurn(session.events);
279
+ const trip = consecutive >= consecutiveDenies
280
+ ? { kind: 'consecutive', count: consecutive }
281
+ : (() => {
282
+ const window = deniesInRecentVerdicts(session.events, windowSize);
283
+ return window >= windowDenies ? { kind: 'window', count: window } : undefined;
284
+ })();
285
+ if (trip === undefined)
286
+ return;
287
+ const circuitId = newCircuitId();
288
+ session.append('autoReview/circuit', {
289
+ circuitId,
290
+ action,
291
+ trip,
292
+ toolName: request.toolName,
293
+ }, { ignorable: true });
294
+ this.ctx.logger.warn(`auto-review circuit breaker tripped (${trip.kind}: ${trip.count}) by ${request.toolName}; action=${action}`);
295
+ if (action === 'abort-turn') {
296
+ request.agent.inject(createUserMessage({
297
+ content: [{ type: 'text', text: messages(this.config.language).circuitNotice(trip.kind, trip.count) }],
298
+ source: { kind: 'plugin', plugin: 'auto-review' },
299
+ }));
300
+ setTimeout(() => {
301
+ request.agent.cancel({ kind: 'hook', reason: `auto-review circuit breaker: ${trip.kind} ${trip.count}` });
302
+ }, 0);
303
+ }
304
+ }
305
+ /**
306
+ * Store one model-visible feedback text for a denied/failed call's tool
307
+ * result, keyed by call id. Consumed once by the post-execute listener;
308
+ * entries expire after a bounded TTL so a result path that never reaches
309
+ * post-execute cannot grow the map. Same call id twice is last-wins (a
310
+ * retried approval replaces its own pending feedback).
311
+ */
312
+ recordFeedback(callId, text) {
313
+ if (callId === undefined)
314
+ return;
315
+ const now = Date.now();
316
+ for (const [key, entry] of this.feedback) {
317
+ if (now - entry.at > FEEDBACK_TTL_MS)
318
+ this.feedback.delete(key);
319
+ }
320
+ this.feedback.set(callId, { text, at: now });
321
+ }
322
+ /**
323
+ * Record a deny reason (plus the anti-circumvention guidance) for the
324
+ * denied call's tool result.
325
+ * @param callId - the denied call.
326
+ * @param toolName - the denied tool.
327
+ * @param reviewId - the verdict event's id (embedded in the injected text).
328
+ * @param reason - the reviewer's reason.
329
+ */
330
+ recordDenyReason(callId, toolName, reviewId, reason) {
331
+ this.recordFeedback(callId, `${denyResultText(reviewId, toolName, reason)}\n${this.config.denyGuidance}`);
332
+ }
333
+ /**
334
+ * Record a fallback-rejection text for the failed call's tool result.
335
+ * @param callId - the failed call.
336
+ * @param reviewId - the fallback verdict event's id (embedded in the text).
337
+ * @param fallback - the failure category.
338
+ * @param error - the failure detail.
339
+ */
340
+ recordFallbackFeedback(callId, reviewId, fallback, error) {
341
+ this.recordFeedback(callId, fallbackResultText(reviewId, fallback, truncate(error, this.config.reasonMaxChars)));
342
+ }
343
+ /**
344
+ * The `tools/post-execute` listener: replace the generic rejection text of
345
+ * a call THIS answerer denied with the recorded feedback (the model-visible
346
+ * content, reconstructable via the embedded marker). Any other call
347
+ * delegates untouched.
348
+ */
349
+ injectDenyReason(exec, result, next) {
350
+ const entry = this.feedback.get(exec.callId);
351
+ if (entry === undefined)
352
+ return next();
353
+ this.feedback.delete(exec.callId);
354
+ // Only the denial result exists for this call (the tool never executed);
355
+ // a non-error result means the chain evolved past us — leave it alone.
356
+ if (!result.isError)
357
+ return next();
358
+ return Promise.resolve({
359
+ kind: 'block',
360
+ feedback: [{ type: 'text', text: entry.text }],
361
+ });
362
+ }
363
+ /**
364
+ * Execute the `/auto-review` command: `on` / `off` write the durable
365
+ * `autoReview/state` override (surviving restore) and inject a switch
366
+ * notice; `status` reports the effective state, both per-turn budgets,
367
+ * and the session's cumulative statistics; `approve [n]` records a
368
+ * one-shot human override for a recent denial.
369
+ * @param invocation - the received command invocation.
370
+ * @returns the command result shown to the user.
371
+ */
372
+ command(invocation) {
373
+ const agent = invocation.agent;
374
+ const session = agent.session;
375
+ const t = messages(this.config.language);
376
+ const input = invocation.rawInput.trim().toLowerCase();
377
+ if (input.startsWith('approve'))
378
+ return this.approveCommand(invocation);
379
+ const current = effectiveAutoReviewState(session.events) ?? this.config.enableByDefault;
380
+ if (input === 'status' || input === '') {
381
+ const stats = reviewStats(session.events);
382
+ const circuit = circuitInOpenTurn(session.events);
383
+ const recent = stats.recent.length === 0
384
+ ? []
385
+ : [t.recentLine(stats.recent.map(verdict => {
386
+ const label = verdict.decision !== undefined
387
+ ? verdict.decision
388
+ : `fallback(${verdict.fallback ?? '?'})`;
389
+ return `${verdict.toolName}: ${label}`;
390
+ }).join(', '))];
391
+ return {
392
+ kind: 'success',
393
+ text: [
394
+ t.statusLine(current),
395
+ t.verdictsLine(autoReviewsInOpenTurn(session.events), this.config.maxReviewsPerTurn),
396
+ t.failuresLine(autoReviewFailuresInOpenTurn(session.events), this.config.maxFailuresPerTurn),
397
+ ...circuit === undefined ? [] : [t.circuitLine(circuit.trip.kind, circuit.trip.count, circuit.action)],
398
+ t.allTimeLine(stats.allows, stats.denies, stats.fallbacks, stats.rejections, stats.avgDurationMs),
399
+ ...recent,
400
+ t.usage,
401
+ ].join('\n'),
402
+ };
403
+ }
404
+ if (input !== 'on' && input !== 'off') {
405
+ return {
406
+ kind: 'error',
407
+ text: t.unknownArg(invocation.rawInput.trim()),
408
+ };
409
+ }
410
+ const enabled = input === 'on';
411
+ if (current === enabled) {
412
+ return { kind: 'success', text: t.already(input.toUpperCase()) };
413
+ }
414
+ ;
415
+ session.append('autoReview/state', { enabled }, { ignorable: true });
416
+ agent.inject(createUserMessage({
417
+ content: [{
418
+ type: 'text',
419
+ text: t.switchedNotice(enabled),
420
+ }],
421
+ source: { kind: 'plugin', plugin: 'auto-review' },
422
+ }));
423
+ return { kind: 'success', text: t.switchedResult(input.toUpperCase()) };
424
+ }
425
+ /**
426
+ * Execute `/auto-review approve [n]`: record a single-use human override
427
+ * for the n-th most recent denial (1 = most recent). The override is
428
+ * consumed by the NEXT same-tool review within `overrideTtlMs`, which
429
+ * carries the authorization as reviewer context — the reviewer still
430
+ * decides.
431
+ * @param invocation - the received command invocation.
432
+ * @returns the command result shown to the user.
433
+ */
434
+ approveCommand(invocation) {
435
+ const agent = invocation.agent;
436
+ const session = agent.session;
437
+ const t = messages(this.config.language);
438
+ const arg = invocation.rawInput.trim().split(/\s+/u)[1];
439
+ const index = arg === undefined ? 1 : Number.parseInt(arg, 10);
440
+ if (!Number.isSafeInteger(index) || index < 1) {
441
+ return {
442
+ kind: 'error',
443
+ text: t.approveInvalid(arg ?? ''),
444
+ };
445
+ }
446
+ const denies = lastDeniedVerdicts(session.events, index);
447
+ const target = denies[index - 1];
448
+ if (target === undefined) {
449
+ return { kind: 'error', text: t.approveNone(index, denies.length) };
450
+ }
451
+ ;
452
+ session.append('autoReview/override', {
453
+ reviewId: target.reviewId,
454
+ toolName: target.toolName,
455
+ }, { ignorable: true });
456
+ return {
457
+ kind: 'success',
458
+ text: t.approveResult(target.toolName, String(target.reviewId), Math.round(this.config.overrideTtlMs / 60_000)),
459
+ };
460
+ }
461
+ }
462
+ /**
463
+ * Mount the plugin: resolve config, register the answerer and the
464
+ * post-execute listener as effects, register the slash command, and register
465
+ * the `autoReview` session projection (when the host provides the
466
+ * session-projection capability — the web profile does; bare test mounts and
467
+ * minimal compositions may not, and the answerer must not depend on it).
468
+ * @param ctx - the host context.
469
+ * @param config - raw plugin config.
470
+ */
471
+ export function apply(ctx, config) {
472
+ const resolved = resolveConfig(config);
473
+ const runtime = new AutoReviewRuntime(ctx, resolved);
474
+ ctx.on('approval/request', (request, next) => runtime.answer(request, next));
475
+ ctx.on('tools/post-execute', (exec, result, next) => runtime.injectDenyReason(exec, result, next));
476
+ ctx.commands.register({
477
+ name: 'auto-review',
478
+ description: messages(resolved.language).description,
479
+ input: { hint: 'on|off|status|approve [n]' },
480
+ handler: invocation => runtime.command(invocation),
481
+ });
482
+ if (ctx.get('sessionProjections') !== undefined) {
483
+ ctx.inject(['sessionProjections'], scope => scope.sessionProjections.register(makeAutoReviewProjection(resolved.enableByDefault)));
484
+ }
485
+ }
486
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,132 @@
1
+ {
2
+ "name": "dsh-auto-review",
3
+ "version": "0.4.0",
4
+ "description": "Second-model AI auto-review for DeepSeek Harness approval requests: a read-only reviewer subagent decides allow/deny on the approval answerer chain, with fail-closed fallback and full session-log audit.",
5
+ "private": false,
6
+ "author": {
7
+ "name": "PerryLink"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/PerryLink/dsh-auto-review.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/PerryLink/dsh-auto-review/issues"
15
+ },
16
+ "homepage": "https://github.com/PerryLink/dsh-auto-review#readme",
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "type": "module",
21
+ "main": "./lib/index.js",
22
+ "types": "./lib/types/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./lib/types/index.d.ts",
26
+ "default": "./lib/index.js"
27
+ },
28
+ "./invariant": {
29
+ "types": "./lib/types/invariant.d.ts",
30
+ "default": "./lib/invariant.js"
31
+ },
32
+ "./client": {
33
+ "types": "./lib/types/client/index.d.ts",
34
+ "default": "./lib/client.js"
35
+ },
36
+ "./package.json": "./package.json"
37
+ },
38
+ "files": [
39
+ "lib",
40
+ "src",
41
+ "cordis.patch.yml",
42
+ "CHANGELOG.md",
43
+ "README.md",
44
+ "README.zh.md",
45
+ "README.es.md",
46
+ "README.pt.md",
47
+ "README.hi.md",
48
+ "LICENSE"
49
+ ],
50
+ "dsh": {
51
+ "bundle": {
52
+ "patch": "./cordis.patch.yml"
53
+ },
54
+ "client": {
55
+ "platform": "web",
56
+ "inject": [
57
+ "@deepseek-ai/dsh-client-connection",
58
+ "@deepseek-ai/dsh-client-runtime",
59
+ "@deepseek-ai/dsh-client-locale",
60
+ "@deepseek-ai/dsh-client-ui-slots",
61
+ "@deepseek-ai/dsh-client-ui-conversation"
62
+ ]
63
+ }
64
+ },
65
+ "keywords": [
66
+ "deepseek-harness",
67
+ "dsh",
68
+ "dsh-plugin",
69
+ "cordis",
70
+ "approval",
71
+ "auto-review",
72
+ "second-model",
73
+ "ai-safety",
74
+ "sandbox",
75
+ "subagent"
76
+ ],
77
+ "engines": {
78
+ "node": "^22.19.0 || >=24.0.0"
79
+ },
80
+ "peerDependencies": {
81
+ "@deepseek-ai/cordis": "^4.0.1",
82
+ "@deepseek-ai/schemastery": "^3.18.0",
83
+ "@deepseek-ai/dsh-agent": "0.1.0-rc.6",
84
+ "@deepseek-ai/dsh-brand": "0.1.0-rc.6",
85
+ "@deepseek-ai/dsh-commands": "0.1.0-rc.6",
86
+ "@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
87
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
88
+ "@deepseek-ai/dsh-session": "0.1.0-rc.6",
89
+ "@deepseek-ai/dsh-session-projection": "0.1.0-rc.6",
90
+ "@deepseek-ai/dsh-subagent": "0.1.0-rc.6",
91
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
92
+ "@deepseek-ai/dsh-user-approval": "0.1.0-rc.6"
93
+ },
94
+ "dependencies": {
95
+ "tsdown": "^0.22.14",
96
+ "typescript": "^5.9.0",
97
+ "zod": "^4.4.3"
98
+ },
99
+ "devDependencies": {
100
+ "@deepseek-ai/cordis": "^4.0.1",
101
+ "@deepseek-ai/schemastery": "^3.18.0",
102
+ "@deepseek-ai/dsh-agent": "0.1.0-rc.6",
103
+ "@deepseek-ai/dsh-api-remotes": "0.1.0-rc.6",
104
+ "@deepseek-ai/dsh-brand": "0.1.0-rc.6",
105
+ "@deepseek-ai/dsh-client-connection": "0.1.0-rc.6",
106
+ "@deepseek-ai/dsh-client-locale": "0.1.0-rc.6",
107
+ "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.6",
108
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.6",
109
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.6",
110
+ "@deepseek-ai/dsh-commands": "0.1.0-rc.6",
111
+ "@deepseek-ai/dsh-invariants": "0.1.0-rc.6",
112
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.6",
113
+ "@deepseek-ai/dsh-session": "0.1.0-rc.6",
114
+ "@deepseek-ai/dsh-session-projection": "0.1.0-rc.6",
115
+ "@deepseek-ai/dsh-subagent": "0.1.0-rc.6",
116
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.6",
117
+ "@deepseek-ai/dsh-user-approval": "0.1.0-rc.6",
118
+ "@types/node": "^22.19.0",
119
+ "@types/react": "18.3.31",
120
+ "jsdom": "^26.1.0",
121
+ "react": "18.3.1",
122
+ "react-dom": "18.3.1",
123
+ "vitest": "^3.2.0"
124
+ },
125
+ "license": "Apache-2.0",
126
+ "scripts": {
127
+ "build": "node scripts/prepare.mjs",
128
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
129
+ "test": "vitest run",
130
+ "verify:self-contained": "node scripts/verify-self-contained.mjs"
131
+ }
132
+ }