Files
wehub-resource-sync 426e9eeabd
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Waiting to run
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Waiting to run
Build Agent Image / build-and-push (push) Waiting to run
Chat shell gestures / Chat shell gesture + parity e2e (push) Waiting to run
ci / test (push) Waiting to run
ci / lint-and-format (push) Waiting to run
ci / build (push) Waiting to run
ci / dev-startup (push) Waiting to run
Cloud Gateway Discord / Test (push) Waiting to run
Cloud Gateway Webhook / Test (push) Waiting to run
Cloud Tests / lint-and-types (push) Waiting to run
Cloud Tests / unit-tests (push) Waiting to run
Cloud Tests / integration-tests (push) Waiting to run
Cloud Tests / e2e-tests (push) Blocked by required conditions
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Apps Worker (Product 2) / Determine environment (push) Waiting to run
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Blocked by required conditions
Deploy Eliza Provisioning Worker / Determine environment (push) Waiting to run
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Blocked by required conditions
Dev Smoke / Classify changed paths (push) Waiting to run
Dev Smoke / bun run dev onboarding chat (push) Blocked by required conditions
Dev Smoke / Vite HMR dependency-level smoke (push) Blocked by required conditions
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Waiting to run
gitleaks / gitleaks (push) Waiting to run
Markdown Links / Relative Markdown Links (push) Waiting to run
Publish @elizaos/example-code / check_npm (push) Waiting to run
Publish @elizaos/example-code / publish_npm (push) Blocked by required conditions
Publish @elizaos/plugin-elizacloud / verify_version (push) Waiting to run
Publish @elizaos/plugin-elizacloud / publish_npm (push) Blocked by required conditions
Quality (Extended) / Homepage Build (PR smoke) (push) Waiting to run
Quality (Extended) / Comment-only diff guard (push) Waiting to run
Quality (Extended) / Format + Type Safety Ratchet (push) Waiting to run
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Waiting to run
Quality (Extended) / Develop Gate (lint) (push) Waiting to run
Sandbox Live Smoke / Sandbox live smoke (push) Waiting to run
Snap Build & Test / Build Snap (amd64) (push) Waiting to run
Snap Build & Test / Build Snap (arm64) (push) Waiting to run
supply-chain / sbom (push) Waiting to run
supply-chain / vulnerability-scan (push) Waiting to run
Build, Push & Deploy to Phala Cloud / build-and-push (push) Waiting to run
Test Packaging / Validate Packaging Configs (push) Waiting to run
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Waiting to run
Test Packaging / Pack & Test JS Tarballs (push) Waiting to run
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Waiting to run
UI Fixture E2E / ui-fixture-e2e (push) Waiting to run
UI Fixture E2E / fixture-e2e (push) Waiting to run
UI Story Gate / story-gate (push) Waiting to run
vault-ci / test (macos-latest) (push) Waiting to run
vault-ci / test (ubuntu-latest) (push) Waiting to run
vault-ci / test (windows-latest) (push) Waiting to run
vault-ci / app-core wiring tests (push) Waiting to run
verify-patches / verify patches/CHECKSUMS.sha256 (push) Waiting to run
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Waiting to run
Voice Benchmark Smoke / voice bench smoke summary (push) Blocked by required conditions
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Waiting to run
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Waiting to run
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Waiting to run
Test Packaging / Build & Test PyPI Package (push) Waiting to run
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

300 lines
7.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Verification runner for the first-party examples workspace.
*
* It discovers example package scripts, checks documentation coverage, and can
* run typecheck, test, and build commands with a JSON report for CI.
*/
import { spawn } from "node:child_process";
import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../../..",
);
const examplesRoot = path.join(repoRoot, "packages", "examples");
const skipDirs = new Set([
".git",
".next",
".next-build",
".turbo",
"build",
"dist",
"node_modules",
]);
const validModes = new Set([
"all",
"build",
"docs",
"list",
"test",
"typecheck",
]);
function usage() {
console.log(`Usage: node packages/examples/scripts/verify-examples.mjs [options]
Options:
--mode <mode> all, list, docs, typecheck, test, or build (default: all)
--dry-run Print commands without executing them
--json <file> Write a JSON report
--timeout <ms> Per-command timeout in milliseconds (default: 900000)
--help Show this help
`);
}
function parseArgs(argv) {
const options = {
dryRun: false,
json: null,
mode: "all",
timeoutMs: 900_000,
};
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index];
if (arg === "--dry-run") {
options.dryRun = true;
} else if (arg === "--help" || arg === "-h") {
usage();
process.exit(0);
} else if (arg === "--json") {
options.json = argv[++index];
if (!options.json) throw new Error("--json requires a file path");
} else if (arg === "--mode") {
options.mode = argv[++index];
if (!validModes.has(options.mode)) {
throw new Error(`Unsupported mode "${options.mode}"`);
}
} else if (arg === "--timeout") {
options.timeoutMs = Number(argv[++index]);
if (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0) {
throw new Error("--timeout requires a positive number");
}
} else {
throw new Error(`Unknown argument "${arg}"`);
}
}
return options;
}
function walk(dir, files = []) {
for (const entry of readdirSync(dir, { withFileTypes: true })) {
if (skipDirs.has(entry.name)) continue;
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
walk(fullPath, files);
} else if (entry.name === "package.json") {
files.push(fullPath);
}
}
return files;
}
function relativeToRepo(file) {
return path.relative(repoRoot, file).split(path.sep).join("/");
}
function getPackages() {
return walk(examplesRoot)
.sort()
.map((packageFile) => {
const packageJson = JSON.parse(readFileSync(packageFile, "utf8"));
const dir = path.dirname(packageFile);
return {
dir,
name: packageJson.name ?? relativeToRepo(dir),
relativeDir: relativeToRepo(dir),
scripts: packageJson.scripts ?? {},
};
});
}
function checkDocs(packages) {
const failures = [];
const rootReadmePath = path.join(examplesRoot, "README.md");
const validationPath = path.join(examplesRoot, "VALIDATION.md");
const setupGuidePath = path.join(examplesRoot, "setup-guide.html");
for (const pkg of packages) {
if (!existsSync(path.join(pkg.dir, "README.md"))) {
failures.push({ package: pkg.relativeDir, reason: "missing README.md" });
}
}
for (const file of [rootReadmePath, validationPath, setupGuidePath]) {
if (!existsSync(file)) {
failures.push({
package: relativeToRepo(path.dirname(file)),
reason: `missing ${path.basename(file)}`,
});
}
}
if (
!existsSync(rootReadmePath) ||
!existsSync(validationPath) ||
!existsSync(setupGuidePath)
) {
return failures;
}
const rootReadme = readFileSync(rootReadmePath, "utf8");
const validation = readFileSync(validationPath, "utf8");
const setupGuide = readFileSync(setupGuidePath, "utf8");
for (const requiredLink of ["setup-guide.html", "VALIDATION.md"]) {
if (!rootReadme.includes(requiredLink)) {
failures.push({
package: "packages/examples",
reason: `README.md missing link to ${requiredLink}`,
});
}
}
for (const pkg of packages) {
const exampleName = pkg.relativeDir.replace(/^packages\/examples\//, "");
if (!validation.includes(`| \`${exampleName}\` |`)) {
failures.push({
package: pkg.relativeDir,
reason: "missing row in VALIDATION.md example matrix",
});
}
}
for (const requiredText of [
"Minecraft",
"AWS",
"GCP",
"Cloudflare",
"Convex",
"Supabase",
"Vercel",
"Social bots",
"Smartglasses",
"Wallet/trading",
]) {
if (!setupGuide.includes(requiredText)) {
failures.push({
package: "packages/examples",
reason: `setup-guide.html missing ${requiredText} setup section`,
});
}
}
return failures;
}
function runCommand(pkg, script, timeoutMs) {
return new Promise((resolve) => {
const startedAt = Date.now();
const child = spawn("bun", ["run", "--cwd", pkg.relativeDir, script], {
cwd: repoRoot,
stdio: "inherit",
});
const timer = setTimeout(() => {
child.kill("SIGTERM");
setTimeout(() => child.kill("SIGKILL"), 5_000).unref();
resolve({
durationMs: Date.now() - startedAt,
package: pkg.relativeDir,
script,
status: "timeout",
});
}, timeoutMs);
child.on("exit", (code, signal) => {
clearTimeout(timer);
resolve({
code,
durationMs: Date.now() - startedAt,
package: pkg.relativeDir,
script,
signal,
status: code === 0 ? "passed" : "failed",
});
});
});
}
async function main() {
const options = parseArgs(process.argv.slice(2));
const packages = getPackages();
const report = {
generatedAt: new Date().toISOString(),
mode: options.mode,
packages: packages.map((pkg) => ({
name: pkg.name,
path: pkg.relativeDir,
scripts: Object.keys(pkg.scripts).sort(),
})),
results: [],
};
if (options.mode === "list") {
for (const pkg of report.packages) {
console.log(`${pkg.path} ${pkg.scripts.join(",")}`);
}
}
if (options.mode === "docs" || options.mode === "all") {
const failures = checkDocs(packages);
if (failures.length === 0) {
console.log("docs passed");
report.results.push({ script: "docs", status: "passed" });
} else {
for (const failure of failures) {
console.error(`${failure.package}: ${failure.reason}`);
}
report.results.push({ failures, script: "docs", status: "failed" });
}
}
const scripts =
options.mode === "all"
? ["typecheck", "test", "build"]
: ["typecheck", "test", "build"].includes(options.mode)
? [options.mode]
: [];
for (const script of scripts) {
for (const pkg of packages) {
if (!pkg.scripts[script]) continue;
const command = `bun run --cwd ${pkg.relativeDir} ${script}`;
if (options.dryRun) {
console.log(command);
report.results.push({
command,
package: pkg.relativeDir,
script,
status: "planned",
});
continue;
}
console.log(`\n== ${script} ${pkg.relativeDir} ==`);
report.results.push(await runCommand(pkg, script, options.timeoutMs));
}
}
if (options.json) {
const outputPath = path.resolve(repoRoot, options.json);
writeFileSync(outputPath, `${JSON.stringify(report, null, 2)}\n`);
console.log(`wrote ${relativeToRepo(outputPath)}`);
}
const failed = report.results.some(
(result) => result.status === "failed" || result.status === "timeout",
);
process.exit(failed ? 1 : 0);
}
main().catch((error) => {
console.error(error instanceof Error ? error.message : error);
process.exit(1);
});