You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(sidebar): move pinned folder workspaces into the Pinned section - #34007
When you pin a git worktree, it moves to the Pinned section at the top of the sidebar. When you pin a folder workspace (a workspace in a folder project that is not a git repo), Orca saves the pin, but the row stays in its project group. This change moves pinned folder workspaces into Pinned too.
What Changed
Before: Select Pin on a folder workspace. The menu then shows Unpin and Orca saves isPinned: true, but the row stays in its project group lane. If no git worktree is pinned, the sidebar shows no Pinned header.
After: A pinned folder workspace shows once, under Pinned, in each Group by mode (repo, workspace-status, pr-status, none). Unpin moves it back to its lane.
Mechanism:
src/shared/sidebar-list/sidebar-row-plan.ts: planSidebarRows divides the renderable folder workspaces into pinned and unpinned. The lanes (buildOrderedGroups, flat mode, appendProjectGroupSections) get only the unpinned ones. The pinned ones go to emitPinnedGroup, sorted with compareFolderWorkspacesForDisplay.
src/shared/sidebar-list/pinned-group-rows.ts: emitPinnedGroup accepts the pinned folder workspaces. The header count includes them. Per-host counts and IDs come from getLaneHostWorktreeCounts / getLaneHostWorktreeIds, which the status and flat lanes already use for folder workspaces. The section now shows when only folder workspaces are pinned. Folder rows come after the git rows, like in the status lanes.
src/renderer/.../navigation/folder-reveal.ts: the reveal of a pinned folder workspace expands Pinned (host-scoped when hosts are shown) and its host, not the project group.
Folder rows have one placement under each pinned display policy. With "show pinned workspaces in their groups" on, a pinned folder workspace shows in Pinned only. Folder rows have one host-identity row key and option ID (render-row.ts, active-descendant-option.ts). A second copy needs separate work on those keys, so this PR does not include it.
Why
All other layers already treat a folder-workspace pin as real: the context menu shows Pin for folder rows, setWorktreesPinnedAndReveal has a folder branch, persistence saves isPinned for folder workspaces, and desktop-sidebar-facts.ts puts folder:<id> in pinnedWorkspaceIds. Only the row planner ignored the flag, because the Pinned section comes from buildWorktreeOccurrencePlan, which gets only git worktrees. #15362 fixed the same kind of gap for the Group by lanes.
This change reuses the existing folder-row and lane host-count functions. I did not add folder workspaces to the worktree occurrence plan, because that plan handles lineage and duplicate occurrences that folder rows do not use.
@lafraia found this bug first and opened #16799 on 2026-08-27. @nwparker agreed it is a bug on 2026-09-06. That PR is still open, and it now conflicts with main: the row builder moved from src/renderer/.../grouping/build-rows.ts to src/shared/sidebar-list/ (planSidebarRows, emitPinnedGroup) after it was opened. This PR uses the same approach as #16799: divide the renderable folder workspaces into pinned and unpinned, and give the Pinned header the lane host-count helpers. This PR applies that approach to the current shared planner.
Renderer buildRows (before the move to src/shared)
Current planSidebarRows in src/shared/sidebar-list/
"Show pinned workspaces in their groups"
Shows a pinned folder workspace in Pinned and in its group. Adds a required sectionKey to FolderWorkspaceRow, with distinct DOM IDs and one primary active surface
Pinned only, with no second copy
Reveal of a pinned folder workspace
Expands Pinned or the group, depending on the policy
Expands Pinned
Size
Larger: row key, option ID, active surface, range selection and keyboard cycle changes
5 files, +37 prod LOC
If the maintainers prefer the full duplicate-copy support, rebasing #16799 onto src/shared/sidebar-list/ is the more complete fix, and I will close this PR. If not, this PR fixes the default policy now, and the duplicate-copy work from #16799 can follow on top of it.
Same e2e profile and state in both images: one pinned git worktree, a Research folder project with Pinned notes (pinned through setWorktreesPinnedAndReveal, which the context menu calls) and Loose notes. Group by: Project.
Before
After
Testing
New cases in build-rows.folder-workspace-lanes.test.ts: the pinned folder row is under Pinned in all four Group by modes and shows only once; Pinned shows when a folder workspace is the only pinned row; a collapsed Pinned hides the row; an SSH project group's pinned folder is counted under its host, with an empty ID array.
New case in folder-reveal.test.ts: the reveal keys for a pinned folder workspace are the host-scoped Pinned key and the host key.
All 8 new cases fail on origin/main and pass with this change.
Toolchain for the results below: Node 24.22.1 and Bun 1.4.4, as package.json and config/.bun-version require.
pnpm lint: 35 of 35 steps pass. pnpm typecheck:ci: no type errors.
pnpm build: passes, including the mobile web bundle.
Tests related to the changed modules (vitest related on the 3 changed source files): 100 files, 746 passed, 0 failed.
pnpm test (full): 68 tests in 21 files fail on my machine, and they fail the same way on unchanged origin/main. None of these files is in the related set above. The causes are local to macOS and this machine: macOS bash 3.2 (mapfile: command not found), the /tmp → /private/tmp symlink, a local username (will) that the transcript secret scanner reports in its fixtures, a blocked registry.npmjs.org, uninstalled cloud/ dependencies (pg), and zsh startup tests that read my shell profile. I expect CI on Linux to cover these.
Visual proof: a temporary Playwright spec (not committed) ran against the e2e Electron build (ORCA_BACKGROUND_LAUNCH=1, electron-headless). I captured the sidebar once without the fix and once with it.
Platforms: macOS (arm64). The change is in platform-independent row planning.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Written with Claude (Anthropic) in the omp coding agent. I reviewed the diff and the before/after output.
Review
AI review summary (Claude, path-correctness lens, trace from producer to consumer): no findings. It checked the renderer sidebar consumers and the mobile feed (sidebar-feed-rows.ts → mobile/src/host-screen/host-sidebar-feed-sections.ts), which shows folder-workspace rows under the current section and so gets the same placement.
Cross-platform: no platform, path, shell or shortcut code changes. The row planner is platform-independent.
SSH/remote/local: folder rows keep their host-qualified keys. The Pinned header's host counts and IDs include folder workspaces, so each host section gets its own Pinned header (tested for an SSH project group). Mixed client and server versions are not affected: no wire format or persisted data changes.
Agents and integrations: no agent, provider or git-provider code changes.
Performance: one filter and one sort over the folder workspaces each time the planner runs. Lanes already sorted the same list.
UI quality: no new components or styles. Pinned folder rows use the existing folder-workspace row and the existing Pinned header. I captured light theme only. The change moves a row and does not change how it looks.
Security: no new input, IPC, network, file or persistence paths.
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
Cross-platform: no platform-specific code.
SSH/remote: folder rows keep their host-qualified keys. Pinned header host counts and IDs include folder workspaces, so each host section gets its own Pinned header.
Mobile: the feed uses the same planner. Pinned folder workspaces show under Pinned on mobile too.
Backwards compatibility: no persisted data changes. isPinned on folder workspaces already exists.
Performance: one filter and sort over the folder workspaces each time the planner runs.
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). Lint, typecheck and build pass locally. The full test suite needs CI; see Testing.
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
Walkthrough
Row planning now sends pinned folder workspaces to the Pinned section and keeps unpinned folders in their regular lanes. The Pinned header includes folder workspaces in its count and host metadata, and the section emits their rows. Folder reveal logic returns the pinned and host-specific group keys. Tests cover grouping modes, collapsed sections, host metadata, and reveal keys.
Priority: Normal
Severity of issue fixed: Medium
Merge Risk: Minimal · up to ff2e6
Pinned folder placement and reveal behavior appear consistent across the inspected paths. No blocking issue remains.
Pre-merge checks: 4 · 1
Failed checks: 1 warning
Check name
Status
Explanation
Resolution
Docstring Coverage
Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 5 files.
Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed checks: 4 passed
Check name
Status
Explanation
Title check
The title clearly and concisely describes the main change: moving pinned folder workspaces into the Pinned section.
Linked Issues check
Issue #34006 requires pinned folder workspaces to appear in Pinned instead of their project-group lane. planSidebarRows separates pinned folder workspaces from lane folder workspaces, passes only un…
Out of Scope Changes check
The changed planner, pinned-section, and folder-reveal code directly supports issue #34006. The added tests verify the required placement, counts, collapse behavior, host scoping, and reveal behavior.…
Description check
The pull request description follows the required template and clearly explains the user impact, implementation, rationale, linked issue, visual proof, testing, AI disclosure, compatibility considerat…
Full details: Linked Issues check
Explanation
Issue #34006 requires pinned folder workspaces to appear in Pinned instead of their project-group lane. planSidebarRows separates pinned folder workspaces from lane folder workspaces, passes only unpinned folders to lane builders, and passes pinned folders to emitPinnedGroup. emitPinnedGroup renders the folder rows, includes them in the header count and host metadata, and shows the section when folder pins are the only pinned items. The supplied test summary covers all four grouping modes, single placement, folder-only Pinned, collapse behavior, SSH host metadata, and reveal keys.
Full details: Out of Scope Changes check
Explanation
The changed planner, pinned-section, and folder-reveal code directly supports issue #34006. The added tests verify the required placement, counts, collapse behavior, host scoping, and reveal behavior. No unrelated change is demonstrated. The PR explicitly excludes duplicate pinned copies when the display policy requests group placement.
Full details: Description check
Explanation
The pull request description follows the required template and clearly explains the user impact, implementation, rationale, linked issue, visual proof, testing, AI disclosure, compatibility considerations, and checklist status. The manual-testing checkbox is unchecked, but the description documents automated, visual, platform, SSH, mobile, and CI-related validation in sufficient detail.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ELI5
When you pin a git worktree, it moves to the Pinned section at the top of the sidebar. When you pin a folder workspace (a workspace in a folder project that is not a git repo), Orca saves the pin, but the row stays in its project group. This change moves pinned folder workspaces into Pinned too.
What Changed
Before: Select Pin on a folder workspace. The menu then shows Unpin and Orca saves
isPinned: true, but the row stays in its project group lane. If no git worktree is pinned, the sidebar shows no Pinned header.After: A pinned folder workspace shows once, under Pinned, in each Group by mode (
repo,workspace-status,pr-status,none). Unpin moves it back to its lane.Mechanism:
src/shared/sidebar-list/sidebar-row-plan.ts:planSidebarRowsdivides the renderable folder workspaces into pinned and unpinned. The lanes (buildOrderedGroups, flat mode,appendProjectGroupSections) get only the unpinned ones. The pinned ones go toemitPinnedGroup, sorted withcompareFolderWorkspacesForDisplay.src/shared/sidebar-list/pinned-group-rows.ts:emitPinnedGroupaccepts the pinned folder workspaces. The header count includes them. Per-host counts and IDs come fromgetLaneHostWorktreeCounts/getLaneHostWorktreeIds, which the status and flat lanes already use for folder workspaces. The section now shows when only folder workspaces are pinned. Folder rows come after the git rows, like in the status lanes.src/renderer/.../navigation/folder-reveal.ts: the reveal of a pinned folder workspace expands Pinned (host-scoped when hosts are shown) and its host, not the project group.Folder rows have one placement under each pinned display policy. With "show pinned workspaces in their groups" on, a pinned folder workspace shows in Pinned only. Folder rows have one host-identity row key and option ID (
render-row.ts,active-descendant-option.ts). A second copy needs separate work on those keys, so this PR does not include it.Why
All other layers already treat a folder-workspace pin as real: the context menu shows Pin for folder rows,
setWorktreesPinnedAndRevealhas a folder branch, persistence savesisPinnedfor folder workspaces, anddesktop-sidebar-facts.tsputsfolder:<id>inpinnedWorkspaceIds. Only the row planner ignored the flag, because the Pinned section comes frombuildWorktreeOccurrencePlan, which gets only git worktrees. #15362 fixed the same kind of gap for the Group by lanes.This change reuses the existing folder-row and lane host-count functions. I did not add folder workspaces to the worktree occurrence plan, because that plan handles lineage and duplicate occurrences that folder rows do not use.
Prior art: #16799
@lafraia found this bug first and opened #16799 on 2026-08-27. @nwparker agreed it is a bug on 2026-09-06. That PR is still open, and it now conflicts with
main: the row builder moved fromsrc/renderer/.../grouping/build-rows.tstosrc/shared/sidebar-list/(planSidebarRows,emitPinnedGroup) after it was opened. This PR uses the same approach as #16799: divide the renderable folder workspaces into pinned and unpinned, and give the Pinned header the lane host-count helpers. This PR applies that approach to the current shared planner.Differences:
buildRows(before the move tosrc/shared)planSidebarRowsinsrc/shared/sidebar-list/sectionKeytoFolderWorkspaceRow, with distinct DOM IDs and one primary active surfaceIf the maintainers prefer the full duplicate-copy support, rebasing #16799 onto
src/shared/sidebar-list/is the more complete fix, and I will close this PR. If not, this PR fixes the default policy now, and the duplicate-copy work from #16799 can follow on top of it.Linked Issue
Fixes #34006
Visual Proof
Same e2e profile and state in both images: one pinned git worktree, a
Researchfolder project with Pinned notes (pinned throughsetWorktreesPinnedAndReveal, which the context menu calls) and Loose notes. Group by: Project.Testing
New cases in
build-rows.folder-workspace-lanes.test.ts: the pinned folder row is under Pinned in all four Group by modes and shows only once; Pinned shows when a folder workspace is the only pinned row; a collapsed Pinned hides the row; an SSH project group's pinned folder is counted under its host, with an empty ID array.New case in
folder-reveal.test.ts: the reveal keys for a pinned folder workspace are the host-scoped Pinned key and the host key.All 8 new cases fail on
origin/mainand pass with this change.pnpm check:changed --maxWorkers=2: 25 of 25 checks pass (format, lint, typecheck, affected tests, ratchets).Toolchain for the results below: Node 24.22.1 and Bun 1.4.4, as
package.jsonandconfig/.bun-versionrequire.pnpm lint: 35 of 35 steps pass.pnpm typecheck:ci: no type errors.pnpm build: passes, including the mobile web bundle.Tests related to the changed modules (
vitest relatedon the 3 changed source files): 100 files, 746 passed, 0 failed.pnpm test(full): 68 tests in 21 files fail on my machine, and they fail the same way on unchangedorigin/main. None of these files is in the related set above. The causes are local to macOS and this machine: macOS bash 3.2 (mapfile: command not found), the/tmp→/private/tmpsymlink, a local username (will) that the transcript secret scanner reports in its fixtures, a blockedregistry.npmjs.org, uninstalledcloud/dependencies (pg), and zsh startup tests that read my shell profile. I expect CI on Linux to cover these.Visual proof: a temporary Playwright spec (not committed) ran against the e2e Electron build (
ORCA_BACKGROUND_LAUNCH=1,electron-headless). I captured the sidebar once without the fix and once with it.Platforms: macOS (arm64). The change is in platform-independent row planning.
I manually tested these changes locally
Automated tests added/updated, or explained why not below
AI Disclosure
Written with Claude (Anthropic) in the omp coding agent. I reviewed the diff and the before/after output.
Review
AI review summary (Claude, path-correctness lens, trace from producer to consumer): no findings. It checked the renderer sidebar consumers and the mobile feed (
sidebar-feed-rows.ts→mobile/src/host-screen/host-sidebar-feed-sections.ts), which showsfolder-workspacerows under the current section and so gets the same placement.Agent skill upstream boundary
Notes
isPinnedon folder workspaces already exists.Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred). Lint, typecheck and build pass locally. The full test suite needs CI; see Testing.