@prism-d1/cli 1.1.2 → 1.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/assets/github-workflows/prism-agent-eval.yml +2 -1
- package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +11 -1
- package/dist/assets/gitlab-workflows/prism-eval-gate.yml +8 -0
- package/dist/assets/infra/lib/constructs/otel-collector-construct.ts +96 -0
- package/dist/assets/infra/lib/dashboard-stack.ts +27 -0
- package/dist/assets/infra/lib/lambda/otel-receiver.ts +278 -8
- package/dist/assets/infra/lib/lambda/pricing/litellm-snapshot.json +3769 -0
- package/dist/assets/infra/lib/lambda/pricing/price-source.ts +56 -0
- package/dist/assets/infra/lib/lambda/pricing/price-table.ts +240 -0
- package/dist/assets/infra/lib/lambda/pricing/prices-key.ts +6 -0
- package/dist/assets/infra/lib/lambda/pricing/reprice.ts +108 -0
- package/dist/assets/infra/lib/lambda/pricing-refresh.ts +352 -0
- package/dist/assets/infra/lib/lambda/velocity-widget.ts +124 -1
- package/dist/assets/infra/package.json +4 -1
- package/dist/assets/metric-hooks/prepare-commit-msg +3 -1
- package/dist/src/codewatch/config.d.ts +17 -0
- package/dist/src/codewatch/config.d.ts.map +1 -0
- package/dist/src/codewatch/config.js +40 -0
- package/dist/src/codewatch/config.js.map +1 -0
- package/dist/src/codewatch/gitleaks.d.ts +49 -0
- package/dist/src/codewatch/gitleaks.d.ts.map +1 -0
- package/dist/src/codewatch/gitleaks.js +160 -0
- package/dist/src/codewatch/gitleaks.js.map +1 -0
- package/dist/src/codewatch/globalHooks.d.ts +52 -0
- package/dist/src/codewatch/globalHooks.d.ts.map +1 -0
- package/dist/src/codewatch/globalHooks.js +235 -0
- package/dist/src/codewatch/globalHooks.js.map +1 -0
- package/dist/src/codewatch/hooks.d.ts +38 -0
- package/dist/src/codewatch/hooks.d.ts.map +1 -0
- package/dist/src/codewatch/hooks.js +176 -0
- package/dist/src/codewatch/hooks.js.map +1 -0
- package/dist/src/codewatch/prepush.d.ts +37 -0
- package/dist/src/codewatch/prepush.d.ts.map +1 -0
- package/dist/src/codewatch/prepush.js +231 -0
- package/dist/src/codewatch/prepush.js.map +1 -0
- package/dist/src/codewatch/results.d.ts +90 -0
- package/dist/src/codewatch/results.d.ts.map +1 -0
- package/dist/src/codewatch/results.js +121 -0
- package/dist/src/codewatch/results.js.map +1 -0
- package/dist/src/codewatch/reviewers/claude.d.ts +9 -0
- package/dist/src/codewatch/reviewers/claude.d.ts.map +1 -0
- package/dist/src/codewatch/reviewers/claude.js +48 -0
- package/dist/src/codewatch/reviewers/claude.js.map +1 -0
- package/dist/src/codewatch/reviewers/index.d.ts +39 -0
- package/dist/src/codewatch/reviewers/index.d.ts.map +1 -0
- package/dist/src/codewatch/reviewers/index.js +97 -0
- package/dist/src/codewatch/reviewers/index.js.map +1 -0
- package/dist/src/codewatch/reviewers/kiro.d.ts +14 -0
- package/dist/src/codewatch/reviewers/kiro.d.ts.map +1 -0
- package/dist/src/codewatch/reviewers/kiro.js +32 -0
- package/dist/src/codewatch/reviewers/kiro.js.map +1 -0
- package/dist/src/codewatch/reviewers/types.d.ts +56 -0
- package/dist/src/codewatch/reviewers/types.d.ts.map +1 -0
- package/dist/src/codewatch/reviewers/types.js +91 -0
- package/dist/src/codewatch/reviewers/types.js.map +1 -0
- package/dist/src/codewatch/rules.d.ts +12 -0
- package/dist/src/codewatch/rules.d.ts.map +1 -0
- package/dist/src/codewatch/rules.js +27 -0
- package/dist/src/codewatch/rules.js.map +1 -0
- package/dist/src/commands/_top/dashboard.d.ts +17 -0
- package/dist/src/commands/_top/dashboard.d.ts.map +1 -0
- package/dist/src/commands/_top/dashboard.js +76 -0
- package/dist/src/commands/_top/dashboard.js.map +1 -0
- package/dist/src/commands/bedrock-protection/scan-account.d.ts.map +1 -1
- package/dist/src/commands/bedrock-protection/scan-account.js +2 -1
- package/dist/src/commands/bedrock-protection/scan-account.js.map +1 -1
- package/dist/src/commands/bedrock-protection/scan-org.d.ts.map +1 -1
- package/dist/src/commands/bedrock-protection/scan-org.js +16 -4
- package/dist/src/commands/bedrock-protection/scan-org.js.map +1 -1
- package/dist/src/commands/bootstrapper/install-eval-harness.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/install-eval-harness.js +15 -48
- package/dist/src/commands/bootstrapper/install-eval-harness.js.map +1 -1
- package/dist/src/commands/bootstrapper/install-git-hooks.d.ts +13 -0
- package/dist/src/commands/bootstrapper/install-git-hooks.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/install-git-hooks.js +28 -147
- package/dist/src/commands/bootstrapper/install-git-hooks.js.map +1 -1
- package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts.map +1 -1
- package/dist/src/commands/bootstrapper/setup-otel-sync.js +5 -39
- package/dist/src/commands/bootstrapper/setup-otel-sync.js.map +1 -1
- package/dist/src/commands/codewatch/pre-commit.d.ts +7 -0
- package/dist/src/commands/codewatch/pre-commit.d.ts.map +1 -0
- package/dist/src/commands/codewatch/pre-commit.js +30 -0
- package/dist/src/commands/codewatch/pre-commit.js.map +1 -0
- package/dist/src/commands/codewatch/pre-push.d.ts +16 -0
- package/dist/src/commands/codewatch/pre-push.d.ts.map +1 -0
- package/dist/src/commands/codewatch/pre-push.js +32 -0
- package/dist/src/commands/codewatch/pre-push.js.map +1 -0
- package/dist/src/commands/codewatch/report.d.ts +22 -0
- package/dist/src/commands/codewatch/report.d.ts.map +1 -0
- package/dist/src/commands/codewatch/report.js +64 -0
- package/dist/src/commands/codewatch/report.js.map +1 -0
- package/dist/src/commands/enable/codewatch.d.ts +15 -0
- package/dist/src/commands/enable/codewatch.d.ts.map +1 -0
- package/dist/src/commands/enable/codewatch.js +186 -0
- package/dist/src/commands/enable/codewatch.js.map +1 -0
- package/dist/src/commands/git/claude-session-context.d.ts.map +1 -1
- package/dist/src/commands/git/claude-session-context.js +2 -1
- package/dist/src/commands/git/claude-session-context.js.map +1 -1
- package/dist/src/commands/git/commit-trailers.js +1 -1
- package/dist/src/commands/git/commit-trailers.js.map +1 -1
- package/dist/src/commands/workshop/verify-setup.d.ts.map +1 -1
- package/dist/src/commands/workshop/verify-setup.js +5 -3
- package/dist/src/commands/workshop/verify-setup.js.map +1 -1
- package/dist/src/dashboard/codewatch.d.ts +106 -0
- package/dist/src/dashboard/codewatch.d.ts.map +1 -0
- package/dist/src/dashboard/codewatch.js +119 -0
- package/dist/src/dashboard/codewatch.js.map +1 -0
- package/dist/src/dashboard/commits.d.ts +96 -0
- package/dist/src/dashboard/commits.d.ts.map +1 -0
- package/dist/src/dashboard/commits.js +207 -0
- package/dist/src/dashboard/commits.js.map +1 -0
- package/dist/src/dashboard/page.d.ts +10 -0
- package/dist/src/dashboard/page.d.ts.map +1 -0
- package/dist/src/dashboard/page.js +315 -0
- package/dist/src/dashboard/page.js.map +1 -0
- package/dist/src/dashboard/payload.d.ts +111 -0
- package/dist/src/dashboard/payload.d.ts.map +1 -0
- package/dist/src/dashboard/payload.js +93 -0
- package/dist/src/dashboard/payload.js.map +1 -0
- package/dist/src/dashboard/report.d.ts +99 -0
- package/dist/src/dashboard/report.d.ts.map +1 -0
- package/dist/src/dashboard/report.js +300 -0
- package/dist/src/dashboard/report.js.map +1 -0
- package/dist/src/dashboard/repos.d.ts +58 -0
- package/dist/src/dashboard/repos.d.ts.map +1 -0
- package/dist/src/dashboard/repos.js +111 -0
- package/dist/src/dashboard/repos.js.map +1 -0
- package/dist/src/dashboard/server.d.ts +52 -0
- package/dist/src/dashboard/server.d.ts.map +1 -0
- package/dist/src/dashboard/server.js +163 -0
- package/dist/src/dashboard/server.js.map +1 -0
- package/dist/src/dashboard/setup.d.ts +52 -0
- package/dist/src/dashboard/setup.d.ts.map +1 -0
- package/dist/src/dashboard/setup.js +129 -0
- package/dist/src/dashboard/setup.js.map +1 -0
- package/dist/src/dashboard/usage.d.ts +43 -0
- package/dist/src/dashboard/usage.d.ts.map +1 -0
- package/dist/src/dashboard/usage.js +88 -0
- package/dist/src/dashboard/usage.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +40 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/utils/audit-bedrock.d.ts +1 -0
- package/dist/src/utils/audit-bedrock.d.ts.map +1 -1
- package/dist/src/utils/audit-bedrock.js +133 -0
- package/dist/src/utils/audit-bedrock.js.map +1 -1
- package/dist/src/utils/audit-org.d.ts +1 -0
- package/dist/src/utils/audit-org.d.ts.map +1 -1
- package/dist/src/utils/audit-org.js +155 -0
- package/dist/src/utils/audit-org.js.map +1 -1
- package/dist/src/utils/otel-sync-schedule.d.ts +22 -0
- package/dist/src/utils/otel-sync-schedule.d.ts.map +1 -0
- package/dist/src/utils/otel-sync-schedule.js +68 -0
- package/dist/src/utils/otel-sync-schedule.js.map +1 -0
- package/dist/src/utils/tool-check.d.ts +14 -0
- package/dist/src/utils/tool-check.d.ts.map +1 -0
- package/dist/src/utils/tool-check.js +42 -0
- package/dist/src/utils/tool-check.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codewatch result schema and writer (local git-hook gate runs).
|
|
3
|
+
*
|
|
4
|
+
* Every local gate run (the pre-commit secret scan, the pre-push review, and a
|
|
5
|
+
* detected skip of either) is written as one JSON file under `.prism/results/`.
|
|
6
|
+
* The schema lives here, not in the hook code, so `prism-cli dashboard` and CI
|
|
7
|
+
* can read the same files without re-deriving the shape.
|
|
8
|
+
*
|
|
9
|
+
* Results are local developer evidence, never committed: the installer adds
|
|
10
|
+
* `.prism/results/` to .gitignore.
|
|
11
|
+
*/
|
|
12
|
+
import { mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
13
|
+
import { dirname, join, resolve } from 'node:path';
|
|
14
|
+
import { appendFileSync, existsSync as fileExists } from 'node:fs';
|
|
15
|
+
import { run } from '../utils/exec.js';
|
|
16
|
+
export const RESULT_SCHEMA_VERSION = 1;
|
|
17
|
+
export const RESULTS_DIR = '.prism/results';
|
|
18
|
+
/** Pre-commit ran with no gitleaks on PATH: the commit was allowed but not secret-scanned. */
|
|
19
|
+
export const REASON_GITLEAKS_MISSING = 'gitleaks-missing';
|
|
20
|
+
export function makeResult(init) {
|
|
21
|
+
return {
|
|
22
|
+
schema_version: RESULT_SCHEMA_VERSION,
|
|
23
|
+
tool_version: null,
|
|
24
|
+
model: null,
|
|
25
|
+
commit: null,
|
|
26
|
+
tree: null,
|
|
27
|
+
branch: null,
|
|
28
|
+
upstream: null,
|
|
29
|
+
base: null,
|
|
30
|
+
summary: null,
|
|
31
|
+
score: null,
|
|
32
|
+
reason: null,
|
|
33
|
+
findings: [],
|
|
34
|
+
...init,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Keeps only characters safe in a file name, so no value can escape the results dir. */
|
|
38
|
+
function safePart(s) {
|
|
39
|
+
return s.replace(/[^A-Za-z0-9_-]/g, '').slice(0, 40) || 'x';
|
|
40
|
+
}
|
|
41
|
+
/** `20261104T202000123Z` -- sortable, colon-free. */
|
|
42
|
+
export function compactTimestamp(iso) {
|
|
43
|
+
return iso.replace(/[-:]/g, '').replace('.', '');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* `<commit12>-<time>-<hook>-<kind>.json`, or `tree-<tree12>-...` when there is
|
|
47
|
+
* no commit yet (pre-commit).
|
|
48
|
+
*/
|
|
49
|
+
export function resultFileName(r) {
|
|
50
|
+
const id = r.commit ? safePart(r.commit.slice(0, 12)) : r.tree ? `tree-${safePart(r.tree.slice(0, 12))}` : 'nocommit';
|
|
51
|
+
return `${id}-${compactTimestamp(r.started_at)}-${safePart(r.hook)}-${safePart(r.kind)}.json`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Writes a result atomically (temp file + rename), so a dashboard reading the
|
|
55
|
+
* directory never sees a half-written file. Returns the absolute path.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* Makes sure `.prism/results/` is ignored in this clone. Under the global
|
|
59
|
+
* hooks a repo may never have had codewatch installed, so it has no .gitignore
|
|
60
|
+
* entry; `.git/info/exclude` is local to the clone and keeps the working tree
|
|
61
|
+
* clean without touching any tracked file. Outside a git repo it does nothing.
|
|
62
|
+
*/
|
|
63
|
+
export function ensureResultsExcluded(repoRoot) {
|
|
64
|
+
const probe = run('git', ['-C', repoRoot, 'check-ignore', '-q', `${RESULTS_DIR}/probe.json`]);
|
|
65
|
+
if (probe.ok)
|
|
66
|
+
return false;
|
|
67
|
+
const p = run('git', ['-C', repoRoot, 'rev-parse', '--path-format=absolute', '--git-path', 'info/exclude']);
|
|
68
|
+
if (!p.ok || !p.stdout)
|
|
69
|
+
return false;
|
|
70
|
+
mkdirSync(dirname(p.stdout), { recursive: true });
|
|
71
|
+
const prefix = fileExists(p.stdout) && !readFileSync(p.stdout, 'utf8').endsWith('\n') ? '\n' : '';
|
|
72
|
+
appendFileSync(p.stdout, `${prefix}# prism-cli codewatch results (local)\n/${RESULTS_DIR}/\n`);
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
export function writeResult(repoRoot, r) {
|
|
76
|
+
const dir = resolve(repoRoot, RESULTS_DIR);
|
|
77
|
+
if (!fileExists(dir)) {
|
|
78
|
+
try {
|
|
79
|
+
ensureResultsExcluded(repoRoot);
|
|
80
|
+
}
|
|
81
|
+
catch { /* never fail a write over this */ }
|
|
82
|
+
}
|
|
83
|
+
mkdirSync(dir, { recursive: true });
|
|
84
|
+
const dest = join(dir, resultFileName(r));
|
|
85
|
+
const tmp = `${dest}.${process.pid}.tmp`;
|
|
86
|
+
writeFileSync(tmp, JSON.stringify(r, null, 2) + '\n', { mode: 0o600 });
|
|
87
|
+
renameSync(tmp, dest);
|
|
88
|
+
return dest;
|
|
89
|
+
}
|
|
90
|
+
/** Every parseable result with its id. Ids come from the directory listing, never from input. */
|
|
91
|
+
export function readResultEntries(repoRoot) {
|
|
92
|
+
const dir = resolve(repoRoot, RESULTS_DIR);
|
|
93
|
+
let files;
|
|
94
|
+
try {
|
|
95
|
+
files = readdirSync(dir).filter((f) => f.endsWith('.json'));
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const out = [];
|
|
101
|
+
for (const f of files) {
|
|
102
|
+
try {
|
|
103
|
+
const r = JSON.parse(readFileSync(join(dir, f), 'utf8'));
|
|
104
|
+
if (r && r.schema_version === RESULT_SCHEMA_VERSION)
|
|
105
|
+
out.push({ id: f.slice(0, -'.json'.length), result: r });
|
|
106
|
+
}
|
|
107
|
+
catch { /* skip */ }
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
/** Reads every parseable result file. Unparseable files are ignored, not fatal. */
|
|
112
|
+
export function readResults(repoRoot) {
|
|
113
|
+
return readResultEntries(repoRoot).map((e) => e.result);
|
|
114
|
+
}
|
|
115
|
+
export function countBySeverity(findings) {
|
|
116
|
+
const c = { high: 0, medium: 0, low: 0 };
|
|
117
|
+
for (const f of findings)
|
|
118
|
+
c[f.severity]++;
|
|
119
|
+
return c;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=results.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"results.js","sourceRoot":"","sources":["../../../src/codewatch/results.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,UAAU,IAAI,UAAU,EAAE,MAAM,SAAS,CAAC;AACnE,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAEvC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAC;AAE5C,8FAA8F;AAC9F,MAAM,CAAC,MAAM,uBAAuB,GAAG,kBAAkB,CAAC;AA+D1D,MAAM,UAAU,UAAU,CAAC,IAAgB;IACzC,OAAO;QACL,cAAc,EAAE,qBAAqB;QACrC,YAAY,EAAE,IAAI;QAClB,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,IAAI;QACV,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,EAAE;QACZ,GAAG,IAAI;KACR,CAAC;AACJ,CAAC;AAED,yFAAyF;AACzF,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;AAC9D,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,CAAc;IAC3C,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;IACtH,OAAO,GAAG,EAAE,IAAI,gBAAgB,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;AAChG,CAAC;AAED;;;GAGG;AACH;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB;IACpD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,WAAW,aAAa,CAAC,CAAC,CAAC;IAC9F,IAAI,KAAK,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IAC3B,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wBAAwB,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,CAAC;IAC5G,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACrC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAClG,cAAc,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,MAAM,2CAA2C,WAAW,KAAK,CAAC,CAAC;IAC/F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,CAAc;IAC1D,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC3C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,IAAI,CAAC;YAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,kCAAkC,CAAC,CAAC;IACvF,CAAC;IACD,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;IACzC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACvE,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtB,OAAO,IAAI,CAAC;AACd,CAAC;AAQD,iGAAiG;AACjG,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC3C,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YACzD,IAAI,CAAC,IAAI,CAAC,CAAC,cAAc,KAAK,qBAAqB;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAChH,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAmB;IACjD,MAAM,CAAC,GAA6B,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IACnE,KAAK,MAAM,CAAC,IAAI,QAAQ;QAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC1C,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReviewerAdapter } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code headless review (`claude -p --output-format json`).
|
|
4
|
+
*
|
|
5
|
+
* The rules and the diff go in the prompt on stdin (no argv length limit, no
|
|
6
|
+
* file outside the working dir to grant access to). Needs no kiro-cli.
|
|
7
|
+
*/
|
|
8
|
+
export declare const claudeAdapter: ReviewerAdapter;
|
|
9
|
+
//# sourceMappingURL=claude.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../../../src/codewatch/reviewers/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuD,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAMvG;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,eAiC3B,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { extractReviewJson, normalizeReview, OUTPUT_CONTRACT } from './types.js';
|
|
2
|
+
/** Read-only tools: the reviewer may look at surrounding code, never change it or run anything. */
|
|
3
|
+
const ALLOWED_TOOLS = ['Read', 'Grep', 'Glob'];
|
|
4
|
+
const DISALLOWED_TOOLS = ['Bash', 'Edit', 'Write', 'NotebookEdit', 'WebFetch', 'WebSearch', 'Task'];
|
|
5
|
+
/**
|
|
6
|
+
* Claude Code headless review (`claude -p --output-format json`).
|
|
7
|
+
*
|
|
8
|
+
* The rules and the diff go in the prompt on stdin (no argv length limit, no
|
|
9
|
+
* file outside the working dir to grant access to). Needs no kiro-cli.
|
|
10
|
+
*/
|
|
11
|
+
export const claudeAdapter = {
|
|
12
|
+
id: 'claude',
|
|
13
|
+
binary: 'claude',
|
|
14
|
+
displayName: 'Claude Code',
|
|
15
|
+
invocation(req) {
|
|
16
|
+
const args = [
|
|
17
|
+
'-p',
|
|
18
|
+
'--output-format', 'json',
|
|
19
|
+
'--allowed-tools', ALLOWED_TOOLS.join(','),
|
|
20
|
+
'--disallowed-tools', DISALLOWED_TOOLS.join(','),
|
|
21
|
+
];
|
|
22
|
+
if (req.model)
|
|
23
|
+
args.push('--model', req.model);
|
|
24
|
+
const input = 'You are a code reviewer. Review ONLY the changes in the diff below, for code quality and security, ' +
|
|
25
|
+
'against these rules. You may read files in the repository for context but must not modify anything.\n\n' +
|
|
26
|
+
`<rules>\n${req.rulesText}\n</rules>\n\n<diff>\n${req.diff}\n</diff>\n\n${OUTPUT_CONTRACT}`;
|
|
27
|
+
return { args, input };
|
|
28
|
+
},
|
|
29
|
+
parse(stdout) {
|
|
30
|
+
// Envelope: {"type":"result","is_error":false,"result":"<text>","modelUsage":{"<model>":{...}},...}
|
|
31
|
+
let env;
|
|
32
|
+
try {
|
|
33
|
+
env = JSON.parse(stdout.trim());
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
throw new Error('Claude Code output is not JSON (expected --output-format json)');
|
|
37
|
+
}
|
|
38
|
+
if (env?.is_error)
|
|
39
|
+
throw new Error(`Claude Code reported an error: ${String(env.result ?? env.subtype ?? 'unknown').slice(0, 300)}`);
|
|
40
|
+
if (typeof env?.result !== 'string')
|
|
41
|
+
throw new Error('Claude Code JSON has no "result" text');
|
|
42
|
+
const models = env.modelUsage && typeof env.modelUsage === 'object' ? Object.keys(env.modelUsage) : [];
|
|
43
|
+
// modelUsage can list a small helper model too; the one with the most output tokens did the review.
|
|
44
|
+
models.sort((a, b) => (env.modelUsage[b]?.outputTokens ?? 0) - (env.modelUsage[a]?.outputTokens ?? 0));
|
|
45
|
+
return normalizeReview(extractReviewJson(env.result), models[0] ?? null);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../../src/codewatch/reviewers/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAwB,MAAM,YAAY,CAAC;AAEvG,mGAAmG;AACnG,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAC/C,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;AAEpG;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAoB;IAC5C,EAAE,EAAE,QAAQ;IACZ,MAAM,EAAE,QAAQ;IAChB,WAAW,EAAE,aAAa;IAC1B,UAAU,CAAC,GAAG;QACZ,MAAM,IAAI,GAAG;YACX,IAAI;YACJ,iBAAiB,EAAE,MAAM;YACzB,iBAAiB,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC;YAC1C,oBAAoB,EAAE,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC;SACjD,CAAC;QACF,IAAI,GAAG,CAAC,KAAK;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,KAAK,GACT,qGAAqG;YACrG,yGAAyG;YACzG,YAAY,GAAG,CAAC,SAAS,yBAAyB,GAAG,CAAC,IAAI,gBAAgB,eAAe,EAAE,CAAC;QAC9F,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IACD,KAAK,CAAC,MAAM;QACV,oGAAoG;QACpG,IAAI,GAAQ,CAAC;QACb,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;QACpF,CAAC;QACD,IAAI,GAAG,EAAE,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QACrI,IAAI,OAAO,GAAG,EAAE,MAAM,KAAK,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvG,oGAAoG;QACpG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC;QACvG,OAAO,eAAe,CAAC,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;IAC3E,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ParsedReview, type ReviewerAdapter, type ReviewerId, type ReviewRequest } from './types.js';
|
|
2
|
+
export * from './types.js';
|
|
3
|
+
export declare const ADAPTERS: Record<ReviewerId, ReviewerAdapter>;
|
|
4
|
+
export { findOnPath, toolVersion } from '../../utils/tool-check.js';
|
|
5
|
+
/** Reviewer tools present on PATH, in REVIEWER_IDS order. */
|
|
6
|
+
export declare function detectReviewers(pathEnv?: string | undefined): ReviewerId[];
|
|
7
|
+
export interface ReviewerChoice {
|
|
8
|
+
/** The reviewer to run, or null when none is available. */
|
|
9
|
+
id: ReviewerId | null;
|
|
10
|
+
/** Where the choice came from. */
|
|
11
|
+
source: 'git-config' | 'prism-config' | 'detected' | 'fallback' | 'none';
|
|
12
|
+
/** Set when the configured reviewer was not available and another was used. */
|
|
13
|
+
note: string | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Precedence: `git config prism.reviewer` (per-clone developer override), then
|
|
17
|
+
* `.prism/config.json` eval.reviewer (team default), then whatever is on PATH.
|
|
18
|
+
*
|
|
19
|
+
* If the chosen tool is not installed, another installed one is used and the
|
|
20
|
+
* substitution is noted, so a Claude Code user on a team that defaults to kiro
|
|
21
|
+
* still gets a review without installing kiro-cli.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveReviewer(opts: {
|
|
24
|
+
gitConfigValue: string | null;
|
|
25
|
+
prismConfigValue: string | null | undefined;
|
|
26
|
+
available: ReviewerId[];
|
|
27
|
+
}): ReviewerChoice;
|
|
28
|
+
export interface ReviewRun {
|
|
29
|
+
ok: boolean;
|
|
30
|
+
review: ParsedReview | null;
|
|
31
|
+
error: string | null;
|
|
32
|
+
rawStdout: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Runs one adapter and parses its output. Never throws: a missing binary, a
|
|
36
|
+
* timeout, a non-zero exit and unparseable output all come back as ok:false.
|
|
37
|
+
*/
|
|
38
|
+
export declare function runReview(adapter: ReviewerAdapter, req: ReviewRequest, timeoutMs: number, binaryPath?: string): ReviewRun;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/codewatch/reviewers/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAA8B,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEtI,cAAc,YAAY,CAAC;AAE3B,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,eAAe,CAGxD,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAEpE,6DAA6D;AAC7D,wBAAgB,eAAe,CAAC,OAAO,GAAE,MAAM,GAAG,SAA4B,GAAG,UAAU,EAAE,CAE5F;AAED,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,EAAE,EAAE,UAAU,GAAG,IAAI,CAAC;IACtB,kCAAkC;IAClC,MAAM,EAAE,YAAY,GAAG,cAAc,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;IACzE,+EAA+E;IAC/E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,SAAS,EAAE,UAAU,EAAE,CAAC;CACzB,GAAG,cAAc,CAuBjB;AAKD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAgCzH"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { findOnPath } from '../../utils/tool-check.js';
|
|
3
|
+
import { claudeAdapter } from './claude.js';
|
|
4
|
+
import { kiroAdapter } from './kiro.js';
|
|
5
|
+
import { isReviewerId, REVIEWER_IDS } from './types.js';
|
|
6
|
+
export * from './types.js';
|
|
7
|
+
export const ADAPTERS = {
|
|
8
|
+
kiro: kiroAdapter,
|
|
9
|
+
claude: claudeAdapter,
|
|
10
|
+
};
|
|
11
|
+
export { findOnPath, toolVersion } from '../../utils/tool-check.js';
|
|
12
|
+
/** Reviewer tools present on PATH, in REVIEWER_IDS order. */
|
|
13
|
+
export function detectReviewers(pathEnv = process.env.PATH) {
|
|
14
|
+
return REVIEWER_IDS.filter((id) => findOnPath(ADAPTERS[id].binary, pathEnv) !== null);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Precedence: `git config prism.reviewer` (per-clone developer override), then
|
|
18
|
+
* `.prism/config.json` eval.reviewer (team default), then whatever is on PATH.
|
|
19
|
+
*
|
|
20
|
+
* If the chosen tool is not installed, another installed one is used and the
|
|
21
|
+
* substitution is noted, so a Claude Code user on a team that defaults to kiro
|
|
22
|
+
* still gets a review without installing kiro-cli.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveReviewer(opts) {
|
|
25
|
+
const { gitConfigValue, prismConfigValue, available } = opts;
|
|
26
|
+
let wanted = null;
|
|
27
|
+
let source = 'detected';
|
|
28
|
+
let note = null;
|
|
29
|
+
if (gitConfigValue) {
|
|
30
|
+
if (isReviewerId(gitConfigValue)) {
|
|
31
|
+
wanted = gitConfigValue;
|
|
32
|
+
source = 'git-config';
|
|
33
|
+
}
|
|
34
|
+
else
|
|
35
|
+
note = `ignored git config prism.reviewer="${gitConfigValue}" (expected ${REVIEWER_IDS.join(' or ')})`;
|
|
36
|
+
}
|
|
37
|
+
if (!wanted && prismConfigValue) {
|
|
38
|
+
if (isReviewerId(prismConfigValue)) {
|
|
39
|
+
wanted = prismConfigValue;
|
|
40
|
+
source = 'prism-config';
|
|
41
|
+
}
|
|
42
|
+
else
|
|
43
|
+
note = `ignored eval.reviewer="${prismConfigValue}" in .prism/config.json`;
|
|
44
|
+
}
|
|
45
|
+
if (wanted && available.includes(wanted))
|
|
46
|
+
return { id: wanted, source, note };
|
|
47
|
+
if (available.length === 0) {
|
|
48
|
+
return { id: null, source: 'none', note: wanted ? `${ADAPTERS[wanted].binary} is not on PATH` : 'neither kiro-cli nor claude is on PATH' };
|
|
49
|
+
}
|
|
50
|
+
if (wanted) {
|
|
51
|
+
return { id: available[0], source: 'fallback', note: `${ADAPTERS[wanted].binary} is not on PATH; used ${ADAPTERS[available[0]].binary} instead` };
|
|
52
|
+
}
|
|
53
|
+
return { id: available[0], source: 'detected', note };
|
|
54
|
+
}
|
|
55
|
+
/** Git sets these for hooks; a reviewer that shells out to git must not inherit them. */
|
|
56
|
+
const GIT_HOOK_ENV = ['GIT_DIR', 'GIT_INDEX_FILE', 'GIT_WORK_TREE', 'GIT_PREFIX', 'GIT_OBJECT_DIRECTORY', 'GIT_ALTERNATE_OBJECT_DIRECTORIES'];
|
|
57
|
+
/**
|
|
58
|
+
* Runs one adapter and parses its output. Never throws: a missing binary, a
|
|
59
|
+
* timeout, a non-zero exit and unparseable output all come back as ok:false.
|
|
60
|
+
*/
|
|
61
|
+
export function runReview(adapter, req, timeoutMs, binaryPath) {
|
|
62
|
+
const env = { ...process.env };
|
|
63
|
+
for (const k of GIT_HOOK_ENV)
|
|
64
|
+
delete env[k];
|
|
65
|
+
let inv;
|
|
66
|
+
try {
|
|
67
|
+
inv = adapter.invocation(req);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
return { ok: false, review: null, error: `could not build invocation: ${e.message}`, rawStdout: '' };
|
|
71
|
+
}
|
|
72
|
+
const res = spawnSync(binaryPath || adapter.binary, inv.args, {
|
|
73
|
+
cwd: req.repoRoot,
|
|
74
|
+
input: inv.input ?? '',
|
|
75
|
+
encoding: 'utf8',
|
|
76
|
+
env,
|
|
77
|
+
timeout: timeoutMs,
|
|
78
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
79
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
80
|
+
});
|
|
81
|
+
const stdout = res.stdout || '';
|
|
82
|
+
if (res.error) {
|
|
83
|
+
const msg = res.error.code === 'ETIMEDOUT'
|
|
84
|
+
? `${adapter.binary} timed out after ${Math.round(timeoutMs / 1000)}s`
|
|
85
|
+
: `${adapter.binary} failed to start: ${res.error.message}`;
|
|
86
|
+
return { ok: false, review: null, error: msg, rawStdout: stdout };
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const review = adapter.parse(stdout);
|
|
90
|
+
return { ok: true, review, error: null, rawStdout: stdout };
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
const exit = res.status !== 0 ? ` (exit ${res.status}${res.stderr ? `: ${res.stderr.trim().slice(0, 200)}` : ''})` : '';
|
|
94
|
+
return { ok: false, review: null, error: `${e.message}${exit}`, rawStdout: stdout };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/codewatch/reviewers/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ReviewerAdapter } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* kiro-cli headless review.
|
|
4
|
+
*
|
|
5
|
+
* Same shape as the CI gate (prism-eval-gate.yml): a short argv prompt that
|
|
6
|
+
* points kiro at files on disk, because kiro-cli has had a bug putting long
|
|
7
|
+
* stdin into HTTP headers. The rule set is passed as context by path -- kiro
|
|
8
|
+
* reads it with fs_read before reviewing.
|
|
9
|
+
*
|
|
10
|
+
* Only fs_read is trusted (`--trust-tools=fs_read`), so in --no-interactive
|
|
11
|
+
* mode any write or shell tool call is refused rather than run.
|
|
12
|
+
*/
|
|
13
|
+
export declare const kiroAdapter: ReviewerAdapter;
|
|
14
|
+
//# sourceMappingURL=kiro.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kiro.d.ts","sourceRoot":"","sources":["../../../../src/codewatch/reviewers/kiro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAElH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,WAAW,EAAE,eAmBzB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { extractReviewJson, normalizeReview, OUTPUT_CONTRACT, stripAnsi } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* kiro-cli headless review.
|
|
4
|
+
*
|
|
5
|
+
* Same shape as the CI gate (prism-eval-gate.yml): a short argv prompt that
|
|
6
|
+
* points kiro at files on disk, because kiro-cli has had a bug putting long
|
|
7
|
+
* stdin into HTTP headers. The rule set is passed as context by path -- kiro
|
|
8
|
+
* reads it with fs_read before reviewing.
|
|
9
|
+
*
|
|
10
|
+
* Only fs_read is trusted (`--trust-tools=fs_read`), so in --no-interactive
|
|
11
|
+
* mode any write or shell tool call is refused rather than run.
|
|
12
|
+
*/
|
|
13
|
+
export const kiroAdapter = {
|
|
14
|
+
id: 'kiro',
|
|
15
|
+
binary: 'kiro-cli',
|
|
16
|
+
displayName: 'kiro-cli',
|
|
17
|
+
invocation(req) {
|
|
18
|
+
const prompt = `You are a code reviewer. First read the review rules in ${req.rulesPath} and follow them. ` +
|
|
19
|
+
`Then read the diff at ${req.diffPath} and review only the changes it introduces, for code quality and security. ` +
|
|
20
|
+
OUTPUT_CONTRACT;
|
|
21
|
+
return {
|
|
22
|
+
args: ['chat', '--no-interactive', '--trust-tools=fs_read', '--model', req.model || 'auto', prompt],
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
parse(stdout) {
|
|
26
|
+
const text = stripAnsi(stdout);
|
|
27
|
+
// kiro-cli prints no machine-readable model; leave it to the caller's
|
|
28
|
+
// requested model.
|
|
29
|
+
return normalizeReview(extractReviewJson(text), null);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=kiro.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kiro.js","sourceRoot":"","sources":["../../../../src/codewatch/reviewers/kiro.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,SAAS,EAAwB,MAAM,YAAY,CAAC;AAElH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,WAAW,GAAoB;IAC1C,EAAE,EAAE,MAAM;IACV,MAAM,EAAE,UAAU;IAClB,WAAW,EAAE,UAAU;IACvB,UAAU,CAAC,GAAG;QACZ,MAAM,MAAM,GACV,2DAA2D,GAAG,CAAC,SAAS,oBAAoB;YAC5F,yBAAyB,GAAG,CAAC,QAAQ,6EAA6E;YAClH,eAAe,CAAC;QAClB,OAAO;YACL,IAAI,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,SAAS,EAAE,GAAG,CAAC,KAAK,IAAI,MAAM,EAAE,MAAM,CAAC;SACpG,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/B,sEAAsE;QACtE,mBAAmB;QACnB,OAAO,eAAe,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IACxD,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Finding } from '../results.js';
|
|
2
|
+
export declare const REVIEWER_IDS: readonly ["kiro", "claude"];
|
|
3
|
+
export type ReviewerId = typeof REVIEWER_IDS[number];
|
|
4
|
+
export declare function isReviewerId(v: unknown): v is ReviewerId;
|
|
5
|
+
export interface ReviewRequest {
|
|
6
|
+
repoRoot: string;
|
|
7
|
+
/** Repo-relative path of the shared rule set (`.prism/review/rules.md`). */
|
|
8
|
+
rulesPath: string;
|
|
9
|
+
/** Contents of the rule set, for adapters that pass it inline. */
|
|
10
|
+
rulesText: string;
|
|
11
|
+
/** Absolute path of the diff file on disk. */
|
|
12
|
+
diffPath: string;
|
|
13
|
+
/** The diff text itself, for adapters that pass it inline. */
|
|
14
|
+
diff: string;
|
|
15
|
+
/** Requested model, if the team pinned one. */
|
|
16
|
+
model?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Invocation {
|
|
19
|
+
args: string[];
|
|
20
|
+
/** Written to the child's stdin. */
|
|
21
|
+
input?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ParsedReview {
|
|
24
|
+
findings: Finding[];
|
|
25
|
+
summary: string | null;
|
|
26
|
+
score: number | null;
|
|
27
|
+
/** Model the tool reported using, if its output says. */
|
|
28
|
+
model: string | null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* One adapter per reviewer tool. An adapter only builds argv and parses
|
|
32
|
+
* output; running the process, timeouts and error handling are shared
|
|
33
|
+
* (see runReview in index.ts), so adding a tool is one small file.
|
|
34
|
+
*/
|
|
35
|
+
export interface ReviewerAdapter {
|
|
36
|
+
id: ReviewerId;
|
|
37
|
+
/** Executable looked up on PATH. */
|
|
38
|
+
binary: string;
|
|
39
|
+
displayName: string;
|
|
40
|
+
invocation(req: ReviewRequest): Invocation;
|
|
41
|
+
/** Throws when the output holds no usable review. */
|
|
42
|
+
parse(stdout: string): ParsedReview;
|
|
43
|
+
}
|
|
44
|
+
/** Output contract both adapters ask for. Matches the CI gate's JSON plus a `rule` field. */
|
|
45
|
+
export declare const OUTPUT_CONTRACT: string;
|
|
46
|
+
/** Strips ANSI escape sequences and carriage returns. */
|
|
47
|
+
export declare function stripAnsi(s: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Finds the last balanced top-level JSON object in free text that parses and
|
|
50
|
+
* has a `findings` array. Models wrap JSON in prose or fences; scanning for
|
|
51
|
+
* balanced braces (string-aware) is more reliable than one greedy regex.
|
|
52
|
+
*/
|
|
53
|
+
export declare function extractReviewJson(text: string): any;
|
|
54
|
+
/** Converts the model's JSON into the shared schema. Tolerates missing fields. */
|
|
55
|
+
export declare function normalizeReview(obj: any, model: string | null): ParsedReview;
|
|
56
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/codewatch/reviewers/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA6B,MAAM,eAAe,CAAC;AAExE,eAAO,MAAM,YAAY,6BAA8B,CAAC;AACxD,MAAM,MAAM,UAAU,GAAG,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC;AAErD,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,UAAU,CAExD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yDAAyD;IACzD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,UAAU,CAAC;IACf,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,GAAG,EAAE,aAAa,GAAG,UAAU,CAAC;IAC3C,qDAAqD;IACrD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC;CACrC;AAED,6FAA6F;AAC7F,eAAO,MAAM,eAAe,QAGyB,CAAC;AAEtD,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG3C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CA6BnD;AAmBD,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,YAAY,CAc5E"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export const REVIEWER_IDS = ['kiro', 'claude'];
|
|
2
|
+
export function isReviewerId(v) {
|
|
3
|
+
return typeof v === 'string' && REVIEWER_IDS.includes(v);
|
|
4
|
+
}
|
|
5
|
+
/** Output contract both adapters ask for. Matches the CI gate's JSON plus a `rule` field. */
|
|
6
|
+
export const OUTPUT_CONTRACT = 'Output ONLY one JSON object, no prose and no code fences: ' +
|
|
7
|
+
'{"findings":[{"file":"path","line":1,"severity":"high|medium|low","category":"security|correctness|performance|maintainability|reliability","rule":"name of the rule from the rules file","message":"str"}],"score":0.0,"summary":"str"}. ' +
|
|
8
|
+
'Use an empty findings array when nothing applies.';
|
|
9
|
+
/** Strips ANSI escape sequences and carriage returns. */
|
|
10
|
+
export function stripAnsi(s) {
|
|
11
|
+
// eslint-disable-next-line no-control-regex
|
|
12
|
+
return s.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, '').replace(/\x1b\][^\x07]*\x07/g, '').replace(/\r/g, '');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Finds the last balanced top-level JSON object in free text that parses and
|
|
16
|
+
* has a `findings` array. Models wrap JSON in prose or fences; scanning for
|
|
17
|
+
* balanced braces (string-aware) is more reliable than one greedy regex.
|
|
18
|
+
*/
|
|
19
|
+
export function extractReviewJson(text) {
|
|
20
|
+
const candidates = [];
|
|
21
|
+
for (let start = text.indexOf('{'); start !== -1; start = text.indexOf('{', start + 1)) {
|
|
22
|
+
let depth = 0;
|
|
23
|
+
let inStr = false;
|
|
24
|
+
let esc = false;
|
|
25
|
+
for (let i = start; i < text.length; i++) {
|
|
26
|
+
const ch = text[i];
|
|
27
|
+
if (inStr) {
|
|
28
|
+
if (esc)
|
|
29
|
+
esc = false;
|
|
30
|
+
else if (ch === '\\')
|
|
31
|
+
esc = true;
|
|
32
|
+
else if (ch === '"')
|
|
33
|
+
inStr = false;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (ch === '"')
|
|
37
|
+
inStr = true;
|
|
38
|
+
else if (ch === '{')
|
|
39
|
+
depth++;
|
|
40
|
+
else if (ch === '}') {
|
|
41
|
+
depth--;
|
|
42
|
+
if (depth === 0) {
|
|
43
|
+
candidates.push(text.slice(start, i + 1));
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
for (let i = candidates.length - 1; i >= 0; i--) {
|
|
50
|
+
try {
|
|
51
|
+
const obj = JSON.parse(candidates[i]);
|
|
52
|
+
if (obj && Array.isArray(obj.findings))
|
|
53
|
+
return obj;
|
|
54
|
+
}
|
|
55
|
+
catch { /* try the next one */ }
|
|
56
|
+
}
|
|
57
|
+
throw new Error('no JSON object with a "findings" array in reviewer output');
|
|
58
|
+
}
|
|
59
|
+
function normSeverity(v) {
|
|
60
|
+
const s = String(v ?? '').toLowerCase();
|
|
61
|
+
if (s === 'critical' || s === 'high')
|
|
62
|
+
return 'high';
|
|
63
|
+
if (s === 'medium' || s === 'moderate')
|
|
64
|
+
return 'medium';
|
|
65
|
+
return 'low';
|
|
66
|
+
}
|
|
67
|
+
/** The rules file uses five categories; the result schema keeps two. */
|
|
68
|
+
function normCategory(v) {
|
|
69
|
+
return String(v ?? '').toLowerCase().includes('secur') ? 'security' : 'quality';
|
|
70
|
+
}
|
|
71
|
+
function normLine(v) {
|
|
72
|
+
const n = typeof v === 'number' ? v : parseInt(String(v ?? ''), 10);
|
|
73
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : null;
|
|
74
|
+
}
|
|
75
|
+
/** Converts the model's JSON into the shared schema. Tolerates missing fields. */
|
|
76
|
+
export function normalizeReview(obj, model) {
|
|
77
|
+
const findings = obj.findings
|
|
78
|
+
.filter((f) => f && typeof f === 'object')
|
|
79
|
+
.map((f) => ({
|
|
80
|
+
severity: normSeverity(f.severity),
|
|
81
|
+
category: normCategory(f.category),
|
|
82
|
+
rule: String(f.rule || f.category || 'unspecified').slice(0, 200),
|
|
83
|
+
file: String(f.file || ''),
|
|
84
|
+
line: normLine(f.line),
|
|
85
|
+
message: String(f.message || '').slice(0, 2000),
|
|
86
|
+
}));
|
|
87
|
+
const score = typeof obj.score === 'number' && Number.isFinite(obj.score) ? obj.score : null;
|
|
88
|
+
const summary = typeof obj.summary === 'string' ? obj.summary.slice(0, 500) : null;
|
|
89
|
+
return { findings, summary, score, model };
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/codewatch/reviewers/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Where install-eval-harness has always put the review rules for kiro-cli. */
|
|
2
|
+
export declare const KIRO_STEERING_RULES = ".kiro/steering/code-review.md";
|
|
3
|
+
/**
|
|
4
|
+
* Ensures the tool-neutral rule set exists at `.prism/review/rules.md`.
|
|
5
|
+
*
|
|
6
|
+
* Seed order: keep an existing rules.md; else copy the repo's
|
|
7
|
+
* `.kiro/steering/code-review.md` (a team may have customised it, and CI
|
|
8
|
+
* reviewed against it until now); else the bundled default -- the same file
|
|
9
|
+
* install-eval-harness ships as steering. Returns what happened.
|
|
10
|
+
*/
|
|
11
|
+
export declare function ensureRulesFile(gitRoot: string, bundledRulesPath: string): 'kept' | 'from-steering' | 'from-bundle';
|
|
12
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/codewatch/rules.ts"],"names":[],"mappings":"AAIA,+EAA+E;AAC/E,eAAO,MAAM,mBAAmB,kCAAkC,CAAC;AAEnE;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,GAAG,eAAe,GAAG,aAAa,CAWnH"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { RULES_PATH } from './config.js';
|
|
4
|
+
/** Where install-eval-harness has always put the review rules for kiro-cli. */
|
|
5
|
+
export const KIRO_STEERING_RULES = '.kiro/steering/code-review.md';
|
|
6
|
+
/**
|
|
7
|
+
* Ensures the tool-neutral rule set exists at `.prism/review/rules.md`.
|
|
8
|
+
*
|
|
9
|
+
* Seed order: keep an existing rules.md; else copy the repo's
|
|
10
|
+
* `.kiro/steering/code-review.md` (a team may have customised it, and CI
|
|
11
|
+
* reviewed against it until now); else the bundled default -- the same file
|
|
12
|
+
* install-eval-harness ships as steering. Returns what happened.
|
|
13
|
+
*/
|
|
14
|
+
export function ensureRulesFile(gitRoot, bundledRulesPath) {
|
|
15
|
+
const dest = resolve(gitRoot, RULES_PATH);
|
|
16
|
+
if (existsSync(dest))
|
|
17
|
+
return 'kept';
|
|
18
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
19
|
+
const steering = resolve(gitRoot, KIRO_STEERING_RULES);
|
|
20
|
+
if (existsSync(steering)) {
|
|
21
|
+
copyFileSync(steering, dest);
|
|
22
|
+
return 'from-steering';
|
|
23
|
+
}
|
|
24
|
+
copyFileSync(bundledRulesPath, dest);
|
|
25
|
+
return 'from-bundle';
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/codewatch/rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,+BAA+B,CAAC;AAEnE;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,gBAAwB;IACvE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC1C,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IACpC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACvD,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC7B,OAAO,eAAe,CAAC;IACzB,CAAC;IACD,YAAY,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;IACrC,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function parsePort(v: string | undefined): number;
|
|
2
|
+
declare const _default: {
|
|
3
|
+
description: string;
|
|
4
|
+
options: {
|
|
5
|
+
flags: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}[];
|
|
8
|
+
action(opts: {
|
|
9
|
+
json?: boolean;
|
|
10
|
+
all?: boolean;
|
|
11
|
+
root?: string;
|
|
12
|
+
port?: string;
|
|
13
|
+
open?: boolean;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
export default _default;
|
|
17
|
+
//# sourceMappingURL=dashboard.d.ts.map
|