Skip to content

fix(desktop): repair CLI workspace opening and Linux launcher identity - #4398

Open
panta82 wants to merge 1 commit into
getpaseo:mainfrom
talentkit:contrib/desktop-cli-open-project
Open

fix(desktop): repair CLI workspace opening and Linux launcher identity#4398
panta82 wants to merge 1 commit into
getpaseo:mainfrom
talentkit:contrib/desktop-cli-open-project

Conversation

@panta82

@panta82 panta82 commented Sep 6, 2026

Copy link
Copy Markdown

Running paseo . from a local folder silently failed to open a workspace in my Linux Desktop installation. Linux windows also appeared under a generic taskbar icon after startup. This is the isolated fix from our fork. The implementation and QA notes below were prepared with a coding agent.

Linked issue

Reported during local use; no GitHub issue filed.

Type of change

  • Bug fix

Reasoning

The CLI launched the Linux AppImage without the sandbox switch used by the installed desktop launcher. Electron exited before its main process could handle the folder argument, and discarded stderr hid the failure.

After fixing the launch, Desktop could still consume and lose the pending folder request during appearance hydration. The existing handler also only registered the project. This change keeps the request alive through startup, waits for the selected host and its advertised capabilities, then opens an existing workspace for that directory or creates and selects one.

The Linux package also omitted resources/icon.png, while Electron published getpaseo-desktop as the window class and the installed launcher expected Paseo. Include the runtime icon and set the desktop identity before startup, preserving an explicitly supplied --class.

Goals

  • paseo . opens a workspace for a newly selected local directory.
  • Reopening the same directory reuses its workspace.
  • Startup hydration and host connection changes preserve the pending request.
  • Launch errors reach the terminal; project/workspace failures appear in Desktop.
  • Packaged Linux windows show the Paseo icon and match their application launcher.

Non-goals

  • Changing the Add Project dialog or daemon lifecycle.
  • Changing sandbox flags for native Linux packages, macOS, or Windows.
  • Changing the wire protocol or adding fallback RPCs for older hosts.

QA

Before the fix, the installed AppImage exited with a SUID sandbox helper error. After the CLI correction, tracing the renderer showed the pending folder read being consumed during startup remounts. The regression test then failed until the listener survived that remount and waited for host capabilities.

Manual Linux verification used two newly created temporary directories, one empty non-Git folder with a space in its name and one Git repository. Neither was registered beforehand. Each launch created one project and one workspace; a repeated Git-directory launch reused the same workspace ID. The empty folder was visually confirmed open in Desktop. Temporary projects were removed through the CLI afterward. This installed-AppImage check ran before rebasing; the automated checks below ran again on this isolated contribution against upstream 38c22139b.

The final Linux AppImage was also rebuilt and installed from the rebased fork with the same icon and identity changes included here. Launching it through the registered desktop entry produced the expected window class and an icon. The app remained running after startup, with no daemon restart.

Before, observed with xprop:
WM_CLASS(STRING) = "getpaseo-desktop", "getpaseo-desktop"
_NET_WM_ICON:  not found.

After, observed with xprop:
WM_CLASS(STRING) = "paseo", "Paseo"
_NET_WM_ICON(CARDINAL) =

The packaged resources/icon.png checksum matched the source asset, and the installed AppImage checksum matched the build artifact. Formatting, typecheck, and lint passed after these changes.

The new desktop tests use a real isolated daemon and browser renderer with the desktop bridge fixture. They exercise a consumed cold-start path, exact workspace URL selection, repeated launch without duplicates, and a missing-directory error. They do not launch a packaged Electron binary.

$ npx vitest run packages/cli/src/commands/open.test.ts --bail=1
 Test Files  1 passed (1)
      Tests  6 passed (6)
   Duration  3.53s (transform 2.10s, setup 0ms, import 3.41s, tests 4ms, environment 0ms)

$ npx playwright test --config packages/desktop/playwright.config.ts packages/desktop/e2e/project-picker.spec.ts --grep 'CLI project launch'
  ✓  1 [desktop] › packages/desktop/e2e/project-picker.spec.ts:14:5 › CLI project launch opens a workspace after cold startup (10.7s)
  ✓  2 [desktop] › packages/desktop/e2e/project-picker.spec.ts:46:5 › CLI project launch reports a missing folder (4.5s)
  2 passed (1.4m)

$ npm run lint
Found 0 warnings and 0 errors.

npm run build:server, npm run typecheck, and npm run format also completed with exit code 0.

Platform coverage: Linux AppImage workspace opening manually before rebase; packaged Linux icon and launcher identity after rebase; Linux desktop renderer on this contribution. macOS and Windows launch argument construction is unit-tested; those platforms and iOS/Android were not run.

Checklist

  • One focused change
  • npm run typecheck passes
  • npm run lint passes
  • npm run format passes
  • QA evidence
  • Tests added or updated where it made sense

Copilot AI lite review requested due to automatic review settings September 6, 2026 13:49
@greptile-apps

greptile-apps Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes project paths passed through the desktop CLI open or reuse workspaces and improves Linux desktop launch behavior.

  • Adds AppImage-specific launch arguments and propagates launch errors to the terminal.
  • Preserves consumed project-open requests through renderer startup and waits for host capabilities before opening a workspace.
  • Adds workspace creation/reuse behavior and desktop E2E coverage.
  • Adds the packaged Linux window icon and aligns the Linux desktop identity.

Confidence Score: 3/5

The PR does not appear safe to merge because two previously reported workspace-opening defects remain unresolved, and the E2E tests still violate an explicit repository requirement.

Equivalent paths can still create duplicate workspaces because reuse compares workspaceDirectory with the raw requested path. A host reconnect can still leave opening.current holding the rejected promise for the same request ID, preventing a retry with the replacement client. The CLI-launch E2E scenarios also still expose renderer setup, URL construction, locators, reload behavior, and daemon assertions directly in long test bodies rather than domain helpers.

Files Needing Attention: packages/app/src/desktop/open-project-workspace.ts, packages/app/src/app/_layout.tsx, packages/desktop/e2e/project-picker.spec.ts

Important Files Changed

Filename Overview
packages/app/src/app/_layout.tsx Moves the CLI project listener above the hydration boundary and coordinates host readiness, workspace opening, navigation, and notifications; the prior reconnect finding remains outstanding.
packages/app/src/desktop/open-project-workspace.ts Registers a project and reuses or creates its workspace; the prior equivalent-path duplicate finding remains outstanding.
packages/cli/src/commands/open.ts Resolves platform-specific desktop launch arguments and reports process-spawn failures.
packages/desktop/e2e/project-picker.spec.ts Covers cold-start opening, reuse, and missing-directory behavior, but the existing rule violation concerning mechanical E2E bodies remains outstanding.
packages/desktop/e2e/support/runtime.ts Extends the desktop fixture with consumable pending-project-path behavior.
packages/desktop/electron-builder.yml Packages the existing PNG icon as a Linux runtime resource.
packages/desktop/src/main.ts Sets the Linux desktop entry identity before creating application windows.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[paseo project-path] --> B[Resolve desktop launch]
    B --> C[Electron receives path]
    C --> D[Preserve pending request through startup]
    D --> E[Choose and connect host]
    E --> F[Verify workspace capabilities]
    F --> G[Register project]
    G --> H{Existing workspace?}
    H -->|Yes| I[Select existing workspace]
    H -->|No| J[Create workspace]
    J --> I
    I --> K[Navigate and show result]
Loading

Reviews (2): Last reviewed commit: "fix(desktop): repair CLI workspace openi..." | Re-trigger Greptile

do {
const page = await input.client.fetchWorkspaces({
filter: { projectId },
page: { limit: 200, ...(cursor ? { cursor } : {}) },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Equivalent Paths Create Duplicates

Opening a directory through a symlink and later through its real path resolves to the same project, but this exact string comparison misses the existing workspace. The second launch therefore creates a duplicate workspace instead of reusing the original one.

Comment on lines +818 to +824
if (opening.current?.requestId !== request.id) {
toast.show(`Opening ${request.path}…`, { durationMs: null });
opening.current = {
requestId: request.id,
promise: openProjectWorkspace({ client, path: request.path }),
};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Reconnect Drops Pending Launch

If the host reconnects while the workspace is opening, the old client rejects its pending requests and HostRuntime supplies a new client. Because the request ID has not changed, this code reuses the rejected promise instead of starting the operation with the new client, so it displays an error and clears the launch request even though the host is connected again.

Comment on lines +14 to +44
test("CLI project launch opens a workspace after cold startup", async ({
page,
projectPickerFixture,
e2eWorkerClient,
}) => {
await installDesktopRuntime(page, {
serverId: getServerId(),
pendingOpenProjectPath: projectPickerFixture.projectPath,
});
await gotoAppShell(page);
await expect(page).toHaveURL(/\/workspace\//u, { timeout: 30_000 });
const workspaces = (await e2eWorkerClient.fetchWorkspaces()).entries.filter(
(workspace) => workspace.workspaceDirectory === projectPickerFixture.projectPath,
);
expect(workspaces).toHaveLength(1);
const workspace = workspaces[0];
projectPickerFixture.rememberProjectId(workspace.projectId);
const workspaceUrl = new RegExp(`/workspace/${workspace.id}(?:[/?#]|$)`, "u");
await expect(page).toHaveURL(workspaceUrl);
const row = page.getByTestId(`sidebar-workspace-row-${getServerId()}:${workspace.id}`);
await expect(row).toBeVisible();

// Reload models a second window receiving the same CLI path.
await page.reload();
await expect(page).toHaveURL(workspaceUrl, { timeout: 30_000 });
await expect(page.getByText(`Opened ${workspace.name}`, { exact: true })).toBeVisible();
await expect(row).toBeVisible();
expect(
(await e2eWorkerClient.fetchWorkspaces({ filter: { projectId: workspace.projectId } })).entries,
).toHaveLength(1);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 E2E Test Exposes Mechanics

This test embeds renderer setup, URL construction, locators, reload steps, daemon queries, and assertions directly in a 31-line body; the failure case at lines 46–56 follows the same pattern. The repository requires E2E bodies to stay roughly 3–8 lines of user-level intent and move mechanical interaction into domain helpers, so this requirement must be satisfied before merging.

Rule Used: # Code Review Pattern Reference: Slop, Tests, Feat... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes directly address the reported failure mode, add targeted unit/E2E coverage for the new behavior, and I did not find any correctness or compatibility issues in the updated launch/open flow.

Pull request overview

Fixes a Linux desktop CLI launch edge case where paseo . could fail to open a workspace by (1) aligning AppImage launch args with the installed desktop launcher so Electron can start reliably, and (2) ensuring the Desktop app preserves and fulfills the pending “open project path” request through startup/hydration by opening (or reusing) a workspace for that directory.

Changes:

  • CLI: factor desktop launch resolution, add Linux AppImage --no-sandbox injection, and surface Electron stderr to the terminal; add unit tests for platform-specific launch args.
  • Desktop app: keep the pending open-project request alive across appearance hydration, wait for host capabilities/connection, then open (or create) and navigate to the matching workspace with user-facing toasts on success/failure.
  • Desktop E2E: extend the runtime bridge to supply a pending CLI path and add Playwright coverage for cold start, reuse (no duplicates), and missing-folder errors.
File summaries
File Description
packages/desktop/e2e/support/runtime.ts Adds a consumable pendingOpenProjectPath to the mocked desktop bridge for E2E scenarios.
packages/desktop/e2e/project-picker.spec.ts Adds E2E coverage for CLI-driven project launch opening/reusing a workspace and reporting missing paths.
packages/cli/src/commands/open.ts Fixes desktop launching across platforms (notably Linux AppImage) and ensures stderr is visible; refactors launch resolution for testability.
packages/cli/src/commands/open.test.ts Adds unit tests verifying platform-specific launch command/args (Linux AppImage vs native package, macOS open, Windows).
packages/app/src/desktop/open-project-workspace.ts Introduces helper to add a project, reuse an existing non-archiving workspace for the directory, or create one.
packages/app/src/app/_layout.tsx Moves/rewrites the open-project listener to survive hydration remounts, gate on host capabilities, open/reuse workspaces, and navigate + toast outcomes.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@panta82
panta82 force-pushed the contrib/desktop-cli-open-project branch from 37eea5d to 9783f21 Compare September 6, 2026 15:35
@panta82 panta82 changed the title fix(desktop): open CLI project paths as workspaces fix(desktop): repair CLI workspace opening and Linux launcher identity Sep 6, 2026
@NOirBRight

Copy link
Copy Markdown

Opened #4504 as a tracker for the Linux launcher-identity half of this PR (GNOME/Wayland dock showing the generic gear because Electron 44 publishes getpaseo-desktop while the packaged desktop file is Paseo.desktop / StartupWMClass=Paseo).

Reproduced independently on Paseo 0.8.0-beta.1 (Electron 44.2.0) / Ubuntu 26.04 GNOME 50.1 Wayland. Running process has CHROME_DESKTOP=getpaseo-desktop.desktop even when launched from /usr/share/applications/Paseo.desktop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants