From 5827e9b5b96aa668081d38b9de44dbd4504062c7 Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 29 May 2026 01:34:39 +0800 Subject: [PATCH] chore: structure v02 check runner --- package.json | 7 +- scripts/check-runner.mjs | 11 ++ scripts/check-runner.test.mjs | 53 +++++++++ scripts/src/check-plan.mjs | 179 ++++++++++++++++++++++++++++ scripts/src/check-runner-lib.mjs | 196 +++++++++++++++++++++++++++++++ 5 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 scripts/check-runner.mjs create mode 100644 scripts/check-runner.test.mjs create mode 100644 scripts/src/check-plan.mjs create mode 100644 scripts/src/check-runner-lib.mjs diff --git a/package.json b/package.json index 2e9adf50..a9dd0b7b 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,11 @@ "private": true, "type": "module", "scripts": { - "validate": "node scripts/repo-reports-guard.mjs && node scripts/run-bun.mjs scripts/validate-contract.mjs && node scripts/run-bun.mjs scripts/deploy-contract-plan.mjs --check && node scripts/run-bun.mjs scripts/deploy-desired-state-plan.mjs --check && node scripts/run-bun.mjs scripts/dev-runtime-provisioning.mjs --check && node scripts/run-bun.mjs scripts/dev-runtime-migration.mjs --check && node scripts/dev-runtime-postflight.mjs --check && node scripts/dev-runtime-hotfix-audit.mjs && node scripts/run-bun.mjs scripts/rpt004-mvp-e2e-harness.mjs --check --no-write && node --check scripts/artifact-runtime-readiness-guard.mjs && node --check scripts/src/artifact-runtime-readiness-guard.mjs && node --check scripts/dev-runtime-hotfix-audit.mjs && node --check scripts/src/dev-runtime-hotfix-audit.mjs && node --test scripts/artifact-runtime-readiness-guard.test.mjs scripts/src/dev-runtime-hotfix-audit.test.mjs", - "check": "node scripts/repo-reports-guard.mjs && node --check scripts/repo-reports-guard.mjs && node --check scripts/src/report-paths.mjs && node --check internal/protocol/index.mjs && node --check internal/build-metadata.mjs && node --check internal/agent/index.mjs && node --check internal/agent/runtime.mjs && node --check internal/audit/index.mjs && node scripts/run-bun.mjs build internal/db/runtime-store.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/db/runtime-store.test.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check internal/mvp-gate/summary.mjs && node scripts/run-bun.mjs build internal/cloud/db-contract.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check internal/dev-entrypoint/cloud-web-routes.mjs && node --check internal/dev-entrypoint/cloud-web-proxy.mjs && node --check internal/dev-entrypoint/cloud-web-proxy.test.mjs && node --check internal/dev-entrypoint/http.mjs && node --check internal/dev-entrypoint/http.test.mjs && node scripts/run-bun.mjs build internal/cloud/code-agent-contract.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/code-agent-session-registry.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/code-agent-session-registry.test.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/code-agent-trace-store.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/codex-stdio-session.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/json-rpc.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/code-agent-chat.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/m3-io-control.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/server.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/server-test-helpers.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/code-agent-trace-store.test.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/server-live-builds.test.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/server-health.test.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/server-agent-chat.test.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build internal/cloud/server-m3-http.test.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check internal/device-pod/fake-data.mjs && node --check internal/sim/model.mjs && node --check internal/sim/model.test.mjs && node --check internal/sim/http.mjs && node --check internal/sim/l2-runtime.mjs && node --check internal/patchpanel/model.mjs && node --check internal/patchpanel/runtime.mjs && node scripts/run-bun.mjs build cmd/hwlab-cloud-api/main.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build cmd/hwlab-cloud-api/provision.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build cmd/hwlab-cloud-api/migrate.ts --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check cmd/hwlab-deepseek-responses-bridge/main.mjs && node --check cmd/hwlab-deepseek-responses-bridge/main.test.mjs && node --test cmd/hwlab-deepseek-responses-bridge/main.test.mjs && node --check cmd/hwlab-edge-proxy/main.mjs && node --check cmd/hwlab-agent-mgr/main.mjs && node --check cmd/hwlab-agent-worker/main.mjs && node --check cmd/hwlab-device-pod/main.mjs && node --check cmd/hwlab-box-simu/main.mjs && node --check cmd/hwlab-gateway/main.mjs && node --check cmd/hwlab-gateway-simu/main.mjs && node --check tools/hwlab-gateway-shell.mjs && node --check tools/hwlab-gateway-tran.mjs && node --check tools/tran.mjs && node --check tools/device-pod-cli.mjs && node --check skills/device-pod-cli/scripts/device-pod-cli.mjs && node --check skills/device-pod-cli/assets/device-host-cli.mjs && node scripts/run-bun.mjs build scripts/cloud-api-runtime-smoke.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build scripts/code-agent-chat-smoke.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check scripts/dev-edge-health-smoke.mjs && node scripts/run-bun.mjs build scripts/src/dev-edge-health-smoke-lib.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build scripts/validate-contract.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check scripts/deploy-contract-plan.test.mjs && node scripts/run-bun.mjs build scripts/deploy-desired-state-plan.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build scripts/src/deploy-desired-state-plan.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check scripts/artifact-runtime-readiness-guard.mjs && node --check scripts/src/artifact-runtime-readiness-guard.mjs && node --check scripts/artifact-runtime-readiness-guard.test.mjs && node --check scripts/report-lifecycle.mjs && node --check scripts/report-lifecycle.test.mjs && node --check scripts/validate-dev-gate-report.mjs && node --check scripts/dev-m3-hardware-loop-smoke.test.mjs && node --check scripts/m3-io-control-e2e.mjs && node scripts/run-bun.mjs build scripts/src/m3-io-control-e2e.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check scripts/m3-io-control-e2e.test.mjs && node --check scripts/dev-cloud-workbench-smoke.test.mjs && node --check scripts/dev-cloud-workbench-layout-smoke.mjs && node --check scripts/rpt004-mvp-e2e-harness.mjs && node scripts/run-bun.mjs build scripts/src/rpt004-mvp-e2e-harness.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check scripts/src/rpt004-mvp-e2e-harness.test.mjs && node --check scripts/validate-dev-m3-cardinality.mjs && node --check scripts/validate-dev-m3-cardinality.test.mjs && node --check scripts/validate-artifact-catalog.mjs && node --check scripts/refresh-artifact-catalog.mjs && node --check scripts/refresh-artifact-catalog.test.mjs && node --check scripts/artifact-publish.mjs && node --check scripts/g14-artifact-publish.mjs && node --check scripts/dev-runtime-base-image.mjs && node --check scripts/src/dev-artifact-services.mjs && node --check scripts/src/registry-capabilities.mjs && node --check scripts/preflight-dev-base-image.mjs && node --check scripts/src/dev-base-image-preflight.mjs && node --check scripts/dev-evidence-blocker-aggregator.mjs && node --check scripts/src/dev-evidence-blocker-aggregator.mjs && node --check scripts/src/dev-evidence-blocker-aggregator.test.mjs && node --check scripts/src/dev-m4-agent-loop-smoke-lib.test.mjs && node --check scripts/d601-k3s-readonly-observability.mjs && node --check scripts/src/d601-k3s-readonly-observability.mjs && node --check scripts/dev-runtime-provisioning.mjs && node scripts/run-bun.mjs build scripts/src/dev-runtime-provisioning.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build scripts/src/dev-runtime-provisioning.test.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check scripts/dev-runtime-migration.mjs && node scripts/run-bun.mjs build scripts/src/dev-runtime-migration.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node scripts/run-bun.mjs build scripts/src/dev-runtime-migration.test.mjs --target=bun --packages=external --outdir=/tmp/hwlab-ts-check && node --check scripts/dev-runtime-postflight.mjs && node --check scripts/src/dev-runtime-postflight.mjs && node --check scripts/src/dev-runtime-postflight.test.mjs && node --check scripts/dev-runtime-hotfix-audit.mjs && node --check scripts/src/dev-runtime-hotfix-audit.mjs && node --check scripts/src/dev-runtime-hotfix-audit.test.mjs && node --test scripts/src/dev-runtime-hotfix-audit.test.mjs && node --check scripts/l2-runtime-contract-smoke.mjs && node --check scripts/patch-panel-runtime-smoke.mjs && node --check scripts/l6-cli-web-smoke.mjs && node --check skills/hwlab-agent-runtime/scripts/hwlab-agent-runtime-cli.mjs && node --check skills/hwlab-agent-runtime/scripts/src/m3-io-skill-client.mjs && node --check tools/hwlab-cli/bin/hwlab-cli.mjs && node --check tools/hwlab-cli/lib/cli.mjs && node --check tools/hwlab-cli/lib/cli.test.mjs && (cd web/hwlab-cloud-web && bun run check) && node scripts/run-bun.mjs scripts/validate-contract.mjs && node scripts/validate-dev-gate-report.mjs && node scripts/report-lifecycle.test.mjs && node scripts/validate-dev-m3-cardinality.mjs && node scripts/validate-artifact-catalog.mjs && node scripts/run-bun.mjs scripts/deploy-desired-state-plan.mjs --check && node scripts/run-bun.mjs scripts/dev-runtime-provisioning.mjs --check && node scripts/run-bun.mjs scripts/dev-runtime-migration.mjs --check && node scripts/run-bun.mjs cmd/hwlab-cloud-api/provision.ts --check && node scripts/run-bun.mjs cmd/hwlab-cloud-api/migrate.ts --check && node scripts/dev-runtime-postflight.mjs --check && node scripts/rpt004-mvp-e2e-harness.mjs --check --no-write && node scripts/dev-evidence-blocker-aggregator.mjs --check && node scripts/l2-runtime-contract-smoke.mjs && node scripts/l6-cli-web-smoke.mjs && (cd web/hwlab-cloud-web && bun run check) && node scripts/run-bun.mjs scripts/code-agent-chat-smoke.mjs && node scripts/run-bun.mjs scripts/cloud-api-runtime-smoke.mjs && sh -n scripts/bootstrap-skills.sh scripts/worker-entrypoint.sh && node scripts/run-bun.mjs test cmd/hwlab-cloud-api/runtime-options.test.ts internal/cloud/code-agent-session-registry.test.ts internal/cloud/json-rpc.test.ts internal/cloud/m3-io-control.test.ts internal/cloud/code-agent-trace-store.test.ts internal/cloud/server-live-builds.test.ts internal/cloud/server-health.test.ts internal/cloud/server-agent-chat.test.ts internal/cloud/server-m3-http.test.ts internal/db/runtime-store.test.ts internal/db/schema.test.ts", + "validate": "node scripts/check-runner.mjs --profile validate", + "check": "node scripts/check-runner.mjs --profile check", + "check:plan": "node scripts/check-runner.mjs --profile check --list", + "check:cloud-api": "node scripts/check-runner.mjs --profile check --group cloud-api", + "check:cloud-web": "node scripts/check-runner.mjs --profile check --group cloud-web", "dev-base-image:preflight": "node scripts/preflight-dev-base-image.mjs", "dev-runtime-base:build": "node scripts/dev-runtime-base-image.mjs", "cloud-api:smoke": "node scripts/run-bun.mjs scripts/cloud-api-runtime-smoke.mjs", diff --git a/scripts/check-runner.mjs b/scripts/check-runner.mjs new file mode 100644 index 00000000..e1f5187b --- /dev/null +++ b/scripts/check-runner.mjs @@ -0,0 +1,11 @@ +#!/usr/bin/env node +import { runCheckRunner } from "./src/check-runner-lib.mjs"; + +try { + const result = await runCheckRunner(process.argv.slice(2)); + process.exit(result.exitCode); +} catch (error) { + const message = error instanceof Error ? error.message : String(error); + process.stderr.write(JSON.stringify({ ok: false, command: "check-runner", error: message }, null, 2) + "\n"); + process.exit(1); +} diff --git a/scripts/check-runner.test.mjs b/scripts/check-runner.test.mjs new file mode 100644 index 00000000..1502fe88 --- /dev/null +++ b/scripts/check-runner.test.mjs @@ -0,0 +1,53 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import test from "node:test"; + +import { checkProfiles } from "./src/check-plan.mjs"; +import { parseCheckRunnerArgs, runCheckRunner, selectTasks } from "./src/check-runner-lib.mjs"; + +test("package scripts delegate to structured check runner", () => { + const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")); + assert.equal(pkg.scripts.check, "node scripts/check-runner.mjs --profile check"); + assert.equal(pkg.scripts.validate, "node scripts/check-runner.mjs --profile validate"); + assert.ok(!pkg.scripts.check.includes("&&")); + assert.ok(!pkg.scripts.validate.includes("&&")); +}); + +test("check plan exposes grouped tasks", () => { + assert.ok(checkProfiles.check.length > 80); + assert.ok(checkProfiles.validate.length > 5); + assert.ok(checkProfiles.check.some((task) => task.group === "cloud-api")); + assert.ok(checkProfiles.check.some((task) => task.group === "cloud-web")); +}); + +test("runner filters profile tasks by group", () => { + const options = parseCheckRunnerArgs(["--profile", "check", "--group", "cloud-api"]); + const tasks = selectTasks(options); + assert.ok(tasks.length > 0); + assert.ok(tasks.every((task) => task.group === "cloud-api")); +}); + +test("runner rejects unknown group and id instead of reporting an empty successful plan", () => { + assert.throws( + () => selectTasks(parseCheckRunnerArgs(["--profile", "check", "--group", "missing-group"])), + /unknown check group/u + ); + assert.throws( + () => selectTasks(parseCheckRunnerArgs(["--profile", "check", "--id", "missing-id"])), + /unknown check task id/u + ); +}); + +test("dry-run returns structured JSON without executing tasks", async () => { + let stdout = ""; + const result = await runCheckRunner(["--profile", "validate", "--group", "repo", "--dry-run"], { + stdout: { write(chunk) { stdout += chunk; } }, + stderr: { write() {} } + }); + assert.equal(result.exitCode, 0); + const payload = JSON.parse(stdout); + assert.equal(payload.mode, "dry-run"); + assert.equal(payload.profile, "validate"); + assert.ok(payload.tasks.length > 0); + assert.ok(payload.tasks.every((task) => task.group === "repo")); +}); diff --git a/scripts/src/check-plan.mjs b/scripts/src/check-plan.mjs new file mode 100644 index 00000000..9334157f --- /dev/null +++ b/scripts/src/check-plan.mjs @@ -0,0 +1,179 @@ +// Mechanical translation of the former root package.json check/validate scripts for #536. +// Keep each task as structured argv so future reviews can see semantic changes. + +export const CHECK_PLAN_VERSION = "v02-structured-check-runner-v1"; + +export const checkProfiles = Object.freeze({ + validate: Object.freeze([ + { id: "validate-001-repo-repo-reports-guard", group: "repo", command: ["node","scripts/repo-reports-guard.mjs"] }, + { id: "validate-002-repo-run-bun", group: "repo", command: ["node","scripts/run-bun.mjs","scripts/validate-contract.mjs"] }, + { id: "validate-003-deploy-run-bun", group: "deploy", command: ["node","scripts/run-bun.mjs","scripts/deploy-contract-plan.mjs","--check"] }, + { id: "validate-004-deploy-run-bun", group: "deploy", command: ["node","scripts/run-bun.mjs","scripts/deploy-desired-state-plan.mjs","--check"] }, + { id: "validate-005-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","scripts/dev-runtime-provisioning.mjs","--check"] }, + { id: "validate-006-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","scripts/dev-runtime-migration.mjs","--check"] }, + { id: "validate-007-dev-runtime-dev-runtime-postflight", group: "dev-runtime", command: ["node","scripts/dev-runtime-postflight.mjs","--check"] }, + { id: "validate-008-dev-runtime-dev-runtime-hotfix-audit", group: "dev-runtime", command: ["node","scripts/dev-runtime-hotfix-audit.mjs"] }, + { id: "validate-009-smoke-run-bun", group: "smoke", command: ["node","scripts/run-bun.mjs","scripts/rpt004-mvp-e2e-harness.mjs","--check","--no-write"] }, + { id: "validate-010-artifact-artifact-runtime-readiness-guard", group: "artifact", command: ["node","--check","scripts/artifact-runtime-readiness-guard.mjs"] }, + { id: "validate-011-artifact-artifact-runtime-readiness-guard", group: "artifact", command: ["node","--check","scripts/src/artifact-runtime-readiness-guard.mjs"] }, + { id: "validate-012-dev-runtime-dev-runtime-hotfix-audit", group: "dev-runtime", command: ["node","--check","scripts/dev-runtime-hotfix-audit.mjs"] }, + { id: "validate-013-dev-runtime-dev-runtime-hotfix-audit", group: "dev-runtime", command: ["node","--check","scripts/src/dev-runtime-hotfix-audit.mjs"] }, + { id: "validate-014-artifact-artifact-runtime-readiness-guard-test", group: "artifact", command: ["node","--test","scripts/artifact-runtime-readiness-guard.test.mjs","scripts/src/dev-runtime-hotfix-audit.test.mjs"] } + ]), + check: Object.freeze([ + { id: "check-001-check-runner-check-runner", group: "check-runner", command: ["node","--check","scripts/check-runner.mjs"] }, + { id: "check-002-check-runner-lib", group: "check-runner", command: ["node","--check","scripts/src/check-runner-lib.mjs"] }, + { id: "check-003-check-runner-plan", group: "check-runner", command: ["node","--check","scripts/src/check-plan.mjs"] }, + { id: "check-004-check-runner-test-syntax", group: "check-runner", command: ["node","--check","scripts/check-runner.test.mjs"] }, + { id: "check-005-check-runner-test", group: "check-runner", command: ["node","--test","scripts/check-runner.test.mjs"] }, + { id: "check-006-repo-repo-reports-guard", group: "repo", command: ["node","scripts/repo-reports-guard.mjs"] }, + { id: "check-007-repo-repo-reports-guard", group: "repo", command: ["node","--check","scripts/repo-reports-guard.mjs"] }, + { id: "check-008-repo-report-paths", group: "repo", command: ["node","--check","scripts/src/report-paths.mjs"] }, + { id: "check-009-repo-index", group: "repo", command: ["node","--check","internal/protocol/index.mjs"] }, + { id: "check-010-repo-build-metadata", group: "repo", command: ["node","--check","internal/build-metadata.mjs"] }, + { id: "check-011-repo-index", group: "repo", command: ["node","--check","internal/agent/index.mjs"] }, + { id: "check-012-repo-runtime", group: "repo", command: ["node","--check","internal/agent/runtime.mjs"] }, + { id: "check-013-repo-index", group: "repo", command: ["node","--check","internal/audit/index.mjs"] }, + { id: "check-014-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/db/runtime-store.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-015-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/db/runtime-store.test.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-016-smoke-summary", group: "smoke", command: ["node","--check","internal/mvp-gate/summary.mjs"] }, + { id: "check-017-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/db-contract.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-018-repo-cloud-web-routes", group: "repo", command: ["node","--check","internal/dev-entrypoint/cloud-web-routes.mjs"] }, + { id: "check-019-repo-cloud-web-proxy", group: "repo", command: ["node","--check","internal/dev-entrypoint/cloud-web-proxy.mjs"] }, + { id: "check-020-repo-cloud-web-proxy-test", group: "repo", command: ["node","--check","internal/dev-entrypoint/cloud-web-proxy.test.mjs"] }, + { id: "check-021-repo-http", group: "repo", command: ["node","--check","internal/dev-entrypoint/http.mjs"] }, + { id: "check-022-repo-http-test", group: "repo", command: ["node","--check","internal/dev-entrypoint/http.test.mjs"] }, + { id: "check-023-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/code-agent-contract.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-024-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/code-agent-session-registry.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-025-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/code-agent-session-registry.test.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-026-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/code-agent-trace-store.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-027-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/codex-stdio-session.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-028-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/json-rpc.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-029-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/code-agent-chat.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-030-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/m3-io-control.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-031-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/server.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-032-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/server-test-helpers.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-033-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/code-agent-trace-store.test.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-034-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/server-live-builds.test.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-035-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/server-health.test.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-036-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/server-agent-chat.test.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-037-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","internal/cloud/server-m3-http.test.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-038-repo-fake-data", group: "repo", command: ["node","--check","internal/device-pod/fake-data.mjs"] }, + { id: "check-039-repo-model", group: "repo", command: ["node","--check","internal/sim/model.mjs"] }, + { id: "check-040-repo-model-test", group: "repo", command: ["node","--check","internal/sim/model.test.mjs"] }, + { id: "check-041-repo-http", group: "repo", command: ["node","--check","internal/sim/http.mjs"] }, + { id: "check-042-smoke-l2-runtime", group: "smoke", command: ["node","--check","internal/sim/l2-runtime.mjs"] }, + { id: "check-043-repo-model", group: "repo", command: ["node","--check","internal/patchpanel/model.mjs"] }, + { id: "check-044-repo-runtime", group: "repo", command: ["node","--check","internal/patchpanel/runtime.mjs"] }, + { id: "check-045-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","cmd/hwlab-cloud-api/main.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-046-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","cmd/hwlab-cloud-api/provision.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-047-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","cmd/hwlab-cloud-api/migrate.ts","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-048-repo-main", group: "repo", command: ["node","--check","cmd/hwlab-deepseek-responses-bridge/main.mjs"] }, + { id: "check-049-repo-main-test", group: "repo", command: ["node","--check","cmd/hwlab-deepseek-responses-bridge/main.test.mjs"] }, + { id: "check-050-repo-main-test", group: "repo", command: ["node","--test","cmd/hwlab-deepseek-responses-bridge/main.test.mjs"] }, + { id: "check-051-repo-main", group: "repo", command: ["node","--check","cmd/hwlab-edge-proxy/main.mjs"] }, + { id: "check-052-repo-main", group: "repo", command: ["node","--check","cmd/hwlab-agent-mgr/main.mjs"] }, + { id: "check-053-repo-main", group: "repo", command: ["node","--check","cmd/hwlab-agent-worker/main.mjs"] }, + { id: "check-054-repo-main", group: "repo", command: ["node","--check","cmd/hwlab-device-pod/main.mjs"] }, + { id: "check-055-repo-main", group: "repo", command: ["node","--check","cmd/hwlab-box-simu/main.mjs"] }, + { id: "check-056-repo-main", group: "repo", command: ["node","--check","cmd/hwlab-gateway/main.mjs"] }, + { id: "check-057-repo-main", group: "repo", command: ["node","--check","cmd/hwlab-gateway-simu/main.mjs"] }, + { id: "check-058-tools-hwlab-gateway-shell", group: "tools", command: ["node","--check","tools/hwlab-gateway-shell.mjs"] }, + { id: "check-059-tools-hwlab-gateway-tran", group: "tools", command: ["node","--check","tools/hwlab-gateway-tran.mjs"] }, + { id: "check-060-tools-tran", group: "tools", command: ["node","--check","tools/tran.mjs"] }, + { id: "check-061-tools-device-pod-cli", group: "tools", command: ["node","--check","tools/device-pod-cli.mjs"] }, + { id: "check-062-tools-device-pod-cli", group: "tools", command: ["node","--check","skills/device-pod-cli/scripts/device-pod-cli.mjs"] }, + { id: "check-063-tools-device-host-cli", group: "tools", command: ["node","--check","skills/device-pod-cli/assets/device-host-cli.mjs"] }, + { id: "check-064-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","scripts/cloud-api-runtime-smoke.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-065-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","build","scripts/code-agent-chat-smoke.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-066-dev-runtime-dev-edge-health-smoke", group: "dev-runtime", command: ["node","--check","scripts/dev-edge-health-smoke.mjs"] }, + { id: "check-067-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","build","scripts/src/dev-edge-health-smoke-lib.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-068-repo-run-bun", group: "repo", command: ["node","scripts/run-bun.mjs","build","scripts/validate-contract.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-069-deploy-deploy-contract-plan-test", group: "deploy", command: ["node","--check","scripts/deploy-contract-plan.test.mjs"] }, + { id: "check-070-deploy-run-bun", group: "deploy", command: ["node","scripts/run-bun.mjs","build","scripts/deploy-desired-state-plan.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-071-deploy-run-bun", group: "deploy", command: ["node","scripts/run-bun.mjs","build","scripts/src/deploy-desired-state-plan.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-072-artifact-artifact-runtime-readiness-guard", group: "artifact", command: ["node","--check","scripts/artifact-runtime-readiness-guard.mjs"] }, + { id: "check-073-artifact-artifact-runtime-readiness-guard", group: "artifact", command: ["node","--check","scripts/src/artifact-runtime-readiness-guard.mjs"] }, + { id: "check-074-artifact-artifact-runtime-readiness-guard-test", group: "artifact", command: ["node","--check","scripts/artifact-runtime-readiness-guard.test.mjs"] }, + { id: "check-075-repo-report-lifecycle", group: "repo", command: ["node","--check","scripts/report-lifecycle.mjs"] }, + { id: "check-076-repo-report-lifecycle-test", group: "repo", command: ["node","--check","scripts/report-lifecycle.test.mjs"] }, + { id: "check-077-dev-runtime-validate-dev-gate-report", group: "dev-runtime", command: ["node","--check","scripts/validate-dev-gate-report.mjs"] }, + { id: "check-078-smoke-dev-m3-hardware-loop-smoke-test", group: "smoke", command: ["node","--check","scripts/dev-m3-hardware-loop-smoke.test.mjs"] }, + { id: "check-079-smoke-m3-io-control-e2e", group: "smoke", command: ["node","--check","scripts/m3-io-control-e2e.mjs"] }, + { id: "check-080-smoke-run-bun", group: "smoke", command: ["node","scripts/run-bun.mjs","build","scripts/src/m3-io-control-e2e.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-081-smoke-m3-io-control-e2e-test", group: "smoke", command: ["node","--check","scripts/m3-io-control-e2e.test.mjs"] }, + { id: "check-082-cloud-web-dev-cloud-workbench-smoke-test", group: "cloud-web", command: ["node","--check","scripts/dev-cloud-workbench-smoke.test.mjs"] }, + { id: "check-083-cloud-web-dev-cloud-workbench-layout-smoke", group: "cloud-web", command: ["node","--check","scripts/dev-cloud-workbench-layout-smoke.mjs"] }, + { id: "check-084-smoke-rpt004-mvp-e2e-harness", group: "smoke", command: ["node","--check","scripts/rpt004-mvp-e2e-harness.mjs"] }, + { id: "check-085-smoke-run-bun", group: "smoke", command: ["node","scripts/run-bun.mjs","build","scripts/src/rpt004-mvp-e2e-harness.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-086-smoke-rpt004-mvp-e2e-harness-test", group: "smoke", command: ["node","--check","scripts/src/rpt004-mvp-e2e-harness.test.mjs"] }, + { id: "check-087-smoke-validate-dev-m3-cardinality", group: "smoke", command: ["node","--check","scripts/validate-dev-m3-cardinality.mjs"] }, + { id: "check-088-smoke-validate-dev-m3-cardinality-test", group: "smoke", command: ["node","--check","scripts/validate-dev-m3-cardinality.test.mjs"] }, + { id: "check-089-deploy-validate-artifact-catalog", group: "deploy", command: ["node","--check","scripts/validate-artifact-catalog.mjs"] }, + { id: "check-090-deploy-refresh-artifact-catalog", group: "deploy", command: ["node","--check","scripts/refresh-artifact-catalog.mjs"] }, + { id: "check-091-deploy-refresh-artifact-catalog-test", group: "deploy", command: ["node","--check","scripts/refresh-artifact-catalog.test.mjs"] }, + { id: "check-092-artifact-artifact-publish", group: "artifact", command: ["node","--check","scripts/artifact-publish.mjs"] }, + { id: "check-093-artifact-g14-artifact-publish", group: "artifact", command: ["node","--check","scripts/g14-artifact-publish.mjs"] }, + { id: "check-094-artifact-dev-runtime-base-image", group: "artifact", command: ["node","--check","scripts/dev-runtime-base-image.mjs"] }, + { id: "check-095-artifact-dev-artifact-services", group: "artifact", command: ["node","--check","scripts/src/dev-artifact-services.mjs"] }, + { id: "check-096-artifact-registry-capabilities", group: "artifact", command: ["node","--check","scripts/src/registry-capabilities.mjs"] }, + { id: "check-097-artifact-preflight-dev-base-image", group: "artifact", command: ["node","--check","scripts/preflight-dev-base-image.mjs"] }, + { id: "check-098-artifact-dev-base-image-preflight", group: "artifact", command: ["node","--check","scripts/src/dev-base-image-preflight.mjs"] }, + { id: "check-099-smoke-dev-evidence-blocker-aggregator", group: "smoke", command: ["node","--check","scripts/dev-evidence-blocker-aggregator.mjs"] }, + { id: "check-100-smoke-dev-evidence-blocker-aggregator", group: "smoke", command: ["node","--check","scripts/src/dev-evidence-blocker-aggregator.mjs"] }, + { id: "check-101-smoke-dev-evidence-blocker-aggregator-test", group: "smoke", command: ["node","--check","scripts/src/dev-evidence-blocker-aggregator.test.mjs"] }, + { id: "check-102-smoke-dev-m4-agent-loop-smoke-lib-test", group: "smoke", command: ["node","--check","scripts/src/dev-m4-agent-loop-smoke-lib.test.mjs"] }, + { id: "check-103-repo-d601-k3s-readonly-observability", group: "repo", command: ["node","--check","scripts/d601-k3s-readonly-observability.mjs"] }, + { id: "check-104-repo-d601-k3s-readonly-observability", group: "repo", command: ["node","--check","scripts/src/d601-k3s-readonly-observability.mjs"] }, + { id: "check-105-dev-runtime-dev-runtime-provisioning", group: "dev-runtime", command: ["node","--check","scripts/dev-runtime-provisioning.mjs"] }, + { id: "check-106-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","build","scripts/src/dev-runtime-provisioning.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-107-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","build","scripts/src/dev-runtime-provisioning.test.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-108-dev-runtime-dev-runtime-migration", group: "dev-runtime", command: ["node","--check","scripts/dev-runtime-migration.mjs"] }, + { id: "check-109-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","build","scripts/src/dev-runtime-migration.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-110-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","build","scripts/src/dev-runtime-migration.test.mjs","--target=bun","--packages=external","--outdir=/tmp/hwlab-ts-check"] }, + { id: "check-111-dev-runtime-dev-runtime-postflight", group: "dev-runtime", command: ["node","--check","scripts/dev-runtime-postflight.mjs"] }, + { id: "check-112-dev-runtime-dev-runtime-postflight", group: "dev-runtime", command: ["node","--check","scripts/src/dev-runtime-postflight.mjs"] }, + { id: "check-113-dev-runtime-dev-runtime-postflight-test", group: "dev-runtime", command: ["node","--check","scripts/src/dev-runtime-postflight.test.mjs"] }, + { id: "check-114-dev-runtime-dev-runtime-hotfix-audit", group: "dev-runtime", command: ["node","--check","scripts/dev-runtime-hotfix-audit.mjs"] }, + { id: "check-115-dev-runtime-dev-runtime-hotfix-audit", group: "dev-runtime", command: ["node","--check","scripts/src/dev-runtime-hotfix-audit.mjs"] }, + { id: "check-116-dev-runtime-dev-runtime-hotfix-audit-test", group: "dev-runtime", command: ["node","--check","scripts/src/dev-runtime-hotfix-audit.test.mjs"] }, + { id: "check-117-dev-runtime-dev-runtime-hotfix-audit-test", group: "dev-runtime", command: ["node","--test","scripts/src/dev-runtime-hotfix-audit.test.mjs"] }, + { id: "check-118-smoke-l2-runtime-contract-smoke", group: "smoke", command: ["node","--check","scripts/l2-runtime-contract-smoke.mjs"] }, + { id: "check-119-smoke-patch-panel-runtime-smoke", group: "smoke", command: ["node","--check","scripts/patch-panel-runtime-smoke.mjs"] }, + { id: "check-120-smoke-l6-cli-web-smoke", group: "smoke", command: ["node","--check","scripts/l6-cli-web-smoke.mjs"] }, + { id: "check-121-tools-hwlab-agent-runtime-cli", group: "tools", command: ["node","--check","skills/hwlab-agent-runtime/scripts/hwlab-agent-runtime-cli.mjs"] }, + { id: "check-122-smoke-m3-io-skill-client", group: "smoke", command: ["node","--check","skills/hwlab-agent-runtime/scripts/src/m3-io-skill-client.mjs"] }, + { id: "check-123-tools-hwlab-cli", group: "tools", command: ["node","--check","tools/hwlab-cli/bin/hwlab-cli.mjs"] }, + { id: "check-124-tools-cli", group: "tools", command: ["node","--check","tools/hwlab-cli/lib/cli.mjs"] }, + { id: "check-125-tools-cli-test", group: "tools", command: ["node","--check","tools/hwlab-cli/lib/cli.test.mjs"] }, + { id: "check-126-cloud-web-check", group: "cloud-web", cwd: "web/hwlab-cloud-web", command: ["bun","run","check"] }, + { id: "check-127-repo-run-bun", group: "repo", command: ["node","scripts/run-bun.mjs","scripts/validate-contract.mjs"] }, + { id: "check-128-dev-runtime-validate-dev-gate-report", group: "dev-runtime", command: ["node","scripts/validate-dev-gate-report.mjs"] }, + { id: "check-129-repo-report-lifecycle-test", group: "repo", command: ["node","scripts/report-lifecycle.test.mjs"] }, + { id: "check-130-smoke-validate-dev-m3-cardinality", group: "smoke", command: ["node","scripts/validate-dev-m3-cardinality.mjs"] }, + { id: "check-131-deploy-validate-artifact-catalog", group: "deploy", command: ["node","scripts/validate-artifact-catalog.mjs"] }, + { id: "check-132-deploy-run-bun", group: "deploy", command: ["node","scripts/run-bun.mjs","scripts/deploy-desired-state-plan.mjs","--check"] }, + { id: "check-133-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","scripts/dev-runtime-provisioning.mjs","--check"] }, + { id: "check-134-dev-runtime-run-bun", group: "dev-runtime", command: ["node","scripts/run-bun.mjs","scripts/dev-runtime-migration.mjs","--check"] }, + { id: "check-135-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","cmd/hwlab-cloud-api/provision.ts","--check"] }, + { id: "check-136-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","cmd/hwlab-cloud-api/migrate.ts","--check"] }, + { id: "check-137-dev-runtime-dev-runtime-postflight", group: "dev-runtime", command: ["node","scripts/dev-runtime-postflight.mjs","--check"] }, + { id: "check-138-smoke-rpt004-mvp-e2e-harness", group: "smoke", command: ["node","scripts/rpt004-mvp-e2e-harness.mjs","--check","--no-write"] }, + { id: "check-139-smoke-dev-evidence-blocker-aggregator", group: "smoke", command: ["node","scripts/dev-evidence-blocker-aggregator.mjs","--check"] }, + { id: "check-140-smoke-l2-runtime-contract-smoke", group: "smoke", command: ["node","scripts/l2-runtime-contract-smoke.mjs"] }, + { id: "check-141-smoke-l6-cli-web-smoke", group: "smoke", command: ["node","scripts/l6-cli-web-smoke.mjs"] }, + { id: "check-142-cloud-web-check", group: "cloud-web", cwd: "web/hwlab-cloud-web", command: ["bun","run","check"] }, + { id: "check-143-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","scripts/code-agent-chat-smoke.mjs"] }, + { id: "check-144-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","scripts/cloud-api-runtime-smoke.mjs"] }, + { id: "check-145-repo-bootstrap-skills-sh", group: "repo", command: ["sh","-n","scripts/bootstrap-skills.sh","scripts/worker-entrypoint.sh"] }, + { id: "check-146-cloud-api-run-bun", group: "cloud-api", command: ["node","scripts/run-bun.mjs","test","cmd/hwlab-cloud-api/runtime-options.test.ts","internal/cloud/code-agent-session-registry.test.ts","internal/cloud/json-rpc.test.ts","internal/cloud/m3-io-control.test.ts","internal/cloud/code-agent-trace-store.test.ts","internal/cloud/server-live-builds.test.ts","internal/cloud/server-health.test.ts","internal/cloud/server-agent-chat.test.ts","internal/cloud/server-m3-http.test.ts","internal/db/runtime-store.test.ts","internal/db/schema.test.ts"] } + ]) +}); + +export function listCheckTasks(profile) { + const tasks = checkProfiles[profile]; + if (!tasks) { + throw new Error(`unknown check profile: ${profile}`); + } + return tasks; +} diff --git a/scripts/src/check-runner-lib.mjs b/scripts/src/check-runner-lib.mjs new file mode 100644 index 00000000..68edd0a3 --- /dev/null +++ b/scripts/src/check-runner-lib.mjs @@ -0,0 +1,196 @@ +import { spawn } from "node:child_process"; +import { existsSync } from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import { CHECK_PLAN_VERSION, checkProfiles, listCheckTasks } from "./check-plan.mjs"; + +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); + +export async function runCheckRunner(argv, io = process) { + const options = parseCheckRunnerArgs(argv); + if (options.help) { + writeJson(io.stdout, helpPayload()); + return { exitCode: 0 }; + } + + const selected = selectTasks(options); + const payload = { + ok: true, + command: "check-runner", + version: CHECK_PLAN_VERSION, + profile: options.profile, + groups: options.groups, + ids: options.ids, + taskCount: selected.length, + tasks: selected.map(serializeTask) + }; + + if (options.list || options.dryRun) { + writeJson(io.stdout, { ...payload, mode: options.list ? "list" : "dry-run" }); + return { exitCode: 0 }; + } + + writeJson(io.stdout, { ...payload, mode: "run-start", tasks: undefined }); + const startedAt = Date.now(); + for (let index = 0; index < selected.length; index += 1) { + const task = selected[index]; + const resolved = resolveTaskCommand(task); + writeJson(io.stdout, { + ok: true, + event: "task-start", + index: index + 1, + total: selected.length, + task: serializeTask(task), + resolvedCommand: resolved.command + }); + const exitCode = await runTask(resolved); + if (exitCode !== 0) { + writeJson(io.stdout, { + ok: false, + event: "task-failed", + task: serializeTask(task), + exitCode, + elapsedMs: Date.now() - startedAt + }); + return { exitCode }; + } + } + + writeJson(io.stdout, { + ok: true, + event: "run-complete", + profile: options.profile, + taskCount: selected.length, + elapsedMs: Date.now() - startedAt + }); + return { exitCode: 0 }; +} + +export function parseCheckRunnerArgs(argv) { + const options = { profile: "check", groups: [], ids: [], list: false, dryRun: false, help: false }; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + const readValue = (name) => { + const inline = arg.match(new RegExp(`^${name}=(.+)$`, "u")); + if (inline) return inline[1]; + const value = argv[index + 1]; + if (!value || value.startsWith("--")) throw new Error(`${name} requires a value`); + index += 1; + return value; + }; + if (arg === "--help" || arg === "-h") options.help = true; + else if (arg === "--profile" || arg.startsWith("--profile=")) options.profile = readValue("--profile"); + else if (arg === "--group" || arg.startsWith("--group=")) options.groups.push(...readValue("--group").split(",").filter(Boolean)); + else if (arg === "--id" || arg.startsWith("--id=")) options.ids.push(...readValue("--id").split(",").filter(Boolean)); + else if (arg === "--list") options.list = true; + else if (arg === "--dry-run") options.dryRun = true; + else throw new Error(`unknown check-runner argument: ${arg}`); + } + if (!checkProfiles[options.profile]) throw new Error(`unknown check profile: ${options.profile}`); + return options; +} + +export function selectTasks(options) { + const groups = new Set(options.groups); + const ids = new Set(options.ids); + const profileTasks = listCheckTasks(options.profile); + const availableGroups = new Set(profileTasks.map((task) => task.group)); + const availableIds = new Set(profileTasks.map((task) => task.id)); + for (const group of groups) { + if (!availableGroups.has(group)) throw new Error(`unknown check group for profile ${options.profile}: ${group}`); + } + for (const id of ids) { + if (!availableIds.has(id)) throw new Error(`unknown check task id for profile ${options.profile}: ${id}`); + } + const selected = profileTasks.filter((task) => { + if (groups.size > 0 && !groups.has(task.group)) return false; + if (ids.size > 0 && !ids.has(task.id)) return false; + return true; + }); + if (selected.length === 0) throw new Error(`check-runner selected no tasks for profile ${options.profile}`); + return selected; +} + +export function resolveTaskCommand(task) { + const [bin, ...args] = task.command; + if (!bin) throw new Error(`task has empty command: ${task.id}`); + const cwd = task.cwd ? path.resolve(repoRoot, task.cwd) : repoRoot; + return { + task, + command: bin === "bun" ? resolveBunCommand(cwd) : bin, + args, + cwd + }; +} + +function runTask(task) { + return new Promise((resolve) => { + const child = spawn(task.command, task.args, { + cwd: task.cwd, + env: process.env, + stdio: ["ignore", "inherit", "inherit"] + }); + child.on("error", (error) => { + process.stderr.write(JSON.stringify({ ok: false, event: "task-spawn-error", task: serializeTask(task.task), error: error.message }, null, 2) + "\n"); + resolve(127); + }); + child.on("exit", (code, signal) => { + if (signal) { + process.stderr.write(JSON.stringify({ ok: false, event: "task-signal", task: serializeTask(task.task), signal }, null, 2) + "\n"); + resolve(128); + return; + } + resolve(code ?? 0); + }); + }); +} + +function resolveBunCommand(cwd) { + for (const candidate of bunCandidates(cwd)) { + if (!candidate) continue; + if (!candidate.includes(path.sep)) return candidate; + if (existsSync(candidate)) return candidate; + } + return "bun"; +} + +function bunCandidates(cwd) { + const exe = process.platform === "win32" ? "bun.exe" : "bun"; + return [ + process.env.HWLAB_BUN_COMMAND, + process.env.HWLAB_BUN_BINARY, + process.env.BUN_BINARY, + path.join(cwd, "node_modules", ".bin", exe), + path.join(repoRoot, "node_modules", ".bin", exe), + path.join(os.homedir(), ".bun", "bin", exe), + "/root/.bun/bin/bun", + "/usr/local/bin/bun", + "bun" + ].filter(Boolean); +} + +function serializeTask(task) { + return { id: task.id, group: task.group, cwd: task.cwd ?? ".", command: task.command }; +} + +function writeJson(stream, value) { + stream.write(JSON.stringify(value, null, 2) + "\n"); +} + +function helpPayload() { + return { + ok: true, + command: "check-runner", + usage: [ + "node scripts/check-runner.mjs --profile check", + "node scripts/check-runner.mjs --profile validate", + "node scripts/check-runner.mjs --profile check --group cloud-api", + "node scripts/check-runner.mjs --profile check --list", + "node scripts/check-runner.mjs --profile check --dry-run" + ], + profiles: Object.keys(checkProfiles), + groups: [...new Set(Object.values(checkProfiles).flat().map((task) => task.group))].sort() + }; +}