Skip to content

fix(projects): create on a server's SSH project; Add Project SSH lists the server's targets - #27331

Merged
OrcaWin merged 4 commits into
mainfrom
OrcaWin/d2q1-v4b-server-ssh-projects
Oct 11, 2026
Merged

OrcaWin merged 4 commits into
mainfrom
OrcaWin/d2q1-v4b-server-ssh-projects

Conversation

@OrcaWin

@OrcaWin OrcaWin commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator
Files Added Deleted Net
Test 6 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​453 $\color{#cf222e}{\Huge{\mathbf{−}}}$​5 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​448
Prod 31 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​672 $\color{#cf222e}{\Huge{\mathbf{−}}}$​161 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​511

ELI5

If your Orca server keeps its own SSH hosts, a computer paired with that server could see projects on those hosts but could not use them. It could not start a new workspace in such a project, and it could not add a new project on one of those hosts. Now it can do both, and the server does the work.

What Changed

1. Creating a workspace in a project on the server's SSH host (#25887)

  • Before: the sidebar + and the New Workspace composer always said "Reconnect SSH target before creating workspaces", and nothing cleared it. Their gate looked the server's SSH target up in this client's SSH map, which never contains it. The composer's Connect button was worse: it asked this client to dial the server's target id.
  • After:
    • Both gates read the status that server reports for its own target.
    • Connect asks the server to connect.
    • When this client cannot verify the target, the server decides and nothing is blocked here. That happens when the server is unreachable or its SSH list hasn't loaded yet; it avoids a dead "Reconnect" button.
    • Your own SSH projects behave exactly as before.

2. Add Project on the server's SSH hosts (#8489, UI half)

  • Before: with a paired server selected, Add Project offered no SSH option at all. Every SSH step (target list, connect, browse, add, Add SSH host) went to this client's own IPC.
  • After: with a server selected, Add Project shows Project on this server's SSH host. It lists the server's hosts and connects them on the server. Add SSH host saves a new host on the server and never touches this client's list. Browsing and adding the project happen on the server, and a non-Git folder goes through the usual confirm dialog, still on the server.
  • Old servers: a server without ssh.target-management.v1 shows the option disabled with "Update this server to add projects on its SSH hosts". There is never a local fallback.

Mechanism

  • One renderer helper, lib/repo-ssh-connection.ts, answers "which machine owns this repo's SSH target". It returns (environmentId, targetId) for a server's target and (null, targetId) for this client's. The sidebar header, the composer gate and the composer Connect button all use it. It also reads status with the existing selectRuntimeAwareSshStatus.
  • The Add Project hook useRemoteRepo takes the selected server. When one is set, it routes list, connect, browse and add through the server RPCs from feat(ssh): a paired client can manage the server's own SSH hosts (ssh.target-management.v1) #27329. The folder browser routes a (server, target) pair the same way.
  • The Add SSH host form panel is reused as-is. It gains a server title and hides "Fill from ~/.ssh/config", because this client's config says nothing about the server's.
  • The capability probe reuses the existing host-capability hook.

Why

The execution host owns everything about its SSH targets (docs/reference/ssh-execution-boundary.md). Reading or dialing a server's target from the client was the root cause of both issues. Routing through the server keeps one source of truth.

The alternative was to keep adding special cases to each gate. One helper fixes every reader at once.

A server whose capability is unknown or missing gets a disabled option with a reason, never a silent local action (docs/reference/remote-wire-compatibility.md).

Linked Issue

Fixes #25887
Fixes #8489

Builds on #27329 (server RPCs, merged first). Tests and ideas adapted from the community PR #8492 by @jae-heo, credited in the tests.

Visual Proof

Not captured: this run had no local Electron (agent constraint). The new UI reuses existing pieces:

  • the Add Project secondary-action row, with the same Monitor icon as "Project on SSH host";
  • the existing remote step, with a muted "has no SSH hosts yet" line and an outline Add SSH host button;
  • the existing Add SSH host form, titled "Add SSH host to ".

Strings are translated in all six locales.

Testing

  • pnpm tc, pnpm lint (owner-routing ratchet 0, runtime-Electron ratchet 0), pnpm run check:code-quality:changed

  • New tests:

    • hooks/composer-state/server-ssh-repo-connect.test.ts fails on main: Connect for a server-owned repo called window.api.ssh.connect. It now asks the server, and local repos are unchanged.
    • lib/repo-ssh-connection.test.ts covers the [Bug]: Remote client can't create workspaces on a server-owned SSH project #25887 gate:
      • server reports connected → create allowed;
      • server reports disconnected → reconnect;
      • unverifiable (server unreachable or not hydrated) → not blocked;
      • local unchanged.
    • AddRepoSteps.default-checkout.test.ts, adapted from fix(ssh): enable server-owned SSH projects in paired clients #8492:
      • the server's hosts are listed, never local ones;
      • a server that can't list them shows why, with no fallback;
      • add goes through the server and refreshes as server-owned;
      • a non-git folder reaches the confirm dialog bound to the server;
      • connect goes through the server.
    • use-remote-file-browser-listing.test.ts: a (server, target) pair is browsed by the server.
    • AddRepoStartSteps.test.tsx: the server option is enabled only when supported, otherwise disabled with the update reason.
  • Focused suites: components/sidebar, hooks, lib, runtime, components/new-workspace, components/settings, i18n, store (2138 files pass).

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

Review

P0/P1 review by two independent reviewers; see comments.

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • SSH: a server's target is never dialed, browsed or registered by the client. An unverifiable state stays unverifiable and is never read as disconnected.
  • Folder workspaces: the non-git confirm path is covered.
  • Not in scope: a nested-repo scan on a server's SSH host. The server's scan cannot reach its SSH targets yet, so the flow adds the selected folder directly.
  • Mobile: unchanged.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

@OrcaWin
OrcaWin requested a review from brennanb2025 as a code owner October 10, 2026 23:14
@OrcaWin
OrcaWin force-pushed the OrcaWin/d2q1-ssh-target-management branch from 7fa838a to 9f1a4dc Compare October 10, 2026 23:17
@OrcaWin
OrcaWin force-pushed the OrcaWin/d2q1-v4b-server-ssh-projects branch from 9f043a9 to 89a2114 Compare October 10, 2026 23:18
@OrcaWin
OrcaWin force-pushed the OrcaWin/d2q1-ssh-target-management branch from 9f1a4dc to f361c91 Compare October 10, 2026 23:51
@OrcaWin
OrcaWin force-pushed the OrcaWin/d2q1-v4b-server-ssh-projects branch from 6932c4a to 30c154d Compare October 10, 2026 23:52
@OrcaWin
OrcaWin force-pushed the OrcaWin/d2q1-ssh-target-management branch from f361c91 to 0d11eb9 Compare October 11, 2026 00:50
@OrcaWin
OrcaWin force-pushed the OrcaWin/d2q1-v4b-server-ssh-projects branch from 30c154d to b7f5009 Compare October 11, 2026 00:50
@OrcaWin
OrcaWin changed the base branch from OrcaWin/d2q1-ssh-target-management to main October 11, 2026 01:26
@OrcaWin
OrcaWin force-pushed the OrcaWin/d2q1-v4b-server-ssh-projects branch from b7f5009 to 3273689 Compare October 11, 2026 01:26
@coderabbitai

coderabbitai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Walkthrough

Walkthrough

The Add Project flow now supports SSH targets owned by a paired server. It can load and connect to those targets, browse their directories, add projects through the server, and add SSH hosts to the server. Repository SSH status checks and connection requests now use the local or runtime environment state that matches the target’s owner. The changes also add server-specific action states, translated UI copy, and tests for server and local routing.


Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: 🟡 Moderate · up to 32736

Projects on a paired server's SSH hosts may show the wrong available agents when the server has several SSH hosts. An old error message can also linger in Add Project. Resolve the agent-detection behavior or explicitly accept it before merging.

Pre-merge checks | Passed 2 | Failed 1 | Inconclusive 2

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 37.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 35 functions across 31 files. (6 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check Inconclusive The linked issue assessment could not be completed. Retry the assessment when the required review evidence is available.
Out of Scope Changes check Inconclusive The linked issue assessment could not be completed. Retry the assessment when the required review evidence is available.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check Passed The title clearly summarizes the two primary changes: creating projects on a server's SSH target and listing server-owned SSH targets in Add Project.
Description check Passed The description is detailed, on-topic, and covers the required explanation, changes, rationale, linked issues, testing, review notes, compatibility considerations, and checklist. Visual proof is not a…

Full details: Docstring Coverage

Explanation

Docstring coverage is 37.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 35 functions across 31 files. (6 skipped: 6 unsupported.)


  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟡 Minor · Clear the stale remote error when reopening the remote step. · AddRepoSteps.tsx:99-133

src/renderer/src/components/sidebar/AddRepoSteps.tsx:99-133
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Clear the stale remote error when reopening the remote step.

When server target loading fails, handleOpenRemoteStep sets remoteError. A later successful reload does not clear it, so the old message can remain visible under the form. Clear the error when the remote load starts.

Suggested fix
       const gen = ++remoteGenRef.current
       setStep('remote')
+      setRemoteError(null)
       try {

ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5a71f489-051b-4490-8460-084ee6738b3f
📥 Commits

Reviewing files that changed from the base of the PR and between e6af897 and 3273689.

📒 Files selected for processing (37)
  • src/renderer/src/components/settings/RepositoryHostSetupsSection.tsx
  • src/renderer/src/components/sidebar/AddRemoteHostSshFormPanel.tsx
  • src/renderer/src/components/sidebar/AddRepoDialog.tsx
  • src/renderer/src/components/sidebar/AddRepoDialogStepContent.tsx
  • src/renderer/src/components/sidebar/AddRepoRemoteStep.tsx
  • src/renderer/src/components/sidebar/AddRepoStartSteps.test.tsx
  • src/renderer/src/components/sidebar/AddRepoStartSteps.tsx
  • src/renderer/src/components/sidebar/AddRepoSteps.default-checkout.test.ts
  • src/renderer/src/components/sidebar/AddRepoSteps.tsx
  • src/renderer/src/components/sidebar/AddServerSshHostDialog.tsx
  • src/renderer/src/components/sidebar/NonGitFolderDialog.tsx
  • src/renderer/src/components/sidebar/RemoteFileBrowser.tsx
  • src/renderer/src/components/sidebar/add-remote-host-ssh-actions.ts
  • src/renderer/src/components/sidebar/add-repo-local-start-actions.ts
  • src/renderer/src/components/sidebar/add-repo-server-ssh-targets.ts
  • src/renderer/src/components/sidebar/repo-header-create-state.test.ts
  • src/renderer/src/components/sidebar/repo-header-create-state.ts
  • src/renderer/src/components/sidebar/use-remote-file-browser-listing.test.ts
  • src/renderer/src/components/sidebar/use-remote-file-browser-listing.ts
  • src/renderer/src/components/sidebar/use-server-ssh-projects.ts
  • src/renderer/src/components/sidebar/worktree-list/rows/SectionHeader.tsx
  • src/renderer/src/components/sidebar/worktree-list/viewport/VirtualizedWorktreeViewport.tsx
  • src/renderer/src/components/sidebar/worktree-list/viewport/virtual-row-context.ts
  • src/renderer/src/hooks/composer-state/host-runtime-effects.ts
  • src/renderer/src/hooks/composer-state/runtime-target-selection.ts
  • src/renderer/src/hooks/composer-state/server-ssh-repo-connect.test.ts
  • src/renderer/src/hooks/composer-state/workspace-identity-state.ts
  • src/renderer/src/hooks/use-repo-ssh-gate-resolver.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/lib/repo-ssh-connection.test.ts
  • src/renderer/src/lib/repo-ssh-connection.ts
  • src/renderer/src/store/slices/runtime-environment-ssh-selectors.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.

Comment on lines +184 to +186
// Why: a server-owned repo's connectionId names that server's own SSH target, which this client
// cannot probe for agents; the server answers for it.
const isRemote = typeof connectionId === 'string' && !runtimeEnvironmentId

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.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Detect agents on the selected SSH target through its server.

When runtimeEnvironmentId is set, isRemote becomes false. The agent lookup and detection call then use only that environment ID, not connectionId. Two SSH targets on the same server therefore share one agent list even when their installed agents differ. Route detection through the server for the selected SSH target, and key its result by both environment and target.

@OrcaWin
OrcaWin merged commit 1dde4c0 into main Oct 11, 2026
29 checks passed
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.

[Bug]: Remote client can't create workspaces on a server-owned SSH project [Bug]: Paired Desktop cannot manage or use headless server SSH targets

1 participant