fix(desktop): repair CLI workspace opening and Linux launcher identity - #4398
fix(desktop): repair CLI workspace opening and Linux launcher identity#4398panta82 wants to merge 1 commit into
Conversation
|
| 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]
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 } : {}) }, |
There was a problem hiding this comment.
| if (opening.current?.requestId !== request.id) { | ||
| toast.show(`Opening ${request.path}…`, { durationMs: null }); | ||
| opening.current = { | ||
| requestId: request.id, | ||
| promise: openProjectWorkspace({ client, path: request.path }), | ||
| }; | ||
| } |
There was a problem hiding this comment.
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.
| 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); | ||
| }); |
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
🟢 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-sandboxinjection, 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.
37eea5d to
9783f21
Compare
|
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 Reproduced independently on Paseo |
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
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 publishedgetpaseo-desktopas the window class and the installed launcher expectedPaseo. 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.Non-goals
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.
The packaged
resources/icon.pngchecksum 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.
npm run build:server,npm run typecheck, andnpm run formatalso 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
npm run typecheckpassesnpm run lintpassesnpm run formatpasses