Repository navigation
Conversation
…p, 1/3) The desktop window and the phone page now list workspaces from main's sidebar feed in shipped builds. ORCA_SIDEBAR_INPUTS_IS_MAIN is true everywhere and the switch leaves the dark-build guards; the follow-ups delete the switch-off paths. Mixed versions: the window still raises the unread flag and stamps Recent for rows of an older paired server (one capability check); a read cancels a raise still waiting on that check; the phone keeps its rows on screen under "Reopen to update". Switch-off unit tests are rewritten to run against an older host or deleted where the behaviour is gone.
…p no stamp path; Mark as read also drops a pending raise
…mp-free window made vacuous
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 Walkthrough
Priority: ➖ Normal Merge Risk: 🟡 Moderate · up to
|
There was a problem hiding this comment.
Actionable comments posted: 2
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
1d7392ee-f938-4433-822c-6282259a63f9
📒 Files selected for processing: 80
config/dark-build-switches.cjsconfig/scripts/dark-build-switches.test.mjsconfig/scripts/generate-rpc-params-catalog.mjsconfig/scripts/mobile-web-bundle-manifest.test.mjsconfig/scripts/orcad-mobile-web-bundle.test.mjsconfig/scripts/verify-packaged-mobile-web-bundle.test.mjsmobile/rpc-foundation/goldens/host-worktree-actions-pin-open-delete.jsonmobile/rpc-foundation/goldens/matrix-host.view-settings-ui.set-1.jsonmobile/rpc-foundation/goldens/matrix-host.worktree-actions-worktree.activate-1.jsonmobile/rpc-foundation/goldens/matrix-host.worktree-actions-worktree.rm-1.jsonmobile/rpc-foundation/goldens/matrix-host.worktree-actions-worktree.set-1.jsonmobile/src/host-screen/host-workspace-list-reopen.test.tsxmobile/src/host-screen/host-workspace-list.tsxmobile/src/host-screen/use-host-list-sections.tsmobile/src/host-screen/use-host-project-sections.test.tsxmobile/src/worktree/host-workspace-list-states.tsxsrc/cli/runtime/websocket-transport.test.tssrc/main/runtime/mobile-rpc-allowlist.test.tssrc/main/runtime/orca-runtime-tests/mobile-creation-and-orchestration-part-04.spec.tssrc/main/runtime/orca-runtime-tests/terminal-side-effect-facts.spec.tssrc/main/runtime/runtime-rpc/runtime-rpc-mobile-method-routing.test.tssrc/main/runtime/sidebar-inputs/sidebar-inputs-switch-off.test.tssrc/main/window/attach-main-window-services.test.tssrc/main/window/main-window-service-stubs.test-fixture.tssrc/main/window/runtime-window-lifecycle-file-open.test.tssrc/main/window/runtime-window-pane-title-notification.test.tssrc/renderer/src/attention/hidden-workspace-notification-mute.test.tssrc/renderer/src/components/native-chat/StructuredAgentSessionAttentionBridge.test.tsxsrc/renderer/src/components/native-chat/structured-attention-dispatch.test.tssrc/renderer/src/components/sidebar/WorktreeList.card-memo-stability.test.tsxsrc/renderer/src/components/sidebar/WorktreeList.empty-project-rows.test.tssrc/renderer/src/components/sidebar/WorktreeList.folder-workspace-rows.test.tssrc/renderer/src/components/sidebar/WorktreeList.group-headers.test.tssrc/renderer/src/components/sidebar/WorktreeList.lineage-agent-expansion-coupling.test.tsxsrc/renderer/src/components/sidebar/WorktreeList.lineage-child-card.test.tssrc/renderer/src/components/sidebar/WorktreeList.lineage-child-real-card.test.tsxsrc/renderer/src/components/sidebar/WorktreeList.status-lane-lineage-drop.test.tsxsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/group-by-none.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/group-by-pr-status.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/group-by-repo.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/group-by-workspace-status.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/scenario-hide-default-branch.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/scenario-hide-sleeping.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/scenario-host-sections.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/scenario-name-order.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/scenario-new-external-inbox.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/scenario-repo-filter.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/scenario-single-host-scope.txtsrc/renderer/src/components/sidebar/__goldens__/sidebar-list/unranked-rows-last.txtsrc/renderer/src/components/sidebar/sidebar-list-goldens.test.tsxsrc/renderer/src/components/sidebar/sidebar-list-parity.test-fixture.tssrc/renderer/src/components/sidebar/sidebar-list-parity.test.tsxsrc/renderer/src/components/sidebar/window-state-sidebar-feed.test-fixture.tssrc/renderer/src/components/sidebar/workspace-view-evaluator-parity.test.tssrc/renderer/src/components/sidebar/worktree-list-lineage-card-test-harness.tssrc/renderer/src/components/sidebar/worktree-list/listing/use-sort-order.test.tsxsrc/renderer/src/components/terminal-pane/terminal-handle-links.test.tssrc/renderer/src/hooks/useIpcEvents-terminal-create-surfacing.test.tssrc/renderer/src/hooks/useUnreadDockBadge.test.tssrc/renderer/src/lib/unread-badge-count-selector.test.tssrc/renderer/src/lib/workspace-surface-reveal.test.tssrc/renderer/src/lib/worktree-activation-created-agent.test.tssrc/renderer/src/store/settled-sort-epoch.test.tssrc/renderer/src/store/slices/folder-workspace-activation-and-activity.test.tssrc/renderer/src/store/slices/store-active-worktree-selection.test.tssrc/renderer/src/store/slices/store-session-terminal-activity.test.tssrc/renderer/src/store/slices/workspace-attention/workspace-attention-slice.tssrc/renderer/src/store/slices/workspace-attention/workspace-unread-characterization.test.tssrc/renderer/src/store/slices/workspace-attention/workspace-unread-flag-host-raises.test.tssrc/renderer/src/store/slices/workspace-attention/workspace-unread-flag.tssrc/renderer/src/store/slices/workspace-attention/workspace-unread-on-screen-characterization.test.tssrc/renderer/src/store/slices/workspace-attention/workspace-unread-removal-characterization.test.tssrc/renderer/src/store/slices/workspace-attention/workspace-unread-screen-moves-characterization.test.tssrc/renderer/src/store/slices/worktrees-activity-persistence.test.tssrc/renderer/src/store/slices/worktrees-unread-state.test.tssrc/renderer/src/store/slices/worktrees/listing/owner-host-sidebar-inputs.tssrc/shared/sidebar-inputs-switch.tssrc/shared/sidebar-list/smart-sort.test.tssrc/shared/workspace-last-active.test.tstests/e2e/helpers/sidebar-inputs-build.ts
💤 Files with no reviewable changes: 14
- src/renderer/src/components/sidebar/sidebar-list-goldens.test.tsx
- src/renderer/src/components/sidebar/goldens/sidebar-list/group-by-pr-status.txt
- src/renderer/src/components/sidebar/goldens/sidebar-list/scenario-repo-filter.txt
- src/renderer/src/components/sidebar/goldens/sidebar-list/scenario-hide-sleeping.txt
- src/renderer/src/components/sidebar/goldens/sidebar-list/unranked-rows-last.txt
- src/main/runtime/sidebar-inputs/sidebar-inputs-switch-off.test.ts
- src/renderer/src/components/sidebar/goldens/sidebar-list/scenario-hide-default-branch.txt
- src/renderer/src/components/sidebar/goldens/sidebar-list/scenario-new-external-inbox.txt
- src/renderer/src/components/sidebar/goldens/sidebar-list/scenario-name-order.txt
- src/renderer/src/components/sidebar/goldens/sidebar-list/group-by-none.txt
- src/renderer/src/components/sidebar/goldens/sidebar-list/scenario-single-host-scope.txt
- src/shared/workspace-last-active.test.ts
- src/renderer/src/store/settled-sort-epoch.test.ts
- src/renderer/src/store/slices/store-active-worktree-selection.test.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.
| "state": "6b0066cfa6bd", | ||
| "effects": ["ca91c555e48e", "da6c9e1a507d", "a8d6bd902609", "4fb40764fe7e"] | ||
| } | ||
| }, | ||
| { | ||
| "id": "host-worktree-actions-pin-open-delete.inner-false-string-error:settled", | ||
| "observation": { | ||
| "sender": ["1c5bb0f1882e", "40f6e6f5e2cd", "47aef1f5918f"], | ||
| "payloads": ["9a2d39ba928f", "47602c8e53e9", "0eb00a9a894a"], | ||
| "sender": ["69cdbfebf29e", "49cbf9dfccdb", "1ef0289204ce"], | ||
| "payloads": ["adc3282cbaf6", "facde8e4bc87", "7a2251b6d74d"], | ||
| "settlements": { | ||
| "mount": "eb79a9b3682a", | ||
| "toggle-pin": "eb79a9b3682a", | ||
| "open-session": "eb79a9b3682a", | ||
| "delete": "eb79a9b3682a" | ||
| }, | ||
| "state": "38c12b517ad0", | ||
| "effects": [ | ||
| "ca91c555e48e", | ||
| "da6c9e1a507d", | ||
| "14ce9f03298e", | ||
| "047f5e4dfc2b", | ||
| "989153283864", | ||
| "04adcc2c4239" | ||
| ] | ||
| "state": "6b0066cfa6bd", | ||
| "effects": ["ca91c555e48e", "da6c9e1a507d", "a8d6bd902609", "4fb40764fe7e"] | ||
| } | ||
| }, | ||
| { | ||
| "id": "host-worktree-actions-pin-open-delete.inner-false-object-error:settled", | ||
| "observation": { | ||
| "sender": ["1c5bb0f1882e", "40f6e6f5e2cd", "d15cb8748ac4"], | ||
| "payloads": ["9a2d39ba928f", "47602c8e53e9", "0eb00a9a894a"], | ||
| "sender": ["69cdbfebf29e", "49cbf9dfccdb", "49c6657ebc51"], | ||
| "payloads": ["adc3282cbaf6", "facde8e4bc87", "7a2251b6d74d"], | ||
| "settlements": { | ||
| "mount": "eb79a9b3682a", | ||
| "toggle-pin": "eb79a9b3682a", | ||
| "open-session": "eb79a9b3682a", | ||
| "delete": "eb79a9b3682a" | ||
| }, | ||
| "state": "38c12b517ad0", | ||
| "effects": [ | ||
| "ca91c555e48e", | ||
| "da6c9e1a507d", | ||
| "14ce9f03298e", | ||
| "047f5e4dfc2b", | ||
| "989153283864", | ||
| "04adcc2c4239" | ||
| ] | ||
| "state": "6b0066cfa6bd", | ||
| "effects": ["ca91c555e48e", "da6c9e1a507d", "a8d6bd902609", "4fb40764fe7e"] |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
#!/bin/bash
fd -t f use-host-worktree-actions.ts mobile --exec sed -n '1,400p' {}
rg -n -C4 "worktree\.rm|ok === false|isPinned|inner" mobile/src/host-screen/use-host-worktree-actions.ts
# Compare settled states/effects against main for the inner-refusal checkpoints
git show origin/main:mobile/rpc-foundation/goldens/matrix-host.worktree-actions-worktree.rm-1.json 2>/dev/null | python3 -c '
import json,sys
d=json.load(sys.stdin)
for c in d["recording"]["checkpoints"]:
o=c["observation"]; print(c["id"], o.get("state"), o.get("effects"))
'
rg -n -C10 '"host-worktree-actions-pin-open-delete"' mobile/rpc-foundation/pilot-scenarios.json | rg -n "worktrees|isPinned|reply" | head -50Repository: stablyai/orca
Length of output: 14402
Restore the row for an inner refusal.
When worktreeRemove.interpret(reply).accepted is false, handleDeleteWorktree restores the item to both lists. The inner-refusal checkpoints must therefore preserve the row and its existing isPinned value, with the corresponding restore effects.
| void ownerRaisesUnreadFlag(get(), worktreeId).then((ownerRaises) => { | ||
| if (!ownerRaises) { | ||
| // A read while the owner was being asked already covers this news. | ||
| if (!ownerRaises && (clearsByWorkspace.get(worktreeId) ?? 0) === clearsBefore) { |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Keep a deferred unread decision bound to its original host.
If two folder rows share a workspace ID, a host change during the owner check changes which row raiseWorkspaceUnreadFlag selects. An unread event for the SSH row can then mark and persist the local row instead. A read on the local row can also increment this workspace-wide counter and discard the pending SSH raise. Capture the row’s host when the unread event arrives. Scope both the read counter and the eventual raise to that host.
…dered The virtualizer renders after the scroll, so the old pick could take a mid-viewport row that stays within overscan of the top and is still mounted there.
There was a problem hiding this comment.
🧹 Nitpick comments: 1
tests/e2e/sidebar-desktop-reads-main.spec.ts: 1
242-257: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winPoll for the final fixture row, not any mounted row near the bottom.
The predicate can return a non-final mounted row before the virtualized list finishes rendering its end. Poll for
many.at(-1)so the reveal assertions cover the intended final row.Suggested fix
- await expect.poll(lastRowAtBottom).not.toBe('') + await expect.poll(lastRowAtBottom).toBe(many.at(-1)) const bottomId = await lastRowAtBottom()
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
e0fa3028-8b58-45cd-b3f7-a7a08cbfef2a
📒 Files selected for processing: 1
tests/e2e/sidebar-desktop-reads-main.spec.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.
…e to show each change before comparing
… row a journey clicks
…x window paints rarely during a native drag; uncover rows under the setup-script card before hovering
… painted frames, and the observer watches only the sidebar
…since it reappears after each activation
…op, so a drag in Smart lands and switches to Manual test(e2e): the sort-stamps spec holds the pane's foreground while its posted hooks stand in for an agent
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
1e9967c4-648b-404c-a8af-e02e565e5232
📒 Files selected for processing: 7
src/renderer/src/components/sidebar/worktree-list/listing/use-order-hold.test.tssrc/renderer/src/components/sidebar/worktree-list/listing/use-order-hold.tstests/e2e/helpers/sidebar-setup-prompt.tstests/e2e/helpers/slept-workspace-probe.tstests/e2e/sidebar-desktop-reads-main.spec.tstests/e2e/sidebar-sort-stamps.spec.tstests/e2e/worktree-lineage-toggle-shortcut.spec.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.
…llows the list's drop commit, instead of a timer
…d before the pane's terminal spawns are cleared by the spawn
…shed creation leaves no empty gap that closes under a drag Main keeps listing a creation for a moment after the window's own entry ends; its row draws nothing, so the rows below jumped 12px when it went. Also drops the order-hold change, which the drag probe showed was not the cause.
…ided for, not whichever row is on screen when the owner answers test(e2e): the reads-main frame log records painted frames only, since every check needs one
… DOM state the input's own task commits, not from painted frames test: the orcad teardown fixture skips a process older than its claimed parent, a stale parent pid that Windows reused for the daemon
…uest bound, so a server slower than 5 s still lists The 5 s bound was made for the phone's synchronous catalog read, which keeps its own 5 s wait. Nothing waits on the producer's background fetch; one runs per server and change notices during it coalesce into one follow-up.
… the desktop does The catalog the desktop window publishes for the phone (mobileRelay.projectSections) left out each project's group and its order in that group, and the phone's reply parser dropped them too. The shared list builder on the phone then filed every grouped project as ungrouped: the group header showed with nothing under it and its projects moved down among the rest. The catalog now carries projectGroupId and projectGroupOrder (optional, so older desktops and pages keep the old list), and the phone draws a group header with the group icon and the desktop's per-level indent. The parity suite now builds the phone's catalog from what the window publishes, with a nested group, a folder-only group and an empty group; an e2e covers a group holding a repo and a folder project, and folding it from either side.
…desktop's cards do Workspace rows under a nested project group now step in with their project header, by what the desktop adds over an ungrouped card: a full tree step a level in a hand-made group, and the header step in a folder-scanned group (one level less for its folder workspaces), capped at six levels as the headers are. The group icon takes the foreground text colour, as on the desktop.
…ved view and project catalog are in, so rows no longer regroup and move in the first moments With the sidebar reading main's feed, main's first snapshot could land before the window had read its saved view settings and its projects, project groups and folders. The list then drew main's rows under the default grouping and sort with 'Unknown' project headers, and regrouped twice within the next ~150 ms. The main-fed list now waits until both halves are in, then draws once.
…up fields and main's repo targets
… has not answered within 500 ms A collapse the desktop answers at once no longer flashes a spinner on its section header.
…omain The window-state feed fixture skips main's projectCatalog domain, which reads servers asynchronously and which the window does not list from; the phone's grouped-project test builds its catalog with main's shared buildSidebarFeedCatalog.
…ished project catalog That catalog is served only with the switch off; switched on, main answers mobileRelay.projectSections from its own catalog (orca-runtime-project-catalog.test.ts).
…st, else the desktop's selection (#31081) * fix(mobile): highlight the workspace this phone last opened on the host, never the desktop's selection * fix(mobile): a list tap highlights its row in the list's own page, and an app list follows a session page's write * fix(mobile): show the desktop's selection until this phone opens a workspace on the host * fix(mobile): fall back to the desktop's selection when this phone's row is not shown, and keep storage off the e2e list helper's imports * fix(mobile): the host list's auto-scroll stays still while a search is in progress * chore(mobile): satisfy React Doctor on the changed lines --------- Co-authored-by: E2E Test <e2e@test.local>
…st the known names
Main's zod bump leaves the root and mobile on different zod copies, so the reply's inferred type
arrived as {} in the e2e typecheck.
…eeping with main's feed (#31249) * fix(sidebar): a slept workspace leaves the list at once under Hide sleeping with main's feed The window stops its own PTYs when it sleeps a workspace, so main never saw the sleep and read the exits as a reconnect gap: its retention kept the row for the 1.5 s settle window. The window now tells main which workspaces it holds asleep, before any kill, and main treats their inactivity as definitive. * fix(sidebar): only this host's window may report its slept workspaces Review: a phone or paired desktop could otherwise send a slept set and skip the reconnect grace for any id. Also states that the report is fire-and-forget.
… and a fold never scrolls the list (#31296)
… the desktop's (#31301) * fix(mobile): the phone's host list never flashes a list shaped unlike the desktop's Before the host's sidebar feed installed, the feed-built list drew worktree.ps's rows flat: no Pinned section, no project groups, no host badges, in another order, then snapped to the desktop's list. It now waits for the feed (the loading spinner), or opens on the host's last installed feed when this page has one. An older desktop without the feed still gets the worktree.ps list. * test(mobile): name the first-frame test's values for their role
…every feed read fails (#31309) Once the sidebar feed reader spent its retries without installing anything, the list stayed on the spinner until the next stream-ready or foreground, though worktree.ps had rows. The reader now says it gave up, and the list draws the worktree.ps rows (or keeps the host's last installed feed) until a later read installs.
…ist at once with main's feed (#31306) * fix(sidebar): closing a last tab and deleting a workspace update main's list at once Closing a workspace's last terminal tab left main counting its PTY live until the exit arrived, so Hide sleeping kept the row ~300-500 ms longer than the window's own list. Main now stops counting a PTY it was asked to stop once no pane shows it, and re-reads activity on the graph change and on the stop request. A deleted row came back as a plain card until main's worktree re-scan landed. The window's pending layer now holds a removed row out until main drops it (the overlay moves to sidebar-pending-overlay.ts to keep the layer under the line limit). * fix(sidebar): a closing terminal stays unverifiable when out of contact, and a failed stop reads running - An unverifiable verdict now wins over "closing": only a live terminal is dropped once it was asked to stop and no pane shows it. - A failed or refused stop (renderer close, stop-and-wait) takes back its stop request, so a terminal that runs on is counted again. - Re-creating a just-removed id on the same host drops that removal's hold, so the new row is listed at once.
|
Replaced by #31466, which landed the fixes from this branch without the switch flip or the interim bridges. The flip itself comes later as its own one-line PR. |
ELI5
The desktop sidebar and the phone's workspace list now get their list from one place: the Orca process that owns the workspaces. Until now that only happened in test builds. This PR turns it on for everyone. For most people nothing looks different. The phone list now matches the desktop list, and a few small things change on purpose (listed below).
This is part 1 of 3. Parts 2 and 3 only delete code that this PR leaves unused.
What Changed
The switch.
ORCA_SIDEBAR_INPUTS_IS_MAINis nowtruein every build: the desktop app, the headless server (orca serve/orcad), the CLI, the browser client, and the phone page. The switch is removed fromconfig/dark-build-switches.cjs, so release packaging no longer refuses it. The branches that check it stay in place for now; part 3 deletes the off side.Before and after, as a user sees it. For most users, nothing changes. These are the deliberate visible changes, all built and signed off in earlier dark PRs:
Mixed versions. Desktops, servers and phones update separately. This PR adds two small things for that:
owner-host-sidebar-inputs.ts. Only an older paired server makes the window raise it. If the user reads the workspace while that check is still in flight, the late raise is dropped, both for opening it and for "Mark as read". Before, the dot could stick.worktree.ps, which it has always had. The window raises the unread dot itself, because the server does not advertiseworkspace-unread.host-raises.v1. Recent order works as before: the window never stamped a server's rows on terminal activity, before or after. Known: in Smart sort, an older server's rows sort by Recent, with no Needs you / Working groups, because older servers write no Smart stamps. This lasts until the server updates.host-raisescapability from that client and leaves raising to it while it is connected. Unread clears still work. Older clients ignore new optional fields such assortedByStamps.worktree.ps,mobileRelay.hosts.*). The paired server rows behind them now come from main's own copy.Known gaps with mixed versions:
worktree.pswithin 5 s (server-worktree-fetch.ts:7). A slower server keeps its last rows until the next refresh.Tests. The unit tests that encoded the old behaviour (the window raising unread for local workspaces, settle timers, the old Smart sort, comment stamping) were rewritten or deleted:
WorktreeList.*render tests draw from a feed built from their store, the way the desktop now does.Why
The owner chose to land this series dark behind one build switch and flip it in one PR. I split the flip into three:
Splitting this way lets a reviewer check the mixed-version behaviour here, and then check parts 2 and 3 as pure deletions.
I kept the switch's branches here instead of deleting the switch at once. Deleting it at once would have mixed about 60 branch removals and several thousand deleted lines into the behaviour review.
Linked Issue
N/A (maintainer; sidebar list series, flip of #30050)
Visual Proof
Before and after, from hidden windows (CDP screenshots) and the real phone page served by the hidden desktop. Kept locally for the owner:
~/orca-lanes/sidebar-flip-shots/index.html.Testing
I manually tested these changes locally
Automated tests added/updated, or explained why not below
Full unit suite: the only failures left also fail on origin/main on this machine (fish shell,
pgin cloud/, process-host rebuilds, orcad forked children,/private/varpaths, the macOS CLI launcher).Full mobile suite,
pnpm tc, mobiletsc, oxlint, anti-slop, changed-code quality, focus-read and max-lines ratchets, oxfmt.e2e, hidden windows (
ORCA_BACKGROUND_LAUNCH=1): 34 sidebar, unread, sort-stamp, phone-feed, lineage and notification specs. 60 passed, 6 skipped (switch-off-only tests that part 3 deletes), 1 failed (layout-compat-old-phone-on-new-server: no darwin baseline, same on main).sidebar-desktop-reads-mainnow runs in every build. Two timing bugs in the test, neither in the product:sidebar-phone-feed-listcompared the phone and desktop right after a pin, while both still showed the old list. The phone hears the change about 300 ms after the desktop. Each step now waits for both to show the change (the Pinned header, the extra highlight, the fold).New tests:
sidebarInputsChangedreaches the renderer.Folder and SSH unread clear on the phone:
orca-runtime-workspace-unread.test.ts"clears a folder workspace and an SSH worktree on their own records when the phone opens them" now runs in the shipped build.Review
Two independent reviews, one of the PR and one of each fix. Applied:
Agent skill upstream boundary
Notes
Security: no new surface. The methods the phone page calls were already allowlisted for the paired desktop. Cross-platform: no platform-specific code. Performance: measured earlier in the series (
sidebar-perf/results-flip.md).Checklist
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)