Merge pull request #69 from Runfusion/codex/improve-local-startup-ux
[codex] improve local startup UX
This commit is contained in:
5
.changeset/improve-local-startup-ux.md
Normal file
5
.changeset/improve-local-startup-ux.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
Improve local dashboard startup by replacing the default full workspace prebuild with a dashboard-client prebuild, adding explicit prebuild modes, and making update notices clearer for source checkouts.
|
||||
@@ -41,8 +41,13 @@ pnpm build:all # full recursive build including desktop/mobile
|
||||
## Development Workflow
|
||||
|
||||
```bash
|
||||
pnpm dev # build + run CLI entrypoint in dev mode
|
||||
pnpm local # fast local dashboard/API startup on a safe localhost port
|
||||
pnpm local --engine # fast local startup with the AI engine enabled
|
||||
pnpm local --prebuild <none|client|full> # local dashboard/API startup with an explicit prebuild level
|
||||
pnpm dev # source-mode CLI; dashboard gets a client-only prebuild, other commands skip it
|
||||
FUSION_DEV_PREBUILD=full pnpm dev dashboard # production-like full workspace prebuild
|
||||
pnpm dev:ui # dashboard dev server only
|
||||
pnpm dev:hmr # dashboard API + Vite HMR UI, with no startup prebuild
|
||||
pnpm lint # lint all packages
|
||||
pnpm test # changed-only workspace tests (falls back to full suite in safety contexts)
|
||||
pnpm test:full # full workspace quality gate (clean-worktree compatible)
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildDevNodeArgs } from "../../../../scripts/dev-with-memory-lib.mjs";
|
||||
import {
|
||||
buildForwardedDevArgs,
|
||||
buildDevNodeArgs,
|
||||
getPrebuildCommand,
|
||||
normalizePrebuildMode,
|
||||
parseDevWrapperArgs,
|
||||
resolvePrebuildMode,
|
||||
} from "../../../../scripts/dev-with-memory-lib.mjs";
|
||||
|
||||
describe("buildDevNodeArgs", () => {
|
||||
it("enables source-condition resolution before loading the tsx runtime", () => {
|
||||
@@ -25,3 +32,63 @@ describe("buildDevNodeArgs", () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("dev-with-memory prebuild options", () => {
|
||||
it("strips wrapper-only prebuild and inspector flags before forwarding CLI args", () => {
|
||||
const parsed = parseDevWrapperArgs(
|
||||
["--inspect=9230", "--prebuild=none", "dashboard", "--port", "4050"],
|
||||
{},
|
||||
);
|
||||
|
||||
expect(parsed).toEqual({
|
||||
inspectFlags: ["--inspect=9230"],
|
||||
args: ["dashboard", "--port", "4050"],
|
||||
requestedPrebuild: "none",
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects explicit empty prebuild modes", () => {
|
||||
expect(() => normalizePrebuildMode("")).toThrow(/Invalid prebuild mode/);
|
||||
expect(() => parseDevWrapperArgs(["--prebuild=", "dashboard"], {})).toThrow(/Invalid prebuild mode/);
|
||||
});
|
||||
|
||||
it("does not inject a dev host when --host=value is already present", () => {
|
||||
expect(buildForwardedDevArgs(["dashboard", "--host=127.0.0.1"])).toEqual([
|
||||
"dashboard",
|
||||
"--host=127.0.0.1",
|
||||
]);
|
||||
});
|
||||
|
||||
it("injects a LAN-reachable dev host for dashboard startup without a host override", () => {
|
||||
expect(buildForwardedDevArgs(["dashboard", "--port", "4050"])).toEqual([
|
||||
"dashboard",
|
||||
"--port",
|
||||
"4050",
|
||||
"--host",
|
||||
"0.0.0.0",
|
||||
]);
|
||||
});
|
||||
|
||||
it("defaults dashboard startup to client-only prebuild instead of full workspace build", () => {
|
||||
expect(resolvePrebuildMode("auto", ["dashboard", "--port", "4050"])).toBe("client");
|
||||
expect(getPrebuildCommand("client")).toEqual({
|
||||
command: "pnpm",
|
||||
args: ["--filter", "@fusion/dashboard", "build:client"],
|
||||
label: "dashboard client build",
|
||||
});
|
||||
});
|
||||
|
||||
it("skips prebuild by default for non-dashboard CLI commands", () => {
|
||||
expect(resolvePrebuildMode("auto", ["task", "list"])).toBe("none");
|
||||
expect(getPrebuildCommand("none")).toBeNull();
|
||||
});
|
||||
|
||||
it("keeps full workspace prebuild available when requested", () => {
|
||||
expect(resolvePrebuildMode("full", ["dashboard"])).toBe("full");
|
||||
expect(getPrebuildCommand("full")).toEqual({
|
||||
command: "pnpm",
|
||||
args: ["build"],
|
||||
label: "workspace build",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -166,8 +166,15 @@ async function flushFrames() {
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
async function waitForFrameUpdateAfterInput() {
|
||||
// Ink can schedule the frame triggered by stdin on the next timer tick.
|
||||
await new Promise((resolve) => setTimeout(resolve, 25));
|
||||
await flushFrames();
|
||||
}
|
||||
|
||||
async function focusSettingsDetailPane(stdin: { write: (chunk: string) => void }, lastFrame: () => string | undefined) {
|
||||
stdin.write("\u001b[C");
|
||||
await waitForFrameUpdateAfterInput();
|
||||
await waitForFrameContains(lastFrame, "[C/V/X/P/L/U/K/R] remote actions");
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ function SplashScreen({ loadingStatus, updateStatus }: { loadingStatus: string;
|
||||
<Text color="cyanBright" dimColor>{FUSION_URL}</Text>
|
||||
<Text color="cyanBright" dimColor>{`v${FUSION_VERSION}`}</Text>
|
||||
{updateStatus?.updateAvailable && (
|
||||
<Text color="yellow" dimColor>{`Update available: v${updateStatus.currentVersion} → v${updateStatus.latestVersion}. Run \`npm install -g @runfusion/fusion\`.`}</Text>
|
||||
<Text color="yellow" dimColor>{`Update available: v${updateStatus.currentVersion} → v${updateStatus.latestVersion}. Run \`fn update\` for an installed CLI, or pull this source checkout.`}</Text>
|
||||
)}
|
||||
<Box height={1} />
|
||||
<Box flexDirection="row" gap={1}>
|
||||
|
||||
@@ -147,7 +147,7 @@ function formatUpdateMessage(updateStatus: StartupUpdateStatus | null): string |
|
||||
return null;
|
||||
}
|
||||
|
||||
return `⬆ Update available: v${updateStatus.latestVersion} (current: v${updateStatus.currentVersion})`;
|
||||
return `⬆ Update available: v${updateStatus.latestVersion} (current: v${updateStatus.currentVersion}). Run \`fn update\` for an installed CLI, or pull the source checkout.`;
|
||||
}
|
||||
|
||||
export class StreamedLogBuffer {
|
||||
|
||||
@@ -11,8 +11,8 @@ export function UpdateAvailableBanner({ latestVersion, currentVersion, onDismiss
|
||||
return (
|
||||
<div className="update-available-banner" role="status" aria-live="polite">
|
||||
<p className="update-available-banner__text">
|
||||
Update available: v{latestVersion} (current: v{currentVersion}). Run <code>npm i -g @runfusion/fusion</code> to
|
||||
update. {" "}
|
||||
Update available: v{latestVersion} (current: v{currentVersion}). Run <code>fn update</code> for an installed CLI,
|
||||
or pull this source checkout.{" "}
|
||||
<a
|
||||
className="update-available-banner__link"
|
||||
href="https://github.com/Runfusion/Fusion/blob/main/CHANGELOG.md"
|
||||
|
||||
@@ -10,7 +10,8 @@ describe("UpdateAvailableBanner", () => {
|
||||
);
|
||||
|
||||
expect(screen.getByText(/Update available: v0.7.0 \(current: v0.6.0\)/)).toBeInTheDocument();
|
||||
expect(screen.getByText("npm i -g @runfusion/fusion")).toBeInTheDocument();
|
||||
expect(screen.getByText("fn update")).toBeInTheDocument();
|
||||
expect(screen.getByText(/or pull this source checkout/)).toBeInTheDocument();
|
||||
expect(screen.getByRole("link", { name: "Release notes" })).toHaveAttribute(
|
||||
"href",
|
||||
"https://github.com/Runfusion/Fusion/blob/main/CHANGELOG.md",
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* live API/WebSocket backend.
|
||||
*
|
||||
* Two processes:
|
||||
* 1. API: `pnpm dev dashboard --no-auth --port <API_PORT>`
|
||||
* (handles the full build, typecheck, engine, etc.)
|
||||
* 1. API: `pnpm dev --prebuild=none dashboard --no-auth --port <API_PORT>`
|
||||
* (source-mode API/engine; Vite serves the browser UI)
|
||||
* 2. Vite: `vite dev` in packages/dashboard
|
||||
* (serves app/ with HMR; proxies /api and WS to the API)
|
||||
*
|
||||
@@ -15,7 +15,7 @@
|
||||
* code) still require restarting this script.
|
||||
*
|
||||
* Env:
|
||||
* FUSION_API_PORT API port (default 4040). Vite's proxy reads the same
|
||||
* FUSION_API_PORT API port (default 4050). Vite's proxy reads the same
|
||||
* var so both sides stay in sync.
|
||||
* FUSION_VITE_PORT Vite dev port (default 5173).
|
||||
*/
|
||||
@@ -28,7 +28,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(__dirname, "..");
|
||||
const dashboardDir = resolve(repoRoot, "packages/dashboard");
|
||||
|
||||
const API_PORT = globalThis.process.env.FUSION_API_PORT ?? "4040";
|
||||
const API_PORT = globalThis.process.env.FUSION_API_PORT ?? "4050";
|
||||
const VITE_PORT = globalThis.process.env.FUSION_VITE_PORT ?? "5173";
|
||||
|
||||
const children = [];
|
||||
@@ -88,13 +88,13 @@ globalThis.process.on("SIGTERM", () => shutdown(0));
|
||||
console.log(`[dev-hmr] starting API on :${API_PORT} + vite on :${VITE_PORT}`);
|
||||
console.log(`[dev-hmr] open http://localhost:${VITE_PORT} for HMR (not the API URL)`);
|
||||
|
||||
// API: green. Runs the existing memory-aware dev entry so the engine, build,
|
||||
// and typecheck all happen exactly as they do for `pnpm dev dashboard`.
|
||||
// API: green. Vite owns the browser UI in this mode, so skip the dashboard
|
||||
// client prebuild and run the API/engine directly from source.
|
||||
launch(
|
||||
"api",
|
||||
"32",
|
||||
"pnpm",
|
||||
["dev", "dashboard", "--no-auth", "--port", API_PORT, "--host", "127.0.0.1"],
|
||||
["dev", "--prebuild=none", "dashboard", "--no-auth", "--port", API_PORT, "--host", "127.0.0.1"],
|
||||
{ cwd: repoRoot, env: { ...globalThis.process.env, FUSION_API_PORT: API_PORT } },
|
||||
);
|
||||
|
||||
|
||||
@@ -16,3 +16,90 @@ export function buildDevNodeArgs({
|
||||
...args,
|
||||
];
|
||||
}
|
||||
|
||||
const VALID_PREBUILD_MODES = new Set(["auto", "none", "client", "full"]);
|
||||
|
||||
export function normalizePrebuildMode(value) {
|
||||
const mode = value === undefined || value === null ? "auto" : String(value).toLowerCase();
|
||||
if (mode === "" || !VALID_PREBUILD_MODES.has(mode)) {
|
||||
throw new Error(`Invalid prebuild mode "${value}". Expected one of: auto, none, client, full.`);
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
export function hasHostOverride(args) {
|
||||
return args.includes("--host") || args.some((arg) => arg.startsWith("--host="));
|
||||
}
|
||||
|
||||
export function buildForwardedDevArgs(args) {
|
||||
const needsDevHostInjection = args[0] === "dashboard" && !hasHostOverride(args);
|
||||
return needsDevHostInjection ? [...args, "--host", "0.0.0.0"] : args;
|
||||
}
|
||||
|
||||
export function parseDevWrapperArgs(rawArgs, env = process.env) {
|
||||
const inspectFlags = [];
|
||||
const args = [];
|
||||
let requestedPrebuild = env.FUSION_DEV_PREBUILD ?? "auto";
|
||||
|
||||
for (let i = 0; i < rawArgs.length; i += 1) {
|
||||
const arg = rawArgs[i];
|
||||
if (arg === "--inspect" || arg === "--inspect-brk" || arg.startsWith("--inspect=") || arg.startsWith("--inspect-brk=")) {
|
||||
inspectFlags.push(arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg === "--prebuild") {
|
||||
const value = rawArgs[i + 1];
|
||||
if (!value) {
|
||||
throw new Error("Missing value for --prebuild. Expected one of: auto, none, client, full.");
|
||||
}
|
||||
requestedPrebuild = value;
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg.startsWith("--prebuild=")) {
|
||||
requestedPrebuild = arg.slice("--prebuild=".length);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg === "--skip-build") {
|
||||
requestedPrebuild = "none";
|
||||
continue;
|
||||
}
|
||||
|
||||
args.push(arg);
|
||||
}
|
||||
|
||||
return {
|
||||
inspectFlags,
|
||||
args,
|
||||
requestedPrebuild: normalizePrebuildMode(requestedPrebuild),
|
||||
};
|
||||
}
|
||||
|
||||
export function resolvePrebuildMode(requestedPrebuild, forwardedArgs) {
|
||||
const mode = normalizePrebuildMode(requestedPrebuild);
|
||||
if (mode !== "auto") {
|
||||
return mode;
|
||||
}
|
||||
|
||||
const command = forwardedArgs[0] ?? "dashboard";
|
||||
return command === "dashboard" ? "client" : "none";
|
||||
}
|
||||
|
||||
export function getPrebuildCommand(mode) {
|
||||
switch (normalizePrebuildMode(mode)) {
|
||||
case "full":
|
||||
return { command: "pnpm", args: ["build"], label: "workspace build" };
|
||||
case "client":
|
||||
return {
|
||||
command: "pnpm",
|
||||
args: ["--filter", "@fusion/dashboard", "build:client"],
|
||||
label: "dashboard client build",
|
||||
};
|
||||
case "none":
|
||||
case "auto":
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,18 @@
|
||||
* Memory-aware development entrypoint for Fusion.
|
||||
*
|
||||
* This script increases the Node.js heap size to prevent memory pressure
|
||||
* during the initial build/start sequence, while preserving argument
|
||||
* during the optional prebuild/start sequence, while preserving argument
|
||||
* pass-through for documented invocations like `pnpm dev dashboard`.
|
||||
*
|
||||
* Cross-platform: Works on Windows, macOS, and Linux.
|
||||
*/
|
||||
import { buildDevNodeArgs } from "./dev-with-memory-lib.mjs";
|
||||
import {
|
||||
buildForwardedDevArgs,
|
||||
buildDevNodeArgs,
|
||||
getPrebuildCommand,
|
||||
parseDevWrapperArgs,
|
||||
resolvePrebuildMode,
|
||||
} from "./dev-with-memory-lib.mjs";
|
||||
|
||||
// Set increased heap size (8GB) to prevent OOM during initial build/start
|
||||
const MEMORY_MB = process.env.FUSION_DEV_MEMORY_MB || "8192";
|
||||
@@ -16,21 +22,14 @@ const MEMORY_MB = process.env.FUSION_DEV_MEMORY_MB || "8192";
|
||||
// Spawn the actual dev command with all arguments passed through
|
||||
const { spawn } = await import("child_process");
|
||||
const rawArgs = process.argv.slice(2);
|
||||
|
||||
// --inspect / --inspect-brk / --inspect=PORT enables the Node inspector.
|
||||
// Strip these from forwarded args so they don't reach the dashboard CLI
|
||||
// parser. We pass them as CLI flags directly to node (NOT via NODE_OPTIONS),
|
||||
// because NODE_OPTIONS is inherited by every grandchild process — every
|
||||
// vitest / agent / claude subprocess would then try to bind 9229 and fail.
|
||||
const inspectFlags = [];
|
||||
const args = [];
|
||||
for (const a of rawArgs) {
|
||||
if (a === "--inspect" || a === "--inspect-brk" || a.startsWith("--inspect=") || a.startsWith("--inspect-brk=")) {
|
||||
inspectFlags.push(a);
|
||||
} else {
|
||||
args.push(a);
|
||||
}
|
||||
let parsedArgs;
|
||||
try {
|
||||
parsedArgs = parseDevWrapperArgs(rawArgs);
|
||||
} catch (error) {
|
||||
console.error(error instanceof Error ? error.message : String(error));
|
||||
process.exit(1);
|
||||
}
|
||||
const { inspectFlags, args, requestedPrebuild } = parsedArgs;
|
||||
|
||||
// NODE_OPTIONS is shared with every spawned node process (build + run +
|
||||
// agents). Heap size belongs here. Inspector flags do NOT — see comment above.
|
||||
@@ -41,11 +40,9 @@ process.env.NODE_OPTIONS = nodeOptions;
|
||||
// mobile devices and other machines on the LAN for testing. Production
|
||||
// builds default to 127.0.0.1; this override only applies when starting
|
||||
// the dashboard via `pnpm dev dashboard` and only if no --host was passed.
|
||||
const needsDevHostInjection =
|
||||
args[0] === "dashboard" && !args.includes("--host");
|
||||
const forwardedArgs = needsDevHostInjection
|
||||
? [...args, "--host", "0.0.0.0"]
|
||||
: args;
|
||||
const forwardedArgs = buildForwardedDevArgs(args);
|
||||
const prebuildMode = resolvePrebuildMode(requestedPrebuild, forwardedArgs);
|
||||
const prebuildCommand = getPrebuildCommand(prebuildMode);
|
||||
|
||||
// Resolve absolute paths to tsx loader so they survive shell quoting.
|
||||
// Use Node's resolver instead of hardcoding the pnpm version-specific path.
|
||||
@@ -73,15 +70,70 @@ function runApp(extraArgs) {
|
||||
tsx.on("close", (c) => process.exit(c ?? 1));
|
||||
}
|
||||
|
||||
// If no args, run default: build + CLI
|
||||
if (forwardedArgs.length === 0) {
|
||||
const pnpm = spawn("pnpm", ["build"], { stdio: "inherit", shell: true });
|
||||
pnpm.on("close", (code) => {
|
||||
if (code !== 0) process.exit(code ?? 1);
|
||||
runApp([]);
|
||||
});
|
||||
async function warnIfSourceVersionBehind() {
|
||||
if (process.env.FUSION_SKIP_STARTUP_UPDATE_PREFLIGHT === "1") {
|
||||
return;
|
||||
}
|
||||
|
||||
let currentVersion;
|
||||
try {
|
||||
const { readFile } = await import("node:fs/promises");
|
||||
const pkg = JSON.parse(await readFile(path.resolve(process.cwd(), "packages/cli/package.json"), "utf8"));
|
||||
currentVersion = typeof pkg.version === "string" ? pkg.version : undefined;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentVersion) return;
|
||||
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 1_500);
|
||||
let payload;
|
||||
try {
|
||||
const response = await fetch("https://registry.npmjs.org/@runfusion%2Ffusion", {
|
||||
signal: controller.signal,
|
||||
});
|
||||
payload = await response.json();
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
const latestVersion = payload?.["dist-tags"]?.latest;
|
||||
if (typeof latestVersion !== "string") return;
|
||||
|
||||
const currentParts = currentVersion.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
||||
const latestParts = latestVersion.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
||||
let latestIsNewer = false;
|
||||
for (let i = 0; i < Math.max(currentParts.length, latestParts.length, 3); i += 1) {
|
||||
const latest = latestParts[i] ?? 0;
|
||||
const current = currentParts[i] ?? 0;
|
||||
if (latest > current) {
|
||||
latestIsNewer = true;
|
||||
break;
|
||||
}
|
||||
if (latest < current) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (latestIsNewer) {
|
||||
console.warn(
|
||||
`\n[fusion] This source checkout is v${currentVersion}, but npm latest is v${latestVersion}. ` +
|
||||
"If you meant to run the latest Fusion, pull/switch branches before startup.\n",
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
// Best-effort only. Startup must not depend on the registry.
|
||||
}
|
||||
}
|
||||
|
||||
await warnIfSourceVersionBehind();
|
||||
|
||||
if (!prebuildCommand) {
|
||||
runApp(forwardedArgs);
|
||||
} else {
|
||||
const build = spawn("pnpm", ["build"], { stdio: "inherit", shell: true });
|
||||
console.log(`[fusion] Running ${prebuildCommand.label} (${prebuildMode}) before source startup...`);
|
||||
const build = spawn(prebuildCommand.command, prebuildCommand.args, { stdio: "inherit", shell: true });
|
||||
build.on("close", (code) => {
|
||||
if (code !== 0) process.exit(code ?? 1);
|
||||
runApp(forwardedArgs);
|
||||
|
||||
@@ -31,6 +31,7 @@ Options:
|
||||
--host <host> Host to bind. Default: 127.0.0.1.
|
||||
--auth Keep bearer-token auth enabled on localhost.
|
||||
--no-auth Disable auth even for a non-localhost host.
|
||||
--prebuild <mode> Startup prebuild: client, none, or full. Default: client.
|
||||
--skip-install Do not auto-run pnpm install when node_modules is missing.
|
||||
--skip-register Do not auto-register this repo in Fusion's project registry.
|
||||
--allow-4040 Allow using reserved dashboard port 4040.
|
||||
@@ -63,6 +64,7 @@ function parseArgs(argv) {
|
||||
host: "127.0.0.1",
|
||||
auth: false,
|
||||
noAuth: false,
|
||||
prebuild: "client",
|
||||
skipInstall: false,
|
||||
skipRegister: false,
|
||||
allow4040: false,
|
||||
@@ -107,6 +109,14 @@ function parseArgs(argv) {
|
||||
case "--no-auth":
|
||||
opts.noAuth = true;
|
||||
break;
|
||||
case "--prebuild": {
|
||||
const value = argv[++i];
|
||||
if (!["none", "client", "full"].includes(value)) {
|
||||
fail("Invalid --prebuild value. Expected one of: none, client, full.");
|
||||
}
|
||||
opts.prebuild = value;
|
||||
break;
|
||||
}
|
||||
case "--skip-install":
|
||||
opts.skipInstall = true;
|
||||
break;
|
||||
@@ -301,12 +311,18 @@ function shouldDisableAuth(opts) {
|
||||
function printSummary(opts, port, dashboardArgs) {
|
||||
const mode = opts.engine ? "dashboard + AI engine" : "dashboard/API only";
|
||||
const auth = dashboardArgs.includes("--no-auth") ? "disabled" : "enabled";
|
||||
const prebuild = opts.prebuild === "client"
|
||||
? "dashboard client only"
|
||||
: opts.prebuild === "full"
|
||||
? "full workspace"
|
||||
: "skipped";
|
||||
console.log();
|
||||
ok(`Starting ${mode}`);
|
||||
console.log(` URL: http://${opts.host === "127.0.0.1" ? "localhost" : opts.host}:${port}`);
|
||||
console.log(` Host: ${opts.host}`);
|
||||
console.log(` Auth: ${auth}`);
|
||||
console.log(` Cmd: node scripts/dev-with-memory.mjs ${dashboardArgs.join(" ")}`);
|
||||
console.log(` Prebuild: ${prebuild}`);
|
||||
console.log(` Cmd: node scripts/dev-with-memory.mjs --prebuild=${opts.prebuild} ${dashboardArgs.join(" ")}`);
|
||||
console.log();
|
||||
}
|
||||
|
||||
@@ -346,7 +362,7 @@ async function main() {
|
||||
const child = spawn(process.execPath, ["scripts/dev-with-memory.mjs", ...dashboardArgs], {
|
||||
cwd: repoRoot,
|
||||
stdio: "inherit",
|
||||
env: process.env,
|
||||
env: { ...process.env, FUSION_DEV_PREBUILD: opts.prebuild },
|
||||
});
|
||||
|
||||
child.on("exit", (code, signal) => {
|
||||
|
||||
Reference in New Issue
Block a user