Merge remote-tracking branch 'upstream/main'

This commit is contained in:
semih
2026-05-11 18:53:23 +00:00
186 changed files with 10859 additions and 5543 deletions

View File

@@ -41,7 +41,7 @@ describe("CLI bundle output", () => {
expect(content).not.toContain('"@fusion/core"');
expect(content).not.toContain('"@fusion/dashboard"');
expect(content).not.toContain('"@fusion/engine"');
expect(content).not.toContain('"@fusion-plugin-examples/roadmap"');
expect(content).not.toContain('"@fusion-plugin-examples/fusion-plugin-roadmap"');
});
it("does not contain runtime memory-backend side-load imports", () => {

View File

@@ -178,8 +178,38 @@ describe("PR checks workflow (.github/workflows/pr-checks.yml)", () => {
expect(content).not.toContain("run: pnpm test\n");
});
it("keeps lint as install + lint only, without Bun/setup build coupling", () => {
const lintSteps = workflow.jobs?.lint?.steps ?? [];
expect(
lintSteps.some(
(step: any) =>
step.name === "Install dependencies" &&
typeof step.run === "string" &&
step.run.includes("pnpm install --frozen-lockfile"),
),
).toBe(true);
expect(
lintSteps.some((step: any) => step.name === "Lint" && typeof step.run === "string" && step.run.includes("pnpm lint")),
).toBe(true);
expect(
lintSteps.some(
(step: any) =>
step.name === "Install Bun" ||
(typeof step.uses === "string" && step.uses.includes("oven-sh/setup-bun")) ||
(typeof step.run === "string" && step.run.includes("pnpm build")),
),
).toBe(false);
});
it("keeps build coverage as an explicit PR gate", () => {
const buildSteps = workflow.jobs?.build?.steps ?? [];
expect(
buildSteps.some(
(step: any) =>
step.name === "Install Bun" ||
(typeof step.uses === "string" && step.uses.includes("oven-sh/setup-bun")),
),
).toBe(true);
expect(
buildSteps.some(
(step: any) => step.name === "Build" && typeof step.run === "string" && step.run.includes("pnpm build"),

View File

@@ -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",
});
});
});

View File

@@ -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");
}

View File

@@ -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}>

View File

@@ -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 {