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
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
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
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
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
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

338 lines
9.6 KiB
JavaScript

#!/usr/bin/env node
/** Supports app-core build, packaging, or development orchestration for run node mjs. */
import { spawn } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import process from "node:process";
import restartExitCodeDefinition from "../../shared/src/restart-exit-code.json" with {
type: "json",
};
import { registerRestartAndShouldAbort } from "./lib/restart-guard.mjs";
import { syncElizaEnvAliases } from "./lib/sync-eliza-env-aliases.mjs";
import {
chooseElizaRuntime,
resolveRuntimeExecPath,
} from "./run-node-runtime.mjs";
const args = process.argv.slice(2);
const cwd = process.cwd();
// Load worktree-specific env overrides (ports, state dir) before building the child env.
// Generated by: bash scripts/worktree-env.sh <slot>
const _worktreeEnvPath = path.join(cwd, ".env.worktree");
if (fs.existsSync(_worktreeEnvPath)) {
try {
const content = fs.readFileSync(_worktreeEnvPath, "utf-8");
for (const line of content.split("\n")) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;
const eq = trimmed.indexOf("=");
if (eq < 1) continue;
const key = trimmed.slice(0, eq).trim();
const val = trimmed.slice(eq + 1).trim();
// override: false — don't clobber explicitly set env vars
if (!process.env[key]) {
process.env[key] = val;
}
}
} catch {
// Ignore read errors — worktree env is optional
}
}
syncElizaEnvAliases();
const env = { ...process.env };
if (!env.ELIZA_NAMESPACE) {
env.ELIZA_NAMESPACE = "eliza";
}
// WHY: The child runs dist/eliza.js, which dynamic-imports @elizaos/plugin-*. Node does not
// use cwd to resolve package names for import("pkg"); we must set NODE_PATH to repo root
// node_modules so those imports succeed. See docs/plugin-resolution-and-node-path.md.
const rootModules = path.join(cwd, "node_modules");
env.NODE_PATH = env.NODE_PATH
? `${rootModules}${path.delimiter}${env.NODE_PATH}`
: rootModules;
const compiler = "tsdown";
const distRoot = path.join(cwd, "dist");
const distEntry = path.join(distRoot, "/entry.js");
const buildStampPath = path.join(distRoot, ".buildstamp");
const srcRoot = path.join(cwd, "src");
const configFiles = [
path.join(cwd, "tsconfig.json"),
path.join(cwd, "package.json"),
];
const statMtime = (filePath) => {
try {
return fs.statSync(filePath).mtimeMs;
} catch {
return null;
}
};
const isExcludedSource = (filePath) => {
const relativePath = path.relative(srcRoot, filePath);
if (relativePath.startsWith("..")) {
return false;
}
return (
relativePath.endsWith(".test.ts") ||
relativePath.endsWith(".test.tsx") ||
relativePath.endsWith(`test-utils.ts`)
);
};
const findLatestMtime = (dirPath, shouldSkip) => {
let latest = null;
const queue = [dirPath];
while (queue.length > 0) {
const current = queue.pop();
if (!current) {
continue;
}
let entries = [];
try {
entries = fs.readdirSync(current, { withFileTypes: true });
} catch {
continue;
}
for (const entry of entries) {
const fullPath = path.join(current, entry.name);
if (entry.isDirectory()) {
queue.push(fullPath);
continue;
}
if (!entry.isFile()) {
continue;
}
if (shouldSkip?.(fullPath)) {
continue;
}
const mtime = statMtime(fullPath);
if (mtime == null) {
continue;
}
if (latest == null || mtime > latest) {
latest = mtime;
}
}
}
return latest;
};
const shouldBuild = () => {
if (env.ELIZA_FORCE_BUILD === "1") {
return true;
}
const stampMtime = statMtime(buildStampPath);
if (stampMtime == null) {
return true;
}
if (statMtime(distEntry) == null) {
return true;
}
for (const filePath of configFiles) {
const mtime = statMtime(filePath);
if (mtime != null && mtime > stampMtime) {
return true;
}
}
const srcMtime = findLatestMtime(srcRoot, isExcludedSource);
if (srcMtime != null && srcMtime > stampMtime) {
return true;
}
return false;
};
const logRunner = (message) => {
if (env.ELIZA_RUNNER_LOG === "0") {
return;
}
process.stderr.write(`[eliza] ${message}\n`);
};
/** Exit code used by the restart action to signal "restart requested". */
const RESTART_EXIT_CODE = restartExitCodeDefinition.restartExitCode;
/** Guard against infinite restart loops. */
const MAX_RESTARTS_IN_WINDOW = 5;
const RESTART_WINDOW_MS = 60_000;
const restartTimestamps = [];
const commandExists = (command) => {
const pathEnv = process.env.PATH ?? "";
if (!pathEnv) return false;
const isWindows = process.platform === "win32";
const extensions = isWindows
? (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean)
: [""];
for (const dir of pathEnv.split(path.delimiter).filter(Boolean)) {
for (const ext of extensions) {
const candidate = path.join(
dir,
isWindows && !command.toLowerCase().endsWith(ext.toLowerCase())
? `${command}${ext}`
: command,
);
if (fs.existsSync(candidate)) return true;
}
}
return false;
};
const runNode = () => {
const hasBun = commandExists("bun");
const hasNode = commandExists("node");
const { runtime, warning } = chooseElizaRuntime({
requestedRuntime: process.env.ELIZA_RUNTIME,
platform: process.platform,
bunVersion: process.versions?.bun,
hasBun,
hasNode,
});
if (warning) {
logRunner(`${warning} Set ELIZA_RUNTIME=bun to force Bun runtime.`);
}
if (runtime === "bun" && !hasBun) {
logRunner("Bun runtime was selected, but bun was not found in PATH.");
process.exit(1);
}
if (runtime === "node" && !hasNode) {
logRunner("Node.js runtime was selected, but node was not found in PATH.");
process.exit(1);
}
const execPath = resolveRuntimeExecPath({
runtime,
currentExecPath: process.execPath,
platform: process.platform,
explicitNodePath: process.env.ELIZA_NODE_PATH,
});
// Forks rename `eliza.mjs` to their own entry filename.
// Letting them override the spawned filename via `ELIZA_ENTRY_FILE` avoids
// every fork having to ship a shim at the old name. Read from `env` (the
// local snapshot built at module load) for consistency with what the child
// process actually receives — `.env.worktree` overrides applied above are
// visible here too.
const entryFile = env.ELIZA_ENTRY_FILE?.trim() || "eliza.mjs";
const nodeProcess = spawn(execPath, [entryFile, ...args], {
cwd,
env,
stdio: "inherit",
});
nodeProcess.on("error", (err) => {
logRunner(`Failed to spawn ${execPath}: ${err.message}`);
process.exit(1);
});
nodeProcess.on("exit", (exitCode, exitSignal) => {
if (exitSignal) {
process.exit(1);
}
// Restart loop: when the agent requests a restart it exits with code 75.
// Re-run the full runner (including the build-staleness check) so any
// source changes are compiled before the new process starts.
if (exitCode === RESTART_EXIT_CODE) {
// Guard against rapid restart loops (window/trim/threshold in restart-guard.mjs).
if (
registerRestartAndShouldAbort(
restartTimestamps,
Date.now(),
MAX_RESTARTS_IN_WINDOW,
RESTART_WINDOW_MS,
)
) {
logRunner(
`Restart loop detected: ${restartTimestamps.length} restarts in ${RESTART_WINDOW_MS / 1000}s — aborting.`,
);
process.exit(1);
}
logRunner("Restart requested — relaunching...");
// Re-check whether a rebuild is needed (source files may have changed).
if (shouldBuild()) {
logRunner("Building TypeScript (dist is stale).");
const bunxArgs = [compiler];
const buildCmd = process.platform === "win32" ? "cmd.exe" : "bunx";
const buildArgs =
process.platform === "win32"
? ["/d", "/s", "/c", "bunx", ...bunxArgs]
: bunxArgs;
const build = spawn(buildCmd, buildArgs, {
cwd,
env,
stdio: "inherit",
});
build.on("error", (err) => {
logRunner(`Failed to spawn ${buildCmd}: ${err.message}`);
process.exit(1);
});
build.on("exit", (code, signal) => {
if (signal || (code !== 0 && code !== null)) {
logRunner("Rebuild failed, restarting anyway.");
} else {
writeBuildStamp();
}
runNode();
});
} else {
runNode();
}
return;
}
process.exit(exitCode ?? 1);
});
};
const writeBuildStamp = () => {
try {
fs.mkdirSync(distRoot, { recursive: true });
fs.writeFileSync(buildStampPath, `${Date.now()}\n`);
} catch (error) {
// Best-effort stamp; still allow the runner to start.
logRunner(
`Failed to write build stamp: ${error?.message ?? "unknown error"}`,
);
}
};
if (!shouldBuild()) {
runNode();
} else {
logRunner("Building TypeScript (dist is stale).");
const bunxArgs = [compiler];
const buildCmd = process.platform === "win32" ? "cmd.exe" : "bunx";
const buildArgs =
process.platform === "win32"
? ["/d", "/s", "/c", "bunx", ...bunxArgs]
: bunxArgs;
const build = spawn(buildCmd, buildArgs, {
cwd,
env,
stdio: "inherit",
});
build.on("error", (err) => {
logRunner(`Failed to spawn ${buildCmd}: ${err.message}`);
process.exit(1);
});
build.on("exit", (code, signal) => {
if (signal) {
process.exit(1);
}
if (code !== 0 && code !== null) {
process.exit(code);
}
writeBuildStamp();
runNode();
});
}