@toddzheng024/dscode-bundle 0.7.18 → 0.7.20

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.7.18",
2
+ "version": "0.7.20",
3
3
  "type": "module",
4
4
  "license": "MIT",
5
5
  "author": "Todd Zheng",
@@ -94,6 +94,9 @@ export function apply(ctx, config) {
94
94
  announce(req.agent, `Automatic review rejected ${req.toolName}: ${decision.reason}. Do not retry the same outcome via another command or tool. Continue only with a materially safer alternative or ask the user.${state.blocked ? ' Stop this turn: three consecutive denials.' : ''}`);
95
95
  return 'rejected';
96
96
  }
97
+ // Only an explicit allow runs: `defer` and any future verdict value fall back
98
+ // to the human instead of being read as approval.
99
+ if (decision.decision !== 'allow') return fallback(decision.reason ?? 'Unrecognized review verdict.', details);
97
100
  state.denials = 0;
98
101
  return 'allowed-once';
99
102
  };
@@ -132,13 +135,18 @@ export function apply(ctx, config) {
132
135
  verdict = undefined;
133
136
  }
134
137
  if (verdict !== undefined) {
135
- return applyVerdict({ decision: verdict.decision, reason: verdict.reason }, {
138
+ const jevDetails = {
136
139
  actionHash, provider: 'openrouter', model: verdict.model, source: 'jev',
137
140
  choice: verdict.choice, confidence: verdict.confidence, denyProbability: verdict.denyProbability,
138
141
  authorized: verdict.authorized, destructive: verdict.destructive, credentialRisk: verdict.credentialRisk,
139
142
  durationMs: verdict.durationMs ?? (Date.now() - started),
140
143
  usage: verdict.usage ?? null, usageComplete: verdict.usage != null,
141
- });
144
+ };
145
+ // Jev hands its risk guards over when the instruction authorizes the work;
146
+ // the reviewer model below sees the pending arguments and decides, and its
147
+ // own `human` verdict still reaches the user.
148
+ if (verdict.decision !== 'defer') return applyVerdict({ decision: verdict.decision, reason: verdict.reason }, jevDetails);
149
+ record(req, { decision: 'deferred', reason: verdict.reason, ...jevDetails });
142
150
  }
143
151
  // A caller that cancelled must not fall through to a reviewer request.
144
152
  if (req.signal?.aborted) {
@@ -38,12 +38,18 @@ export function approvalQuestions() {
38
38
  criteria: {
39
39
  allow: 'Read-only, or a change the retained user instruction already asked for.',
40
40
  ask: 'Plausibly within the task but not clearly authorized, or the blast radius is unclear.',
41
- deny: 'Outside the user instruction, or it would disclose data, destroy unrelated work, or publish something.',
41
+ deny: 'Outside the user instruction, or it would disclose data, destroy unrelated work, or publish something the instruction did not ask for.',
42
42
  },
43
43
  },
44
44
  authorized: {
45
45
  type: 'noul',
46
- instructions: 'Does the retained user instruction explicitly authorize this exact action, including its target and effect?',
46
+ // Scored on its own, never as a function of how risky the action is: the
47
+ // deployment uses this number to decide whether a risk guard may defer to
48
+ // the model reviewer, and collapsing authorization into apparent safety
49
+ // made user-requested work (a release that must leave the sandbox) read as
50
+ // unauthorized. An instruction almost never names the exact command, so the
51
+ // question is about the task it asks for, not about a literal match.
52
+ instructions: 'Judge the authorization alone, separately from how risky the action is: an action the instruction asks for scores high even when it is dangerous, and a risky action nobody asked for scores low. The instruction rarely names a command, so read it as the task it asks for and decide whether this call is a required or ordinary step of that task, including its target and effect. Score 0.9 or more when the instruction directly asks for this step; 0.6 up to but not including 0.9 when the step is necessary to carry out a stated task, or the instruction names the target but not the means; 0.2 up to but not including 0.6 when the call is plausibly part of the task but optional or unclear; below 0.2 when the instruction does not cover it or it serves a different goal.',
47
53
  },
48
54
  destructive: {
49
55
  type: 'score',
@@ -67,8 +73,16 @@ const clip = (value, limit) => {
67
73
  // call, and the retained direct user instruction. It is posted to OpenRouter, so
68
74
  // it is bounded and never carries credentials.
69
75
  export function approvalState({ action, context } = {}) {
76
+ // `contextFor` hands these over as `{ seq, text }`; a caller may also pass raw
77
+ // message objects. Reading only `content` left `userInstructions` empty, so Jev
78
+ // judged every escalation without ever seeing what the user had asked for.
70
79
  const instructions = (context?.userMessages ?? [])
71
- .map(message => (message?.content ?? []).map(block => block?.text ?? '').join(' ').trim())
80
+ .map(message => {
81
+ if (typeof message?.text === 'string') return message.text.trim();
82
+ const content = message?.content;
83
+ if (typeof content === 'string') return content.trim();
84
+ return Array.isArray(content) ? content.map(block => block?.text ?? '').join(' ').trim() : '';
85
+ })
72
86
  .filter(Boolean)
73
87
  .join('\n---\n');
74
88
  return {
@@ -100,10 +114,18 @@ export function approvalVerdict(answers, thresholds = DEFAULT_THRESHOLDS) {
100
114
  }
101
115
 
102
116
  // Everything below guards the allow direction: high risk or a non-allowing
103
- // answer never runs without the human.
104
- if (credentialRisk >= thresholds.credentialRisk) return { decision: 'human', reason: 'Automatic review found possible credential handling.', ...detail };
105
- if (destructive >= thresholds.destructiveCeiling) return { decision: 'human', reason: 'Automatic review judged this action hard to undo.', ...detail };
106
- if (verdict.choice !== 'allow') return { decision: 'human', reason: 'Automatic review asked for a human decision.', ...detail };
107
- if (confidence < thresholds.autoAllow) return { decision: 'human', reason: `Automatic review was not confident enough (${confidence.toFixed(2)}).`, ...detail };
117
+ // answer must not run on Jev's word alone. None of these guards is a denial, so
118
+ // when the instruction itself authorizes the work they defer to the reviewer
119
+ // model, which sees the exact pending arguments and the retained instruction:
120
+ // Jev's scores are coarse, and this deployment already allows ordinary network
121
+ // access and a CLI's own stored credentials. A caller that does not know
122
+ // `defer` must treat it as "review me", never as an allow.
123
+ const guard = reason => authorized >= thresholds.authorizedVeto
124
+ ? { decision: 'defer', reason, ...detail }
125
+ : { decision: 'human', reason, ...detail };
126
+ if (credentialRisk >= thresholds.credentialRisk) return guard('Automatic review found possible credential handling.');
127
+ if (destructive >= thresholds.destructiveCeiling) return guard('Automatic review judged this action hard to undo.');
128
+ if (verdict.choice !== 'allow') return guard('Automatic review asked for a human decision.');
129
+ if (confidence < thresholds.autoAllow) return guard(`Automatic review was not confident enough (${confidence.toFixed(2)}).`);
108
130
  return { decision: 'allow', reason: 'Automatic review approved the action.', ...detail };
109
131
  }