Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions LifeOS/install/skills/Evals/Graders/CodeBased/StaticAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

import { BaseGrader, registerGrader, type GraderContext } from '../Base.ts';
import type { GraderConfig, GraderResult, StaticAnalysisParams } from '../../Types/index.ts';
import { $ } from 'bun';

// Windows has no /bin/sh; cmd takes /c where POSIX shells take -c.
const SHELL_PREFIX = process.platform === 'win32' ? ['cmd', '/c'] : ['/bin/sh', '-c'];

export class StaticAnalysisGrader extends BaseGrader {
type = 'static_analysis' as const;
Expand All @@ -26,14 +28,28 @@ export class StaticAnalysisGrader extends BaseGrader {

for (const command of params.commands) {
try {
const result = await $`cd ${workingDir} && ${command}`.quiet().nothrow();
// Run through a shell: the command is a user-authored string ("bun test",
// "eslint . --max-warnings 0"), and a tagged-template interpolation would
// escape the whole string into a single argv token, so nothing would run.
const proc = Bun.spawn([...SHELL_PREFIX, command], {
cwd: workingDir,
stdout: 'pipe',
stderr: 'pipe',
});
const [stdout, stderr, exitCode] = await Promise.all([
new Response(proc.stdout).text(),
new Response(proc.stderr).text(),
proc.exited,
]);

const output = result.stdout.toString() + result.stderr.toString();
const output = stdout + stderr;
const warnings = this.countIssues(output, 'warning');
const errors = this.countIssues(output, 'error');

// Pass if no errors (and no warnings if fail_on_warning is set)
const passed = errors === 0 && (!params.fail_on_warning || warnings === 0);
// A non-zero exit is a failure on its own: a tool that reports its verdict
// only through its exit status (tsc, most test runners) prints nothing the
// keyword scan below would ever count.
const passed = exitCode === 0 && errors === 0 && (!params.fail_on_warning || warnings === 0);

results.push({
command,
Expand Down