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

230 lines
6.8 KiB
JavaScript

#!/usr/bin/env node
/**
* Command-line helper for the Plugin Build app packaging, mobile, or
* Playwright automation lane.
*/
import { spawn } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import process from "node:process";
import { fileURLToPath } from "node:url";
import {
CAPACITOR_PLUGIN_NAMES,
NATIVE_PLUGINS_ROOT,
} from "./capacitor-plugin-names.mjs";
const scriptFile = fileURLToPath(import.meta.url);
const __dirname = path.dirname(scriptFile);
const verbosePluginBuild = process.env.ELIZA_VERBOSE_PLUGIN_BUILD === "1";
const WORKSPACE_RUNTIME_PACKAGES = new Map([
[
"@elizaos/core",
path.resolve(NATIVE_PLUGINS_ROOT, "..", "packages", "core"),
],
]);
// Only these values in a plugin's `platforms` array are treated as build-host
// gates. Anything else (e.g. "node", "browser") is a runtime hint and does
// not block building on the current host.
export const OS_PLATFORMS = new Set(["darwin", "linux", "win32"]);
/**
* Decide whether a plugin should be built on the current host, based on the
* `eliza.platforms` / `elizaos.platforms` allowlist in its package.json, or
* by detecting Capacitor mobile plugins via their peer dependency.
*
* Rules (in order):
* 1. Explicit `platforms` pure-OS allowlist → build only when host is listed.
* 2. `platforms` mixing runtime hints (e.g. "node", "browser") → build everywhere.
* 3. No `platforms` but `@capacitor/core` peer dep → mobile-only, skip on desktop.
* 4. No signal → build everywhere.
*
* @param {unknown} pkg — parsed package.json (or undefined)
* @param {string} hostPlatform — the current `process.platform` value
* @returns {boolean}
*/
export function shouldBuildPluginForHost(pkg, hostPlatform) {
const platforms =
(pkg && typeof pkg === "object" && pkg.eliza?.platforms) ??
(pkg && typeof pkg === "object" && pkg.elizaos?.platforms);
if (Array.isArray(platforms) && platforms.length > 0) {
const isPureOsAllowlist = platforms.every((p) => OS_PLATFORMS.has(p));
if (!isPureOsAllowlist) {
return true;
}
return platforms.includes(hostPlatform);
}
// No explicit metadata — @capacitor/core peer dep is a reliable mobile-only
// signal (every proper Capacitor plugin lists it). Skip on all desktop hosts.
const peerDeps =
(pkg && typeof pkg === "object" && pkg.peerDependencies) ?? {};
if ("@capacitor/core" in peerDeps) {
return false;
}
return true;
}
const NATIVE_PLUGIN_DIR_PREFIX = "plugin-native-";
function pluginDirFor(pluginsDir, name) {
return path.join(pluginsDir, `${NATIVE_PLUGIN_DIR_PREFIX}${name}`);
}
function readPluginPackageJson(pluginsDir, name) {
const pkgPath = path.join(pluginDirFor(pluginsDir, name), "package.json");
const raw = fs.readFileSync(pkgPath, "utf8");
try {
return JSON.parse(raw);
} catch (error) {
throw new Error(
`[plugins] ${pkgPath} is not valid JSON: ${
error instanceof Error ? error.message : String(error)
}`,
);
}
}
function hasBuildScript(pkg) {
return (
pkg &&
typeof pkg === "object" &&
pkg.scripts &&
typeof pkg.scripts === "object" &&
typeof pkg.scripts.build === "string"
);
}
function run(command, args, cwd) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
cwd,
stdio: "inherit",
env: process.env,
});
child.on("error", (error) => {
reject(new Error(`${command} failed to start: ${error.message}`));
});
child.on("exit", (code, signal) => {
if (signal) {
reject(new Error(`${command} exited due to signal ${signal}`));
return;
}
if ((code ?? 1) !== 0) {
reject(new Error(`${command} exited with code ${code ?? 1}`));
return;
}
resolve();
});
});
}
function logVerbose(message) {
if (verbosePluginBuild) {
console.log(message);
}
}
function hasPackageDependency(pkg, packageName) {
if (!pkg || typeof pkg !== "object") return false;
for (const field of [
"dependencies",
"devDependencies",
"peerDependencies",
"optionalDependencies",
]) {
const deps = pkg[field];
if (deps && typeof deps === "object" && packageName in deps) {
return true;
}
}
return false;
}
async function buildWorkspaceRuntimePackagesForPlugins(pluginEntries) {
if (process.env.ELIZA_DEV_SOURCE === "1") {
logVerbose(
"[plugins] skipping workspace runtime package builds (ELIZA_DEV_SOURCE=1)",
);
return;
}
const requiredPackages = new Set();
for (const { pkg } of pluginEntries) {
for (const packageName of WORKSPACE_RUNTIME_PACKAGES.keys()) {
if (hasPackageDependency(pkg, packageName)) {
requiredPackages.add(packageName);
}
}
}
for (const packageName of requiredPackages) {
const packageDir = WORKSPACE_RUNTIME_PACKAGES.get(packageName);
const packageJsonPath = path.join(packageDir, "package.json");
if (!fs.existsSync(packageJsonPath)) {
throw new Error(
`[plugins] ${packageName} dependency is required but ${packageJsonPath} does not exist`,
);
}
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
if (!pkg?.scripts?.build) {
throw new Error(
`[plugins] ${packageName} dependency is required but has no build script`,
);
}
console.log(`[plugins] building workspace dependency ${packageName}`);
await run("bun", ["run", "build"], packageDir);
}
}
async function main() {
const pluginsDir = NATIVE_PLUGINS_ROOT;
const pluginNames = CAPACITOR_PLUGIN_NAMES;
const skipPlugins =
process.env.SKIP_NATIVE_PLUGINS === "1" || process.env.CI === "true";
if (skipPlugins) {
console.log(
"[plugins] skipping native plugin builds (CI or explicitly disabled)",
);
return;
}
const buildablePlugins = pluginNames
.map((name) => ({ name, pkg: readPluginPackageJson(pluginsDir, name) }))
.filter(({ name, pkg }) => {
if (!hasBuildScript(pkg)) {
logVerbose(`[plugin:${name}] skipping — no build script`);
return false;
}
if (shouldBuildPluginForHost(pkg, process.platform)) {
return true;
}
const platforms = pkg?.eliza?.platforms ?? pkg?.elizaos?.platforms;
logVerbose(
`[plugin:${name}] skipping — declares platforms=${JSON.stringify(
platforms,
)}, host is ${process.platform}`,
);
return false;
});
await buildWorkspaceRuntimePackagesForPlugins(buildablePlugins);
await Promise.all(
buildablePlugins.map(async ({ name }) => {
logVerbose(`[plugin:${name}] building...`);
await run("bun", ["run", "build"], pluginDirFor(pluginsDir, name));
logVerbose(`[plugin:${name}] done`);
}),
);
}
const isDirectRun =
process.argv[1] && path.resolve(process.argv[1]) === path.resolve(scriptFile);
if (isDirectRun) {
await main();
}