* fix(app): reorder settings sections for better grouping * feat(app): add setup hint and paseo.sh link on mobile welcome screen New app store users land on the welcome screen with no context. Show a brief explanation that the desktop app or server is needed, plus a link to paseo.sh — only on mobile (iOS/Android), hidden on web/desktop. * docs(release): add pre-release sanity check and clarify changelog scope Add a Codex 5.4 review step before cutting releases to catch breaking changes and backward-compatibility issues (mobile apps lag behind desktop/daemon updates). Clarify that the changelog always covers the delta from the previous stable release, not from the last RC. * feat(cli): support `paseo .` to open desktop app with project directory Similar to VS Code's `code .`, users can now type `paseo .` or `paseo <path>` to open the Paseo desktop app with that directory as the active project. - Desktop shims detect path-like first args and launch Electron in GUI mode with --open-project instead of CLI passthrough mode - Electron main process parses --open-project, sends IPC event to renderer, and forwards via second-instance for the already-running case - Renderer OpenProjectListener reuses existing openProject() RPC flow - Standalone CLI discovers the desktop app per platform and spawns it
166 lines
4.9 KiB
TypeScript
166 lines
4.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
createNodeEntrypointInvocation,
|
|
parseCliPassthroughArgsFromArgv,
|
|
type NodeEntrypointSpec,
|
|
} from "./node-entrypoint-launcher";
|
|
|
|
const CLI_ENTRYPOINT: NodeEntrypointSpec = {
|
|
entryPath: "/tmp/paseo-cli.js",
|
|
execArgv: ["--import", "tsx"],
|
|
};
|
|
|
|
describe("node-entrypoint-launcher", () => {
|
|
describe("parseCliPassthroughArgsFromArgv", () => {
|
|
it("returns null when no CLI args are provided", () => {
|
|
expect(
|
|
parseCliPassthroughArgsFromArgv({
|
|
argv: ["/Applications/Paseo.app/Contents/MacOS/Paseo"],
|
|
isDefaultApp: false,
|
|
forceCli: false,
|
|
}),
|
|
).toBeNull();
|
|
});
|
|
|
|
it("ignores macOS GUI launch arguments", () => {
|
|
expect(
|
|
parseCliPassthroughArgsFromArgv({
|
|
argv: ["/Applications/Paseo.app/Contents/MacOS/Paseo", "-psn_0_12345"],
|
|
isDefaultApp: false,
|
|
forceCli: false,
|
|
}),
|
|
).toBeNull();
|
|
});
|
|
|
|
it("ignores --no-sandbox injected by Linux wrapper", () => {
|
|
expect(
|
|
parseCliPassthroughArgsFromArgv({
|
|
argv: ["/usr/bin/Paseo", "--no-sandbox", "status"],
|
|
isDefaultApp: false,
|
|
forceCli: false,
|
|
}),
|
|
).toEqual(["status"]);
|
|
});
|
|
|
|
it("returns null when only --no-sandbox is present", () => {
|
|
expect(
|
|
parseCliPassthroughArgsFromArgv({
|
|
argv: ["/usr/bin/Paseo", "--no-sandbox"],
|
|
isDefaultApp: false,
|
|
forceCli: false,
|
|
}),
|
|
).toBeNull();
|
|
});
|
|
|
|
it("preserves CLI flags for direct app invocations", () => {
|
|
expect(
|
|
parseCliPassthroughArgsFromArgv({
|
|
argv: ["/Applications/Paseo.app/Contents/MacOS/Paseo", "--version"],
|
|
isDefaultApp: false,
|
|
forceCli: false,
|
|
}),
|
|
).toEqual(["--version"]);
|
|
});
|
|
|
|
it("passes --open-project through as a normal CLI arg", () => {
|
|
expect(
|
|
parseCliPassthroughArgsFromArgv({
|
|
argv: [
|
|
"/Applications/Paseo.app/Contents/MacOS/Paseo",
|
|
"--open-project",
|
|
"/tmp/project",
|
|
],
|
|
isDefaultApp: false,
|
|
forceCli: false,
|
|
}),
|
|
).toEqual(["--open-project", "/tmp/project"]);
|
|
});
|
|
|
|
it("forces CLI mode for shim launches even without args", () => {
|
|
expect(
|
|
parseCliPassthroughArgsFromArgv({
|
|
argv: ["/Applications/Paseo.app/Contents/MacOS/Paseo"],
|
|
isDefaultApp: false,
|
|
forceCli: true,
|
|
}),
|
|
).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("createNodeEntrypointInvocation", () => {
|
|
it("uses the packaged runner when the desktop app is packaged", () => {
|
|
expect(
|
|
createNodeEntrypointInvocation({
|
|
execPath: "/Applications/Paseo.app/Contents/MacOS/Paseo",
|
|
isPackaged: true,
|
|
packagedRunnerPath: "/Applications/Paseo.app/Contents/Resources/app.asar/dist/daemon/node-entrypoint-runner.js",
|
|
entrypoint: CLI_ENTRYPOINT,
|
|
argvMode: "bare",
|
|
args: ["ls", "--json"],
|
|
baseEnv: { PATH: "/usr/bin" },
|
|
}),
|
|
).toEqual({
|
|
command: "/Applications/Paseo.app/Contents/MacOS/Paseo",
|
|
args: [
|
|
"/Applications/Paseo.app/Contents/Resources/app.asar/dist/daemon/node-entrypoint-runner.js",
|
|
"bare",
|
|
"/tmp/paseo-cli.js",
|
|
"ls",
|
|
"--json",
|
|
],
|
|
env: {
|
|
PATH: "/usr/bin",
|
|
ELECTRON_RUN_AS_NODE: "1",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("uses the entrypoint directly in development", () => {
|
|
expect(
|
|
createNodeEntrypointInvocation({
|
|
execPath: "/opt/homebrew/bin/electron",
|
|
isPackaged: false,
|
|
packagedRunnerPath: null,
|
|
entrypoint: CLI_ENTRYPOINT,
|
|
argvMode: "bare",
|
|
args: ["ls"],
|
|
baseEnv: { PATH: "/usr/bin" },
|
|
}),
|
|
).toEqual({
|
|
command: "/opt/homebrew/bin/electron",
|
|
args: ["--import", "tsx", "/tmp/paseo-cli.js", "ls"],
|
|
env: {
|
|
PATH: "/usr/bin",
|
|
ELECTRON_RUN_AS_NODE: "1",
|
|
},
|
|
});
|
|
});
|
|
|
|
it("keeps node-style argv for packaged script entrypoints", () => {
|
|
expect(
|
|
createNodeEntrypointInvocation({
|
|
execPath: "/Applications/Paseo.app/Contents/MacOS/Paseo",
|
|
isPackaged: true,
|
|
packagedRunnerPath: "/Applications/Paseo.app/Contents/Resources/app.asar/dist/daemon/node-entrypoint-runner.js",
|
|
entrypoint: CLI_ENTRYPOINT,
|
|
argvMode: "node-script",
|
|
args: ["--dev"],
|
|
baseEnv: { PATH: "/usr/bin" },
|
|
}),
|
|
).toEqual({
|
|
command: "/Applications/Paseo.app/Contents/MacOS/Paseo",
|
|
args: [
|
|
"/Applications/Paseo.app/Contents/Resources/app.asar/dist/daemon/node-entrypoint-runner.js",
|
|
"node-script",
|
|
"/tmp/paseo-cli.js",
|
|
"--dev",
|
|
],
|
|
env: {
|
|
PATH: "/usr/bin",
|
|
ELECTRON_RUN_AS_NODE: "1",
|
|
},
|
|
});
|
|
});
|
|
});
|
|
});
|