clud-bug 0.6.34 → 0.7.0-rc.2
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/bin/clud-bug.js +10 -1353
- package/dist/cli/agents-md.d.ts +16 -0
- package/dist/cli/agents-md.d.ts.map +1 -0
- package/dist/cli/agents-md.js +226 -0
- package/dist/cli/agents-md.js.map +1 -0
- package/dist/cli/audit.d.ts +13 -0
- package/dist/cli/audit.d.ts.map +1 -0
- package/dist/cli/audit.js +90 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/branch-protection.d.ts +57 -0
- package/dist/cli/branch-protection.d.ts.map +1 -0
- package/dist/cli/branch-protection.js +118 -0
- package/dist/cli/branch-protection.js.map +1 -0
- package/dist/cli/edit-workflow.d.ts +18 -0
- package/dist/cli/edit-workflow.d.ts.map +1 -0
- package/dist/cli/edit-workflow.js +43 -0
- package/dist/cli/edit-workflow.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +18 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/main.d.ts +3 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +1336 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/skill-usage.d.ts +109 -0
- package/dist/cli/skill-usage.d.ts.map +1 -0
- package/dist/cli/skill-usage.js +380 -0
- package/dist/cli/skill-usage.js.map +1 -0
- package/dist/cli/skills.d.ts +56 -0
- package/dist/cli/skills.d.ts.map +1 -0
- package/dist/cli/skills.js +292 -0
- package/dist/cli/skills.js.map +1 -0
- package/dist/cli/update.d.ts +29 -0
- package/dist/cli/update.d.ts.map +1 -0
- package/dist/cli/update.js +186 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/cli/usage.d.ts +142 -0
- package/dist/cli/usage.d.ts.map +1 -0
- package/dist/cli/usage.js +348 -0
- package/dist/cli/usage.js.map +1 -0
- package/dist/core/audit.d.ts +8 -0
- package/dist/core/audit.d.ts.map +1 -0
- package/dist/core/audit.js +47 -0
- package/dist/core/audit.js.map +1 -0
- package/dist/core/detect.d.ts +77 -0
- package/dist/core/detect.d.ts.map +1 -0
- package/dist/core/detect.js +262 -0
- package/dist/core/detect.js.map +1 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +31 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/prompt-builder.d.ts +164 -0
- package/dist/core/prompt-builder.d.ts.map +1 -0
- package/dist/core/prompt-builder.js +419 -0
- package/dist/core/prompt-builder.js.map +1 -0
- package/dist/core/prompts.d.ts +9 -0
- package/dist/core/prompts.d.ts.map +1 -0
- package/dist/core/prompts.js +401 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/render-review.d.ts +6 -0
- package/dist/core/render-review.d.ts.map +1 -0
- package/dist/core/render-review.js +219 -0
- package/dist/core/render-review.js.map +1 -0
- package/dist/core/render.d.ts +13 -0
- package/dist/core/render.d.ts.map +1 -0
- package/dist/core/render.js +80 -0
- package/dist/core/render.js.map +1 -0
- package/dist/core/review-schema-zod.d.ts +240 -0
- package/dist/core/review-schema-zod.d.ts.map +1 -0
- package/dist/core/review-schema-zod.js +218 -0
- package/dist/core/review-schema-zod.js.map +1 -0
- package/dist/core/review-schema.d.ts +42 -0
- package/dist/core/review-schema.d.ts.map +1 -0
- package/dist/core/review-schema.js +156 -0
- package/dist/core/review-schema.js.map +1 -0
- package/dist/core/review-writeback.d.ts +139 -0
- package/dist/core/review-writeback.d.ts.map +1 -0
- package/dist/core/review-writeback.js +313 -0
- package/dist/core/review-writeback.js.map +1 -0
- package/dist/core/skills.d.ts +122 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +636 -0
- package/dist/core/skills.js.map +1 -0
- package/package.json +30 -4
- package/{lib/agents-md.js → src/cli/agents-md.ts} +25 -14
- package/{lib/audit.js → src/cli/audit.ts} +37 -44
- package/{lib/branch-protection.js → src/cli/branch-protection.ts} +75 -11
- package/{lib/edit-workflow.js → src/cli/edit-workflow.ts} +32 -11
- package/src/cli/index.ts +101 -0
- package/src/cli/main.ts +1376 -0
- package/{lib/skill-usage.js → src/cli/skill-usage.ts} +168 -94
- package/src/cli/skills.ts +386 -0
- package/{lib/update.js → src/cli/update.ts} +68 -27
- package/{lib/usage.js → src/cli/usage.ts} +167 -76
- package/src/core/audit.ts +53 -0
- package/{lib/detect.js → src/core/detect.ts} +100 -47
- package/src/core/index.ts +155 -0
- package/src/core/prompt-builder.ts +561 -0
- package/{lib/prompts.js → src/core/prompts.ts} +16 -2
- package/{lib/render-review.js → src/core/render-review.ts} +57 -25
- package/{lib/render.js → src/core/render.ts} +36 -10
- package/src/core/review-schema-zod.ts +262 -0
- package/{lib/review-schema.js → src/core/review-schema.ts} +68 -5
- package/src/core/review-writeback.ts +446 -0
- package/{lib/skills.js → src/core/skills.ts} +339 -342
- package/templates/workflow-py.yml.tmpl +2 -2
- package/templates/workflow-ts.yml.tmpl +2 -2
- package/templates/workflow.yml.tmpl +17 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/core/render.ts"],"names":[],"mappings":"AA8BA,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,80 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { serializedReviewSchema } from './review-schema.js';
|
|
6
|
+
const PLACEHOLDER_RE = /\{\{([A-Z_]+)\}\}/g;
|
|
7
|
+
// CLUD_BUG_VERSION (0.0.O / v0.6.22) — read from this package's
|
|
8
|
+
// package.json at module-load time. The rendered workflow uses
|
|
9
|
+
// `npx --yes clud-bug@<CLUD_BUG_VERSION>` in the post-step that renders
|
|
10
|
+
// structured output to markdown. Pinning to the version that ran
|
|
11
|
+
// `clud-bug init` guarantees the renderer's output shape matches the
|
|
12
|
+
// prompt's expectations.
|
|
13
|
+
//
|
|
14
|
+
// IMPORTANT (v0.7.0 TS migration): the JS source lived at lib/render.js,
|
|
15
|
+
// so `join(__dirname, '..', 'package.json')` reached the package root
|
|
16
|
+
// from one level up. The TS port compiles to dist/core/render.js, which
|
|
17
|
+
// is TWO levels deep (dist/core/) — so we walk up TWO levels to find
|
|
18
|
+
// package.json. Without this adjustment, module-load would throw at
|
|
19
|
+
// runtime with "ENOENT dist/package.json". Verify on rebuild via:
|
|
20
|
+
// node -e "import('./dist/core/render.js').then(m => console.log(m.DEFAULTS.CLUD_BUG_VERSION))"
|
|
21
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
const PKG_VERSION = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf8')).version;
|
|
23
|
+
// Default values for substitution tokens that every template uses.
|
|
24
|
+
// Callers can override per-render by passing the same key in `vars`.
|
|
25
|
+
//
|
|
26
|
+
// CCA_VERSION pins `anthropics/claude-code-action` to a specific tag in
|
|
27
|
+
// every shipped workflow. Without this, templates resolved `@v1` (the
|
|
28
|
+
// floating major), so upstream changes could silently land in installed
|
|
29
|
+
// workflows mid-cycle. Bumping the pin requires a clud-bug release, which
|
|
30
|
+
// makes the upgrade visible + lets users opt out by pinning a different
|
|
31
|
+
// version in their own forked workflow.
|
|
32
|
+
export const DEFAULTS = {
|
|
33
|
+
CCA_VERSION: 'v1.0.133',
|
|
34
|
+
CLUD_BUG_VERSION: PKG_VERSION,
|
|
35
|
+
REVIEW_SCHEMA: serializedReviewSchema(),
|
|
36
|
+
};
|
|
37
|
+
// Multi-line value substitution preserves YAML/Markdown indentation by
|
|
38
|
+
// applying the placeholder line's leading whitespace to every
|
|
39
|
+
// continuation line. Single-line values pass through unchanged so
|
|
40
|
+
// existing tokens (CCA_VERSION, PROJECT_DESCRIPTION) keep current behavior.
|
|
41
|
+
export function render(template, vars) {
|
|
42
|
+
const merged = { ...DEFAULTS, ...vars };
|
|
43
|
+
return template.replace(PLACEHOLDER_RE, (_match, key, offset) => {
|
|
44
|
+
if (!(key in merged)) {
|
|
45
|
+
throw new Error(`Missing template variable: ${key}`);
|
|
46
|
+
}
|
|
47
|
+
const value = String(merged[key]);
|
|
48
|
+
if (!value.includes('\n')) {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
const lineStart = template.lastIndexOf('\n', offset - 1) + 1;
|
|
52
|
+
const leadingWhitespaceMatch = template.slice(lineStart, offset).match(/^(\s*)/);
|
|
53
|
+
const indent = leadingWhitespaceMatch ? (leadingWhitespaceMatch[1] ?? '') : '';
|
|
54
|
+
return value
|
|
55
|
+
.split('\n')
|
|
56
|
+
.map((line, i) => (i === 0 || line === '' ? line : indent + line))
|
|
57
|
+
.join('\n');
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
export async function renderFile(path, vars) {
|
|
61
|
+
const tmpl = await readFile(path, 'utf8');
|
|
62
|
+
return render(tmpl, vars);
|
|
63
|
+
}
|
|
64
|
+
export function pickTemplate(languages) {
|
|
65
|
+
if (languages.includes('typescript') || languages.includes('javascript')) {
|
|
66
|
+
return 'workflow-ts.yml.tmpl';
|
|
67
|
+
}
|
|
68
|
+
if (languages.includes('python')) {
|
|
69
|
+
return 'workflow-py.yml.tmpl';
|
|
70
|
+
}
|
|
71
|
+
return 'workflow.yml.tmpl';
|
|
72
|
+
}
|
|
73
|
+
export function templateLanguage(tmplName) {
|
|
74
|
+
if (tmplName === 'workflow-ts.yml.tmpl')
|
|
75
|
+
return 'ts';
|
|
76
|
+
if (tmplName === 'workflow-py.yml.tmpl')
|
|
77
|
+
return 'py';
|
|
78
|
+
return 'generic';
|
|
79
|
+
}
|
|
80
|
+
//# 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,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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"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// Zod-typed review schema for the AI-Gateway-shape consumer (clud-bug-app).
|
|
2
|
+
//
|
|
3
|
+
// The CLI runtime in `./review-schema.ts` ships a plain JSON-Schema object
|
|
4
|
+
// because that's what the Agent SDK validator expects on the
|
|
5
|
+
// `--json-schema '<JSON>'` argument. The App's runtime instead funnels the
|
|
6
|
+
// model output through the Vercel AI SDK, which derives a JSON Schema from
|
|
7
|
+
// a Zod schema. Both consumers need to agree on the WIRE shape — separate
|
|
8
|
+
// `critical_findings[] / minor_findings[] / preexisting_findings[]` arrays
|
|
9
|
+
// per SPEC §1.8.1 — but each builds its validator from a different source.
|
|
10
|
+
//
|
|
11
|
+
// This module ports the App's Zod schemas + flat-shape helpers into core
|
|
12
|
+
// so a future drift between the App's Zod and the CLI's JSON-Schema lives
|
|
13
|
+
// in one repo. The equivalence test (test/review-schema-zod.test.js)
|
|
14
|
+
// asserts the two schemas describe the same wire shape (required fields,
|
|
15
|
+
// finding-item shape) for every release.
|
|
16
|
+
//
|
|
17
|
+
// Ported from clud-bug-app/lib/review-schema.ts (commit shipped 2026-06-08).
|
|
18
|
+
// The pure helpers (`flattenFindings`, `unflattenFindings`,
|
|
19
|
+
// `deriveSummaryCounts`, `deriveSkillsReferenced`, `buildReviewFromFindings`)
|
|
20
|
+
// are byte-equivalent to the App's helpers — see test for the equivalence
|
|
21
|
+
// fixtures.
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
// Severity buckets per SPEC §1.8.1. Only used by the internal `Finding`
|
|
24
|
+
// type — the wire `findingItemSchema` does NOT carry severity.
|
|
25
|
+
export const severityValues = ['critical', 'minor', 'preexisting'];
|
|
26
|
+
export const severitySchema = z.enum(severityValues);
|
|
27
|
+
// Status header at the top of the review file.
|
|
28
|
+
export const statusHeaderValues = [
|
|
29
|
+
'critical findings',
|
|
30
|
+
'clean',
|
|
31
|
+
'bare',
|
|
32
|
+
];
|
|
33
|
+
export const statusHeaderSchema = z.enum(statusHeaderValues);
|
|
34
|
+
export const summaryCountsSchema = z.object({
|
|
35
|
+
critical: z.number().int().min(0),
|
|
36
|
+
minor: z.number().int().min(0),
|
|
37
|
+
preexisting: z.number().int().min(0),
|
|
38
|
+
resolved_from_prior: z.number().int().min(0),
|
|
39
|
+
still_open: z.number().int().min(0),
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* Wire-shape finding item — NO severity field (mirrors the CLI's
|
|
43
|
+
* `FINDING_ITEM` JSON Schema in `./review-schema.ts`). Severity is implicit
|
|
44
|
+
* in which array the item lives in (`critical_findings`/`minor_findings`/
|
|
45
|
+
* `preexisting_findings`).
|
|
46
|
+
*/
|
|
47
|
+
export const findingItemSchema = z.object({
|
|
48
|
+
skill: z.string().min(1),
|
|
49
|
+
file: z.string().optional(),
|
|
50
|
+
line: z.number().int().min(1).optional(),
|
|
51
|
+
summary: z.string().min(1),
|
|
52
|
+
reasoning: z.string().optional(),
|
|
53
|
+
});
|
|
54
|
+
/** Per-skill scan report — one entry per loaded skill (even silent ones). */
|
|
55
|
+
export const perSkillScanItemSchema = z.object({
|
|
56
|
+
skill: z.string(),
|
|
57
|
+
outcome: z.string(),
|
|
58
|
+
});
|
|
59
|
+
/** Dedicated-section block for `review_mode: dedicated` skills. */
|
|
60
|
+
export const dedicatedSectionSchema = z.object({
|
|
61
|
+
section_name: z.string(),
|
|
62
|
+
skill: z.string(),
|
|
63
|
+
findings: z.array(findingItemSchema),
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* Full review payload — wire shape. The model produces this; the App
|
|
67
|
+
* orchestrator immediately flattens to the internal `Finding[]` shape via
|
|
68
|
+
* `flattenFindings()` for multi-pass + aggregator work, then unflattens
|
|
69
|
+
* back via `unflattenFindings()` before writeback.
|
|
70
|
+
*/
|
|
71
|
+
export const reviewSchema = z.object({
|
|
72
|
+
status_header: statusHeaderSchema,
|
|
73
|
+
summary_counts: summaryCountsSchema,
|
|
74
|
+
per_skill_scan: z.array(perSkillScanItemSchema),
|
|
75
|
+
critical_findings: z.array(findingItemSchema),
|
|
76
|
+
minor_findings: z.array(findingItemSchema),
|
|
77
|
+
preexisting_findings: z.array(findingItemSchema),
|
|
78
|
+
dedicated_sections: z.array(dedicatedSectionSchema).optional(),
|
|
79
|
+
diagnostics: z.array(z.string()).optional(),
|
|
80
|
+
skills_referenced: z.array(z.string()),
|
|
81
|
+
last_reviewed_sha: z.string(),
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* Zod schema describing the internal Finding shape (for tests + cross-check
|
|
85
|
+
* Pass 2 independentFindings). The wire equivalent is `findingItemSchema`
|
|
86
|
+
* which does NOT have severity.
|
|
87
|
+
*/
|
|
88
|
+
export const findingSchema = findingItemSchema.extend({
|
|
89
|
+
severity: severitySchema,
|
|
90
|
+
});
|
|
91
|
+
/**
|
|
92
|
+
* Flatten wire-shape `Review.critical_findings / minor_findings /
|
|
93
|
+
* preexisting_findings` into a single `Finding[]` with severity tagged.
|
|
94
|
+
* Preserves ordering: criticals first, then minors, then preexistings.
|
|
95
|
+
*/
|
|
96
|
+
export function flattenFindings(review) {
|
|
97
|
+
const out = [];
|
|
98
|
+
for (const f of review.critical_findings)
|
|
99
|
+
out.push({ ...f, severity: 'critical' });
|
|
100
|
+
for (const f of review.minor_findings)
|
|
101
|
+
out.push({ ...f, severity: 'minor' });
|
|
102
|
+
for (const f of review.preexisting_findings)
|
|
103
|
+
out.push({ ...f, severity: 'preexisting' });
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Inverse of `flattenFindings`: split a flat `Finding[]` back into the
|
|
108
|
+
* three wire-shape arrays. Used at writeback time after multi-pass
|
|
109
|
+
* aggregation has produced the final flat list.
|
|
110
|
+
*/
|
|
111
|
+
export function unflattenFindings(findings) {
|
|
112
|
+
const stripSeverity = (f) => {
|
|
113
|
+
const { severity: _s, ...rest } = f;
|
|
114
|
+
return rest;
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
critical_findings: findings.filter((f) => f.severity === 'critical').map(stripSeverity),
|
|
118
|
+
minor_findings: findings.filter((f) => f.severity === 'minor').map(stripSeverity),
|
|
119
|
+
preexisting_findings: findings.filter((f) => f.severity === 'preexisting').map(stripSeverity),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Derive `summary_counts` from a flat `Finding[]` list. Canonical
|
|
124
|
+
* source-of-truth used by the orchestrator after flattening, to
|
|
125
|
+
* overwrite the model's potentially-drifted counts.
|
|
126
|
+
*/
|
|
127
|
+
export function deriveSummaryCounts(findings) {
|
|
128
|
+
return {
|
|
129
|
+
critical: findings.filter((f) => f.severity === 'critical').length,
|
|
130
|
+
minor: findings.filter((f) => f.severity === 'minor').length,
|
|
131
|
+
preexisting: findings.filter((f) => f.severity === 'preexisting').length,
|
|
132
|
+
resolved_from_prior: 0,
|
|
133
|
+
still_open: 0,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Derive `skills_referenced` from a flat `Finding[]` list, preserving
|
|
138
|
+
* citation order (first appearance wins) and deduplicating.
|
|
139
|
+
*/
|
|
140
|
+
export function deriveSkillsReferenced(findings) {
|
|
141
|
+
const seen = new Set();
|
|
142
|
+
const out = [];
|
|
143
|
+
for (const f of findings) {
|
|
144
|
+
if (seen.has(f.skill))
|
|
145
|
+
continue;
|
|
146
|
+
seen.add(f.skill);
|
|
147
|
+
out.push(f.skill);
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Test helper: build a wire-shape `Review` from a flat `Finding[]` list.
|
|
153
|
+
* Tests historically built reviews with a flat `findings: [...]` field; the
|
|
154
|
+
* wire shape (separate severity arrays + per_skill_scan + last_reviewed_sha
|
|
155
|
+
* required) is more verbose. This helper keeps fixtures short — pass a
|
|
156
|
+
* flat list, get back a valid wire-shape Review with derived counts and
|
|
157
|
+
* skills.
|
|
158
|
+
*
|
|
159
|
+
* Production code should NOT use this; it constructs reviews from AI output
|
|
160
|
+
* directly. This is purely for test ergonomics.
|
|
161
|
+
*/
|
|
162
|
+
export function buildReviewFromFindings(opts) {
|
|
163
|
+
const split = unflattenFindings(opts.findings);
|
|
164
|
+
// Default status_header is derived from severity, NOT just emptiness.
|
|
165
|
+
// The App's original buildReviewFromFindings defaulted to
|
|
166
|
+
// 'critical findings' for ANY non-empty list, including minor-only and
|
|
167
|
+
// preexisting-only inputs. That was a bug (caught by clud-bug-review
|
|
168
|
+
// on PR #158): a review with only minor findings should be 'clean', not
|
|
169
|
+
// 'critical findings'. Fixed here on port to core.
|
|
170
|
+
//
|
|
171
|
+
// Callers that need the old behavior can pass `status_header` explicitly.
|
|
172
|
+
// Callers that want SPEC §1.8.1 semantics (the default) get the correct
|
|
173
|
+
// bucket: criticals present → 'critical findings'; else → 'clean'.
|
|
174
|
+
const hasCritical = opts.findings.some((f) => f.severity === 'critical');
|
|
175
|
+
const defaultStatus = hasCritical ? 'critical findings' : 'clean';
|
|
176
|
+
return {
|
|
177
|
+
status_header: opts.status_header ?? defaultStatus,
|
|
178
|
+
summary_counts: deriveSummaryCounts(opts.findings),
|
|
179
|
+
skills_referenced: deriveSkillsReferenced(opts.findings),
|
|
180
|
+
per_skill_scan: opts.per_skill_scan ?? [],
|
|
181
|
+
critical_findings: split.critical_findings,
|
|
182
|
+
minor_findings: split.minor_findings,
|
|
183
|
+
preexisting_findings: split.preexisting_findings,
|
|
184
|
+
...(opts.dedicated_sections !== undefined
|
|
185
|
+
? { dedicated_sections: opts.dedicated_sections }
|
|
186
|
+
: {}),
|
|
187
|
+
...(opts.diagnostics !== undefined ? { diagnostics: opts.diagnostics } : {}),
|
|
188
|
+
last_reviewed_sha: opts.last_reviewed_sha ?? '',
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// D.2.5 — cross-check pass schema
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
/**
|
|
195
|
+
* Per-finding verdict from a cross-check pass. The pass2 model echoes
|
|
196
|
+
* back Pass 1's findings by 0-indexed `pass1Index` + `agreed`/`disagreed`
|
|
197
|
+
* + rationale. The aggregator stitches these into
|
|
198
|
+
* `MultiPassReview.findings[].attributions`.
|
|
199
|
+
*
|
|
200
|
+
* Cross-check Pass 2 operates on a flat finding list (its own
|
|
201
|
+
* representation), so its independentFindings carry severity — uses the
|
|
202
|
+
* legacy `findingSchema` shape.
|
|
203
|
+
*/
|
|
204
|
+
export const crossCheckVerdictSchema = z.object({
|
|
205
|
+
pass1Index: z.number().int().min(0),
|
|
206
|
+
verdict: z.enum(['agreed', 'disagreed']),
|
|
207
|
+
rationale: z.string().optional(),
|
|
208
|
+
});
|
|
209
|
+
/**
|
|
210
|
+
* Full cross-check response. Pass 2 outputs verdicts on Pass-1 findings
|
|
211
|
+
* plus its own independent finds (in the internal `findingSchema` shape
|
|
212
|
+
* with severity, since cross-check works on already-flattened lists).
|
|
213
|
+
*/
|
|
214
|
+
export const crossCheckSchema = z.object({
|
|
215
|
+
verdicts: z.array(crossCheckVerdictSchema),
|
|
216
|
+
independentFindings: z.array(findingSchema),
|
|
217
|
+
});
|
|
218
|
+
//# sourceMappingURL=review-schema-zod.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-schema-zod.js","sourceRoot":"","sources":["../../src/core/review-schema-zod.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
type JSONSchemaObject = Record<string, unknown>;
|
|
2
|
+
export declare const REVIEW_SCHEMA: JSONSchemaObject;
|
|
3
|
+
export declare function serializedReviewSchema(): string;
|
|
4
|
+
export type FindingSeverity = 'critical' | 'minor' | 'preexisting';
|
|
5
|
+
export interface ReviewFinding {
|
|
6
|
+
skill: string;
|
|
7
|
+
summary: string;
|
|
8
|
+
file?: string;
|
|
9
|
+
line?: number;
|
|
10
|
+
reasoning?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface PerSkillScanItem {
|
|
13
|
+
skill: string;
|
|
14
|
+
outcome: string;
|
|
15
|
+
}
|
|
16
|
+
export interface DedicatedSection {
|
|
17
|
+
section_name: string;
|
|
18
|
+
skill: string;
|
|
19
|
+
findings: ReviewFinding[];
|
|
20
|
+
}
|
|
21
|
+
export interface ReviewSummaryCounts {
|
|
22
|
+
critical: number;
|
|
23
|
+
minor: number;
|
|
24
|
+
preexisting: number;
|
|
25
|
+
resolved_from_prior: number;
|
|
26
|
+
still_open: number;
|
|
27
|
+
}
|
|
28
|
+
export type ReviewStatusHeader = 'critical findings' | 'clean' | 'bare';
|
|
29
|
+
export interface ReviewData {
|
|
30
|
+
status_header: ReviewStatusHeader | string;
|
|
31
|
+
summary_counts: ReviewSummaryCounts;
|
|
32
|
+
per_skill_scan: PerSkillScanItem[];
|
|
33
|
+
critical_findings: ReviewFinding[];
|
|
34
|
+
minor_findings: ReviewFinding[];
|
|
35
|
+
preexisting_findings: ReviewFinding[];
|
|
36
|
+
skills_referenced: string[];
|
|
37
|
+
last_reviewed_sha: string;
|
|
38
|
+
dedicated_sections?: DedicatedSection[];
|
|
39
|
+
diagnostics?: string[];
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=review-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-schema.d.ts","sourceRoot":"","sources":["../../src/core/review-schema.ts"],"names":[],"mappings":"AAqCA,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA4ChD,eAAO,MAAM,aAAa,EAAE,gBAgF3B,CAAC;AAMF,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAUD,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,GAAG,aAAa,CAAC;AAEnE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG,OAAO,GAAG,MAAM,CAAC;AAExE,MAAM,WAAW,UAAU;IACzB,aAAa,EAAE,kBAAkB,GAAG,MAAM,CAAC;IAC3C,cAAc,EAAE,mBAAmB,CAAC;IACpC,cAAc,EAAE,gBAAgB,EAAE,CAAC;IACnC,iBAAiB,EAAE,aAAa,EAAE,CAAC;IACnC,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,oBAAoB,EAAE,aAAa,EAAE,CAAC;IACtC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB"}
|