Plan N1 / spec §10 / §22.4 / §16 Phase 7.
apps/daemon/src/plugins/atoms/build-test.ts ships the daemon-side
implementation that the bundled plugins/_official/atoms/build-test
SKILL.md fragment locks the contract for:
runBuildTest({ cwd, buildCommand?, testCommand?, ... }) → BuildTestReport
The runner:
- Honours explicit overrides (highest priority).
- Otherwise infers commands from package.json scripts:
typecheck (or build) → `{pm} run typecheck`
test → `{pm} run test`
- Auto-picks the package manager from lockfile presence
(pnpm-lock.yaml → pnpm; yarn.lock → yarn; else npm).
- Skips a half cleanly when no command resolved, recording an
explicit reason. Skipped doesn't flip the matching signal off
(a project that opts out of typecheck still gets build.passing=true).
- Caps combined stdout+stderr at 1 MiB by default, marks
truncated output with '…[truncated]'.
- Per-command timeout 5min default, sends SIGTERM at expiry.
- Spawn function is pluggable so callers can inject a stub.
writeBuildTestReport() persists the canonical critique/build-test.json
+ critique/build-test.log layout the SKILL.md fragment promises.
UntilSignals gains 'build.passing' + 'tests.passing' so a plan can
write `until: 'build.passing && tests.passing'` directly. Closes
the spec §22.4 limit-1 gap that was blocking scenario 2 (code
migration) from natively expressing 'build/test pass = converged'.
The score axis (legacy critique.score) maps:
both pass → 5
only build pass → 3
both fail → 1
so existing pipelines that read critique.score keep working.
Daemon tests: 1521 → 1528 (+7 cases on plugins-build-test:
both-pass, build-fail, skip-with-reason, log truncation, npm
script inference, pnpm preference, JSON + log persistence).
Co-authored-by: Tom Huang <1043269994@qq.com>