diff --git a/LifeOS/install/skills/Evals/Graders/CodeBased/StaticAnalysis.ts b/LifeOS/install/skills/Evals/Graders/CodeBased/StaticAnalysis.ts index 2ef1f59858..6fec77a99f 100755 --- a/LifeOS/install/skills/Evals/Graders/CodeBased/StaticAnalysis.ts +++ b/LifeOS/install/skills/Evals/Graders/CodeBased/StaticAnalysis.ts @@ -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; @@ -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,