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
230 lines
6.8 KiB
JavaScript
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();
|
|
}
|