agent-roast 0.3.0 → 0.5.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/README.md +120 -16
- package/dist/{chunk-SMZZAGFS.js → chunk-FUAUIURY.js} +734 -223
- package/dist/cli.js +126 -15
- package/dist/index.d.ts +104 -23
- package/dist/index.js +33 -3
- package/package.json +5 -3
package/dist/cli.js
CHANGED
|
@@ -1,48 +1,66 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
ConfigError,
|
|
3
4
|
GitError,
|
|
4
5
|
GitResolutionError,
|
|
5
6
|
InvalidDetectorError,
|
|
7
|
+
RULE_GUIDES,
|
|
8
|
+
VALID_DETECTORS,
|
|
6
9
|
auditPullRequest,
|
|
10
|
+
checkProject,
|
|
7
11
|
formatGithubStepSummary,
|
|
12
|
+
generateShieldsJson,
|
|
13
|
+
generateShieldsMarkdown,
|
|
14
|
+
generateSvgBadge,
|
|
8
15
|
initProject,
|
|
9
16
|
loadConfig,
|
|
10
|
-
roastRepository
|
|
11
|
-
|
|
17
|
+
roastRepository,
|
|
18
|
+
writeBaseline
|
|
19
|
+
} from "./chunk-FUAUIURY.js";
|
|
12
20
|
|
|
13
21
|
// src/cli.ts
|
|
14
22
|
import { Command } from "commander";
|
|
15
23
|
import { createRequire } from "module";
|
|
16
24
|
import * as fs from "fs";
|
|
25
|
+
import * as path from "path";
|
|
17
26
|
var require2 = createRequire(import.meta.url);
|
|
18
27
|
var pkg = require2("../package.json");
|
|
19
28
|
var program = new Command();
|
|
20
|
-
program.name("agent-roast").description("Audit your git history or PR diffs for AI coding shortcuts and panic loops").version(pkg.version || "0.
|
|
29
|
+
program.name("agent-roast").description("Audit your git history or PR diffs for AI coding shortcuts and panic loops").version(pkg.version || "0.4.0").argument("[path]", "Path to git repository (default: current directory)", ".").option("-a, --all", "Audit ALL commits regardless of AI attribution tags", false).option("-s, --since <time>", "Time window for git analysis", "90 days ago").option("-v, --verbose", "Show commit SHAs and line snippets for all infractions", false).option("--json", "Output results as raw JSON", false).option("--staged", "Audit staged changes before committing (including the first commit)", false).option("--base <ref>", "Base git ref/branch for PR mode audit (e.g. origin/main)").option("--head <ref>", "Head git ref/SHA for PR mode audit (default: HEAD)", "HEAD").option("--fail-on <rules>", "Comma-separated detectors that trigger CI failure").option("--fail-under <score>", "Fail CI if agent score is below threshold (0-100)").option("--format <format>", "Output format: terminal, json, github, markdown", "terminal").option("--authors", "Display author names and emails in report", false).action(async (repoPath, options) => {
|
|
21
30
|
try {
|
|
22
31
|
if (process.env.GITHUB_EVENT_NAME === "pull_request_target") {
|
|
23
32
|
console.warn(
|
|
24
33
|
"Warning: pull_request_target runs with elevated repository privileges. agent-roast recommends running on 'pull_request'."
|
|
25
34
|
);
|
|
26
35
|
}
|
|
36
|
+
if (options.staged && options.base) throw new ConfigError("--staged cannot be combined with --base.");
|
|
37
|
+
if (!["terminal", "json", "github", "markdown"].includes(options.format)) {
|
|
38
|
+
throw new ConfigError("--format must be terminal, json, github, or markdown.");
|
|
39
|
+
}
|
|
40
|
+
if (options.failUnder !== void 0 && (options.failUnder.trim() === "" || !Number.isFinite(Number(options.failUnder)) || Number(options.failUnder) < 0 || Number(options.failUnder) > 100)) {
|
|
41
|
+
throw new ConfigError("--fail-under must be a number between 0 and 100.");
|
|
42
|
+
}
|
|
43
|
+
if (!options.base && !options.staged && options.failOn !== void 0) {
|
|
44
|
+
throw new ConfigError("--fail-on requires --base or --staged.");
|
|
45
|
+
}
|
|
46
|
+
if (!options.base && !options.staged && !options.json && !["terminal", "json"].includes(options.format)) {
|
|
47
|
+
throw new ConfigError("Repository audits support terminal or json format; use --base or --staged for github/markdown.");
|
|
48
|
+
}
|
|
27
49
|
const config = await loadConfig(repoPath);
|
|
28
|
-
if (options.base) {
|
|
29
|
-
|
|
30
|
-
if (options.failOn) {
|
|
31
|
-
failOnRules = options.failOn.split(",").map((s) => s.trim()).filter(Boolean);
|
|
32
|
-
} else {
|
|
33
|
-
const errorRules = Object.entries(config.rules || {}).filter(([_, level]) => level === "error").map(([rule]) => rule);
|
|
34
|
-
failOnRules = errorRules.length > 0 ? errorRules : ["test-skip"];
|
|
35
|
-
}
|
|
50
|
+
if (options.base || options.staged) {
|
|
51
|
+
const failOnRules = options.failOn !== void 0 ? options.failOn.split(",").map((s) => s.trim()).filter(Boolean) : config.failOn;
|
|
36
52
|
const chosenFormat = options.json ? "json" : options.format || "terminal";
|
|
37
53
|
const prResult = await auditPullRequest({
|
|
38
54
|
cwd: repoPath,
|
|
39
55
|
base: options.base,
|
|
56
|
+
staged: options.staged,
|
|
40
57
|
head: options.head || "HEAD",
|
|
41
58
|
failOn: failOnRules,
|
|
42
59
|
format: chosenFormat,
|
|
43
60
|
verbose: options.verbose,
|
|
44
61
|
authors: options.authors,
|
|
45
|
-
ignorePaths: config.ignorePaths
|
|
62
|
+
ignorePaths: config.ignorePaths,
|
|
63
|
+
rules: config.rules
|
|
46
64
|
});
|
|
47
65
|
if (process.env.GITHUB_STEP_SUMMARY) {
|
|
48
66
|
try {
|
|
@@ -76,9 +94,11 @@ has-supported-changes=${prResult.hasSupportedChanges}
|
|
|
76
94
|
all: options.all,
|
|
77
95
|
verbose: options.verbose,
|
|
78
96
|
json: options.json,
|
|
79
|
-
|
|
97
|
+
panicLoopWindowMinutes: config.panicLoopWindowMinutes,
|
|
98
|
+
ignorePaths: config.ignorePaths,
|
|
99
|
+
rules: config.rules
|
|
80
100
|
});
|
|
81
|
-
if (options.json) {
|
|
101
|
+
if (options.json || options.format === "json") {
|
|
82
102
|
console.log(JSON.stringify(result.summary, null, 2));
|
|
83
103
|
} else {
|
|
84
104
|
console.log(result.output);
|
|
@@ -91,7 +111,7 @@ has-supported-changes=${prResult.hasSupportedChanges}
|
|
|
91
111
|
}
|
|
92
112
|
}
|
|
93
113
|
} catch (err) {
|
|
94
|
-
if (err instanceof GitResolutionError || err instanceof InvalidDetectorError || err instanceof GitError || err.name === "GitError") {
|
|
114
|
+
if (err instanceof ConfigError || err instanceof GitResolutionError || err instanceof InvalidDetectorError || err instanceof GitError || err.name === "GitError") {
|
|
95
115
|
console.error(`agent-roast error: ${err.message}`);
|
|
96
116
|
process.exitCode = 2;
|
|
97
117
|
} else {
|
|
@@ -100,6 +120,53 @@ has-supported-changes=${prResult.hasSupportedChanges}
|
|
|
100
120
|
}
|
|
101
121
|
}
|
|
102
122
|
});
|
|
123
|
+
program.command("check").description("Check current tracked and non-ignored untracked source files").argument("[path]", "Path to a git repository", ".").option("--baseline <file>", "Report only findings not accepted in this baseline").option("--write-baseline <file>", "Save current findings for adoption (refuses to overwrite)").addHelpText("after", "\nOutput options: --format terminal|json|github|markdown, --json, --fail-on <rules>\nExamples:\n agent-roast check\n agent-roast check --write-baseline .agentroast-baseline.json\n agent-roast check --baseline .agentroast-baseline.json --format json").action(async (repoPath, opts) => {
|
|
124
|
+
try {
|
|
125
|
+
const global = program.opts();
|
|
126
|
+
if (global.base || global.staged || global.failUnder !== void 0 || global.all || program.getOptionValueSource("head") === "cli" || program.getOptionValueSource("since") === "cli") {
|
|
127
|
+
throw new ConfigError("check inspects current files; history, --base, --head, --staged and --fail-under options do not apply.");
|
|
128
|
+
}
|
|
129
|
+
if (opts.baseline && opts.writeBaseline) throw new ConfigError("--baseline and --write-baseline cannot be combined.");
|
|
130
|
+
const result = await checkProject({
|
|
131
|
+
cwd: repoPath,
|
|
132
|
+
baseline: opts.baseline,
|
|
133
|
+
failOn: global.failOn !== void 0 ? global.failOn.split(",").map((rule) => rule.trim()).filter(Boolean) : void 0,
|
|
134
|
+
format: global.json ? "json" : global.format
|
|
135
|
+
});
|
|
136
|
+
if (opts.writeBaseline) {
|
|
137
|
+
if (!result.complete) throw new ConfigError("Cannot create a baseline from an incomplete scan. Resolve skipped files first.");
|
|
138
|
+
const basePath = path.resolve(repoPath, opts.writeBaseline);
|
|
139
|
+
writeBaseline(basePath, result.infractions);
|
|
140
|
+
const message = `Baseline created: ${basePath}
|
|
141
|
+
Accepted ${result.totalFindings} existing findings. The code has not been fixed.
|
|
142
|
+
Review and commit the baseline, then run check --baseline <file> to catch new findings.`;
|
|
143
|
+
console.log(global.json || global.format === "json" ? JSON.stringify({ operation: "write-baseline", baseline: basePath, acceptedFindings: result.totalFindings }, null, 2) : message);
|
|
144
|
+
process.exitCode = 0;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
console.log(result.output);
|
|
148
|
+
process.exitCode = result.exitCode;
|
|
149
|
+
} catch (err) {
|
|
150
|
+
console.error(`agent-roast check error: ${err instanceof Error ? err.message : String(err)}`);
|
|
151
|
+
process.exitCode = 2;
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
program.command("explain <rule>").description("Explain a detector, its limits, and how to address a finding").action((rule) => {
|
|
155
|
+
if (!VALID_DETECTORS.includes(rule)) {
|
|
156
|
+
console.error(`Unknown rule '${rule}'. Valid rules: ${VALID_DETECTORS.join(", ")}`);
|
|
157
|
+
process.exitCode = 2;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const guide = RULE_GUIDES[rule];
|
|
161
|
+
console.log(`${rule}: ${guide.title}
|
|
162
|
+
|
|
163
|
+
Why: ${guide.why}
|
|
164
|
+
|
|
165
|
+
Next: ${guide.suggestion}
|
|
166
|
+
|
|
167
|
+
Example: ${guide.example}
|
|
168
|
+
`);
|
|
169
|
+
});
|
|
103
170
|
program.command("init").description("Initialize .agentroastrc.json and CI/hook configurations").argument("[dir]", "Directory to initialize", ".").option("-y, --yes", "Skip interactive prompts and use defaults", false).option("--ci", "Generate GitHub Actions workflow file", false).option("--hook", "Install Git pre-commit hook", false).action(async (targetDir, opts) => {
|
|
104
171
|
try {
|
|
105
172
|
const res = await initProject({
|
|
@@ -127,4 +194,48 @@ program.command("init").description("Initialize .agentroastrc.json and CI/hook c
|
|
|
127
194
|
process.exitCode = 1;
|
|
128
195
|
}
|
|
129
196
|
});
|
|
197
|
+
program.command("badge").description("Generate an AI discipline badge (SVG, Markdown, or Shields JSON)").argument("[path]", "Path to git repository (default: current directory)", ".").option("-a, --all", "Audit ALL commits regardless of AI attribution tags", false).option("-s, --since <time>", "Time window for git analysis", "90 days ago").option("--label <text>", "Badge label text", "AI Discipline").option("--out <file>", "Output SVG file path (e.g. ./badge.svg)").action(async (repoPath, opts) => {
|
|
198
|
+
try {
|
|
199
|
+
const rootOpts = program.opts();
|
|
200
|
+
const isJson = Boolean(opts.json || rootOpts.json);
|
|
201
|
+
const isAll = Boolean(opts.all || rootOpts.all);
|
|
202
|
+
const since = opts.since || rootOpts.since || "90 days ago";
|
|
203
|
+
const config = await loadConfig(repoPath);
|
|
204
|
+
const result = await roastRepository({
|
|
205
|
+
cwd: repoPath,
|
|
206
|
+
since,
|
|
207
|
+
all: isAll,
|
|
208
|
+
ignorePaths: config.ignorePaths,
|
|
209
|
+
rules: config.rules,
|
|
210
|
+
panicLoopWindowMinutes: config.panicLoopWindowMinutes
|
|
211
|
+
});
|
|
212
|
+
const score = result.summary.score;
|
|
213
|
+
const label = opts.label || "AI Discipline";
|
|
214
|
+
if (isJson) {
|
|
215
|
+
const payload = generateShieldsJson(score, label);
|
|
216
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
217
|
+
process.exitCode = 0;
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (opts.out) {
|
|
221
|
+
const svg = generateSvgBadge(score, label);
|
|
222
|
+
const outPath = path.resolve(opts.out);
|
|
223
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
224
|
+
fs.writeFileSync(outPath, svg, "utf-8");
|
|
225
|
+
console.log(`Generated SVG badge at: ${opts.out}`);
|
|
226
|
+
process.exitCode = 0;
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const markdown = generateShieldsMarkdown(score, label);
|
|
230
|
+
console.log(`
|
|
231
|
+
Badge for README.md:
|
|
232
|
+
|
|
233
|
+
${markdown}
|
|
234
|
+
`);
|
|
235
|
+
process.exitCode = 0;
|
|
236
|
+
} catch (err) {
|
|
237
|
+
console.error(`Error generating badge: ${err.message}`);
|
|
238
|
+
process.exitCode = 1;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
130
241
|
program.parse(process.argv);
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ interface Infraction {
|
|
|
19
19
|
commitHash: string;
|
|
20
20
|
commitDate: string;
|
|
21
21
|
reason: string;
|
|
22
|
+
suggestion?: string;
|
|
22
23
|
}
|
|
23
24
|
interface MetricSummary {
|
|
24
25
|
schemaVersion: string;
|
|
@@ -49,18 +50,23 @@ interface RoastOptions {
|
|
|
49
50
|
authors?: boolean;
|
|
50
51
|
ignorePaths?: string[];
|
|
51
52
|
scoreThreshold?: number;
|
|
53
|
+
rules?: Record<string, "error" | "warn" | "off">;
|
|
54
|
+
panicLoopWindowMinutes?: number;
|
|
52
55
|
}
|
|
53
56
|
interface PrAuditOptions {
|
|
54
57
|
cwd?: string;
|
|
55
|
-
base
|
|
56
|
-
head
|
|
58
|
+
base?: string;
|
|
59
|
+
head?: string;
|
|
60
|
+
staged?: boolean;
|
|
57
61
|
failOn?: string[];
|
|
58
|
-
format?: "terminal" | "json" | "github";
|
|
62
|
+
format?: "terminal" | "json" | "github" | "markdown";
|
|
59
63
|
verbose?: boolean;
|
|
60
64
|
authors?: boolean;
|
|
61
65
|
ignorePaths?: string[];
|
|
66
|
+
rules?: Record<string, "error" | "warn" | "off">;
|
|
62
67
|
}
|
|
63
68
|
interface PrAuditResult {
|
|
69
|
+
mode?: "pr" | "staged";
|
|
64
70
|
schemaVersion: string;
|
|
65
71
|
baseSha: string;
|
|
66
72
|
headSha: string;
|
|
@@ -77,6 +83,32 @@ interface PrAuditResult {
|
|
|
77
83
|
output: string;
|
|
78
84
|
exitCode: number;
|
|
79
85
|
}
|
|
86
|
+
interface CheckOptions {
|
|
87
|
+
cwd?: string;
|
|
88
|
+
failOn?: string[];
|
|
89
|
+
format?: "terminal" | "json" | "github" | "markdown";
|
|
90
|
+
baseline?: string;
|
|
91
|
+
signal?: AbortSignal;
|
|
92
|
+
}
|
|
93
|
+
interface CheckResult {
|
|
94
|
+
schemaVersion: string;
|
|
95
|
+
mode: "check";
|
|
96
|
+
filesInspected: number;
|
|
97
|
+
linesInspected: number;
|
|
98
|
+
totalFindings: number;
|
|
99
|
+
infractions: Infraction[];
|
|
100
|
+
baselineCount: number;
|
|
101
|
+
staleBaselineCount: number;
|
|
102
|
+
skippedFiles: {
|
|
103
|
+
file: string;
|
|
104
|
+
reason: string;
|
|
105
|
+
}[];
|
|
106
|
+
complete: boolean;
|
|
107
|
+
failedRules: string[];
|
|
108
|
+
passed: boolean;
|
|
109
|
+
exitCode: number;
|
|
110
|
+
output: string;
|
|
111
|
+
}
|
|
80
112
|
|
|
81
113
|
interface AiAttributionResult {
|
|
82
114
|
isAiAttributed: boolean;
|
|
@@ -110,7 +142,7 @@ declare class GitError extends Error {
|
|
|
110
142
|
code: number | null;
|
|
111
143
|
constructor(stderr: string, code: number | null);
|
|
112
144
|
}
|
|
113
|
-
declare const HERMETIC_GIT_FLAGS: readonly ["-c", "core.quotepath=false", "-c", "diff.noprefix=false", "-c", "diff.mnemonicPrefix=false", "--no-pager"];
|
|
145
|
+
declare const HERMETIC_GIT_FLAGS: readonly ["-c", "core.quotepath=false", "-c", "core.fsmonitor=false", "-c", "diff.noprefix=false", "-c", "diff.mnemonicPrefix=false", "--no-pager"];
|
|
114
146
|
declare function getHermeticGitEnv(extraEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
115
147
|
declare function parseGitLogStream(stream: Readable, onCommit: (commit: ParsedCommit, stats: {
|
|
116
148
|
skippedLongLines: number;
|
|
@@ -130,7 +162,7 @@ declare function unquoteGitPath(pathStr: string): string;
|
|
|
130
162
|
*/
|
|
131
163
|
declare function parseDiff(rawDiff: string): ParseDiffResult;
|
|
132
164
|
declare function streamGitLog(cwd?: string, since?: string): Readable;
|
|
133
|
-
declare function streamGitDiff(cwd: string, baseSha: string, headSha: string): Readable;
|
|
165
|
+
declare function streamGitDiff(cwd: string, baseSha: string, headSha: string, staged?: boolean): Readable;
|
|
134
166
|
/**
|
|
135
167
|
* Validates and resolves a git ref to a full commit SHA safely using --end-of-options.
|
|
136
168
|
* Exits with code 2 on failure.
|
|
@@ -151,6 +183,7 @@ declare function isTestFile(filePath: string): boolean;
|
|
|
151
183
|
*/
|
|
152
184
|
declare function auditFileDiffs(files: ParsedFileDiff[], commitHash?: string, commitDate?: string, options?: {
|
|
153
185
|
ignorePaths?: string[];
|
|
186
|
+
rules?: Record<string, "error" | "warn" | "off">;
|
|
154
187
|
}): {
|
|
155
188
|
infractions: Infraction[];
|
|
156
189
|
hasSupportedChanges: boolean;
|
|
@@ -178,9 +211,13 @@ declare class MetricsCollector {
|
|
|
178
211
|
private activePanicChain;
|
|
179
212
|
private includeAll;
|
|
180
213
|
private ignorePaths?;
|
|
214
|
+
private rules?;
|
|
215
|
+
private panicLoopWindowMinutes;
|
|
181
216
|
constructor(options?: {
|
|
182
217
|
all?: boolean;
|
|
183
218
|
ignorePaths?: string[];
|
|
219
|
+
rules?: Record<string, "error" | "warn" | "off">;
|
|
220
|
+
panicLoopWindowMinutes?: number;
|
|
184
221
|
});
|
|
185
222
|
recordSkipped(stats: {
|
|
186
223
|
skippedLongLines?: number;
|
|
@@ -197,15 +234,18 @@ declare function formatTerminalCard(summary: MetricSummary, options: {
|
|
|
197
234
|
verbose?: boolean;
|
|
198
235
|
}): string;
|
|
199
236
|
declare function formatPrTerminalCard(result: PrAuditResult): string;
|
|
200
|
-
|
|
201
|
-
* Generates GitHub Actions workflow commands (::error and ::warning)
|
|
202
|
-
* respecting GitHub's limits (max 10 annotations per level per step).
|
|
203
|
-
*/
|
|
204
|
-
declare function formatGithubAnnotations(result: PrAuditResult): string;
|
|
237
|
+
declare function formatGithubAnnotations(result: Pick<PrAuditResult, "infractions" | "failedRules">): string;
|
|
205
238
|
/**
|
|
206
239
|
* Generates GitHub Step Summary Markdown
|
|
207
240
|
*/
|
|
208
241
|
declare function formatGithubStepSummary(result: PrAuditResult): string;
|
|
242
|
+
/**
|
|
243
|
+
* Generates rich GitHub PR Comment Markdown (for PR comments / sticky bots)
|
|
244
|
+
*/
|
|
245
|
+
declare function formatPrMarkdownComment(result: PrAuditResult): string;
|
|
246
|
+
/** Current-tree report emphasizes next actions and explicitly accounts for baseline debt. */
|
|
247
|
+
declare function formatCheckTerminal(result: CheckResult): string;
|
|
248
|
+
declare function formatCheckMarkdown(result: CheckResult): string;
|
|
209
249
|
|
|
210
250
|
interface AgentRoastConfig {
|
|
211
251
|
/** Detector rules to fail CI on in PR mode */
|
|
@@ -220,10 +260,10 @@ interface AgentRoastConfig {
|
|
|
220
260
|
panicLoopWindowMinutes?: number;
|
|
221
261
|
}
|
|
222
262
|
declare const DEFAULT_CONFIG: AgentRoastConfig;
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
*/
|
|
263
|
+
declare class ConfigError extends Error {
|
|
264
|
+
constructor(message: string);
|
|
265
|
+
}
|
|
266
|
+
/** Invalid policy must stop the audit instead of silently changing CI behavior. */
|
|
227
267
|
declare function loadConfig(cwd?: string): AgentRoastConfig;
|
|
228
268
|
/**
|
|
229
269
|
* Matches a relative or normalized file path against an array of glob ignore patterns.
|
|
@@ -241,21 +281,62 @@ interface InitResult {
|
|
|
241
281
|
skipped: string[];
|
|
242
282
|
}
|
|
243
283
|
declare const DEFAULT_CONFIG_TEMPLATE: {
|
|
244
|
-
$schema: string;
|
|
245
284
|
ignorePaths: string[];
|
|
246
285
|
rules: {
|
|
247
|
-
"
|
|
248
|
-
"empty-catch": string;
|
|
249
|
-
"trivial-assert": string;
|
|
250
|
-
"stub-abandonment": string;
|
|
251
|
-
"mock-leak": string;
|
|
286
|
+
[x: string]: "error" | "warn" | "off";
|
|
252
287
|
};
|
|
253
288
|
scoreThreshold: number;
|
|
254
289
|
};
|
|
255
|
-
declare const GITHUB_WORKFLOW_TEMPLATE = "name: Agent Roast\non:\n pull_request:\n branches: [main, master]\n
|
|
256
|
-
declare const PRE_COMMIT_HOOK_TEMPLATE = "#!/bin/sh\n# Run agent-roast pre-commit verification\nnpx agent-roast --
|
|
290
|
+
declare const GITHUB_WORKFLOW_TEMPLATE = "name: Agent Roast\non:\n pull_request:\n branches: [main, master]\n\npermissions:\n contents: read\n\njobs:\n audit:\n name: Audit AI Shortcuts\n runs-on: ubuntu-latest\n steps:\n - name: Checkout repository\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Run agent-roast PR check\n if: github.event_name == 'pull_request'\n uses: Nari-Ab/agent-roast@v1\n with:\n base: ${{ github.event.pull_request.base.sha }}\n head: ${{ github.event.pull_request.head.sha }}\n format: github\n";
|
|
291
|
+
declare const PRE_COMMIT_HOOK_TEMPLATE = "#!/bin/sh\n# Run agent-roast pre-commit verification\nnpx --no-install agent-roast --staged\n";
|
|
257
292
|
declare function initProject(options?: InitOptions): Promise<InitResult>;
|
|
258
293
|
|
|
294
|
+
interface ShieldsEndpointResponse {
|
|
295
|
+
schemaVersion: 1;
|
|
296
|
+
label: string;
|
|
297
|
+
message: string;
|
|
298
|
+
color: string;
|
|
299
|
+
}
|
|
300
|
+
declare function getScoreColor(score: number | null): {
|
|
301
|
+
name: string;
|
|
302
|
+
hex: string;
|
|
303
|
+
};
|
|
304
|
+
declare function generateSvgBadge(score: number | null, label?: string): string;
|
|
305
|
+
declare function generateShieldsMarkdown(score: number | null, label?: string, repoUrl?: string): string;
|
|
306
|
+
declare function generateShieldsJson(score: number | null, label?: string): ShieldsEndpointResponse;
|
|
307
|
+
|
|
308
|
+
/** Read current tracked and non-ignored untracked source; never run project code. */
|
|
309
|
+
declare function checkProject(options?: CheckOptions): Promise<CheckResult>;
|
|
310
|
+
|
|
311
|
+
interface FindingBaseline {
|
|
312
|
+
schemaVersion: "1.0.0";
|
|
313
|
+
fingerprintVersion: 1;
|
|
314
|
+
entries: {
|
|
315
|
+
fingerprint: string;
|
|
316
|
+
count: number;
|
|
317
|
+
}[];
|
|
318
|
+
}
|
|
319
|
+
/** Line-independent but multiplicity-aware; adding the same shortcut twice is new. */
|
|
320
|
+
declare function findingFingerprint(finding: Infraction): string;
|
|
321
|
+
declare function createBaseline(findings: Infraction[]): FindingBaseline;
|
|
322
|
+
declare function loadBaseline(filename: string): FindingBaseline;
|
|
323
|
+
declare function applyBaseline(findings: Infraction[], baseline: FindingBaseline): {
|
|
324
|
+
findings: Infraction[];
|
|
325
|
+
baselineCount: number;
|
|
326
|
+
staleBaselineCount: number;
|
|
327
|
+
};
|
|
328
|
+
/** Publish a complete file atomically and refuse to replace an existing baseline. */
|
|
329
|
+
declare function writeBaseline(filename: string, findings: Infraction[]): void;
|
|
330
|
+
|
|
331
|
+
interface RuleGuide {
|
|
332
|
+
title: string;
|
|
333
|
+
why: string;
|
|
334
|
+
suggestion: string;
|
|
335
|
+
example: string;
|
|
336
|
+
}
|
|
337
|
+
/** Review guidance, not automatic edits: legitimate exceptions need context. */
|
|
338
|
+
declare const RULE_GUIDES: Record<DetectorType, RuleGuide>;
|
|
339
|
+
|
|
259
340
|
declare class InvalidDetectorError extends Error {
|
|
260
341
|
constructor(message: string);
|
|
261
342
|
}
|
|
@@ -265,4 +346,4 @@ declare function roastRepository(options?: RoastOptions): Promise<{
|
|
|
265
346
|
}>;
|
|
266
347
|
declare function auditPullRequest(options: PrAuditOptions): Promise<PrAuditResult>;
|
|
267
348
|
|
|
268
|
-
export { type AgentRoastConfig, type AiAttributionResult, type CommitInfo, DEFAULT_CONFIG, DEFAULT_CONFIG_TEMPLATE, type DetectorType, FIELD_SEPARATOR, GITHUB_WORKFLOW_TEMPLATE, GitError, GitResolutionError, HERMETIC_GIT_FLAGS, type Infraction, type InitOptions, type InitResult, InvalidDetectorError, type MetricSummary, MetricsCollector, PRE_COMMIT_HOOK_TEMPLATE, type ParseDiffResult, type ParsedCommit, type ParsedDiffLine, type ParsedFileDiff, type PrAuditOptions, type PrAuditResult, RECORD_SEPARATOR, type RoastOptions, VALID_DETECTORS, auditFileDiffs, auditPullRequest, detectAiAttribution, findMergeBase, formatGithubAnnotations, formatGithubStepSummary, formatPrTerminalCard, formatTerminalCard, generateShareUrl, getHermeticGitEnv, initProject, isCodeFile, isTestFile, loadConfig, matchIgnorePath, parseDiff, parseGitLogStream, resolveCommitSha, roastRepository, streamGitDiff, streamGitLog, stripStringAndRegexLiterals, unquoteGitPath };
|
|
349
|
+
export { type AgentRoastConfig, type AiAttributionResult, type CheckOptions, type CheckResult, type CommitInfo, ConfigError, DEFAULT_CONFIG, DEFAULT_CONFIG_TEMPLATE, type DetectorType, FIELD_SEPARATOR, type FindingBaseline, GITHUB_WORKFLOW_TEMPLATE, GitError, GitResolutionError, HERMETIC_GIT_FLAGS, type Infraction, type InitOptions, type InitResult, InvalidDetectorError, type MetricSummary, MetricsCollector, PRE_COMMIT_HOOK_TEMPLATE, type ParseDiffResult, type ParsedCommit, type ParsedDiffLine, type ParsedFileDiff, type PrAuditOptions, type PrAuditResult, RECORD_SEPARATOR, RULE_GUIDES, type RoastOptions, type RuleGuide, type ShieldsEndpointResponse, VALID_DETECTORS, applyBaseline, auditFileDiffs, auditPullRequest, checkProject, createBaseline, detectAiAttribution, findMergeBase, findingFingerprint, formatCheckMarkdown, formatCheckTerminal, formatGithubAnnotations, formatGithubStepSummary, formatPrMarkdownComment, formatPrTerminalCard, formatTerminalCard, generateShareUrl, generateShieldsJson, generateShieldsMarkdown, generateSvgBadge, getHermeticGitEnv, getScoreColor, initProject, isCodeFile, isTestFile, loadBaseline, loadConfig, matchIgnorePath, parseDiff, parseGitLogStream, resolveCommitSha, roastRepository, streamGitDiff, streamGitLog, stripStringAndRegexLiterals, unquoteGitPath, writeBaseline };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
ConfigError,
|
|
3
4
|
DEFAULT_CONFIG,
|
|
4
5
|
DEFAULT_CONFIG_TEMPLATE,
|
|
5
6
|
FIELD_SEPARATOR,
|
|
@@ -11,20 +12,33 @@ import {
|
|
|
11
12
|
MetricsCollector,
|
|
12
13
|
PRE_COMMIT_HOOK_TEMPLATE,
|
|
13
14
|
RECORD_SEPARATOR,
|
|
15
|
+
RULE_GUIDES,
|
|
14
16
|
VALID_DETECTORS,
|
|
17
|
+
applyBaseline,
|
|
15
18
|
auditFileDiffs,
|
|
16
19
|
auditPullRequest,
|
|
20
|
+
checkProject,
|
|
21
|
+
createBaseline,
|
|
17
22
|
detectAiAttribution,
|
|
18
23
|
findMergeBase,
|
|
24
|
+
findingFingerprint,
|
|
25
|
+
formatCheckMarkdown,
|
|
26
|
+
formatCheckTerminal,
|
|
19
27
|
formatGithubAnnotations,
|
|
20
28
|
formatGithubStepSummary,
|
|
29
|
+
formatPrMarkdownComment,
|
|
21
30
|
formatPrTerminalCard,
|
|
22
31
|
formatTerminalCard,
|
|
23
32
|
generateShareUrl,
|
|
33
|
+
generateShieldsJson,
|
|
34
|
+
generateShieldsMarkdown,
|
|
35
|
+
generateSvgBadge,
|
|
24
36
|
getHermeticGitEnv,
|
|
37
|
+
getScoreColor,
|
|
25
38
|
initProject,
|
|
26
39
|
isCodeFile,
|
|
27
40
|
isTestFile,
|
|
41
|
+
loadBaseline,
|
|
28
42
|
loadConfig,
|
|
29
43
|
matchIgnorePath,
|
|
30
44
|
parseDiff,
|
|
@@ -34,9 +48,11 @@ import {
|
|
|
34
48
|
streamGitDiff,
|
|
35
49
|
streamGitLog,
|
|
36
50
|
stripStringAndRegexLiterals,
|
|
37
|
-
unquoteGitPath
|
|
38
|
-
|
|
51
|
+
unquoteGitPath,
|
|
52
|
+
writeBaseline
|
|
53
|
+
} from "./chunk-FUAUIURY.js";
|
|
39
54
|
export {
|
|
55
|
+
ConfigError,
|
|
40
56
|
DEFAULT_CONFIG,
|
|
41
57
|
DEFAULT_CONFIG_TEMPLATE,
|
|
42
58
|
FIELD_SEPARATOR,
|
|
@@ -48,20 +64,33 @@ export {
|
|
|
48
64
|
MetricsCollector,
|
|
49
65
|
PRE_COMMIT_HOOK_TEMPLATE,
|
|
50
66
|
RECORD_SEPARATOR,
|
|
67
|
+
RULE_GUIDES,
|
|
51
68
|
VALID_DETECTORS,
|
|
69
|
+
applyBaseline,
|
|
52
70
|
auditFileDiffs,
|
|
53
71
|
auditPullRequest,
|
|
72
|
+
checkProject,
|
|
73
|
+
createBaseline,
|
|
54
74
|
detectAiAttribution,
|
|
55
75
|
findMergeBase,
|
|
76
|
+
findingFingerprint,
|
|
77
|
+
formatCheckMarkdown,
|
|
78
|
+
formatCheckTerminal,
|
|
56
79
|
formatGithubAnnotations,
|
|
57
80
|
formatGithubStepSummary,
|
|
81
|
+
formatPrMarkdownComment,
|
|
58
82
|
formatPrTerminalCard,
|
|
59
83
|
formatTerminalCard,
|
|
60
84
|
generateShareUrl,
|
|
85
|
+
generateShieldsJson,
|
|
86
|
+
generateShieldsMarkdown,
|
|
87
|
+
generateSvgBadge,
|
|
61
88
|
getHermeticGitEnv,
|
|
89
|
+
getScoreColor,
|
|
62
90
|
initProject,
|
|
63
91
|
isCodeFile,
|
|
64
92
|
isTestFile,
|
|
93
|
+
loadBaseline,
|
|
65
94
|
loadConfig,
|
|
66
95
|
matchIgnorePath,
|
|
67
96
|
parseDiff,
|
|
@@ -71,5 +100,6 @@ export {
|
|
|
71
100
|
streamGitDiff,
|
|
72
101
|
streamGitLog,
|
|
73
102
|
stripStringAndRegexLiterals,
|
|
74
|
-
unquoteGitPath
|
|
103
|
+
unquoteGitPath,
|
|
104
|
+
writeBaseline
|
|
75
105
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-roast",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Offline code checks for skipped tests, swallowed errors, unfinished stubs and AI coding shortcuts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
"build": "tsup",
|
|
18
18
|
"dev": "tsup --watch",
|
|
19
19
|
"test": "vitest run",
|
|
20
|
-
"prepublishOnly": "npm run build"
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"pretest": "npm run build",
|
|
22
|
+
"typecheck": "tsc --noEmit"
|
|
21
23
|
},
|
|
22
24
|
"keywords": [
|
|
23
25
|
"ai",
|