clud-bug 0.6.34 → 0.7.0-rc.11

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 (153) hide show
  1. package/README.md +20 -0
  2. package/bin/clud-bug.js +10 -1353
  3. package/data/canonical-v1.json +37 -0
  4. package/dist/cli/agents-md.d.ts +16 -0
  5. package/dist/cli/agents-md.d.ts.map +1 -0
  6. package/dist/cli/agents-md.js +226 -0
  7. package/dist/cli/agents-md.js.map +1 -0
  8. package/dist/cli/audit.d.ts +13 -0
  9. package/dist/cli/audit.d.ts.map +1 -0
  10. package/dist/cli/audit.js +90 -0
  11. package/dist/cli/audit.js.map +1 -0
  12. package/dist/cli/branch-protection.d.ts +57 -0
  13. package/dist/cli/branch-protection.d.ts.map +1 -0
  14. package/dist/cli/branch-protection.js +118 -0
  15. package/dist/cli/branch-protection.js.map +1 -0
  16. package/dist/cli/configure-github.d.ts +58 -0
  17. package/dist/cli/configure-github.d.ts.map +1 -0
  18. package/dist/cli/configure-github.js +242 -0
  19. package/dist/cli/configure-github.js.map +1 -0
  20. package/dist/cli/edit-workflow.d.ts +18 -0
  21. package/dist/cli/edit-workflow.d.ts.map +1 -0
  22. package/dist/cli/edit-workflow.js +43 -0
  23. package/dist/cli/edit-workflow.js.map +1 -0
  24. package/dist/cli/index.d.ts +9 -0
  25. package/dist/cli/index.d.ts.map +1 -0
  26. package/dist/cli/index.js +19 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/cli/main.d.ts +3 -0
  29. package/dist/cli/main.d.ts.map +1 -0
  30. package/dist/cli/main.js +2067 -0
  31. package/dist/cli/main.js.map +1 -0
  32. package/dist/cli/skill-usage.d.ts +109 -0
  33. package/dist/cli/skill-usage.d.ts.map +1 -0
  34. package/dist/cli/skill-usage.js +380 -0
  35. package/dist/cli/skill-usage.js.map +1 -0
  36. package/dist/cli/skills.d.ts +56 -0
  37. package/dist/cli/skills.d.ts.map +1 -0
  38. package/dist/cli/skills.js +292 -0
  39. package/dist/cli/skills.js.map +1 -0
  40. package/dist/cli/update.d.ts +29 -0
  41. package/dist/cli/update.d.ts.map +1 -0
  42. package/dist/cli/update.js +205 -0
  43. package/dist/cli/update.js.map +1 -0
  44. package/dist/cli/usage.d.ts +142 -0
  45. package/dist/cli/usage.d.ts.map +1 -0
  46. package/dist/cli/usage.js +348 -0
  47. package/dist/cli/usage.js.map +1 -0
  48. package/dist/core/audit.d.ts +8 -0
  49. package/dist/core/audit.d.ts.map +1 -0
  50. package/dist/core/audit.js +47 -0
  51. package/dist/core/audit.js.map +1 -0
  52. package/dist/core/auto-resolve.d.ts +235 -0
  53. package/dist/core/auto-resolve.d.ts.map +1 -0
  54. package/dist/core/auto-resolve.js +293 -0
  55. package/dist/core/auto-resolve.js.map +1 -0
  56. package/dist/core/configure-github.d.ts +179 -0
  57. package/dist/core/configure-github.d.ts.map +1 -0
  58. package/dist/core/configure-github.js +289 -0
  59. package/dist/core/configure-github.js.map +1 -0
  60. package/dist/core/detect.d.ts +77 -0
  61. package/dist/core/detect.d.ts.map +1 -0
  62. package/dist/core/detect.js +262 -0
  63. package/dist/core/detect.js.map +1 -0
  64. package/dist/core/diff-findings.d.ts +96 -0
  65. package/dist/core/diff-findings.d.ts.map +1 -0
  66. package/dist/core/diff-findings.js +261 -0
  67. package/dist/core/diff-findings.js.map +1 -0
  68. package/dist/core/formal-review.d.ts +79 -0
  69. package/dist/core/formal-review.d.ts.map +1 -0
  70. package/dist/core/formal-review.js +71 -0
  71. package/dist/core/formal-review.js.map +1 -0
  72. package/dist/core/index.d.ts +17 -0
  73. package/dist/core/index.d.ts.map +1 -0
  74. package/dist/core/index.js +66 -0
  75. package/dist/core/index.js.map +1 -0
  76. package/dist/core/inline-threads.d.ts +160 -0
  77. package/dist/core/inline-threads.d.ts.map +1 -0
  78. package/dist/core/inline-threads.js +369 -0
  79. package/dist/core/inline-threads.js.map +1 -0
  80. package/dist/core/prompt-builder.d.ts +164 -0
  81. package/dist/core/prompt-builder.d.ts.map +1 -0
  82. package/dist/core/prompt-builder.js +419 -0
  83. package/dist/core/prompt-builder.js.map +1 -0
  84. package/dist/core/prompts.d.ts +9 -0
  85. package/dist/core/prompts.d.ts.map +1 -0
  86. package/dist/core/prompts.js +401 -0
  87. package/dist/core/prompts.js.map +1 -0
  88. package/dist/core/render-review.d.ts +6 -0
  89. package/dist/core/render-review.d.ts.map +1 -0
  90. package/dist/core/render-review.js +219 -0
  91. package/dist/core/render-review.js.map +1 -0
  92. package/dist/core/render.d.ts +13 -0
  93. package/dist/core/render.d.ts.map +1 -0
  94. package/dist/core/render.js +62 -0
  95. package/dist/core/render.js.map +1 -0
  96. package/dist/core/resolve-verifier.d.ts +46 -0
  97. package/dist/core/resolve-verifier.d.ts.map +1 -0
  98. package/dist/core/resolve-verifier.js +187 -0
  99. package/dist/core/resolve-verifier.js.map +1 -0
  100. package/dist/core/review-schema-zod.d.ts +240 -0
  101. package/dist/core/review-schema-zod.d.ts.map +1 -0
  102. package/dist/core/review-schema-zod.js +218 -0
  103. package/dist/core/review-schema-zod.js.map +1 -0
  104. package/dist/core/review-schema.d.ts +42 -0
  105. package/dist/core/review-schema.d.ts.map +1 -0
  106. package/dist/core/review-schema.js +156 -0
  107. package/dist/core/review-schema.js.map +1 -0
  108. package/dist/core/review-writeback.d.ts +193 -0
  109. package/dist/core/review-writeback.d.ts.map +1 -0
  110. package/dist/core/review-writeback.js +364 -0
  111. package/dist/core/review-writeback.js.map +1 -0
  112. package/dist/core/skills.d.ts +147 -0
  113. package/dist/core/skills.d.ts.map +1 -0
  114. package/dist/core/skills.js +726 -0
  115. package/dist/core/skills.js.map +1 -0
  116. package/dist/core/version.d.ts +2 -0
  117. package/dist/core/version.d.ts.map +1 -0
  118. package/dist/core/version.js +4 -0
  119. package/dist/core/version.js.map +1 -0
  120. package/package.json +37 -5
  121. package/{lib/agents-md.js → src/cli/agents-md.ts} +25 -14
  122. package/{lib/audit.js → src/cli/audit.ts} +37 -44
  123. package/{lib/branch-protection.js → src/cli/branch-protection.ts} +75 -11
  124. package/src/cli/configure-github.ts +329 -0
  125. package/{lib/edit-workflow.js → src/cli/edit-workflow.ts} +32 -11
  126. package/src/cli/index.ts +107 -0
  127. package/src/cli/main.ts +2204 -0
  128. package/{lib/skill-usage.js → src/cli/skill-usage.ts} +168 -94
  129. package/src/cli/skills.ts +386 -0
  130. package/{lib/update.js → src/cli/update.ts} +87 -27
  131. package/{lib/usage.js → src/cli/usage.ts} +167 -76
  132. package/src/core/audit.ts +53 -0
  133. package/src/core/auto-resolve.ts +488 -0
  134. package/src/core/configure-github.ts +497 -0
  135. package/{lib/detect.js → src/core/detect.ts} +100 -47
  136. package/src/core/diff-findings.ts +323 -0
  137. package/src/core/formal-review.ts +168 -0
  138. package/src/core/index.ts +250 -0
  139. package/src/core/inline-threads.ts +471 -0
  140. package/src/core/prompt-builder.ts +561 -0
  141. package/{lib/prompts.js → src/core/prompts.ts} +16 -2
  142. package/{lib/render-review.js → src/core/render-review.ts} +57 -25
  143. package/{lib/render.js → src/core/render.ts} +37 -17
  144. package/src/core/resolve-verifier.ts +228 -0
  145. package/src/core/review-schema-zod.ts +262 -0
  146. package/{lib/review-schema.js → src/core/review-schema.ts} +68 -5
  147. package/src/core/review-writeback.ts +565 -0
  148. package/{lib/skills.js → src/core/skills.ts} +456 -342
  149. package/src/core/version.ts +3 -0
  150. package/templates/clud-bug-review.md.tmpl +115 -0
  151. package/templates/workflow-py.yml.tmpl +80 -3
  152. package/templates/workflow-ts.yml.tmpl +80 -3
  153. package/templates/workflow.yml.tmpl +175 -8
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;CACvB;AAWD,eAAO,MAAM,QAAQ,EAAE,cAItB,CAAC;AAOF,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAM3E,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAkBjE;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhF;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAQxD;AAKD,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAEvD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAInE"}
@@ -0,0 +1,62 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { serializedReviewSchema } from './review-schema.js';
3
+ import { PKG_VERSION } from './version.js';
4
+ const PLACEHOLDER_RE = /\{\{([A-Z_]+)\}\}/g;
5
+ // Default values for substitution tokens that every template uses.
6
+ // Callers can override per-render by passing the same key in `vars`.
7
+ //
8
+ // CCA_VERSION pins `anthropics/claude-code-action` to a specific tag in
9
+ // every shipped workflow. Without this, templates resolved `@v1` (the
10
+ // floating major), so upstream changes could silently land in installed
11
+ // workflows mid-cycle. Bumping the pin requires a clud-bug release, which
12
+ // makes the upgrade visible + lets users opt out by pinning a different
13
+ // version in their own forked workflow.
14
+ export const DEFAULTS = {
15
+ CCA_VERSION: 'v1.0.133',
16
+ CLUD_BUG_VERSION: PKG_VERSION,
17
+ REVIEW_SCHEMA: serializedReviewSchema(),
18
+ };
19
+ // Multi-line value substitution preserves YAML/Markdown indentation by
20
+ // applying the placeholder line's leading whitespace to every
21
+ // continuation line. Single-line values pass through unchanged so
22
+ // existing tokens (CCA_VERSION, PROJECT_DESCRIPTION) keep current behavior.
23
+ export function render(template, vars) {
24
+ const merged = { ...DEFAULTS, ...vars };
25
+ return template.replace(PLACEHOLDER_RE, (_match, key, offset) => {
26
+ if (!(key in merged)) {
27
+ throw new Error(`Missing template variable: ${key}`);
28
+ }
29
+ const value = String(merged[key]);
30
+ if (!value.includes('\n')) {
31
+ return value;
32
+ }
33
+ const lineStart = template.lastIndexOf('\n', offset - 1) + 1;
34
+ const leadingWhitespaceMatch = template.slice(lineStart, offset).match(/^(\s*)/);
35
+ const indent = leadingWhitespaceMatch ? (leadingWhitespaceMatch[1] ?? '') : '';
36
+ return value
37
+ .split('\n')
38
+ .map((line, i) => (i === 0 || line === '' ? line : indent + line))
39
+ .join('\n');
40
+ });
41
+ }
42
+ export async function renderFile(path, vars) {
43
+ const tmpl = await readFile(path, 'utf8');
44
+ return render(tmpl, vars);
45
+ }
46
+ export function pickTemplate(languages) {
47
+ if (languages.includes('typescript') || languages.includes('javascript')) {
48
+ return 'workflow-ts.yml.tmpl';
49
+ }
50
+ if (languages.includes('python')) {
51
+ return 'workflow-py.yml.tmpl';
52
+ }
53
+ return 'workflow.yml.tmpl';
54
+ }
55
+ export function templateLanguage(tmplName) {
56
+ if (tmplName === 'workflow-ts.yml.tmpl')
57
+ return 'ts';
58
+ if (tmplName === 'workflow-py.yml.tmpl')
59
+ return 'py';
60
+ return 'generic';
61
+ }
62
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { PriorFinding, VerifyOutcome } from './auto-resolve.js';
2
+ export declare const VERIFIER_SYSTEM: string;
3
+ export interface VerifySingleFindingInput {
4
+ finding: PriorFinding;
5
+ /** Code at the finding's anchor BEFORE the fix-push. Empty when deleted. */
6
+ codeBefore: string;
7
+ /** Code at the finding's anchor AFTER the fix-push. Empty when deleted. */
8
+ codeAfter: string;
9
+ /** Optional: unified-diff hunk at the anchor. */
10
+ diffAtAnchor?: string;
11
+ }
12
+ /**
13
+ * Builds the user-facing prompt body.
14
+ *
15
+ * Prompt-injection defense:
16
+ * - System prompt is module-scope, NOT derived from user content.
17
+ * - User content (finding body, code, diff) is wrapped in fence-
18
+ * delimited blocks with clear labels. The model knows the
19
+ * boundaries.
20
+ * - Output is parsed with `parseVerifierResponse` which validates
21
+ * the verdict against a fixed enum + caps rationale at 500 chars.
22
+ * A model coerced to emit "ADDRESSED!" outside the JSON shape
23
+ * gets routed to UNCERTAIN+api-error (fail-closed).
24
+ */
25
+ export declare function buildVerifierPrompt(input: VerifySingleFindingInput): string;
26
+ /**
27
+ * Parses the model's text response into a `VerifyOutcome`. Fail-closed:
28
+ * any malformed input → UNCERTAIN+api-error with the failure mode in
29
+ * the rationale, so the caller's auto-resolve rules route through
30
+ * human review (never silently ADDRESSED).
31
+ *
32
+ * Tolerates:
33
+ * - Leading/trailing whitespace
34
+ * - The model wrapping the JSON in ```json fences (strips them)
35
+ * - Extra fields (ignored)
36
+ *
37
+ * Rejects:
38
+ * - Empty / non-string input
39
+ * - Non-JSON / malformed JSON
40
+ * - Missing or non-string `verdict`
41
+ * - `verdict` not in the allowed enum
42
+ * - Missing or empty `rationale`
43
+ * - `rationale` longer than 500 chars (caps at 500 in the outcome)
44
+ */
45
+ export declare function parseVerifierResponse(text: unknown): VerifyOutcome;
46
+ //# sourceMappingURL=resolve-verifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-verifier.d.ts","sourceRoot":"","sources":["../../src/core/resolve-verifier.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAMrE,eAAO,MAAM,eAAe,QA6BhB,CAAC;AAMb,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,YAAY,CAAC;IACtB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,MAAM,CA4C3E;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa,CAmElE"}
@@ -0,0 +1,187 @@
1
+ // Wave 5b — D.2.6 per-thread fix-verifier prompt + response parser.
2
+ //
3
+ // On every fix-push, the CLI verb asks Claude DIRECTLY for each prior
4
+ // thread: "the prior reviewer said X. Here is the BEFORE / AFTER /
5
+ // DIFF. Did the new commit address the original finding?" Verdicts:
6
+ //
7
+ // ADDRESSED — fix unambiguously resolves the original concern
8
+ // NOT_ADDRESSED — original concern still applies
9
+ // UNCERTAIN — can't tell; routes through human review
10
+ //
11
+ // This module is PURE — prompt builder + response parser. The actual
12
+ // Anthropic Messages API call lives in `src/cli/main.ts::runResolveThreads`
13
+ // (raw `fetch()` — no `@anthropic-ai/sdk` dep so the npm package stays
14
+ // dep-light). Tests inject mocked verifier outcomes via the
15
+ // `runAutoResolve` `verifier` callback in `./auto-resolve`.
16
+ //
17
+ // Ported from `clud-bug-app/lib/resolve-verifier.ts:162-260`. Differences:
18
+ // - No `@ai-sdk/anthropic` / `zod` dependency. Response parsing is
19
+ // hand-rolled JSON extraction with manual validation.
20
+ // - DROP `verifySingleFinding` (App-side IO entry point). The CLI
21
+ // verb owns the API call directly.
22
+ // - DROP `aggregateMultiPassVerdicts` — OSS is single-pass.
23
+ // ---------------------------------------------------------------------------
24
+ // System prompt — hard-coded, NOT derived from user content (anti-injection)
25
+ // ---------------------------------------------------------------------------
26
+ export const VERIFIER_SYSTEM = [
27
+ 'You are a code-review fix verifier. Your only job is to decide whether a',
28
+ 'specific code change addressed a specific prior reviewer concern.',
29
+ '',
30
+ 'You are NOT writing a new code review. You are NOT looking for new issues.',
31
+ 'You are NOT judging style. You are answering one question: did the change',
32
+ 'between BEFORE and AFTER resolve the concern raised in the prior finding?',
33
+ '',
34
+ 'Your verdict MUST be exactly one of: ADDRESSED, NOT_ADDRESSED, UNCERTAIN.',
35
+ '',
36
+ 'Rules:',
37
+ '- ADDRESSED: the AFTER code unambiguously resolves the original concern.',
38
+ ' Partial fixes that leave the core problem unsolved are NOT ADDRESSED.',
39
+ '- NOT_ADDRESSED: the AFTER code still has the original problem, OR the',
40
+ ' change is unrelated to the concern, OR the change made the problem worse.',
41
+ '- UNCERTAIN: you cannot tell from the BEFORE / AFTER alone. Use this when',
42
+ ' the context is too narrow, the change is subtle and could go either way,',
43
+ ' or the concern depends on code you cannot see. Never guess — say',
44
+ ' UNCERTAIN when you would be guessing.',
45
+ '',
46
+ 'Treat the prior finding as a black box: it might be wrong, but you are not',
47
+ 'judging the finding. You are judging whether the new code resolves what it',
48
+ 'said. If the finding asked for X and the change does X, mark ADDRESSED even',
49
+ 'if X is unnecessary.',
50
+ '',
51
+ 'Reply with a JSON object on a single line, no markdown fence, no surrounding',
52
+ 'prose. Shape:',
53
+ ' {"verdict":"ADDRESSED"|"NOT_ADDRESSED"|"UNCERTAIN","rationale":"<one sentence>"}',
54
+ 'Rationale MUST be one sentence, max 500 characters.',
55
+ ].join('\n');
56
+ // ---------------------------------------------------------------------------
57
+ // Prompt builder — pure (no env, no Date.now, no timestamps)
58
+ // ---------------------------------------------------------------------------
59
+ /**
60
+ * Builds the user-facing prompt body.
61
+ *
62
+ * Prompt-injection defense:
63
+ * - System prompt is module-scope, NOT derived from user content.
64
+ * - User content (finding body, code, diff) is wrapped in fence-
65
+ * delimited blocks with clear labels. The model knows the
66
+ * boundaries.
67
+ * - Output is parsed with `parseVerifierResponse` which validates
68
+ * the verdict against a fixed enum + caps rationale at 500 chars.
69
+ * A model coerced to emit "ADDRESSED!" outside the JSON shape
70
+ * gets routed to UNCERTAIN+api-error (fail-closed).
71
+ */
72
+ export function buildVerifierPrompt(input) {
73
+ const f = input.finding;
74
+ const anchor = f.line !== undefined ? `${f.file}:${f.line}` : f.file;
75
+ const sev = f.severity === 'critical' ? '🔴 critical' : '🟡 minor';
76
+ const parts = [];
77
+ parts.push(`A prior code review (skill: \`${f.skill}\`, severity: ${sev}) flagged \`${anchor}\` with this finding:`);
78
+ parts.push('');
79
+ parts.push('```');
80
+ parts.push('PRIOR FINDING:');
81
+ parts.push(f.body);
82
+ parts.push('```');
83
+ parts.push('');
84
+ parts.push('The PR author has since pushed a new commit. Here is the code BEFORE and AFTER:');
85
+ parts.push('');
86
+ parts.push('```');
87
+ parts.push('BEFORE:');
88
+ parts.push(input.codeBefore || '(empty — file did not exist or was empty)');
89
+ parts.push('```');
90
+ parts.push('');
91
+ parts.push('```');
92
+ parts.push('AFTER:');
93
+ parts.push(input.codeAfter || '(empty — file was deleted or emptied)');
94
+ parts.push('```');
95
+ if (input.diffAtAnchor) {
96
+ parts.push('');
97
+ parts.push('```');
98
+ parts.push('DIFF AT ANCHOR:');
99
+ parts.push(input.diffAtAnchor);
100
+ parts.push('```');
101
+ }
102
+ parts.push('');
103
+ parts.push('Did this change ADDRESS the original finding?');
104
+ parts.push('Reply with the JSON object only — single line, no markdown fence, no prose.');
105
+ return parts.join('\n');
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // Response parser — extracts `{verdict, rationale}` from the model text
109
+ // ---------------------------------------------------------------------------
110
+ /**
111
+ * Parses the model's text response into a `VerifyOutcome`. Fail-closed:
112
+ * any malformed input → UNCERTAIN+api-error with the failure mode in
113
+ * the rationale, so the caller's auto-resolve rules route through
114
+ * human review (never silently ADDRESSED).
115
+ *
116
+ * Tolerates:
117
+ * - Leading/trailing whitespace
118
+ * - The model wrapping the JSON in ```json fences (strips them)
119
+ * - Extra fields (ignored)
120
+ *
121
+ * Rejects:
122
+ * - Empty / non-string input
123
+ * - Non-JSON / malformed JSON
124
+ * - Missing or non-string `verdict`
125
+ * - `verdict` not in the allowed enum
126
+ * - Missing or empty `rationale`
127
+ * - `rationale` longer than 500 chars (caps at 500 in the outcome)
128
+ */
129
+ export function parseVerifierResponse(text) {
130
+ if (typeof text !== 'string' || !text.trim()) {
131
+ return {
132
+ verdict: 'UNCERTAIN',
133
+ source: 'api-error',
134
+ rationale: 'verifier returned empty or non-string response',
135
+ };
136
+ }
137
+ // Strip optional ```json … ``` or ``` … ``` fence.
138
+ let body = text.trim();
139
+ const fenced = body.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?```$/);
140
+ if (fenced)
141
+ body = fenced[1].trim();
142
+ let parsed;
143
+ try {
144
+ parsed = JSON.parse(body);
145
+ }
146
+ catch (err) {
147
+ return {
148
+ verdict: 'UNCERTAIN',
149
+ source: 'api-error',
150
+ rationale: `verifier response was not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
151
+ };
152
+ }
153
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
154
+ return {
155
+ verdict: 'UNCERTAIN',
156
+ source: 'api-error',
157
+ rationale: 'verifier response was not a JSON object',
158
+ };
159
+ }
160
+ const obj = parsed;
161
+ const verdict = obj.verdict;
162
+ const rationale = obj.rationale;
163
+ if (verdict !== 'ADDRESSED' &&
164
+ verdict !== 'NOT_ADDRESSED' &&
165
+ verdict !== 'UNCERTAIN') {
166
+ return {
167
+ verdict: 'UNCERTAIN',
168
+ source: 'api-error',
169
+ rationale: `verifier emitted unknown verdict: ${JSON.stringify(verdict)}`,
170
+ };
171
+ }
172
+ if (typeof rationale !== 'string' || !rationale.trim()) {
173
+ return {
174
+ verdict: 'UNCERTAIN',
175
+ source: 'api-error',
176
+ rationale: 'verifier response missing rationale',
177
+ };
178
+ }
179
+ // Cap rationale at 500 chars per the system prompt's contract.
180
+ const trimmed = rationale.trim().slice(0, 500);
181
+ return {
182
+ verdict,
183
+ rationale: trimmed,
184
+ source: 'model',
185
+ };
186
+ }
187
+ //# sourceMappingURL=resolve-verifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-verifier.js","sourceRoot":"","sources":["../../src/core/resolve-verifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,240 @@
1
+ import { z } from 'zod';
2
+ export declare const severityValues: readonly ["critical", "minor", "preexisting"];
3
+ export declare const severitySchema: z.ZodEnum<{
4
+ critical: "critical";
5
+ minor: "minor";
6
+ preexisting: "preexisting";
7
+ }>;
8
+ export type Severity = z.infer<typeof severitySchema>;
9
+ export declare const statusHeaderValues: readonly ["critical findings", "clean", "bare"];
10
+ export declare const statusHeaderSchema: z.ZodEnum<{
11
+ "critical findings": "critical findings";
12
+ clean: "clean";
13
+ bare: "bare";
14
+ }>;
15
+ export type StatusHeader = z.infer<typeof statusHeaderSchema>;
16
+ export declare const summaryCountsSchema: z.ZodObject<{
17
+ critical: z.ZodNumber;
18
+ minor: z.ZodNumber;
19
+ preexisting: z.ZodNumber;
20
+ resolved_from_prior: z.ZodNumber;
21
+ still_open: z.ZodNumber;
22
+ }, z.core.$strip>;
23
+ export type SummaryCounts = z.infer<typeof summaryCountsSchema>;
24
+ /**
25
+ * Wire-shape finding item — NO severity field (mirrors the CLI's
26
+ * `FINDING_ITEM` JSON Schema in `./review-schema.ts`). Severity is implicit
27
+ * in which array the item lives in (`critical_findings`/`minor_findings`/
28
+ * `preexisting_findings`).
29
+ */
30
+ export declare const findingItemSchema: z.ZodObject<{
31
+ skill: z.ZodString;
32
+ file: z.ZodOptional<z.ZodString>;
33
+ line: z.ZodOptional<z.ZodNumber>;
34
+ summary: z.ZodString;
35
+ reasoning: z.ZodOptional<z.ZodString>;
36
+ }, z.core.$strip>;
37
+ export type FindingItem = z.infer<typeof findingItemSchema>;
38
+ /** Per-skill scan report — one entry per loaded skill (even silent ones). */
39
+ export declare const perSkillScanItemSchema: z.ZodObject<{
40
+ skill: z.ZodString;
41
+ outcome: z.ZodString;
42
+ }, z.core.$strip>;
43
+ export type PerSkillScanItem = z.infer<typeof perSkillScanItemSchema>;
44
+ /** Dedicated-section block for `review_mode: dedicated` skills. */
45
+ export declare const dedicatedSectionSchema: z.ZodObject<{
46
+ section_name: z.ZodString;
47
+ skill: z.ZodString;
48
+ findings: z.ZodArray<z.ZodObject<{
49
+ skill: z.ZodString;
50
+ file: z.ZodOptional<z.ZodString>;
51
+ line: z.ZodOptional<z.ZodNumber>;
52
+ summary: z.ZodString;
53
+ reasoning: z.ZodOptional<z.ZodString>;
54
+ }, z.core.$strip>>;
55
+ }, z.core.$strip>;
56
+ export type DedicatedSection = z.infer<typeof dedicatedSectionSchema>;
57
+ /**
58
+ * Full review payload — wire shape. The model produces this; the App
59
+ * orchestrator immediately flattens to the internal `Finding[]` shape via
60
+ * `flattenFindings()` for multi-pass + aggregator work, then unflattens
61
+ * back via `unflattenFindings()` before writeback.
62
+ */
63
+ export declare const reviewSchema: z.ZodObject<{
64
+ status_header: z.ZodEnum<{
65
+ "critical findings": "critical findings";
66
+ clean: "clean";
67
+ bare: "bare";
68
+ }>;
69
+ summary_counts: z.ZodObject<{
70
+ critical: z.ZodNumber;
71
+ minor: z.ZodNumber;
72
+ preexisting: z.ZodNumber;
73
+ resolved_from_prior: z.ZodNumber;
74
+ still_open: z.ZodNumber;
75
+ }, z.core.$strip>;
76
+ per_skill_scan: z.ZodArray<z.ZodObject<{
77
+ skill: z.ZodString;
78
+ outcome: z.ZodString;
79
+ }, z.core.$strip>>;
80
+ critical_findings: z.ZodArray<z.ZodObject<{
81
+ skill: z.ZodString;
82
+ file: z.ZodOptional<z.ZodString>;
83
+ line: z.ZodOptional<z.ZodNumber>;
84
+ summary: z.ZodString;
85
+ reasoning: z.ZodOptional<z.ZodString>;
86
+ }, z.core.$strip>>;
87
+ minor_findings: z.ZodArray<z.ZodObject<{
88
+ skill: z.ZodString;
89
+ file: z.ZodOptional<z.ZodString>;
90
+ line: z.ZodOptional<z.ZodNumber>;
91
+ summary: z.ZodString;
92
+ reasoning: z.ZodOptional<z.ZodString>;
93
+ }, z.core.$strip>>;
94
+ preexisting_findings: z.ZodArray<z.ZodObject<{
95
+ skill: z.ZodString;
96
+ file: z.ZodOptional<z.ZodString>;
97
+ line: z.ZodOptional<z.ZodNumber>;
98
+ summary: z.ZodString;
99
+ reasoning: z.ZodOptional<z.ZodString>;
100
+ }, z.core.$strip>>;
101
+ dedicated_sections: z.ZodOptional<z.ZodArray<z.ZodObject<{
102
+ section_name: z.ZodString;
103
+ skill: z.ZodString;
104
+ findings: z.ZodArray<z.ZodObject<{
105
+ skill: z.ZodString;
106
+ file: z.ZodOptional<z.ZodString>;
107
+ line: z.ZodOptional<z.ZodNumber>;
108
+ summary: z.ZodString;
109
+ reasoning: z.ZodOptional<z.ZodString>;
110
+ }, z.core.$strip>>;
111
+ }, z.core.$strip>>>;
112
+ diagnostics: z.ZodOptional<z.ZodArray<z.ZodString>>;
113
+ skills_referenced: z.ZodArray<z.ZodString>;
114
+ last_reviewed_sha: z.ZodString;
115
+ }, z.core.$strip>;
116
+ export type Review = z.infer<typeof reviewSchema>;
117
+ /**
118
+ * Internal flat-finding type used by App orchestrator, multi-pass
119
+ * aggregator, skill-usage telemetry, etc. Created from a wire-shape
120
+ * `Review` via `flattenFindings()`. Has explicit `severity` field so
121
+ * internal code doesn't need to track which array a finding came from.
122
+ *
123
+ * Exported from the core barrel as `ZodFinding` to disambiguate from
124
+ * the CLI-shape `ReviewFinding` (which never carries severity — its
125
+ * severity comes from the array it lives in).
126
+ */
127
+ export type Finding = FindingItem & {
128
+ severity: Severity;
129
+ };
130
+ /**
131
+ * Zod schema describing the internal Finding shape (for tests + cross-check
132
+ * Pass 2 independentFindings). The wire equivalent is `findingItemSchema`
133
+ * which does NOT have severity.
134
+ */
135
+ export declare const findingSchema: z.ZodObject<{
136
+ skill: z.ZodString;
137
+ file: z.ZodOptional<z.ZodString>;
138
+ line: z.ZodOptional<z.ZodNumber>;
139
+ summary: z.ZodString;
140
+ reasoning: z.ZodOptional<z.ZodString>;
141
+ severity: z.ZodEnum<{
142
+ critical: "critical";
143
+ minor: "minor";
144
+ preexisting: "preexisting";
145
+ }>;
146
+ }, z.core.$strip>;
147
+ /**
148
+ * Flatten wire-shape `Review.critical_findings / minor_findings /
149
+ * preexisting_findings` into a single `Finding[]` with severity tagged.
150
+ * Preserves ordering: criticals first, then minors, then preexistings.
151
+ */
152
+ export declare function flattenFindings(review: Review): Finding[];
153
+ /**
154
+ * Inverse of `flattenFindings`: split a flat `Finding[]` back into the
155
+ * three wire-shape arrays. Used at writeback time after multi-pass
156
+ * aggregation has produced the final flat list.
157
+ */
158
+ export declare function unflattenFindings(findings: Finding[]): {
159
+ critical_findings: FindingItem[];
160
+ minor_findings: FindingItem[];
161
+ preexisting_findings: FindingItem[];
162
+ };
163
+ /**
164
+ * Derive `summary_counts` from a flat `Finding[]` list. Canonical
165
+ * source-of-truth used by the orchestrator after flattening, to
166
+ * overwrite the model's potentially-drifted counts.
167
+ */
168
+ export declare function deriveSummaryCounts(findings: Finding[]): SummaryCounts;
169
+ /**
170
+ * Derive `skills_referenced` from a flat `Finding[]` list, preserving
171
+ * citation order (first appearance wins) and deduplicating.
172
+ */
173
+ export declare function deriveSkillsReferenced(findings: Finding[]): string[];
174
+ /**
175
+ * Test helper: build a wire-shape `Review` from a flat `Finding[]` list.
176
+ * Tests historically built reviews with a flat `findings: [...]` field; the
177
+ * wire shape (separate severity arrays + per_skill_scan + last_reviewed_sha
178
+ * required) is more verbose. This helper keeps fixtures short — pass a
179
+ * flat list, get back a valid wire-shape Review with derived counts and
180
+ * skills.
181
+ *
182
+ * Production code should NOT use this; it constructs reviews from AI output
183
+ * directly. This is purely for test ergonomics.
184
+ */
185
+ export declare function buildReviewFromFindings(opts: {
186
+ findings: Finding[];
187
+ status_header?: StatusHeader;
188
+ last_reviewed_sha?: string;
189
+ per_skill_scan?: PerSkillScanItem[];
190
+ dedicated_sections?: DedicatedSection[];
191
+ diagnostics?: string[];
192
+ }): Review;
193
+ /**
194
+ * Per-finding verdict from a cross-check pass. The pass2 model echoes
195
+ * back Pass 1's findings by 0-indexed `pass1Index` + `agreed`/`disagreed`
196
+ * + rationale. The aggregator stitches these into
197
+ * `MultiPassReview.findings[].attributions`.
198
+ *
199
+ * Cross-check Pass 2 operates on a flat finding list (its own
200
+ * representation), so its independentFindings carry severity — uses the
201
+ * legacy `findingSchema` shape.
202
+ */
203
+ export declare const crossCheckVerdictSchema: z.ZodObject<{
204
+ pass1Index: z.ZodNumber;
205
+ verdict: z.ZodEnum<{
206
+ agreed: "agreed";
207
+ disagreed: "disagreed";
208
+ }>;
209
+ rationale: z.ZodOptional<z.ZodString>;
210
+ }, z.core.$strip>;
211
+ export type CrossCheckVerdictSchema = z.infer<typeof crossCheckVerdictSchema>;
212
+ /**
213
+ * Full cross-check response. Pass 2 outputs verdicts on Pass-1 findings
214
+ * plus its own independent finds (in the internal `findingSchema` shape
215
+ * with severity, since cross-check works on already-flattened lists).
216
+ */
217
+ export declare const crossCheckSchema: z.ZodObject<{
218
+ verdicts: z.ZodArray<z.ZodObject<{
219
+ pass1Index: z.ZodNumber;
220
+ verdict: z.ZodEnum<{
221
+ agreed: "agreed";
222
+ disagreed: "disagreed";
223
+ }>;
224
+ rationale: z.ZodOptional<z.ZodString>;
225
+ }, z.core.$strip>>;
226
+ independentFindings: z.ZodArray<z.ZodObject<{
227
+ skill: z.ZodString;
228
+ file: z.ZodOptional<z.ZodString>;
229
+ line: z.ZodOptional<z.ZodNumber>;
230
+ summary: z.ZodString;
231
+ reasoning: z.ZodOptional<z.ZodString>;
232
+ severity: z.ZodEnum<{
233
+ critical: "critical";
234
+ minor: "minor";
235
+ preexisting: "preexisting";
236
+ }>;
237
+ }, z.core.$strip>>;
238
+ }, z.core.$strip>;
239
+ export type CrossCheck = z.infer<typeof crossCheckSchema>;
240
+ //# sourceMappingURL=review-schema-zod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-schema-zod.d.ts","sourceRoot":"","sources":["../../src/core/review-schema-zod.ts"],"names":[],"mappings":"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"}