feat: enhance NodeCG runtime management and packaging

- Update .gitignore and .prettierignore to exclude additional cache and configuration files.
- Revise README.md for clarity on build processes and runtime behavior.
- Improve architecture documentation to reflect changes in startup flow and module responsibilities.
- Modify troubleshooting guide to address common runtime issues and installation steps.
- Enhance ESLint configuration to ignore more directories.
- Update package.json scripts for better build and distribution processes.
- Introduce build-scoreko-bundle.mjs for building the Scoreko bundle.
- Implement prepare-nodecg-runtime.mjs for managing NodeCG runtime installation and updates.
- Add runtime-provisioner.ts to handle user-specific NodeCG runtime provisioning.
- Create tests for runtime provisioning to ensure correct behavior.
- Refactor process-manager.ts and main.ts to integrate new runtime management logic.
This commit is contained in:
2026-05-09 17:45:36 +02:00
parent b10b8adb98
commit 41e4e91c4b
16 changed files with 737 additions and 100 deletions
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env node
import { existsSync, mkdirSync, rmSync } from "node:fs";
import path from "node:path";
import { spawnSync } from "node:child_process";
const electronRoot = process.cwd();
const bundleRoot = path.resolve(electronRoot, "..");
const packageJsonPath = path.join(bundleRoot, "package.json");
const pnpmLockPath = path.join(bundleRoot, "pnpm-lock.yaml");
const nodeModulesPath = path.join(bundleRoot, "node_modules");
if (!existsSync(packageJsonPath) || !existsSync(pnpmLockPath)) {
console.error(`Scoreko bundle root was not found at: ${bundleRoot}`);
process.exit(1);
}
if (!existsSync(nodeModulesPath)) {
console.error(
[
"The Scoreko bundle dependencies are not installed.",
`Run this once from ${bundleRoot}:`,
" pnpm install",
].join("\n"),
);
process.exit(1);
}
const generatedBundleEntries = ["extension", "node_modules/.vite", "shared/dist", "dashboard", "graphics"];
const childEnv = {
...process.env,
COREPACK_HOME: process.env.COREPACK_HOME ?? path.join(electronRoot, ".corepack"),
PATH: `${path.join(bundleRoot, "node_modules", ".bin")}${path.delimiter}${process.env.PATH ?? ""}`,
};
function removeGeneratedOutput(relativePath) {
const targetPath = path.resolve(bundleRoot, relativePath);
if (!targetPath.startsWith(`${bundleRoot}${path.sep}`)) {
throw new Error(`Refusing to remove path outside the bundle root: ${targetPath}`);
}
rmSync(targetPath, { recursive: true, force: true });
}
function runCommand(command, args) {
const result = spawnSync(command, args, {
cwd: bundleRoot,
stdio: "inherit",
shell: process.platform === "win32",
env: childEnv,
});
if (result.error) {
console.error(`Could not run '${command} ${args.join(" ")}': ${result.error.message}`);
process.exit(1);
}
if (result.status !== 0) {
process.exit(result.status ?? 1);
}
}
function runLocalBin(commandName, args) {
const extension = process.platform === "win32" ? ".CMD" : "";
runCommand(path.join(bundleRoot, "node_modules", ".bin", `${commandName}${extension}`), args);
}
for (const entry of generatedBundleEntries) {
removeGeneratedOutput(entry);
}
for (const entry of ["shared/dist", "dashboard", "graphics", "extension"]) {
mkdirSync(path.join(bundleRoot, entry), { recursive: true });
}
runLocalBin("vite", ["build", "--configLoader", "runner"]);
runLocalBin("tsc", ["-b", "tsconfig.extension.json"]);