cc-reviewer 6.1.0 → 6.2.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/dist/handoff.d.ts CHANGED
@@ -218,8 +218,13 @@ export declare function selectRole(focusAreas?: FocusArea[]): ReviewerRole;
218
218
  export declare const ADVERSARIAL_REVIEWER: ReviewerRole;
219
219
  /**
220
220
  * Build an adversarial handoff prompt with challenge-mode stance sections.
221
- * Same structure as buildHandoffPrompt but adds adversarial XML sections
222
- * and uses the ADVERSARIAL_REVIEWER role.
221
+ *
222
+ * Block structure ported from openai/codex-plugin-cc's adversarial-review
223
+ * prompt: tagged XML blocks (operating_stance, attack_surface, review_method,
224
+ * finding_bar, calibration_rules, grounding_rules, final_check) so the prompt
225
+ * has stable internal structure the reviewer can lean on. CC's handoff
226
+ * sections (uncertainties / decisions / questions / focus / files / focus
227
+ * instructions) are layered on after as our differentiator.
223
228
  */
224
229
  export declare function buildAdversarialHandoffPrompt(options: PromptOptions): string;
225
230
  export interface PromptOptions {
package/dist/handoff.js CHANGED
@@ -186,8 +186,13 @@ export const ADVERSARIAL_REVIEWER = {
186
186
  };
187
187
  /**
188
188
  * Build an adversarial handoff prompt with challenge-mode stance sections.
189
- * Same structure as buildHandoffPrompt but adds adversarial XML sections
190
- * and uses the ADVERSARIAL_REVIEWER role.
189
+ *
190
+ * Block structure ported from openai/codex-plugin-cc's adversarial-review
191
+ * prompt: tagged XML blocks (operating_stance, attack_surface, review_method,
192
+ * finding_bar, calibration_rules, grounding_rules, final_check) so the prompt
193
+ * has stable internal structure the reviewer can lean on. CC's handoff
194
+ * sections (uncertainties / decisions / questions / focus / files / focus
195
+ * instructions) are layered on after as our differentiator.
191
196
  */
192
197
  export function buildAdversarialHandoffPrompt(options) {
193
198
  const { handoff } = options;
@@ -195,34 +200,36 @@ export function buildAdversarialHandoffPrompt(options) {
195
200
  const sections = [];
196
201
  // SECTION 1: ROLE
197
202
  sections.push(`# ROLE: ${role.name}\n\n${role.systemPrompt}`);
198
- // SECTION 2: ADVERSARIAL STANCE
199
- sections.push(`## ADVERSARIAL STANCE
200
-
201
- <operating_stance>
202
- Default to skepticism. Assume the change can fail in subtle, high-cost,
203
- or user-visible ways until the evidence says otherwise. Do not give credit
204
- for good intent, partial fixes, or likely follow-up work.
203
+ // SECTION 2: ADVERSARIAL STANCE — tagged blocks form the operating contract
204
+ sections.push(`<operating_stance>
205
+ Default to skepticism.
206
+ Assume the change can fail in subtle, high-cost, or user-visible ways until the evidence says otherwise.
207
+ Do not give credit for good intent, partial fixes, or likely follow-up work.
208
+ If something only works on the happy path, treat that as a real weakness.
205
209
  </operating_stance>
206
210
 
207
211
  <attack_surface>
208
- Prioritized failure categories:
209
- 1. Auth/permissions bypass
210
- 2. Data loss or corruption
211
- 3. Rollback safety
212
- 4. Race conditions / concurrency
213
- 5. Empty-state / null / timeout handling
214
- 6. Version skew / backwards compatibility
215
- 7. Observability gaps (missing logs, metrics, alerts)
212
+ Prioritize the kinds of failures that are expensive, dangerous, or hard to detect:
213
+ - auth, permissions, tenant isolation, and trust boundaries
214
+ - data loss, corruption, duplication, and irreversible state changes
215
+ - rollback safety, retries, partial failure, and idempotency gaps
216
+ - race conditions, ordering assumptions, stale state, and re-entrancy
217
+ - empty-state, null, timeout, and degraded dependency behavior
218
+ - version skew, schema drift, migration hazards, and compatibility regressions
219
+ - observability gaps that would hide failure or make recovery harder
216
220
  </attack_surface>
217
221
 
218
222
  <review_method>
219
- Actively try to disprove the change. Look for violated invariants,
220
- missing guards, unhandled failure paths. If the user supplied a focus area,
221
- weight it heavily, but still report any other material issue you can defend.
223
+ Actively try to disprove the change.
224
+ Look for violated invariants, missing guards, unhandled failure paths, and assumptions that stop being true under stress.
225
+ Trace how bad inputs, retries, concurrent actions, or partially completed operations move through the code.
226
+ If the user supplied a focus area, weight it heavily, but still report any other material issue you can defend.
222
227
  </review_method>
223
228
 
224
229
  <finding_bar>
225
- Material findings only. Each must answer:
230
+ Report only material findings.
231
+ Do not include style feedback, naming feedback, low-value cleanup, or speculative concerns without evidence.
232
+ Each finding must answer:
226
233
  1. What can go wrong?
227
234
  2. Why is this code path vulnerable?
228
235
  3. What is the likely impact?
@@ -230,15 +237,25 @@ Material findings only. Each must answer:
230
237
  </finding_bar>
231
238
 
232
239
  <calibration_rules>
233
- Prefer one strong finding over several weak ones. If you cannot defend
234
- a finding from the provided code, drop it.
240
+ Prefer one strong finding over several weak ones.
241
+ Do not dilute serious issues with filler.
242
+ If the change looks safe, say so directly and return no findings.
235
243
  </calibration_rules>
236
244
 
237
245
  <grounding_rules>
238
- Be aggressive, but stay grounded. Every finding must be defensible from
239
- the repository context. No speculative findings. No "might be an issue"
240
- without concrete evidence from the code.
241
- </grounding_rules>`);
246
+ Be aggressive, but stay grounded.
247
+ Every finding must be defensible from the repository context or tool outputs.
248
+ Do not invent files, lines, code paths, incidents, attack chains, or runtime behavior you cannot support.
249
+ If a conclusion depends on an inference, state that explicitly in the finding body and keep the confidence honest.
250
+ </grounding_rules>
251
+
252
+ <final_check>
253
+ Before finalizing, check that each finding is:
254
+ - adversarial rather than stylistic
255
+ - tied to a concrete code location
256
+ - plausible under a real failure scenario
257
+ - actionable for an engineer fixing the issue
258
+ </final_check>`);
242
259
  // SECTION 3: TASK (same as standard)
243
260
  sections.push(`## YOUR TASK
244
261
 
package/dist/schema.d.ts CHANGED
@@ -11,6 +11,15 @@ export declare const ConfidenceLevel: z.ZodEnum<["verified", "high", "medium", "
11
11
  export type ConfidenceLevel = z.infer<typeof ConfidenceLevel>;
12
12
  export declare const ConfidenceScore: z.ZodNumber;
13
13
  export type ConfidenceScore = z.infer<typeof ConfidenceScore>;
14
+ /**
15
+ * Sentinel used when a reviewer omits `confidence` on a finding, agreement,
16
+ * or disagreement. Confidence is required by the Zod schema, but external
17
+ * CLIs occasionally drop the field — rather than reject the whole review,
18
+ * normalization fills it with this midpoint value. 0.5 reads as "the
19
+ * reviewer did not commit to a confidence" without skewing the result
20
+ * toward "confidently right" or "confidently wrong".
21
+ */
22
+ export declare const DEFAULT_FINDING_CONFIDENCE = 0.5;
14
23
  export declare const CodeLocation: z.ZodObject<{
15
24
  file: z.ZodString;
16
25
  line_start: z.ZodOptional<z.ZodNumber>;
package/dist/schema.js CHANGED
@@ -12,6 +12,15 @@ export const SeverityLevel = z.enum(['critical', 'high', 'medium', 'low', 'info'
12
12
  export const ConfidenceLevel = z.enum(['verified', 'high', 'medium', 'low', 'uncertain']);
13
13
  // Numeric confidence score (0-1)
14
14
  export const ConfidenceScore = z.number().min(0).max(1);
15
+ /**
16
+ * Sentinel used when a reviewer omits `confidence` on a finding, agreement,
17
+ * or disagreement. Confidence is required by the Zod schema, but external
18
+ * CLIs occasionally drop the field — rather than reject the whole review,
19
+ * normalization fills it with this midpoint value. 0.5 reads as "the
20
+ * reviewer did not commit to a confidence" without skewing the result
21
+ * toward "confidently right" or "confidently wrong".
22
+ */
23
+ export const DEFAULT_FINDING_CONFIDENCE = 0.5;
15
24
  // =============================================================================
16
25
  // CODE LOCATION
17
26
  // =============================================================================
@@ -40,7 +49,7 @@ export const ReviewFinding = z.object({
40
49
  'other'
41
50
  ]).describe('Primary category of the finding'),
42
51
  severity: SeverityLevel.describe('Impact severity level'),
43
- confidence: ConfidenceScore.describe('Confidence in this finding (0-1)'),
52
+ confidence: ConfidenceScore.describe('Confidence in this finding (0-1). Required. If the reviewer omits this field, normalizeReviewOutput fills it with DEFAULT_FINDING_CONFIDENCE (0.5) so the whole review is not dropped.'),
44
53
  title: z.string().max(120).describe('Brief title summarizing the issue'),
45
54
  description: z.string().describe('Detailed explanation of the finding'),
46
55
  location: CodeLocation.optional().describe('Where in the code this applies'),
@@ -269,10 +278,28 @@ export function getReviewOutputJsonSchema() {
269
278
  }
270
279
  };
271
280
  }
281
+ /**
282
+ * Fill `confidence` with the sentinel when an object-shaped item omits it.
283
+ * Leaves non-object items alone so downstream Zod validation still surfaces
284
+ * a useful error for genuinely malformed entries.
285
+ */
286
+ function fillMissingConfidence(item) {
287
+ if (!item || typeof item !== 'object' || Array.isArray(item))
288
+ return item;
289
+ const obj = item;
290
+ if (typeof obj.confidence === 'number')
291
+ return obj;
292
+ return { ...obj, confidence: DEFAULT_FINDING_CONFIDENCE };
293
+ }
272
294
  /**
273
295
  * Normalize reviewer output that deviates from the strict schema.
274
296
  * Handles common patterns from external CLIs (e.g. Gemini returning
275
297
  * agreements as strings instead of objects, missing required fields).
298
+ *
299
+ * Notably: `confidence` is required on findings/agreements/disagreements,
300
+ * but reviewers occasionally drop it. Rather than reject the whole review,
301
+ * we fill the missing field with DEFAULT_FINDING_CONFIDENCE so the rest of
302
+ * the review survives validation.
276
303
  */
277
304
  function normalizeReviewOutput(parsed) {
278
305
  const normalized = { ...parsed };
@@ -280,13 +307,13 @@ function normalizeReviewOutput(parsed) {
280
307
  if (!normalized.reviewer) {
281
308
  normalized.reviewer = 'external';
282
309
  }
283
- // Normalize agreements: string[] -> Agreement[]
310
+ // Normalize agreements: string[] -> Agreement[], then fill missing confidence
284
311
  if (Array.isArray(normalized.agreements)) {
285
312
  normalized.agreements = normalized.agreements.map((a) => {
286
313
  if (typeof a === 'string') {
287
- return { original_claim: a, assessment: 'correct', confidence: 0.7 };
314
+ return { original_claim: a, assessment: 'correct', confidence: DEFAULT_FINDING_CONFIDENCE };
288
315
  }
289
- return a;
316
+ return fillMissingConfidence(a);
290
317
  });
291
318
  }
292
319
  else {
@@ -296,6 +323,14 @@ function normalizeReviewOutput(parsed) {
296
323
  normalized.disagreements = normalized.disagreements ?? [];
297
324
  normalized.alternatives = normalized.alternatives ?? [];
298
325
  normalized.findings = normalized.findings ?? [];
326
+ // Fill missing confidence on findings and disagreements (Zod requires it;
327
+ // dropping the whole review for one missing scalar is worse than a sentinel)
328
+ if (Array.isArray(normalized.findings)) {
329
+ normalized.findings = normalized.findings.map(fillMissingConfidence);
330
+ }
331
+ if (Array.isArray(normalized.disagreements)) {
332
+ normalized.disagreements = normalized.disagreements.map(fillMissingConfidence);
333
+ }
299
334
  // Normalize optional response arrays — drop non-array values
300
335
  if (normalized.uncertainty_responses !== undefined && !Array.isArray(normalized.uncertainty_responses)) {
301
336
  delete normalized.uncertainty_responses;
@@ -435,7 +470,7 @@ export function parseLegacyMarkdownOutput(markdown, reviewer) {
435
470
  output.agreements.push({
436
471
  original_claim: content.split(':')[0] || content,
437
472
  assessment: 'correct',
438
- confidence: 0.7,
473
+ confidence: DEFAULT_FINDING_CONFIDENCE,
439
474
  });
440
475
  }
441
476
  }
@@ -450,7 +485,7 @@ export function parseLegacyMarkdownOutput(markdown, reviewer) {
450
485
  output.disagreements.push({
451
486
  original_claim: content.split(':')[0] || content,
452
487
  issue: 'incorrect',
453
- confidence: 0.7,
488
+ confidence: DEFAULT_FINDING_CONFIDENCE,
454
489
  reason: content,
455
490
  });
456
491
  }
@@ -469,7 +504,7 @@ export function parseLegacyMarkdownOutput(markdown, reviewer) {
469
504
  id: `legacy-${idx++}`,
470
505
  category: 'other',
471
506
  severity: 'medium',
472
- confidence: 0.6,
507
+ confidence: DEFAULT_FINDING_CONFIDENCE,
473
508
  title: content.slice(0, 100),
474
509
  description: content,
475
510
  location: locationMatch ? {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-reviewer",
3
- "version": "6.1.0",
3
+ "version": "6.2.0",
4
4
  "description": "MCP server for Claude Code - Get second-opinion feedback from Codex/Gemini CLIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",