Skip to content

fix(agents): scope Settings agent list and quick-launch menu to the remote-server host - #9790

Merged
brennanb2025 merged 8 commits into
mainfrom
brennanb2025/fix-windows-ssh-remote
Jul 23, 2026
Merged

brennanb2025 merged 8 commits into
mainfrom
brennanb2025/fix-windows-ssh-remote

Conversation

@brennanb2025

Copy link
Copy Markdown
Contributor

Problem

With a paired Remote Server set as the Active Server (orca serve on a headless Linux box, client on Windows/macOS), two surfaces list the client's agents instead of the server's:

  • Settings → Agents — AgentsPane called useDetectedAgents() with no target, which always runs preflight.detectAgents on the local main process. It never read settings.activeRuntimeEnvironmentId.
  • + menu quick-launch items — QuickLaunchButton resolved the host via the SSH-only getConnectionIdFromState, which returns null for paired-runtime worktrees, falling back to local detection. (The SSH path came from feat(ssh): detect remote-host CLI agents in quick-launch menu #1027 and was never extended when paired runtimes arrived.)

Worktree-create already routed correctly (useComposerState builds a runtime target and dispatches detection over the relay), which is exactly how the reporting user narrowed it down: server agents in worktree-create, local agents everywhere else. Reported on Discord (Windows 1.4.137/1.4.146 client + Linux headless server, both surfaces confirmed by screenshots).

Fix

  • New hooks/useAgentDetectionTarget.ts — extracts TabBar's inline ssh/runtime/local owner resolution into a shared hook. TabBar behavior is unchanged; QuickLaunch now uses the same resolution, so the + menu probes the worktree's owning runtime host.
  • AgentsPane scopes detection to the Active Server when one is set (matching the settings-page contract that the Active Server routes provider checks), shows a muted on <server> badge next to "N detected", and swaps the Refresh tooltip. Enable/disable/default toggles remain client-side settings.
  • New store/slices/runtime-detected-agents.ts — runtime detection split out of detected-agents.ts (the addition crossed the 300-line max-lines cap; no ratchet bump). Adds refreshRuntimeDetectedAgents: preflight.refreshAgents over the relay for a real login-shell PATH re-read, falling back to preflight.detectAgents on servers that predate the refresh RPC, and keeping the last known list when the runtime is unreachable. useDetectedAgents().refresh/isRefreshing are now target-aware for local, SSH, and runtime hosts.

Testing

  • Repro-first: new tests assert the detection target each surface passes — they fail on the previous code (QuickLaunch passed null, AgentsPane passed nothing) and pass now.
  • New slice tests: runtime refresh via preflight.refreshAgents, fallback to preflight.detectAgents for older servers, and no cache wipe on total failure; retain/clear prune the new refresh state.
  • 2,093 tests across 154 files (store, tab-bar, hooks, settings), full 3-project typecheck, oxlint, max-lines ratchet, and localization catalog + locale parity all green.
  • Not live-verified against a real client↔server pairing; the reporter's screenshots confirm the live behavior and the routing layer is test-covered.

Notes

  • verify:localization-coverage is currently red on main itself (two unlocalized ai-vault strings: AiVaultSessionDropLayer.tsx:260, ai-vault-session-launch-actions.ts:150) — unrelated to this change, left untouched.
  • Follow-up candidate: OrchestrationSkillAgentCoverage.tsx still calls useDetectedAgents() local-only.

…emote-server host

With a paired Remote Server as the Active Server, Settings → Agents and the
tab-bar + quick-launch items always ran agent detection on the local client's
PATH, so a Windows client showed its own agents while worktree-create
correctly listed the server's.

- Extract TabBar's ssh/runtime/local owner resolution into a shared
  useAgentDetectionTargetForWorktree hook and use it in QuickLaunch, which
  previously resolved only SSH connections and fell back to local for
  paired-runtime worktrees.
- Scope AgentsPane detection (and its Refresh button) to the Active Server,
  with an "on <server>" badge showing which host the list came from.
  Enable/disable/default toggles remain client-side settings.
- Split runtime detection into store/slices/runtime-detected-agents.ts and add
  refreshRuntimeDetectedAgents: preflight.refreshAgents over the relay
  (login-shell PATH re-read), falling back to preflight.detectAgents on
  servers that predate the refresh RPC, keeping the last known list when the
  runtime is unreachable.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Agent detection now supports local, SSH, and runtime targets through a shared worktree resolver. Runtime agent state moved into a dedicated Zustand slice with cached results, refresh and detection flags, in-flight deduplication, cleanup, and fallback detection. Settings and tab-bar components pass explicit targets to useDetectedAgents, while settings UI displays the active server context and target-specific refresh text. Tests and locale files were updated accordingly.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description lacks the required Summary, Screenshots, AI Review Report, and Security Audit sections and does not use the template's testing checklist format. Add the missing template sections, include the testing checklist items, and provide screenshots or 'No visual change', an AI review report, a security audit, and notes.
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main user-visible change: scoping agent lists and quick-launch detection to the remote-server host.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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: 2

🧹 Nitpick comments (2)
src/renderer/src/store/slices/runtime-detected-agents.ts (1)

48-156: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider extracting the repeated "commit-if-still-current" guard.

The if (runtime{Detect,Refresh}Promises.get(environmentId) === pending) { set(...) } pattern is duplicated four times (two in ensureRuntimeDetectedAgents, two in refreshRuntimeDetectedAgents). A small shared helper (e.g. commitIfCurrent(map, id, pending, updater)) would reduce the risk of the guard being dropped or diverging in a future edit.

src/renderer/src/store/slices/detected-agents.test.ts (1)

565-676: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding coverage for ensureRuntimeDetectedAgents, clearRuntimeDetectedAgents, and retainRuntimeDetectedAgents.

This file only exercises refreshRuntimeDetectedAgents. The other three exported actions contain the empty-result re-detect logic, the mid-flight-removal guards, and the pruning behavior for removed environments — all non-trivial and worth a dedicated test each (e.g., detect dedup, clear during in-flight detect, retain pruning both cache and in-flight maps).


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e8313b5a-3cba-423f-bbfa-84e11d66a887

📥 Commits

Reviewing files that changed from the base of the PR and between 54c1ec5 and bb04a9a.

📒 Files selected for processing (19)
  • src/renderer/src/components/settings/AgentsPane.test.tsx
  • src/renderer/src/components/settings/AgentsPane.tsx
  • src/renderer/src/components/tab-bar/QuickLaunchButton.test.ts
  • src/renderer/src/components/tab-bar/QuickLaunchButton.tsx
  • src/renderer/src/components/tab-bar/TabBar.tsx
  • src/renderer/src/hooks/useAgentDetectionTarget.ts
  • src/renderer/src/hooks/useDetectedAgents.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.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/store/index.ts
  • src/renderer/src/store/slices/detected-agents.test.ts
  • src/renderer/src/store/slices/detected-agents.ts
  • src/renderer/src/store/slices/diffComments.test.ts
  • src/renderer/src/store/slices/runtime-detected-agents.ts
  • src/renderer/src/store/slices/store-test-helpers.ts
  • src/renderer/src/store/types.ts
💤 Files with no reviewable changes (1)
  • src/renderer/src/store/slices/detected-agents.ts

@AmethystLiang AmethystLiang added the orca-remote-server Remote Orca Server / orca serve / paired remote runtime label Jul 22, 2026

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

Caution

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

⚠️ Outside diff range comments (1)
src/renderer/src/hooks/useDetectedAgents.ts (1)

106-122: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

refresh() silently targets local when target is still unresolved (isUnknown).

isUnknown (target undefined, i.e. "not yet hydrated") is checked for detectedIds/isLoading, but refresh() has no such guard — it falls through the runtime/ssh checks straight to refreshLocal(). If a caller invokes refresh() during that hydration window, it refreshes the wrong host, exactly the "silent no-op" the inline Why comment above warns about for known remote targets.

🩹 Proposed fix
   const refresh = useCallback((): Promise<TuiAgent[]> => {
+    if (isUnknown) {
+      return Promise.resolve([])
+    }
     if (targetKind === 'runtime' && targetId) {
       return refreshRuntime(targetId)
     }
     if (targetKind === 'ssh' && targetId) {
       return refreshRemote(targetId)
     }
     return refreshLocal()
-  }, [targetKind, targetId, refreshRuntime, refreshRemote, refreshLocal])
+  }, [isUnknown, targetKind, targetId, refreshRuntime, refreshRemote, refreshLocal])

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5dd9c0d9-8b83-4c34-814e-407bce5cac48

📥 Commits

Reviewing files that changed from the base of the PR and between 3d92591 and ce009d5.

📒 Files selected for processing (9)
  • src/renderer/src/components/settings/AgentsPane.test.tsx
  • src/renderer/src/components/settings/AgentsPane.tsx
  • src/renderer/src/components/tab-bar/QuickLaunchButton.test.ts
  • src/renderer/src/hooks/useAgentDetectionTarget.ts
  • src/renderer/src/hooks/useDetectedAgents.test.tsx
  • src/renderer/src/hooks/useDetectedAgents.ts
  • src/renderer/src/store/slices/detected-agents.test.ts
  • src/renderer/src/store/slices/detected-agents.ts
  • src/renderer/src/store/slices/runtime-detected-agents.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/renderer/src/hooks/useAgentDetectionTarget.ts
  • src/renderer/src/components/tab-bar/QuickLaunchButton.test.ts
  • src/renderer/src/store/slices/runtime-detected-agents.ts
  • src/renderer/src/store/slices/detected-agents.ts
  • src/renderer/src/components/settings/AgentsPane.tsx

@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


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f6fca619-f751-4426-8e6a-065372050539

📥 Commits

Reviewing files that changed from the base of the PR and between 65a9a4b and d8fed0a.

📒 Files selected for processing (5)
  • src/renderer/src/components/settings/OrchestrationSkillAgentCoverage.tsx
  • src/renderer/src/hooks/useAgentDetectionTarget.test.ts
  • src/renderer/src/hooks/useAgentDetectionTarget.ts
  • src/renderer/src/hooks/useDetectedAgents.test.tsx
  • src/renderer/src/hooks/useDetectedAgents.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/renderer/src/hooks/useDetectedAgents.ts
  • src/renderer/src/hooks/useDetectedAgents.test.tsx
  • src/renderer/src/hooks/useAgentDetectionTarget.ts

@brennanb2025
brennanb2025 merged commit ee6319e into main Jul 23, 2026
1 check passed
brennanb2025 added a commit to sdhilip200/orca that referenced this pull request Jul 29, 2026
The coverage widget dropped useDetectedAgents' detection target, which reads
as "host not yet known": detectedIds pins to null, so loading never clears and
the widget spins forever. It also reverted the remote-host scoping from stablyai#9790.

- Restore the { kind: 'local' } target and assert it in the component test,
  whose useDetectedAgents mock previously ignored its arguments.
- Cover the discovery contract renderer coverage consumes: every deduped
  rootPath must key an owning source, or that agent silently reads uncovered.
brennanb2025 pushed a commit that referenced this pull request Jul 29, 2026
Settings → Orchestration → Agent coverage decided whether each detected agent had the orchestration skill by matching a skill's single `rootPath` against a hand-maintained table of path segments. Skill discovery dedups by canonical file path, so when one provider home is a symlink onto another agent's skills directory — which `npx skills add --global` does — the two collapse into one row and the absorbed roots survive only in `rootPaths`, which the old matcher ignored. With `~/.grok/skills` symlinked onto `~/.claude/skills`, Claude read Ready and Grok read Missing even though Grok loads the same files.

Now classifies every entry in `rootPaths` and resolves each root through the `SkillDiscoverySource` the scanner already returns, accepting it when `sourceKind` is not `repo` and `owner` is either the agent's owner or `null`. Deletes `ORCHESTRATION_SKILL_LOCATIONS` and `ORCHESTRATION_SKILL_LOCATION_IDS_BY_AGENT` — a renderer-side mirror of `buildSkillDiscoverySources` that had to be hand-edited for every new provider root, which is what caused this class of bug.

No discovery roots change here; those landed in #8510.

Fixed during review:
- Restored the required `{ kind: 'local' }` argument to `useDetectedAgents`. Dropping it failed typecheck (TS2554) and pinned `detectedIds` to null, leaving the widget on "Checking installed agents and skill paths…" forever. It also reverted the remote-host scoping from #9790.
- Stopped a duplicate repo root from shadowing an owning home root. `SkillDiscoverySource.path` is not unique: when the scan cwd is the home directory, `~/.claude/skills` is scanned as both a home root and a repo root, and a path-keyed Map is last-write-wins — so every agent read Missing while the panel above said Installed. Guaranteed in Settings on a WSL project.
- Carried OMP coverage in the owner-based shape so #6422's coverage-table hunks could be dropped on merge.

Behavior note: an orchestration skill inside an enabled Claude plugin now counts for Claude. That is a deliberate consequence of trusting the scanner's ownership data, matches how the Codex plugin cache was already treated, and is pinned by a test.

Refs #8256

Co-authored-by: sdhilip200 <49802211+sdhilip200@users.noreply.github.com>
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…emote-server host (stablyai#9790)

* fix(agents): scope Settings agent list and quick-launch menu to the remote-server host

With a paired Remote Server as the Active Server, Settings → Agents and the
tab-bar + quick-launch items always ran agent detection on the local client's
PATH, so a Windows client showed its own agents while worktree-create
correctly listed the server's.

- Extract TabBar's ssh/runtime/local owner resolution into a shared
  useAgentDetectionTargetForWorktree hook and use it in QuickLaunch, which
  previously resolved only SSH connections and fell back to local for
  paired-runtime worktrees.
- Scope AgentsPane detection (and its Refresh button) to the Active Server,
  with an "on <server>" badge showing which host the list came from.
  Enable/disable/default toggles remain client-side settings.
- Split runtime detection into store/slices/runtime-detected-agents.ts and add
  refreshRuntimeDetectedAgents: preflight.refreshAgents over the relay
  (login-shell PATH re-read), falling back to preflight.detectAgents on
  servers that predate the refresh RPC, keeping the last known list when the
  runtime is unreachable.

* fix(agents): avoid redundant runtime refresh fallback

* fix(agents): dedupe SSH agent refreshes

* fix(agents): preserve remote host boundaries

* fix(agents): prevent remote detection refresh races

* fix(agents): harden remote detection failures

* fix(agents): keep unresolved detection off local host

* fix(agents): keep cold remote ownership unresolved
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
Settings → Orchestration → Agent coverage decided whether each detected agent had the orchestration skill by matching a skill's single `rootPath` against a hand-maintained table of path segments. Skill discovery dedups by canonical file path, so when one provider home is a symlink onto another agent's skills directory — which `npx skills add --global` does — the two collapse into one row and the absorbed roots survive only in `rootPaths`, which the old matcher ignored. With `~/.grok/skills` symlinked onto `~/.claude/skills`, Claude read Ready and Grok read Missing even though Grok loads the same files.

Now classifies every entry in `rootPaths` and resolves each root through the `SkillDiscoverySource` the scanner already returns, accepting it when `sourceKind` is not `repo` and `owner` is either the agent's owner or `null`. Deletes `ORCHESTRATION_SKILL_LOCATIONS` and `ORCHESTRATION_SKILL_LOCATION_IDS_BY_AGENT` — a renderer-side mirror of `buildSkillDiscoverySources` that had to be hand-edited for every new provider root, which is what caused this class of bug.

No discovery roots change here; those landed in stablyai#8510.

Fixed during review:
- Restored the required `{ kind: 'local' }` argument to `useDetectedAgents`. Dropping it failed typecheck (TS2554) and pinned `detectedIds` to null, leaving the widget on "Checking installed agents and skill paths…" forever. It also reverted the remote-host scoping from stablyai#9790.
- Stopped a duplicate repo root from shadowing an owning home root. `SkillDiscoverySource.path` is not unique: when the scan cwd is the home directory, `~/.claude/skills` is scanned as both a home root and a repo root, and a path-keyed Map is last-write-wins — so every agent read Missing while the panel above said Installed. Guaranteed in Settings on a WSL project.
- Carried OMP coverage in the owner-based shape so stablyai#6422's coverage-table hunks could be dropped on merge.

Behavior note: an orchestration skill inside an enabled Claude plugin now counts for Claude. That is a deliberate consequence of trusting the scanner's ownership data, matches how the Codex plugin cache was already treated, and is pinned by a test.

Refs stablyai#8256

Co-authored-by: sdhilip200 <49802211+sdhilip200@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

orca-remote-server Remote Orca Server / orca serve / paired remote runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants