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
320 lines
10 KiB
JavaScript
320 lines
10 KiB
JavaScript
/**
|
|
* End-to-end smoke for the packaged `elizaos` CLI: packs the workspace package,
|
|
* installs it into temporary global/local locations, and exercises create /
|
|
* upgrade flows against generated projects.
|
|
*/
|
|
|
|
import { execFileSync } from "node:child_process";
|
|
import * as fs from "node:fs";
|
|
import * as os from "node:os";
|
|
import * as path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
const packageDir = path.resolve(scriptDir, "..");
|
|
const tmpBaseDir =
|
|
process.env.ELIZAOS_SMOKE_TMPDIR ||
|
|
(fs.existsSync("/tmp") ? "/tmp" : os.tmpdir());
|
|
const tmpRoot = fs.mkdtempSync(
|
|
path.join(tmpBaseDir, "elizaos-packaged-smoke-"),
|
|
);
|
|
const shouldKeepTemp = process.env.ELIZAOS_SMOKE_KEEP_TEMP === "1";
|
|
const shouldInstallGeneratedFullstack =
|
|
process.env.ELIZAOS_SMOKE_FULLSTACK_INSTALL === "1";
|
|
const shouldSmokeEject = process.env.ELIZAOS_SMOKE_EJECT === "1";
|
|
const shouldUseRemoteUpstream =
|
|
process.env.ELIZAOS_SMOKE_REMOTE_UPSTREAM === "1";
|
|
const shouldSkipGlobalInstall =
|
|
process.env.ELIZAOS_SMOKE_SKIP_GLOBAL_INSTALL === "1";
|
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
const bunCommand = process.platform === "win32" ? "bun.exe" : "bun";
|
|
const elizaosBinName = process.platform === "win32" ? "elizaos.cmd" : "elizaos";
|
|
const localUpstreamRepo = path.resolve(packageDir, "..", "..");
|
|
const cliEnv =
|
|
!shouldUseRemoteUpstream &&
|
|
fs.existsSync(
|
|
path.join(localUpstreamRepo, "packages", "app-core", "package.json"),
|
|
)
|
|
? {
|
|
...process.env,
|
|
ELIZAOS_UPSTREAM_BRANCH: process.env.ELIZAOS_UPSTREAM_BRANCH ?? "",
|
|
ELIZAOS_UPSTREAM_REPO:
|
|
process.env.ELIZAOS_UPSTREAM_REPO || localUpstreamRepo,
|
|
}
|
|
: process.env;
|
|
const fullstackInstallEnv = {
|
|
...process.env,
|
|
ELIZA_NO_VISION_DEPS: process.env.ELIZA_NO_VISION_DEPS || "1",
|
|
SKIP_AVATAR_CLONE: process.env.SKIP_AVATAR_CLONE || "1",
|
|
};
|
|
|
|
function run(command, args, options = {}) {
|
|
return execFileSync(command, args, {
|
|
cwd: options.cwd,
|
|
encoding: "utf8",
|
|
env: options.env,
|
|
stdio: ["ignore", "pipe", "pipe"],
|
|
});
|
|
}
|
|
|
|
function commandExists(command) {
|
|
try {
|
|
execFileSync(process.platform === "win32" ? "where" : "which", [command]);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function packCliPackage() {
|
|
if (commandExists(npmCommand)) {
|
|
return run(npmCommand, ["pack", packageDir, "--pack-destination", tmpRoot]);
|
|
}
|
|
|
|
if (!commandExists(bunCommand)) {
|
|
throw new Error("Neither npm nor bun is available for packaged smoke test");
|
|
}
|
|
|
|
return run(bunCommand, ["pm", "pack", "--destination", tmpRoot, "--quiet"], {
|
|
cwd: packageDir,
|
|
});
|
|
}
|
|
|
|
function installCliPackage(smokeDir, tarballPath) {
|
|
if (commandExists(npmCommand)) {
|
|
run(npmCommand, ["install", tarballPath], { cwd: smokeDir });
|
|
return;
|
|
}
|
|
|
|
run(bunCommand, ["add", tarballPath], { cwd: smokeDir });
|
|
}
|
|
|
|
function availableGlobalManagers() {
|
|
const managers = [];
|
|
if (commandExists(npmCommand)) managers.push("npm");
|
|
if (commandExists(bunCommand)) managers.push("bun");
|
|
if (managers.length === 0) {
|
|
throw new Error(
|
|
"Neither npm nor bun is available for global packaged smoke test",
|
|
);
|
|
}
|
|
return managers;
|
|
}
|
|
|
|
function installCliPackageGlobally(manager, prefixDir, tarballPath) {
|
|
if (manager === "npm") {
|
|
run(npmCommand, [
|
|
"install",
|
|
"--global",
|
|
"--prefix",
|
|
prefixDir,
|
|
"--no-audit",
|
|
"--no-fund",
|
|
tarballPath,
|
|
]);
|
|
return;
|
|
}
|
|
|
|
run(bunCommand, ["add", "--global", tarballPath], {
|
|
env: { ...process.env, BUN_INSTALL: prefixDir },
|
|
});
|
|
}
|
|
|
|
function getTarballName(output) {
|
|
const lines = output
|
|
.split(/\r?\n/)
|
|
.map((line) => line.trim())
|
|
.filter(Boolean);
|
|
const tarball = [...lines].reverse().find((line) => line.endsWith(".tgz"));
|
|
if (!tarball) {
|
|
throw new Error(
|
|
`Unable to determine tarball name from npm pack output:\n${output}`,
|
|
);
|
|
}
|
|
return tarball;
|
|
}
|
|
|
|
function getInstalledCli(smokeDir) {
|
|
return path.join(smokeDir, "node_modules", ".bin", elizaosBinName);
|
|
}
|
|
|
|
function getGloballyInstalledCli(prefixDir) {
|
|
const binPath =
|
|
process.platform === "win32"
|
|
? elizaosBinName
|
|
: path.join("bin", elizaosBinName);
|
|
return path.join(prefixDir, binPath);
|
|
}
|
|
|
|
function assertPathExists(targetPath) {
|
|
if (!fs.existsSync(targetPath)) {
|
|
throw new Error(`Expected path to exist: ${targetPath}`);
|
|
}
|
|
}
|
|
|
|
function assertPathMissing(targetPath) {
|
|
if (fs.existsSync(targetPath)) {
|
|
throw new Error(`Expected path to be absent: ${targetPath}`);
|
|
}
|
|
}
|
|
|
|
function runCli(smokeDir, cwd, args) {
|
|
return run(getInstalledCli(smokeDir), args, { cwd, env: cliEnv });
|
|
}
|
|
|
|
function availableCliRuntimes() {
|
|
// The bin's ESM imports are resolved by whatever runtime EXECUTES the bin,
|
|
// not by whatever installed it. node and bun apply the package "exports" map
|
|
// differently, so #8000 (ERR_PACKAGE_PATH_NOT_EXPORTED) can reproduce under
|
|
// one and not the other. Exercise every runtime that is on PATH.
|
|
const runtimes = [];
|
|
if (commandExists("node")) runtimes.push("node");
|
|
if (commandExists(bunCommand)) runtimes.push(bunCommand);
|
|
if (runtimes.length === 0) {
|
|
throw new Error("Neither node nor bun is available to execute the CLI");
|
|
}
|
|
return runtimes;
|
|
}
|
|
|
|
function runGlobalCli(prefixDir, cwd, args) {
|
|
// Run the installed bin under each runtime explicitly. execFileSync throws on
|
|
// a non-zero exit, so a successful return is the "exit 0" assertion.
|
|
const globalCli = getGloballyInstalledCli(prefixDir);
|
|
for (const runtime of availableCliRuntimes()) {
|
|
run(runtime, [globalCli, ...args], { cwd, env: cliEnv });
|
|
}
|
|
}
|
|
|
|
function smokeGlobalInstall(tarballPath) {
|
|
// Exercise EVERY available package manager: a global bin resolves through a
|
|
// stricter ESM path than a local install, and npm vs bun differ there. The
|
|
// ERR_PACKAGE_PATH_NOT_EXPORTED class (elizaOS/eliza#8000) only reproduces on
|
|
// global install, so testing a single manager can miss it.
|
|
for (const manager of availableGlobalManagers()) {
|
|
const prefixDir = path.join(tmpRoot, `global-${manager}`);
|
|
fs.mkdirSync(prefixDir, { recursive: true });
|
|
installCliPackageGlobally(manager, prefixDir, tarballPath);
|
|
|
|
const globalCli = getGloballyInstalledCli(prefixDir);
|
|
assertPathExists(globalCli);
|
|
// --version and --help both run the full module-init import chain (the bin
|
|
// shim's top-level imports) before commander short-circuits, so either
|
|
// would surface ERR_PACKAGE_PATH_NOT_EXPORTED. Assert both, under both
|
|
// node and bun.
|
|
runGlobalCli(prefixDir, tmpRoot, ["--version"]);
|
|
runGlobalCli(prefixDir, tmpRoot, ["--help"]);
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
let passed = false;
|
|
|
|
try {
|
|
run("bun", ["run", "build"], { cwd: packageDir });
|
|
|
|
const packOutput = packCliPackage();
|
|
const tarballName = getTarballName(packOutput);
|
|
const tarballPath = path.isAbsolute(tarballName)
|
|
? tarballName
|
|
: path.join(tmpRoot, tarballName);
|
|
|
|
if (!shouldSkipGlobalInstall) {
|
|
smokeGlobalInstall(tarballPath);
|
|
}
|
|
|
|
const smokeDir = path.join(tmpRoot, "smoke");
|
|
fs.mkdirSync(smokeDir, { recursive: true });
|
|
fs.writeFileSync(
|
|
path.join(smokeDir, "package.json"),
|
|
`${JSON.stringify({ name: "elizaos-packaged-smoke", private: true }, null, 2)}\n`,
|
|
);
|
|
installCliPackage(smokeDir, tarballPath);
|
|
|
|
runCli(smokeDir, smokeDir, ["info"]);
|
|
|
|
const workspaceDir = path.join(smokeDir, "workspace");
|
|
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
|
|
runCli(smokeDir, workspaceDir, [
|
|
"create",
|
|
"plugin-demo",
|
|
"--template",
|
|
"plugin",
|
|
"--language",
|
|
"typescript",
|
|
"--yes",
|
|
]);
|
|
const pluginDir = path.join(workspaceDir, "plugin-demo");
|
|
assertPathExists(path.join(pluginDir, "package.json"));
|
|
assertPathExists(path.join(pluginDir, ".elizaos", "template.json"));
|
|
if (shouldInstallGeneratedFullstack) {
|
|
run("bun", ["install"], { cwd: pluginDir });
|
|
run("bun", ["run", "typecheck"], { cwd: pluginDir });
|
|
run("bun", ["run", "build"], { cwd: pluginDir });
|
|
}
|
|
runCli(smokeDir, pluginDir, ["upgrade", "--check"]);
|
|
|
|
runCli(smokeDir, workspaceDir, [
|
|
"create",
|
|
"project-demo",
|
|
"--template",
|
|
"project",
|
|
"--yes",
|
|
]);
|
|
const projectDir = path.join(workspaceDir, "project-demo");
|
|
assertPathExists(path.join(projectDir, "package.json"));
|
|
assertPathExists(path.join(projectDir, ".elizaos", "template.json"));
|
|
assertPathExists(path.join(projectDir, "apps", "app", "package.json"));
|
|
assertPathMissing(path.join(projectDir, "eliza"));
|
|
const packageModeOutput = run(
|
|
"node",
|
|
["scripts/eliza-source-mode.mjs", "packages"],
|
|
{ cwd: projectDir },
|
|
);
|
|
if (!packageModeOutput.includes("beta")) {
|
|
throw new Error(
|
|
`Expected generated package mode to default to beta. Output:\n${packageModeOutput}`,
|
|
);
|
|
}
|
|
if (shouldInstallGeneratedFullstack) {
|
|
run("bun", ["install"], { cwd: projectDir, env: fullstackInstallEnv });
|
|
run("bun", ["run", "typecheck"], {
|
|
cwd: projectDir,
|
|
env: fullstackInstallEnv,
|
|
});
|
|
run("bun", ["run", "build"], {
|
|
cwd: projectDir,
|
|
env: fullstackInstallEnv,
|
|
});
|
|
}
|
|
runCli(smokeDir, projectDir, ["upgrade", "--check"]);
|
|
|
|
if (shouldSmokeEject) {
|
|
const currentBranch = run("git", ["branch", "--show-current"], {
|
|
cwd: localUpstreamRepo,
|
|
}).trim();
|
|
run("node", ["scripts/eliza-source-mode.mjs", "local"], {
|
|
cwd: projectDir,
|
|
env: {
|
|
...fullstackInstallEnv,
|
|
ELIZA_BRANCH: currentBranch || "develop",
|
|
ELIZA_GIT_URL: localUpstreamRepo,
|
|
},
|
|
});
|
|
assertPathExists(path.join(projectDir, "eliza", "package.json"));
|
|
assertPathExists(path.join(projectDir, ".elizaos", "source-mode"));
|
|
}
|
|
|
|
passed = true;
|
|
console.log("elizaos packaged smoke test passed");
|
|
} finally {
|
|
if (!shouldKeepTemp && passed) {
|
|
fs.rmSync(tmpRoot, { force: true, recursive: true });
|
|
} else if (!passed || shouldKeepTemp) {
|
|
console.log(`elizaos packaged smoke temp dir: ${tmpRoot}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
main();
|