mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 02:17:31 +00:00
f5bdd62f41507b2feb8e1a94decc59c55525b001
380
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8ea884135e |
fix(runtime): bind serve-host terminals to their workspace at create (#38864)
Terminals a paired desktop or mobile client opened on a headless serve host got a workspace-less serve-<uuid> session id, so the host inferred their owner from the cwd. Folder workspaces that share a path then traded those terminals whenever one was listed, and deleting a workspace stopped terminals shown in another. Serve ids now carry the workspace like every other daemon id. Inventory refresh keeps a persisted layout binding even when a targeted listing does not include its workspace, so restored serve-<uuid> terminals stay put. A cwd guess is recorded as such and never drives a worktree-scoped stop. Fixes #36716 Reported-by: Guy Shechter (@shechter) Co-authored-by: Bing.Z <zzb@gxsmjx.com> |
||
|
|
e92552a413 |
Keep Claude plugin UI out of chat and recover blocked replies (#37965)
Keep Claude plugin status and toast frames out of native chat, and give terminal-input requests an actionable failure with safe conversation recovery. Preserve genuine outside replies while hiding internal repair content. Tracked in STA-13468. Built on #37480 by @agustin2606. Co-authored-by: agustin2606 <agustinvarela2606@gmail.com> |
||
|
|
8417fa890a | refactor(main): group agent runtime code by defining owner (#38565) | ||
|
|
2f217b4d0d |
refactor(daemon): group endpoint, provider, session and transport owners (#38462)
* refactor(daemon): group transport, provider, endpoint, and terminal owners * refactor(daemon): consolidate owner imports and preserve pinned baseline sources * refactor(daemon): import termination budgets from their defining owner * fix(ci): retain serve mode coverage for extracted orcad startup * fix daemon build smoke to load concrete argument owner * read daemon protocol facts from historical defining paths * route protocol revision owners through compatibility checks |
||
|
|
6bb2e13c35 |
refactor(tooling): organize remaining scripts by domain owners (#38407)
* refactor(tooling): group remaining scripts by concrete domain owners * fix(tooling): preserve relocated launcher resource roots |
||
|
|
5434ee9933 |
fix(ci): unblock the release cut's Windows skill gate and Linux golden run (#38443)
* fix(ci): run the release skill-sharing Electron install step in bash #38130 turned this step into a POSIX path fallback, but the skill sharing release gate also runs on windows-2022, where the default shell is PowerShell. The step failed with a ParserError, so release-preflight skipped every build for the v1.4.250 cut. * test(e2e): keep the one-time Codex notice out of golden runs The v1.4.250 golden e2e on Linux timed out clicking New Terminal: the 'Orca now runs Codex without its shared server' toast fires once when the golden stub (a Codex terminal) appears, and here it landed while the + menu was open and closed it. Mark it seen in the completed-user fixture like the other one-time notices, and restore that fixture from the workflow ref in the release golden job so a recovered tag uses it. --------- Co-authored-by: m4air <m4air@Mac.localdomain> |
||
|
|
7c0ef1725e |
test(e2e): layout oracle restart comparison honors terminalsRestart (#38271)
relaunch() already lets a scenario declare terminalsRestart and passes it to oracle.step, but compareRestart masked PTY ids only for coldDaemon, so sleep-quit-resume reported its permitted terminal restart as a PTY id change. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
0b73edc6e7 |
Add Chat UI choice to onboarding (#36204)
* Add Chat UI choice to onboarding and tailor agent tours * Add setup guide controls for Chat UI and Yolo permissions * Refresh native chat agents and improve surface radio controls - Re-read the host inventory alongside workspace refreshes, including WSL - Recognize downloaded, ready chat runtimes without a CLI on PATH - Standardize onboarding and checklist surface choices on accessible radio variants * Show full-access agent overrides in Yolo mode settings * Polish Chat UI onboarding and clarify terminal fallbacks - Group agents by launch surface and refresh selection previews - Add scroll-edge fades to reveal clipped onboarding content * Recognize ready custom Chat commands and nested scroll changes * Advance agent tour after selecting a new tab type * Install onboarding skills for selected chat providers - Route Chat UI setup to local provider-specific skill roots - Improve tour focus, Escape handling, and delayed target transitions * Keep split lesson while a new pane mounts; update renamed skill in test * Assert agentDefaultSurface in Chat UI onboarding e2e * Open the chosen Chat UI agent when a new project's default checkout opens * Make the onboarding chat preview match native chat - Soften the selected preview tile styling. - Accept a leading separator in dev:fresh arguments. * Fix scrolling in the onboarding agent step * Preserve initial working directory when opening empty workspaces Also check only remaining tour steps for unfinished actions. * Fix tour resumption after completed split steps |
||
|
|
7bf0377072 | refactor: place terminal and workspace contracts with concrete owners (#38061) | ||
|
|
e98c6a439a |
test: remove 2816 low-value test declarations (#38030)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
d09519f0f1 | refactor: group workspace and runtime contracts by defining owner (#38018) | ||
|
|
926f8bad13 | refactor: organize terminal and runtime contract owners (#38011) | ||
|
|
da96fadec3 | refactor: organize source-control contract owners (#37990) | ||
|
|
2c03c4b989 | refactor: organize agent status and lifecycle owners (#37961) | ||
|
|
7b45308ee8 |
fix(mobile): type desktop replies from shared contracts and keep phone list facts beside the desktop row (#37917)
* refactor(mobile): keep phone list facts beside the desktop's worktree row
The phone wrote its own list facts (lineage depth, host labels, list keys
and so on) onto the worktree.ps row object it got from the desktop, so a
desktop field with one of those names would be read as the phone's own.
List items are now { row, view }: the row is the desktop's, typed from the
shared RuntimeWorktreePsSummary contract, and view holds what the phone
works out. Host labels are a lookup beside the rows instead of fields on
them. A type test fails if the desktop row gains a view field's name or a
type the phone row would not accept, and a contract test feeds rows from
the desktop's own worktree.ps builder through the phone list.
* fix(mobile): type desktop replies from shared contracts and reject unchecked rows (#37923)
* wip: contract guards
* fix(mobile): type desktop replies from the shared contracts and ban unchecked z.custom
Session tabs, the createSupport reply and native-chat frames were typed by
hand on the phone, so a desktop change could leave the phone compiling
against a stale shape. They are now Pick/Partial of shared types; the
createSupport reply and native-chat transcript frames gain shared types the
desktop uses too, which also gives the phone the 'chat-program' reason it
was missing. Type tests fail when a desktop tab gains a phone-only name or
a field type the phone would not accept.
Catalog rows were admitted with z.custom<Worktree>() and no check. They now
need a string worktreeId, and an ast-grep rule rejects a z.custom with no
check anywhere in mobile/src.
* test(mobile): the desktop contract check also catches a null the phone would not accept
|
||
|
|
d5f2a17cd2 | refactor: group agent launch contracts under concrete owners (#37915) | ||
|
|
f758771364 | refactor: group browser lifecycle and extension implementation owners (#37910) | ||
|
|
fadc93c794 |
fix(mobile): stream desktop-hosted server browser tabs (#37705)
* fix(mobile): stream desktop-hosted server browser tabs * test(mobile): record paired desktop browser interactions * fix(mobile): type browser relay settings and test adapters * fix(browser): avoid redundant retained paint mutations * fix(browser): keep retained viewer state free of React |
||
|
|
c0cb95d62e |
test: remove 131 low-value harness, main, and renderer tests (#37825)
* test: remove 20 low-value harness and client tests * test: retire fake-agent and layout-oracle self-tests * test: retire source route for removed usage smoke * test: include 21 further low-value tests and remove unused fixture helper --------- Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> |
||
|
|
f3088d53c9 | refactor(main): group terminal support by lifecycle owner (#37660) | ||
|
|
ac4a21f3d2 |
test(e2e): update two WSL specs to the stopped-distro copy and serve-only Settings (#37394)
wsl-host-paired-phone asserted the pre-#36771 'isn't running' copy; it now asserts the stable remote_runtime_unavailable code and '<distro> is stopped'. wsl-move-dialog's gate-closed case seeds a saved host, which since #34683 puts the app in serve-only: the WSL hosts section still lists the host. Assert instead that Add is hidden and the host row's menu has no move entry. Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
fe78cff1aa |
test: remove 20 low-value tests across 11 files (#37404)
* test: remove 20 low-value test declarations * test: prune allowances for removed Git profiling suite --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
5d59efc3ad |
test: remove 12 low-value test declarations (#37391)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
5c27709ca3 |
test: remove 21 low-value test declarations (#37373)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
5467bf3d25 |
fix: preview remote HTML outside registered workspaces (#36791)
* fix: preview remote HTML outside registered workspaces * fix(terminal): keep HTML from hosts without re-grantable files in the editor * fix(doc-preview): check outside-workspace reads by host-canonical path and page large workspace assets * fix(doc-preview): check approved folders for workspace assets of outside documents * test(e2e): read the preview guest without a type assertion * test(e2e): explain the outside-workspace preview timeout * test(doc-preview): type the pinned grant target in the share test --------- Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> |
||
|
|
a82538c3be | refactor(runtime): organize session records and runtime modules (#37070) | ||
|
|
ec0d3cedd1 |
Plugin panels talk to their worker; panel storage, settings and agent events (#37013)
* feat(plugins): panels talk to their own worker, read storage, settings and events
- plugin.request (host API 1.2): a panel or editor asks its plugin's worker, which answers with
orca.panels.handle(name); the worker pushes with orca.panels.post. Same plugin only, JSON
checked, 1 MiB answers, 256 KiB/200-per-10s posts, a deadline and the panel's lifetime.
- Panels and editors get storage.*, settings.* and secrets.* behind the same capabilities, and
storage/settings onDidChange on every surface; events.subscribe delivers workspace and agent
events to panels that hold the read capability.
- contributes.settings: typed settings (a JSON Schema subset) with defaults and value checks.
- Frames get orca.plugin/storage/settings/secrets; components panels import plugin, storage,
settings, secrets from 'orca', and atom(key, init, { persist: 'storage' }) shares a value with
the worker. Workers get orca.panels/storage/settings/secrets sugar.
- One typed contract: declare module 'orca' { interface PluginRequests / PluginPanelEvents }.
- Desktop push channel per open panel session (plugins:openPanelPush).
* feat(plugins): Orca Settings shows and edits a plugin's contributes.settings
The plugin page lists declared settings with Orca's own controls (switch, picker, text and
number fields, Reset to default). Edits are checked against the declaration in main, written to
the plugin's settings, and reach open panels and the running worker through onDidChange.
* docs(plugins): hello-tsx talks to its worker; authoring guide covers panels, workers and data
The example now uses one of each: plugin.request answered by orca.panels.handle, a worker post
heard with plugin.on, a persist: 'storage' atom the worker watches, two contributes.settings and
agent.status.changed in the panel, all typed by one src/protocol.ts. The build-less TSX e2e
drives the whole loop.
* fix(plugins): typed bridge overloads, panel call budget, settings IPC and catalog keys
- PluginBridgeApi/PanelsApi use overloads: declared names are typed (and complete), any other
name carries JSON; no never-unions for the type-aware lint.
- The per-plugin panel call budget is 120 per 10 s, since a panel loading storage atoms,
settings and its first requests makes a burst; the hostile fixture floods past it.
- Settings IPC builds its host per call; the settings section's strings are in en.json.
* test(plugins): the example's declared settings show under the plugin with the person's value
* refactor(plugins): keep hello-tsx the minimal starter; the bridge demo is hello-worker-panel
hello-tsx goes back to a sandboxed-ui panel with no worker or capabilities. The worker, protocol,
storage atom, settings and events move to examples/plugins/hello-worker-panel, with their own
e2e (plugin-worker-panel) and PR route.
* feat(plugins): test kit covers the panel bridge and plugin data
mockHost keeps the plugin's storage, settings and secrets in memory (seeded with storage,
settings, secrets; read with host.data()) and fakes the worker with requests, so plugin.request,
storage/settings/secrets and persist: 'storage' atoms work under mount(), writes reach
onDidChange, and panel.post(event, payload) is what plugin.on hears. Typed by PluginRequests and
PluginPanelEvents.
* test(plugins): focusInGuest waits for the guest and retries focusing as one step
Under load the custom-editor guest could still be attaching, so executeJavaScript threw
'dom-ready' before the focus poll began. Wait for waitForGuestReady, then retry focusing the
webview and the element together, tolerating a guest that is still attaching or remounts.
* docs(plugins): the authoring skill covers panels, workers and data; persistence leaves the renderer
- skill-guides/orca-plugin-authoring.md gains Panels, workers and data (plugin.request/on,
orca.panels.handle/post, persist: 'storage', contributes.settings, panel events, test kit), and
its generated references read orca-services.d.ts for shell, files, on and the bridge types.
- After the dev-loop rebase, persisted-atom wiring (queue plus storage sync) moves to
createDeclarativePersistence so the renderer stays under max-lines.
* feat(plugins): panels show agents: agents.list, terminal ids on agent events, workspace.changed
- agents.list (agent:read, every surface): the focused workspace's agents with terminalId,
title, agent kind, state and stateStartedAt, from the hook server's store.
- agent.status.changed carries terminalId and title: paneKey mapped through the runtime's
terminal list (tabId:leafId) or the status's terminal handle; looked up only while a plugin
listens, in arrival order.
- workspace.readContext terminals carry title; workspace.changed (workspace:read) fires after
workspace session writes when the focused workspace or its terminals change.
- Event subscriptions are kept per panel session, so one made before the push channel opens
still counts.
- shell.openExternal never prompts on a hidden or minimized window: it settles
{ opened: false, reason: 'consent-unavailable' } and says so in the plugin log, which also
notes 'waiting for the person to confirm' while a prompt is up; the rate budget is spent only
when Orca acts. e2e launches never open a real browser or mail client.
- A worker may export activate as default or by name; docs, typings and the authoring skill
document the entry, the agent events and a live agent status recipe.
* fix(plugins): the plugin page names the workspace.changed subscription
* fix(plugins): workers activate only by default export, and say so when it is named
Orca calls the worker module's default export. A module with a named `activate` and no default
now fails to start with an error naming the fix (`export default function activate(orca)`),
instead of being called by a fallback; docs, typings and the skill say default export.
hello-worker-panel gains a picker setting (suggestionOrder) the worker reads.
|
||
|
|
89f9ce08de |
refactor(shared): organize session contracts and projections (#36979)
* refactor(shared): organize session contracts and projections * chore: tighten dropped-path flaky pattern allowance * docs: preserve current agent instructions with valid formatting |
||
|
|
57454e6d7e | refactor(agent-session): group lifecycle records and direct owners (#36909) | ||
|
|
abbbdd7714 | feat(plugins): isolated plugin frames, off by default (#36813) | ||
|
|
7d76028a5c | refactor: group agent session journal and request modules (#36882) | ||
|
|
7e2f29aaf1 |
Open native chats on the phone in place (#36315)
* Open native chats on the phone in place * Preserve desktop host and agent when opening chats * Preserve chat opening and captured lifecycle contracts * test: cover sender focus and unconfirmed chat close outcomes * test: exercise structured worker CLI lifecycle through runtime socket * test: use checked parked mail observation in CLI integration * test: validate provider notification correlation identities * test: construct checked lifecycle and navigation fixtures * Keep cross-program session proofs in their test program * Localize mobile chat opening feedback and complete runtime contracts * Use the mocked text component identity in History feedback proof * Temporarily expose grown E2E type diagnostics * Keep E2E timer and fetch fixtures in their runtime domains * Reconcile decreased E2E wait pattern counts * Preserve live test clocks and expose remaining type diagnostics * Keep mobile session data types independent of native views * Complete structured session wire surface fixtures * Expose existing grown E2E type diagnostics temporarily * Preserve checked wire fixture tab mock signatures * Preserve worker redrive when automatic close is refused * Honor automatic close admission before settlement and retirement * test: retain History reveal and close publication race * Match automation reveal callback to activation result * Align CLI integration fixture with current settings and output * Prevent retained chats from reopening removed workspaces * Import notification types directly from their owner * Unify local removal fences for accepted worktree aliases * Keep cross-surface authority tests in the combined test project * Initialize coordinator mail test workspace ownership * Register the retained automation chat test workspace * Use checked inputs in worker start failure test * Preserve the automation test repository host literal |
||
|
|
ae09815770 |
Support automations in Orca Mobile (#31617)
* Add host-owned automations flow to mobile * fix: resolve initial mobile automation CI failures * Preserve automation target identity and mobile action state * Preserve selected automation targets through discovery and terminal launch * Cover draft reversion after uncertain automation creation * Preserve automation target and submitted action authority * Preserve selected hosts and editor operations across restored state * Refresh mobile web bundle measurements for merged routes * Fix automation history observation and catalog scaling * Fix automation mobile presentation and merged launch bindings * Refresh measured mobile bundle sweep and correct automation test inputs * Move real-module test loads to collection and consolidate imports * Use typed row access to count worktree ownership reads * Refresh selected automation history on matching host events * Fix automation contract types and merged test imports * Fix automation theme updates and committed history ownership * Update folder terminal contract fixtures for canonical host catalogs * Consolidate historical session activation fixture imports * Repair automation contract project boundaries and owner type ports * Preserve acquired automation folder owners and fix integration lint * Retain terminal pane owners captured at connect * Use checked pane manager context in owner retention test * fix: adapt merged editor and terminal test contracts * fix: preserve captured automation targets and terminal owners * fix: honor explicit automation source clears and refusal contracts * test: construct terminal transport mocks with checked types * test: supply retained-owner context in terminal fixtures * test: align terminal fixtures with callable mocks and store ports * fix(mobile): localize automation screens and run details * fix(mobile): use automation translations in context * fix: preserve editor owner checks and automation repair guidance * fix: reconcile captured workspace contracts after main sync * Repair automation integration tests and retained target diagnostics * Keep test support owned by registered unit roots * Expose full blocked automation run reasons in menus * Anchor mobile bundle envelope to measured route sweep * fix(mobile): localize coded automation run failures * fix: preserve automation decisions and captured resource ownership * fix: qualify remaining automation workspace owner consumers * fix: preserve resolved watch and child editor owners * fix(editor): share qualified worktree watch ownership * fix(editor): reuse immutable repo ownership lookup * fix: preserve host ownership without duplicate catalog scans * fix: align automation destination host types and ratchets * fix: align mobile bundle envelope with measured sweep * fix(mobile): resolve automation setup policy before save * test(mobile): qualify reconciled automation target inspection * fix(mobile): keep server setup consent within its authority * fix: accept narrow qualified workspace owner snapshots * fix: reuse qualified owner state for workspace directories * fix(mobile): localize known automation orphan reasons * Correct automation controller and Chat harness types * Refresh editor requests after paired host restart * Refresh measured mobile web bundle envelope |
||
|
|
76cf164cf9 |
Chat UI leaves Experimental: each agent's Chat or CLI choice decides what opens (#36110)
* Chat UI leaves Experimental: each agent's Chat | CLI choice decides launches Remove the experimentalNativeChat switch and every gate on it. The Chat settings page, Default Agent Chat | CLI choice, + menu Chat/CLI rows, source-control surface choice, Antigravity chat section and orchestration chat-error switch are always present. What a new launch opens comes only from the per-agent choice (no saved choice opens a chat) plus the existing support checks. - One lookup, nativeChatPreferenceFor, keyed by agent id so host-registered agents read the same way; unreadable settings still open a terminal. - A relayed desktop stamp (nativeChatDefault) maps onto the launched agent; an explicit surface still wins. Old phones' createSupport keeps admitting by the host's per-agent choice. - settings.get stops publishing the retired switch keys; nothing in the repo reads them from a host. - Startup chat sync and hydration run when some agent can open as a chat or the machine already holds chats. - The retired key is stripped on load. The one-time upgrade tip from the chat upgrade is retired with its audience record; a new record, captured once from the raw profile, marks which existing profiles had Chat UI off. - The window-side AI-button tab path, which only ran with the switch off, is deleted. * Keep profiles that had Chat UI off on the terminal Existing users who never turned Chat UI on would otherwise see new agent launches open as chats, since an agent without a saved choice now opens as a chat. The one-time load step that records the new audience also sets every known agent to CLI for those profiles, in the same save and only when the record was absent, overwriting saved chat choices the old switch masked. Profiles that had Chat UI on and new profiles are untouched. Browser profiles keep their own settings, so the web client does the same once: a stored switch that is not on seeds CLI choices, and dropping the key marks the step done. Agents first seen after this step open as chats. * Agents without a saved Chat | CLI choice open as their CLI An agent with no saved choice now opens in the terminal for everyone, including fresh installs and agents first seen later. The one-time load step carries what launches opened while Chat UI was experimental: with the switch on, every known agent without a saved choice is saved as chat; with it off, chat choices the switch masked are saved as CLI. Existing profiles join the launch tip audience whether the switch was on or off. Browser profiles get the same carry from their saved key. The startup chat restore and host agent list now run only when some agent is saved as chat or the runtime holds chats. * Preserve owned terminal launches and local chat choices * Clarify chat and terminal support * Explain worker CLI integration timeout budget * Use checked annotations for chat graduation test fixtures * Store agent surface default separately from per-agent overrides * Preserve explicit Chat intent across default changes * Preserve current browser settings during host replies * Correct browser settings factory and regression types * Name exported launch fixture mock types and clarify agent defaults * Preserve settings fallbacks and complete launch test lifecycles * Check allocated tab identity before launch fixture interpolation * Register combined integration project for compiler parity probes * Use checked settings in the launch test fixture * Preserve retired Chat preference data privately * Align chat E2E fixtures and capture pane lifecycle evidence * Use typed raw settings in retention contracts * Consolidate transcript diagnostic imports * test: align chat fixtures with live pane and native menu contracts * test: capture relay tab selection loss diagnostics * test: wait for owned shells before synthetic chat fixtures * test: preserve all-host visibility in SSH observer * test: bind synthetic transcript fixtures before provider seeding * test: assert selected chat owner after narrow image preview * ci: allow fifth compiler project to complete comparison * Type the web-terminal fixture's chat map without an assertion * Right-click the selection itself in the chat copy spec |
||
|
|
8c777ea465 |
plugins: tell once when an automatic update waits for your review (#36462)
* plugins: tell once when an automatic update waits for review When the auto-updater holds back an update because it asks for more access or moved repository, show one toast per plugin version (grouped when several wait). Review opens the existing per-plugin update review or the Updates list; it never installs or approves. Told versions persist across restarts, kill-listed plugins are skipped, and the copy is protected from language packs. * test(plugins): wait on the update pass instead of sleeping in the review toast e2e |
||
|
|
a1f7f97671 |
Orchestration v3: coordinators end their turn and Orca wakes them (#36137)
* fix(orchestration): keep a terminal's mail from being consumed by another terminal, and let settled structured workers take further tasks A plain orchestration check consumed the named terminal's mail whatever terminal ran it, so a coordinator checking a worker's handle took the worker's message. A consuming check from a terminal whose own live pane is a different terminal's is now refused; --peek and --all still read it without consuming. worker-start --terminal and dispatch --inject routed a structured worker (structworker_ handle) as a terminal and failed with terminal_unsupported_for_agent_session. Any agent-session party now takes its task as a send into its session, while a structured worker keeps the pane and process authority its first Dispatch had. * fix(orchestration): fence check by live terminal incl. acks; defer injecting structured workers Review fixes for the mail fence and structured worker reuse: - The check fence compares the caller's and the mailbox's live terminal process instead of recorded panes, so exited terminals keep the old behaviour and two processes sharing a recorded pane are told apart. It also covers --ack in every read mode. The caller lookup is shared with the lifecycle caller fence. - dispatch --inject to a structured worker stays refused as before: an injected Dispatch takes no custody, so releasing the first Dispatch could close a session working on the second. worker-start --terminal reuse transfers custody and stays supported. - worker-start decides pane-less chat authority from the resolved party and passes the session down, so delivery and next commands no longer re-derive it from the address spelling. - Receipts name an agent session, not a chat. * fix(orchestration): an exited caller's env pane names no caller The caller lookup fell back to the env pane key whenever the env handle was not live, so an exited terminal's pane resolved to whatever terminal now occupies it, and a tmux worker's own check was refused. The pane fallback now applies only when the env handle is not proven exited. * fix(terminal): keep surviving terminals streaming to main after a restart Main now attaches every live local daemon session it adopts at startup, not only ones a window pane or remote view is showing, and re-attaches after a daemon endpoint drop. The attach snapshot seeds main's screen, tail and title, and an attached-but-silent agent gets an output clock so readiness can see it has gone quiet. Waits on a survivor main could not attach fail at once instead of timing out. * fix(terminal): restore only pane-less streams after endpoint loss; one attach state - Endpoint loss re-attaches in main only sessions no renderer view reports; a pane restores its own. - The attach hide skips views mid-attach and leaves a pane's own hidden claim alone on failure. - One per-session stream state (attaching, attached, lost) replaces three sets and is forgotten on exit. - Waits retry the attach before failing, including after a failed re-attach. - The output clock starts wherever a reattach result is seeded, so pane reattaches get it too. * refactor(terminal): attach survivors at inventory adoption only; waits on unattached survivors fail at once; one ptyId output clock * test(e2e): scope the restart attach spec's terminal listing to the unopened workspace * fix(terminal): narrow survivor attach: waits behave as on main, one quiet clock per generation, keep main's hidden mark on failed attach * Teach the orchestration guide when to hand off and to end the turn after dispatch * Rewrap a messaging reference line * Keep the original placement default and skill trigger; keep the accuracy fixes * Point DAG retries at --retry-of and drop the last blocking-wait instruction * Check the served orchestration guide by its new worker heading * Apply council review: best-effort wake, full completion rule, restored safety rules, fixed scope and settled wording * Say when the orchestration skill applies, and prefer own subagents otherwise * Name the polling, steering, checkout, and worker fan-out habits to avoid * fix(orchestration): wake a coordinator whose turn ended while its program still reports working Claude Code keeps its OSC 7501 report on working while an agent-teams teammate is alive, even after the lead's own turn ends. The mailbox gate, idle edges and tui-idle all read that report, so worker mail was stored and never typed. A hook turn end newer than the program's working report now counts as rest; hook rows re-classify the PTY so the existing idle edge delivers. Agent Teams panes now join their claude hook rows. * fix(orchestration): compare the lead's own turn end, not the row's receipt A child's hook restamps the row's receivedAt while the lead's turn is still the old one, which could mark rest under a newer program working report. Use the lead's turn-end stamp on this runtime's clock, after the latest input. * feat(orchestration): a consuming check marks the batch it returns as handled * Say why watch scripts and open waits block the wake * feat(orchestration): release settled workers automatically after a grace period * fix(orchestration): use checked row reads for delivery cursors * fix(orchestration): trust a live own-process turn end instead of comparing clocks Drop programActivitySince and the turn-end clock mapping: replays and SSH host clocks made the comparison unreliable. A Claude lead counts as at rest under a program working report when its hook turn end is a live transition from this pane's host and launch, past the existing input and respawn floors. * test(orchestration): drop cast in ack no-op check * test(orchestration): seed legacy outstanding batch for held chat nudges * test(orchestration): built CLI check hands its batch over * test(orchestration): annotate unchanged casts and stub the keep item in tab menu tests * fix(orchestration): let real input, explicit release and host releases converge with automatic release - Record worker takeover at the owning runtime when it accepts UI input, before the bytes reach the PTY. - Run remote attachment releases through the same per-resource single-flight as local ones. - Apply the confirmed-release home projection when host observation reports a host-side release, and carry the host deadline in fleet snapshots. - Prove restart recovery with a file-backed database reopened by a fresh runtime. * test(orchestration): classify the keep RPC's worker fields instead of counting methods * fix(orchestration): checked delivery reads and observer and recovery help * refactor(orchestration): end a check when it hands over a batch; wake rides the wait result * fix(orchestration): refuse an automatic close after real input, join remote releases, converge the home - An automatic close checks the terminal's last driving-input time right before closing and keeps a worker someone typed into after worker_done; typing itself does no orchestration database work. - Remote releases share the per-resource single-flight with local release, so a home worker-release joins the host timer's close. - Host fleet snapshots and federationShow report released and the pending deadline; the home applies the existing release projection inside its observation fence. - Real restart tests: a file-backed database reopened by a fresh runtime releases a missed deadline once and finishes interrupted requests. * fix(orchestration): receipt a shared wake batch on arrival and report the applied Run ack * fix(orchestration): deliver the wake to a working coordinator; agents queue mid-turn input The wake was typed only into a live idle pane, so a Claude lead whose program status stayed working (teammate alive) never got it. Agents queue or steer text typed mid-turn, so a pane takes mail when live idle or working; dialogs, permission prompts, exited agents, unsettled panes and cold-parked Enter still hold it. Drops the held-batch Enter deferral and the per-turn-end hook logic. * fix(orchestration): record each remote release request before joining, publish archives only through the conditional commit - Each remote release caller records its own request before joining a close under way, and the close decides on the current row, so an explicit release that overlaps the host timer clears the automatic deadline. - Remote capture publishes its archive through commitWorkerTerminalArchiveForRelease, so a retain during capture leaves no stale archive for worker-read. - Remote worker-show projects the fenced host deadline and its next action. - The input guard lives in its own module instead of the scheduler. * feat(orchestration): start a worker in one step; worker-start creates the coordinator's Run when none is bound worker-start --spec now creates and binds a Run for a root coordinator with no bound Run, through the same path run-create uses, and names the Run it created or joined in every receipt. Workers on a Dispatch keep starting helpers in their own Run and never get a new one. A new CLI against an older runtime runs run-create and retries; old CLIs need no change. * fix(orchestration): drop the older-runtime fallback; check the spec before a Run is created The CLI fallback matched a refusal text the client decorates, could not prove the caller was a root coordinator on an older runtime, and recovered an inner run-create under the worker-start command. Older runtimes keep their refusal and the guide says to run-create first there. The prompt budget check now runs before worker-start can create a Run. * Route report-back requests to coordinators, complete the steer command, and label the wake loop branches * Say workers are done only when worker_done confirms, wait for helpers to settle, and let bare-shell workers exit * Route report-back requests away from handoff and steer supervised workers through their mailbox * docs(orchestration): teach auto-handled check, retry-request and inbox recovery in the guides * Describe the mid-turn wake in the messaging reference * docs(orchestration): say terminal workers are released 2 minutes after worker_done - The guide's Completion section, the reuse recipe and the recovery reference now describe the automatic release and its autoReleaseAt deadline: reuse or worker-retain before it; explicit worker-release still works and is required for chat workers and workers without a deadline. - The worker preamble says the terminal stays available until Orca releases it, about 2 minutes after worker_done unless retained. - Regenerated the bundled guides. * feat(orchestration): receipts say when to end the turn * feat(orchestration): tell the coordinator when a worker stops without worker_done * test+docs: worker stop reports * fix(orchestration): judge the empty-check stop with execution-host verdicts * test: drop casts from worker stop tests * Say that report-back requests still mean end the turn * Say that report-back requests still mean end the turn * fix(orchestration): stop reports wait for children, keep their Dispatch, and relay intact * fix(orchestration): a stop belongs to the Dispatch active when it was seen; restored stamps announce nothing * fix(orchestration): never say to stop while a remote worker runs * Shrink the orchestration guide to the end-state workflow * fix(orchestration): stop reports quote the agent's last words, or the screen for errors and prompts * fix(orchestration): withhold the stop while chat failure mail is off * test: a clean finish quotes the agent's last words * fix(orchestration): stop asking workers for heartbeats Workers are no longer told to send periodic heartbeats. A heartbeat that still arrives from an older worker or peer only records last_heartbeat_at: it is stored already handled, so it never lands in a coordinator inbox and never wakes a coordinator or a check --wait. Removes the stale-heartbeat warning and the heartbeat interval plumbing that only fed the preamble. * fix(settings): remove the worker heartbeat controls The Worker heartbeats switch and Heartbeat interval field only changed the worker preamble text, which no longer mentions heartbeats. Saved values are dropped on load as retired settings. * fix(orchestration): wake a coordinator that reports program status but never sets a title Program status only re-classified a pane that had a title, so a titleless agent (agy) never got a live status and the wake gate refused it. * fix(orchestration): a new Run no longer cuts a coordinator off from its earlier Run * test(orchestration): drop heartbeat-batch cases the handled heartbeat row removed * fix(orchestration): redact capabilities from a stop report's quoted output * fix(orchestration): never wake a mailbox for a heartbeat One rule at the runtime notification entry replaces per-call-site read checks, so mutation replay and federated control-mail import stay silent for heartbeats too. * Shrink the orchestration references and worker preamble to the end-state workflow * Name the older-Orca bind refusal as worker-start prints it * Owner-fence test: a refused foreign ack changes nothing, whatever the worker's own check already handled * Integration: drop the duplicate consumingCheck after merging #34043 and #35293 * Integration: await the worker-start next receipt before naming its Run * Apply review round 1: drain to zero, release without auto-release, retry after stop, Run before a DAG * Apply review round 2: start ready DAG Tasks, block when no failure wake, replay sends by request ID * Apply review round 3: one receipt-based wait rule for starts and wakes * fix(orchestration): a worker stopped without reporting needs action, and stop keeps its output worker-list projected a stop-reported attempt as live, in_progress, no action. It now projects finished_unverified with a worker-read recovery until mail reaches the worker. worker-stop closed the terminal before anything archived it, so release reported the archive unavailable; stop now archives the output first. * Revert "Owner-fence test: a refused foreign ack changes nothing, whatever the worker's own check already handled" This reverts commit |
||
|
|
a68230334e |
Let automations run in Chat (#34332)
* Let automations run in Chat or Terminal through the shared agent launcher * Preserve automation targets and complete owned terminal lifecycles * Keep stale prompt projection available when recomputing * Count repeated desktop lifecycle resource cleanup * Preserve automation targets and observe committed chat work * Scope automation observation and reconciliation work to each operation * Restore automation server composition and process import boundaries * fix(automations): preserve busy chat reuse and runtime boundaries * Correct shutdown test acquisition and exported measurement types * Correct automation fixture contracts and duplicate imports * Keep Chat automations separate from Terminal execution * Preserve Chat automation intent while support loads * Resolve automation Chat validation diagnostics * Remove unused automation style directives * Make automation surface classes statically inspectable * Move automation surface styling into a toggle group variant * Correct automation launch test receipt and output fixtures * Account for pane and prompt journal reads in delivery test * Preserve admitted automation surface across save effects * Separate automation page test actions from their lifecycle owner * Complete automation route test fixture input * Reopen saved automation chats through the existing record owner * test: isolate session action fixtures and complete tab groups |
||
|
|
0a12f82757 |
fix(browser): list browser tabs restored after a restart in tab list and load them on switch (#35563)
* feat(browser): list restored tabs in tab list and load them on demand After a restart Orca restores browser tabs lazily: a tab gets a page only once the user opens it. tab list only reported tabs with a live page, so an agent in a worktree with 26 restored tabs saw one and concluded there were none. tab list now reads the tab bar from the session snapshot the renderer already publishes on every tab change, and reports every tab in tab-bar order. Tabs without a page carry loaded: false. tab switch and tab close --index resolve indexes against the same list, and switching to an unloaded tab loads it in the background first. Waking a page now also waits for its first load to finish, so the next command does not read a blank page. Headless serve keeps every page live, so it lists as before. * fix(browser): list the tab bar even when Orca has no window open With the window closed the app keeps running and its restored tabs still exist, so tab list should report them. Headless snapshots are built from live pages only, and the merge dedupes those, so dropping the window check lists nothing extra there. * fix(browser): list an id held by a live page and a client page once * fix(browser): wait for the first load of a tab headless serve wakes Headless serve starts a restored page and returned at once, so the next command could read a blank page mid-load. It now waits for the first load, as the window path already did. * refactor(browser): keep the tab listing beside the browser tab catalog Main moved the runtime browser commands into runtime/browser/ since this was written. Also drops a window lookup the catalog no longer uses, and corrects the headless note: those snapshots list saved pages that have not started yet. * fix(browser): keep paired-server mirrors out of tab list and close indexed rows like --page A window also publishes the browser tabs it mirrors from paired runtimes, which this host can never load, so the tab bar is read only for workspaces this host owns. tab close --index now closes the listed row exactly as --page does, keeping its worktree, so an unstarted headless tab is retired instead of reported closed and left saved. With nothing active, the first live page is marked current again, matching where a pageless command goes. * fix(browser): wait for first load only on tab switch, and show tab indexes from the listing Every --page command wakes an unloaded page, including the tab show a remote browser pane awaits before streaming, so waiting up to 10 s for the first load there held the stream back. Only tab switch waits now. tab show reports a tab's index from the same listing tab list and close use. * fix(browser): list restored tabs in an SSH host's bridged workspace, and reject fractional close indexes An SSH host's workspace can have no repo row on the desktop, yet its pages render in the desktop window, so the bridge's scoped workspace counts as this host's own. A non-integer --index no longer falls through to closing the active tab. * test(browser): give the restored-tabs e2e's timeout and lease wait their reasons * test(browser): read restored-tabs RPC results through the shared e2e reader Reuses the browser e2e rpc helper instead of a local Reflect.get copy, and types the listing test's snapshot rows. * fix(browser): index tab show in the caller's scope, as tab list does * fix(browser): report an out-of-range close index as browser_tab_not_found Matches tab switch, so agents can recover by re-listing. The restored-tabs e2e now asserts the raw loaded value instead of coercing a missing one. --------- Co-authored-by: fanzzzd <fanzzzd@outlook.com> |
||
|
|
b67c5254f0 |
fix(browser): agent fill, select, upload and type change the page or fail with a reason (#36263)
* fix(browser): fill, select, upload and type act on the agent's element or fail * refactor(browser): move agent key commands into their own bridge layer; fix test sender call |
||
|
|
46237aa148 |
fix(e2e): return from every path of the WSL boot guard's running-list read (#36261)
#36256 made one branch return the retry promise while the others fell through, which trips noImplicitReturns (TS7030) and turns the e2e typecheck ratchet red on main. |
||
|
|
593e1dbc60 |
test(e2e): retry a WSL terminate that never took, once, when Orca launched nothing (#36256)
* test(e2e): retry a WSL terminate that never took, once, when Orca launched nothing * test(e2e): log PTY spawns for the E9 guard and refuse the terminate retry after one |
||
|
|
2a5f6c79c1 |
test(e2e): on the real WSL lane, background work never starts the stopped distro (E9 guard) (#35590)
* test(e2e): on the real WSL lane, background work never starts the stopped distro (E9 guard) The Windows real-WSL lane opens a project inside its own imported distro, terminates that distro, and runs a window of background work elsewhere (focus/blur/reveal, workspace switches, a linked issue/PR card, Settings panes, Tasks, account switches). Every child the main process starts is logged; no wsl.exe may run anything in the distro (listings are fine), and `wsl --list --running`, watched each second, must never show it, which also catches UNC touches. Opening a terminal in the WSL workspace then starts it. A participation check fails the lane if the guard skipped. * test(e2e): actually render each Settings pane in the WSL lane's E9 background window openSettingsTarget alone only set the navigation target, so no pane mounted and none of its reads (servers, accounts, agents, integrations, CLI status, the repo pane's orca.yaml check) ran. Open Settings, wait for each pane's section to mount, then close it. * test(e2e): harden the WSL lane's E9 guard per review - process-host logs every spawn to ORCA_E2E_SPAWN_LOG when set, so the guard sees worker-thread and inheriting-child spawns (e.g. the Codex rate-limit fetch), sync ones included. - The spawn baseline is taken before `wsl --terminate`, and the running-list watcher starts right after it, so work in the stopping window counts. - A wsl.exe launch counts as starting the distro unless it names another or only lists/terminates. - The watcher is async with a 5 s timeout and non-overlapping ticks; a failed read is retried and fails the guard after three, never reads as "stopped". The recorder throws if it cannot hook, and the spawn log must be non-empty. The doc names the watcher as the authoritative assertion. * test(e2e): bound the terminate grace, keep the spawn log out of shipped runs, tolerate torn lines - The watcher forgives running reads only within 3 s of `--terminate` and before its first not-running read, which the rounds now await; any running read after it fails the guard. - Main drops ORCA_E2E_SPAWN_LOG outside e2e mode (no ORCA_E2E_USER_DATA_DIR) before anything spawns, so no daemon, PTY or agent inherits it; the log holds full argv, tests only. - readSpawnLog skips a line torn by a concurrent append. * test(e2e): no blocking wsl.exe in the WSL lane's E9 guard, and a timeline for failures The first lane run was cancelled at the 30-minute job limit while the guard step had run 25 minutes: past three 5-minute test timeouts, which only a blocked worker survives. Every wsl.exe call (setup, terminate, cleanup) is now async with a timeout, so a hung one fails the test. The guard logs a timestamped timeline (each running-list read, terminate, rounds) for diagnosis, and the job limit goes to 50 minutes for the three added runs. * test(e2e): let the setup's own WSL terminal launch settle before the terminate; 10 s grace The lane run failed with "Ubuntu was still listed 3000 ms after --terminate" in all three runs. The timeline showed why: focusing the WSL workspace in setup is a user act that opens a WSL terminal, and its launch (codex trust probe, PTY, hook relay) landed about a second after the terminate and restarted the distro. Setup now waits for that terminal's PTY and for wsl.exe launches to go quiet for 3 s before terminating. The grace is two running-list reads (10 s). * test(e2e): interleave wsl.exe launches into the E9 guard's timeline The lane saw the distro boot about two seconds after the terminate with nothing naming the launcher; each running-list tick now also prints the wsl.exe launches logged since the last one. * test(e2e): time and stack every logged spawn and main's WSL UNC touches The E9 guard printed spawns at its poll time, up to a second late, and with no caller. Each record now carries when it happened and the caller's stack, and main's fs touches of \\wsl.localhost paths are logged too, so a boot with no wsl.exe launch before it can still be attributed. * test(e2e): keep spawn-log stacks and main's fs hooks strictly to e2e mode process-host now writes the spawn log, and captures caller stacks, only when ORCA_E2E_USER_DATA_DIR is set as well, so a stray log variable in a CLI or daemon environment does nothing. The main-process fs/spawn hook refuses to install outside an e2e-mode app, and a source scan pins that no shipped code imports or installs it. * test(e2e): guard a focused WSL workspace left idle through the stop Device runs saw a stopped distro restart with its bridge workspace focused and nothing touched: the stop's own fallout re-ran renderer reads as user acts. The new case keeps that workspace focused with a folder expanded in the Explorer and Source Control shown, terminates, and idles. Shared guard helpers move to tests/e2e/helpers/wsl-boot-guard.ts. * test(e2e): capture caller stacks deep enough to reach the IPC handler * test(e2e): give the focused-idle guard's timeout bump its reason |
||
|
|
b28f54c5f3 |
plugins: make Try it do the thing instead of opening the plugin page (#35846)
* plugins: make Try it do the thing instead of opening the plugin page * plugins: address review on Try it (row's icon theme, language switch result, pending plugins) |
||
|
|
ad2cce3af3 |
feat(mobile): show a voice meter and timer while dictating, with start and stop haptics (#35500)
* feat(mobile): show a voice meter and timer while dictating, with start and stop haptics The phone meters the PCM it already streams with desktop's analyzer, now shared from src/shared, so both shells get a level without a native event crossing the page bridge. Recording start and stop tap the phone, iOS now allows haptics during input, and "Dictation inserted" only shows for live terminal input, where the text can be hidden. * refactor(mobile): keep the dictation hooks under the line cap after #35502 Moves the start tap and stop tick into useMobileDictationHaptics and shares one current-finish guard in finishDictation. |
||
|
|
edc0373fcd |
plugins: Plugin Alpha (#35470)
* i18n(plugins): drop retired plugin strings from the Portuguese catalog
* i18n: keep the empty project group in the Spanish and French catalogs
* i18n: retire translated entries for plugin strings this change rewords or removes
* plugins: syntax contributions
A plugin can contribute up to 16 syntaxes: a TextMate grammar, optional
language configuration, and the file extensions and names it claims.
Main validates every grammar when the plugin is approved (shape, scope,
size, nesting) and lists only the file associations. A language's
grammars cross IPC only when a matching file opens, and includes must
resolve inside the same plugin. Catalog releases can declare syntax.
* plugins: highlight files with plugin syntaxes
Files Orca shows as plain text use a matching plugin syntax. Its grammar
compiles once in a worker that stays warm between edits and runs under
core's per-line limits; a worker that stops reporting progress or crashes
is terminated, the language stays plain, and the plugin card says so.
Tokens reach Monaco as semantic tokens, so Monaco asks only for models
shown in an editor, keeps one request per model, and keeps painting the
previous colors, shifted by edits, until the new pass lands. Plugin
languages borrow ids from a pool of fixed Monaco languages, counted by
the editors using them; a language no editor uses moves its models back
to plain text, and the least recently used idle slots are reused first.
* plugins: Gleam syntax example pack
An official-style data plugin with the upstream Gleam TextMate grammar
(Apache-2.0, provenance and license alongside) and language
configuration. A test installs it through the production inspection and
loads it through the syntax registry.
* plugins: list themes, icon themes and syntaxes in the marketplace preview
The preview's Includes line named only language packs, commands,
shortcuts, VM recipes, panels and events, so a theme or syntax pack read
as "Manifest metadata only".
* fix(plugins): a syntax failure belongs to one revision, not the syntax id
A grammar that failed in revision A kept the plugin card flagged after revision B
replaced it. Failures are now keyed by id@revision, matching the runtime slots,
and dropped when the installed list no longer contains that revision.
* chore(plugins): format the Gleam example grammar
* plugins: import the Monaco editor API, not the full bundle, from the syntax runtime
* plugins: type the syntax engine against the Monaco API it uses
* plugins: suggest a catalog plugin for files Orca can't open
When a file shows as plain text or as a binary Orca can't display, and a
cached catalog lists a release whose fileTypes include its extension, the
editor offers it: View plugin opens the marketplace preview (never an
install), Not now hides it for the session, and Don't suggest remembers
the extension. Suggestions come only from cached, verified catalogs, skip
kill-listed releases and anything an installed (even disabled) plugin
already handles, and can be turned off in Plugins settings. A release's
fileTypes must match its manifest's syntax extensions.
* fix(plugins): scope the file-type suggestion's Not now to the file type
The editor stays mounted when its file changes, so a single hidden flag
suppressed the suggestion for the next file type too. Track which file
type was hidden instead.
* plugins: type the plugin-owned settings normalizer inputs
* plugins: update the preview-request callback ref after render, not during it
* test(plugins): smoke specs for themes, syntaxes and file-type suggestions
Three end-to-end specs join the demo and marketplace journeys:
- an app theme and icon theme apply from Settings and fall back when the
plugin is disabled;
- a plugin syntax highlights an already-open file, re-highlights it after a
grammar update, and lets go when disabled;
- a v2 catalog release with fileTypes is suggested for an unknown file,
View plugin opens its preview without installing, and Don't suggest is
remembered.
The marketplace spec's Git fixture helpers move to a shared helper.
* test(plugins): say why the file-type suggestion e2e needs a longer timeout
* test(editor): install Monaco's cancellation guard in the owner view-state test
The test mocks monaco-setup, which skips the guard production installs, so
a disposed editor's pending word highlight surfaced as two unhandled
"Canceled" rejections once plugin syntaxes added a render. The run
passed but reported errors.
* plugins: plugin app themes recolor the code editor
When a plugin app theme is active, every Monaco surface (editor, diffs,
notebook cells, code excerpts, automation prompt) uses a theme derived
from the colors the document is actually painted with: editor background,
text, line numbers, cursor, selection, current line and widgets. Syntax
colors stay the built-in light or dark ones; if text would fall below
4.5:1 or a syntax color below 3:1 on the plugin's editor background, the
editor keeps its built-in theme. Colors are resolved to hex through the
browser's own parser, so color-mix() and other CSS color forms work. The
theme is redefined when the plugin updates or the mode changes, and the
editor returns to the built-in theme when the plugin theme is deselected,
disabled or removed.
* refactor(plugins): one module per contribution point and a single points table
The manifest's contributes object, the execution-profile derivation and the
catalog type list now read one PLUGIN_CONTRIBUTION_POINTS table instead of
three hand-kept lists.
* refactor(plugins): express id and path rules as patterns
Plugin ids and relative paths now validate with a regex first, so a generated
JSON Schema can carry them as `pattern`. The predicate only adds what a
pattern cannot (reserved names, Windows device names), and a bad value
reports one issue instead of two.
* plugins: document every manifest and catalog field in the schema
Each field now carries a description, examples and the Orca release that
first reads it, and each contribution item has a named fragment id. Manifest
v2 accepts an optional $schema key for editor completion, and the catalog
gains an authoring schema built from the same field definitions.
* plugins: generate published JSON Schemas and author references from zod
pnpm generate:plugin-schemas writes schemas/plugins/orca-plugin.schema.json,
schemas/plugins/orca-marketplace.v2.schema.json and the matching reference
pages under docs/reference from the runtime schemas. A test fails when the
committed files drift, when a field lacks a description or since-version,
when a documented example does not validate, and when the schema and the
runtime disagree on bundled manifests or known-bad inputs.
* plugins: report every manifest and catalog mistake with its path
Manifest and catalog validation now lists up to eight distinct problems as
`contributes.themes[0].label: must not be empty` instead of zod's first raw
message, and rewrites parser wording (required, unknown keys, allowed
values, limits) into what the author should change.
* plugins: say which Orca a newer plugin or catalog release needs
A manifest the strict schema rejects is pre-read for engines.orca and
manifestVersion first, so a plugin built for a newer Orca reports
"requires Orca >=X (this is Y)" instead of unknown-key noise. A catalog
release whose minimumOrca is above this build stays listed but is refused
before anything is downloaded.
* plugins: version the published schemas and pin v2 fields to a real release
Schemas move under schemas/plugins/v2/ so a later breaking format can
publish beside them without changing what a pinned URL means, and the
example plugin authors copy carries its own copy for offline completion.
Fields new with manifest v2 cite one constant, PLUGIN_MANIFEST_V2_SINCE
(1.4.232, the release after the latest tag), and a test fails once a tag at
or above it ships without manifest v2. The reference documents format 1 as
legacy.
* plugins: open review when enabling a plugin that was never approved
Dismissing the review dialog records keep-disabled without consent. Turning
the plugin's switch back on then only cleared the disable, so it returned
to "Needs review" with no dialog. Enabling now opens the review whenever
the result is still pending.
* plugins: release details for the plugin detail page
Catalog releases may carry a license, repository and homepage (https only),
an updatedAt date and a short plain-text changelog; an invalid value is
dropped so it never hides the plugin. Manifests may declare license and
homepage. Marketplace listings flatten name, version and those details, and
installed plugins report license, homepage, repository and the version a
rollback would restore.
The JSON lint-staged step no longer fails a commit whose only staged JSON
files are generated schemas the formatter ignores.
* plugins: fold in the schema review
- Parity runs both ways: documented examples also pass their zod field,
bundled manifests pass both the schema and the runtime, and manifest and
catalog negatives (traversal, oversize, wrong types, duplicates) fail in
both. A table lists every rule only the runtime can enforce, and each is
named in the description of the field it constrains.
- The published files carry the format in their names
(orca-plugin.v2.schema.json, orca-marketplace.v2.schema.json); $id stays
on main until the v2 release, and a test demands the release tag once it
exists.
- The v1 since-value is 1.4.160, the first release that read plugins, and a
test pins it to the tags. engines.orca documents that format 2 needs at
least the release that ships it.
- v2 catalog sources strip unknown keys like the rest of the entry, and the
v2 runtime schema is derived from the one authoring definition, whose
plugins field documents the duplicate-id rule. Contribution types and
categories declare uniqueItems; fileTypes items come from the file-type
schema itself.
- Issue messages no longer depend on zod's English: a missing field is told
from the input, and every pattern carries its own message. Unknown-key
lists show five keys plus a count, and each line is capped at 200
characters.
- A prerelease host (1.5.0-rc.1) now ranks below its release, as in semver.
* plugins: read the rollback version on demand, not while listing
The plugin list is rebuilt at startup and on every plugin change, and each
installed plugin cost a directory read to find the version a rollback would
restore. That moves to plugins:getRollbackVersion, which the detail page
calls when it shows the action, and a test pins the list build to zero
filesystem calls.
* plugins: v1.4.232 shipped without manifest v2, so v2 fields cite 1.4.233
The release-tag check caught it: v1.4.232 was cut from main before this
stack landed.
* plugins: list installed plugins while the plugin system is off
With the system off the service discovers nothing, so plugins:list returned
an empty list and the settings page could not show what is installed. The
client list now reads the install tree on demand in that state and projects
every plugin as disabled; nothing is activated or started, and startup with
the system off still does no plugin I/O. Older clients that hid the list
while off are unaffected.
Also for the plugin page: plugins:getInstalledManifest returns one installed
plugin's parsed manifest on demand, marketplace installs report the catalog
ref beside its URL, and the listing type declares the release record it
already carried.
* plugins: final schema decisions for catalogs and versioning
Catalog
- The catalog is orca-catalog.json with a required catalogVersion: 2; a
client that sees a higher version refuses with "update Orca to browse
this catalog". New clients read it first and fall back to the frozen
orca-marketplace.json, which export-legacy-plugin-catalog.mjs generates.
- Parsing is tolerant at every level: unknown keys are stripped, unreadable
entries and releases are skipped, over-limit lists are trimmed, a repeated
id keeps the first copy, invalid display-only fields are dropped.
pnpm validate:plugin reports each of those as an error for authors and CI.
- Entries list releases newest first; Orca offers the first whose
minimumOrca it meets, and shows "Needs Orca X" only when none fits.
Versioning
- engines.orca is the only gate and must cover the newest since-version of
every field and enum value used (capabilities, events and built-in actions
now carry per-value since tables). The check is part of the v2 schema, so
validation, catalog checks and installs all enforce it.
- pluginApi is optional in format 2 (defaults to 1) and refused on data and
instructional plugins. Format 2 rejects unknown keys at every level,
including engines, author and every contribution item.
- contributes.agents is reserved for coding-agent definitions and must be
empty in format 2 until their format exists.
- Plugins are gated against the newer of the app version and the newest
since this build defines, so development and local builds, whose package
version only moves at release, read the fields they introduce.
The policy is written into the generated references and pinned by tests.
* plugins: one-click install for content-only plugins, and the verified profile on the list
installMarketplacePlugin takes an optional enableIfData. Main then turns the
plugin on in the same step only when the installed, verified manifest is
execution: data, approving exactly the fingerprint it just installed through
the normal consent path; anything else comes back needsReview: true, whatever
the renderer sends. Older hosts ignore the field and leave the plugin pending.
Installed plugins now report their verified execution profile, so the plugin
page never infers "content only" from the absence of a worker.
* plugins: images and contribution summaries for plugin pages
Manifest format 2 gains cover and screenshots (alt text required), and its
icon must be a square PNG or WebP. Images are checked at install from their
headers only: static PNG, JPEG or WebP, per-kind pixel and byte limits, at
most 4096 pixels a side and 8 MB in total, so nothing is ever decoded to
decide trust.
Catalog releases may carry images stored in the catalog repository and
pinned by SHA-256, a summary of what they add, and the capabilities they ask
for, so a listing can show the plugin completely before anything is
downloaded. All three are dropped when unreadable; the summary and
capabilities must match the manifest exactly at install. pnpm validate:plugin
checks each image's hash, size and format against the repository files.
* plugins: serve plugin and catalog images from verified bytes
Images reach the renderer only as orca-plugin-image URLs, which main serves
with nosniff and the type it read from the header:
- catalog images are read from the catalog repository at the fetched
commit, kept only when their hash, size and format match, and cached by
SHA-256; a listing references only those;
- preview images are cached by hash before the staging tree is deleted;
- installed plugins' images are named by plugin, install hash and slot and
re-checked on every read, so listing plugins still reads no files.
Listings, previews and installed plugins carry an images field the plugin
page can render without fetching anything else.
* plugins: catalog theme palettes, and one-click never approves a dev override
Catalog releases may list up to four theme palettes (hex colors only) so a
listing can draw theme cards before install; they are display-only and
dropped when invalid. One-click enable now also refuses when a development
override shadows the installed plugin, since those are not the bytes the
user just chose.
* plugins: one-click approves only the fingerprint the user saw
installMarketplacePlugin takes an optional expectedFingerprint, the
preview's consentFingerprint. With enableIfData, main now approves only
when the installed fingerprint equals it, so bytes that changed between
preview and install stay pending for review instead of being enabled. The
release commit is already pinned by resolvedCommit. Older hosts ignore the
field.
* plugins: gate manifest v2 on 1.4.242 and publish schemas under docs/schemas
v1.4.240 shipped without manifest v2, so the first release that reads it is 1.4.242.
The root-directory guard refuses a new top-level schemas/ folder.
* plugins: read unvalidated schema input through a typed object guard and break the image validation import cycle
* plugins: one place decides an installed plugin's status word
Pull the status ranking, label and enabled/needs-review checks out of the settings row so the
coming list rows and detail page read the same words. No visual change.
* plugins: one list entry shape for installed and catalog plugins
PluginListEntry joins an installed plugin to its catalog listing (or stands for a listing alone),
and matchesPluginSearch is the one search both lists use. No visual change.
* plugins: usePluginCatalog owns catalog loading, refresh and preview
Sources, listings, refresh, the install/update preview and the outside preview request move out
of PluginMarketplaceBrowser into one hook the coming list and detail page share. The browser
keeps only its view state. No visual change.
* plugins: one plugin list with fixed slots, a plugin page, and inline states
- Installed plugins first, then one group per catalog (verified/unverified · owner or URL), capped
at 6 rows with Show N more; every plugin appears once
- Rows: the name opens the plugin page and covers the row; status, action, switch and ⋯ are
fixed-width sibling slots in Tab order. Update {version} is the action when a catalog has a newer
release; Stopped offers Restart with a red mark on the switch; Blocked offers Remove…
- Plugin page in the same pane: what it adds (commands with platform shortcut chips, panels,
recipes, contribution summary), what it can access, logs, and info. Back link, Alt+← or ⌘[
return focus to the row
- States inside the list: skeletons, a catalog that fails only affects its own group, no results
with Clear search, nothing installed. Plugins off keeps the installed list visible, dimmed
- Add plugin ▾ (folder, Git URL) replaces Install plugin; Plugin system stays at the top
- Catalog listings now expose their release (name, version, minimum Orca, types) to the renderer
* plugins: filter by category and catalog, one review for Update all, Needs newer Orca
- Filter popover (category, catalog) next to search; search and filters show every match
- Update all opens one review: updates that ask for new access are expanded with what's new, the
rest are one line, any can be unticked; installs run one at a time
- A catalog release that needs a newer Orca says so and disables Install, in the row and the page
- Installing from a plugin page shows a review with only access and source, since the page just
showed what it adds
* plugins: plugin page uses the manifest name; Off status word; official isn't a category
* plugins: catalog sources live in the Add plugin menu
* plugins: search takes its own row when the list is narrow
* plugins: release notes, license and links on the plugin page; roll back names its version
* plugins: fix list review findings
Plugin page owns the pane (back link and plugin header only); Adds to Orca names
every contribution; access never reads as 'nothing' when the check failed; filter
kinds have readable names; Update all is reachable, fetches once per open and
routes updates needing review; installed plugins join their own catalog;
attention-first order; paused list while plugins are off.
* plugins: readable category names on the plugin page
* plugins: Update all keeps its set; reviews queue; updates only from the plugin's own catalog
* plugins: name what an off or unreviewed plugin adds from its manifest; join catalogs by url and ref
* plugins: Needs Orca checks use the version plugins are gated against
Main gates plugins on pluginHostVersion, the newer of the app version and the
newest since-version the build reads. The plugin page compared releases to the
raw app version, so a development or local build showed Needs Orca for plugins
it would install.
* test(plugins): e2e journeys follow the redesigned plugin list
The page offers "Turn on plugins" while the system is off, catalog rows share
the installed rows' data-plugin-key, the review action is "Review", and an
enabled plugin reads "On".
* plugins: describe access from the verified execution profile, never from "no worker"
A commands-and-shortcuts plugin's page said "Content only. It has no code that runs."
because the page treated "no worker" as "no code". A worker plugin without capabilities
read "runs in a sandbox". The page now classifies from the catalog release's execution
profile (install refuses bytes whose manifest differs), the fetched manifest, or the
installed manifest's profile from the plugin list's `execution` field. Unknown stays
"Reading…" or "Couldn't read", never content only. The review dialog uses the same
profile, and an older host that omits it is reviewed as instructional.
* fix(plugins): read revision-scoped syntax failures on detail pages
* plugins: use the Blocks glyph for icon themes in the plugin page
* plugins: update latest-value refs after render in the update dialog and page navigation
* i18n: retire translated entries for plugin strings this change rewords or removes
* plugins: one action to install, inline consent, and a picture-first catalog
Settings > Plugins no longer opens a confirm dialog and then a review dialog.
- Content-only catalog plugins install from their card or page in one click; main
turns them on only when the verified manifest is data. Undo stays in place for 10s.
- Plugins that run code or instructions show "If you install <Name>, it can:" on the
host security surface above one Install & enable, which stays off until the access
rows are read, and approves exactly the fingerprint shown. Review of an installed
plugin happens on its page too (Enable / Keep off); Remove stays in its menu.
- The catalog is a grid of cards drawn from what each plugin is (its theme colours once
installed, a code sample, keycaps), with the name as a stretched link and one action.
- The page pins the listing it opened, says "Newer version available" instead of
swapping rows, and previews are prefetched only on hover intent, capped per visit.
- The plugin system switch, file suggestions, catalog sources and development folders
move into a header menu; amber text uses a contrast-safe token.
* plugins: give the reworded no-access line its own key so English shows the new copy
* plugins: pin installs to the release shown, warn by what a plugin carries, disclose replaced shortcuts
- The page pins the listing it opened; a preview of any other release (commit, catalog
commit or execution profile) leaves Install & enable off and shows "Newer version
available". One-click installs from a card refuse the same mismatch.
- Warnings are the union of the verified profile and the contributions: a panel that
also adds commands gets the instructions warning, never "bounded" or "own files only";
unknown contributions over-warn. Access rows follow the same rule.
- Shortcuts that replace one of yours are named in the consent before install, from the
manifest or the catalog summary; the shortcut list itself stays in Adds to Orca.
- Pages paint from the catalog summaries, capabilities and theme palettes, and show the
cover (or the card's art) as a hero, with screenshots in a strip and lightbox.
- Installing fills a reserved status line and keeps its action row (Undo, Use now), so
the page doesn't move; the settings scroller keeps a stable gutter.
- Row art names the plugin type instead of initials, rows drop the "Needs review" word,
the content hash moves into the menu, and card art is tinted and coloured.
* plugins: catalog covers on cards
* plugins: Review reopens its page after Back; hero art and stable status line follow what an installed plugin carries
* test(plugins): e2e journeys review and install on the plugin page, with no dialogs
* plugins: install exactly the release shown, classify from the full manifest, polish the page
Code review:
- A page or card arms Install only when the preview matches everything the listing showed
(catalog commit, release commit, content hash, execution); any change, including a
catalog-only refresh, reads "Newer version available". One-click installs send the
preview's fingerprint as expectedFingerprint, so main turns on only those bytes.
- Install stays off while a catalog refresh is in flight.
- Trust uses the full verified preview manifest when present; a capped catalog summary
counts as unknown and gets the stronger warning.
- The installed-manifest read is keyed by plugin and installed revision, so a same-key
update never pairs old contents with the new fingerprint.
- A failed Undo shows its error on the card or page and keeps Undo to retry.
- The security-surface test now covers the inline consent instead of the removed dialog.
Visual:
- Lightbox: close button clear of the image, "1 of N" with previous/next and arrow keys,
content scrolls on short windows, focus returns to the opening thumbnail.
- Keycap art shows the plugin's own first shortcut, larger, with the platform's keys.
- The hero fills the content column; a screenshot identical to the cover isn't repeated.
- "Change in Shortcuts" is a link; the chip says "Adds commands" (or "Runs a worker",
"Adds a panel", "Content only"); the disabled button says "Reading what it can access…".
- A content-only plugin's action row keeps fixed slots, so its note doesn't move on install.
* plugins: keep the decision above the fold, route suggestions to the page, final review fixes
- The page shows the decision (Install, the consent, Enable) before the picture, and the
picture is capped and cropped from its centre, so the button is in view at 1280x800 and
900x700. Nothing grows after first paint.
- The consent gives no access verdict while the plugin is still being read.
- A file-type suggestion opens the plugin's page instead of the old install dialog; that
dialog now serves updates only.
- A theme plugin reserves its "Use now" line from first paint; the action slot and its
button share one width.
- The file-suggestion toggle reports a failed save; a failed Undo is reported once, on
the card or page that offered it.
- Cards show a plain trust chip ("Content only", "Adds commands"); the local and bundled
group reads "Bundled & local".
- Install error copy moves into the protected plugin namespace, and the new consent
components join the language-pack security pins.
- Dead code goes: the keybinding consent preview (its conflict helper stays), its strings,
trustRunsNothing and the access-only preview plumbing.
* test(plugins): the file-type suggestion opens the plugin page, not a dialog
* plugins: the install decision sits top-right beside the name; no plugin on/off switch in the UI
- Plugin page: Install (content only), Install & enable (disabled until its access is read),
Enable / Keep off (installed, waiting for review) and the installed switch share one slot
top-right of the title. The consent sits directly under the header with no button of its
own; the "Can't reach anything outside its own files" note sits on the line under the
publisher, which every state reserves, so nothing moves between states.
- Removed "Turn off plugins" from the ⋯ menu and the "Turn on plugins" button from the off
state. The setting and all gating stay: off now comes only from policy, and the page says
so without a switch.
- e2e journeys turn plugins on through the setting and use the page's one button.
* plugins: restore Turn on plugins, drop Undo, add Remove to installed card menu
Plugins stay opt-in, so the off state keeps its Turn on button; only the
menu's Turn off item stays removed. Installed catalog cards get a sibling
more-actions menu with Remove (immediate, inline error) and Turn off/on,
inside a fixed-width action slot so the footer doesn't shift.
* test(plugins): installing a theme plugin never changes the active theme
* fix(plugins): confirm card removal before deleting data
* fix(plugins): pause review queue when leaving plugin page
* fix(plugins): disclose execution changes before updating
* refactor(plugins): share single and bulk update review
* refactor(plugins): share installed card and row actions
* test(plugins): cover confirmed removal and shared update review
* feat(plugins): offer icon and terminal themes after install
* test(plugins): capture settled review dialog screenshots
* fix(plugins): make installed contributions discoverable and actionable
* fix(plugins): label card-install toast Try it and mark terminal-theme Use now buttons
The toast action opens the plugin page rather than applying a theme, so it
always says Try it. Terminal themes often share their app themes' names, so
their Use now buttons carry a terminal icon. Update the update-review e2e for
the Use now accessible names.
* fix(plugins): apply a theme plugin's themes when the user installs or enables it
Installing (card or page) or enabling a plugin that adds themes now applies its
app theme (matching the current light/dark mode), icon theme and terminal theme
at once, with a 'Now using' toast whose Switch back restores the previous
selections. Updates, startup discovery and catalog refreshes never apply.
Co-Authored-By: Claude <noreply@anthropic.com>
* plugins: call toast actions through a typed button in tests; key card art by stable names
* i18n(plugins): drop retired plugin strings from the Portuguese catalog
* test(plugins): say why the update review e2e needs a longer timeout
* i18n: retire translated entries for plugin strings this change rewords or removes
* refactor(plugins): organize main plugin files by responsibility
* refactor(plugins): group shared plugin schemas and contracts
* refactor(plugins): organize renderer plugin surfaces
* plugins: keep the plugin service under the line limit after the folder moves
* refactor(plugins): move the JSON object guard beside the manifest schemas
* test(plugins): move the flaky-test baseline entries with the worker tests they count
* test(plugins): point the panel lifetime test at the reorganized plugin folders
* plugins: reserve skills, mcpServers, taskSources, connections and settings contribution keys
Format 2 accepts each key only as an empty list, so the points can ship later as additive
minors without a new manifest format.
* plugins: freeze host API v0 with a generated reference and refuse unknown pluginApi majors
The method table now carries a summary and an optional deprecatedSince, and renders
docs/reference/plugin-host-api.md with the stability and deprecation policy. A manifest
naming a newer host API major fails with "update Orca" instead of "must be 1".
* plugins: name the bad release in catalog validation and re-ask on any execution profile change
validate:plugin now reports each unreadable release with its reason (for example a tag
instead of a full commit SHA) rather than a count. The consent fingerprint includes a
declared non-data execution profile, so a data pack that becomes instructional no longer
keeps its one-click approval. Tests pin that catalogs drop non-SHA releases, that a
repository cannot load or approve a plugin it carries, and that added capabilities or a
changed profile always need re-approval.
* plugins: add the author guide, theme token list, v2 examples and a printed catalog release entry
docs/reference/plugin-authoring.md walks write, load a development folder, validate and
publish. The theme token table is generated from the public token set and its fallbacks.
hello-orca and hostile-panel move to manifest format 2. validate:plugin on a plugin
repository root materializes HEAD the way install does and prints the release entry to
paste into orca-catalog.json.
* plugins: name the host API type renderer and reserved contribution fields for their role
* plugins: gate the bundled example plugins on 1.4.240
* plugins: reserve orca, orca-*, official, anthropic, openai and github publishers
* plugins: rename storage/secrets to storage:own/secrets:own and gate events by domain capability
events:subscribe and the events.subscribe host method are gone; workspace events need
workspace:read and agent status needs the new agents:read. Format 1 manifests keep their old
names, rewritten on parse.
* plugins: move samples and fixtures off the now-reserved orca-samples publisher
* plugins: name the public surface workspace, not worktree
Events become workspace.created/removed with workspaceId and a kind field, agent status
carries workspaceId, and command context/keybinding when use workspace. Format 1 names are
rewritten on parse, v1 workers still receive worktree.* handlers, and clients treat any
non-global context from older hosts as workspace-scoped.
* plugins: rename the instructional execution profile to declarative
* plugins: move agents into the reserved contribution keys
Format 2 keeps contributes.agents empty like every reserved point; format 1 entries, which
Orca never read, are dropped on parse so they stay inert and bind no content.
* plugins: skip unknown theme tokens and icon slots at runtime, refuse them in validate:plugin
A token or slot added in a later release no longer fails the whole theme on older Orca.
validate:plugin now parses each theme, terminal theme and icon theme strictly. App themes
accept an optional schemaVersion 1.
* plugins: inject panel design tokens as --orca-* custom properties
* plugins: accept a closed, documented list of panel icons
Format 1 panels keep any icon name: a known one in either Lucide spelling is canonicalized,
an unknown one is dropped and shows plug, as before.
* plugins: make catalog release types optional and derive them
Every required release field is permanent for old clients, and types repeat what contributes
and execution already say. Printed release entries no longer include it.
* plugins: strip unknown kill-list and consent fields instead of refusing them
A strict kill list froze old clients on their cached list as soon as a later list added a
field, silently stopping revocation; a strict consent request would refuse a newer client's
optional review field.
* plugins: check only the shape of a panel action in the renderer
The host's capability gate already refuses methods panels may not call. Filtering against the
client's own method list blocked every panel method a newer host added on older clients,
including remote and SSH ones.
* plugins: read a leading >=x.y.z from engines.orca leniently in the compatibility pre-read
* plugins: derive content-bound approval from the contribution policy table
Each point now declares bindsContent, replacing the hand-kept list in the consent
fingerprint, so a new point such as mcpServers cannot swap bytes under an old approval by
being forgotten.
* plugins: name the host API "Host API 1" and add a stability section to the author guide
The guide now lists what is stable and what is experimental: the agent status payload, the
worker process model, language-pack keys, validate:plugin output beyond its exit codes,
settings:own and manifest format 1. Secrets copy now says encrypted file, not OS keychain.
* plugins: make the hello-orca sample speak in plain words
The worker command returns a sentence instead of a JSON object, and the panel labels
terminals by position instead of their opaque ids.
* plugins: give plugins short branch names, not refs/heads/...
* plugins: panels can no longer type into terminals; workers only (D3)
terminal.sendText with Enter runs shell commands locally or over SSH, which
the sandboxed-panel tier's "limited" consent copy did not convey. The
capability copy now says so, and the sample panel no longer types.
* plugins: put full-access worker plugins behind a second setting, off by default (D2)
Trusted workers are unsandboxed Node, so the plugin system switch alone no
longer lets them run. With "Allow plugins that run code with full access"
off, main refuses to install a full-access catalog release, approve or enable
one, and keeps installed workers stopped with an error naming the setting.
The catalog card says "Full access · turned off in settings" and links to
the switch; the worker chip now reads "Full access".
* plugins: bind dev-folder approval to the folder it was given for
A dev plugin's consent fingerprint now includes the folder's canonical path,
so approving one dev folder no longer approves another folder whose
manifest claims the same key and capabilities. The development dialog now
says edits inside an approved folder run without another review.
* plugins: close WebRTC as an outbound channel from panels
CSP has no WebRTC directive, so a panel could reach a STUN/TURN server it
controls despite connect-src 'none'. The panel shell now locks
RTCPeerConnection to undefined before plugin code runs, and the main window
that hosts panels gets the same WebRTC IP-handling policy as doc preview
guests. DNS-prefetch hints remain the residual doc preview already accepts.
* plugins: stop language packs relabelling trust copy outside plugin settings
Protection covered only plugin copy under settings, so a content-only pack
could rename the catalog's Official badge, the file-type suggestion banner,
or swap Allow and Deny on agent approvals. Those components are now
protected whole, the same way the plugin security dialogs are.
* plugins: refuse Git URLs with a dash-led user or host, or a '..' host
ssh reads a leading '-' as an option, and the scp form is not normalized, so
'stablyai/../evil' read as the official owner. The shared URL check used by
the catalog schema, validate:plugin and every install path now refuses these,
and provenance parsing refuses '..' path segments.
* plugins: flag an update whose catalog moved it to another repository
An update whose catalog now points at a different repository showed the new
URL without saying it changed. The update review now names the old and new
repository and leaves that update unticked, so it installs only once the
user opts in.
* plugins: sample worker returns a readable toast; sample panel shows no internal ids
Hello Orca's ping returned raw JSON, which the command toast printed as-is,
and its panel showed the full ref name. It now returns a sentence and shows
the plain branch name.
* plugins: move runtime policy checks and catalog types out of files over the line limit
* plugins: refresh the plugin safety list every 6 hours while plugins are on
Revocations previously reached a session only at launch or when plugins were
turned on, so a long-running Orca kept running a revoked plugin.
* plugins: main sends an update from a moved repository to review
The update dialog left such updates unticked, but main still accepted a
one-click approval for them. Main now compares the installed and new
repository itself and always answers needsReview.
* plugins: label the plugin system Alpha instead of Experimental
Settings badge, nav entry badge, search/description copy in all locales,
and plugin docs' stability sections. Setting keys are unchanged.
* plugins: trim the Plugin settings menu to titles and a short full-access hint
* plugins: reserve statusBarItems and sidebarCards and list planned contribution points
Both keys are rejected when non-empty, like the other reserved points. The
manifest and authoring references gain a Planned contribution points list
built from one table. Also moves the Alpha note on the host API page into its
generator so the schema/doc parity test passes again.
* plugins: an update that asks for nothing new keeps its approval
Before, any catalog update to a declarative, sandboxed-ui or trusted-worker
plugin changed its consent fingerprint (it binds the package bytes), so the
plugin turned off and waited for review after every Update. Only content-only
(data) plugins kept running.
Main now reads the approved version before installing and, when the update
comes from the same repository and adds no capability, no higher execution
profile, and no new command, shortcut, panel, event or VM recipe, records the
new fingerprint so the plugin stays on. Anything that grows access, a moved
repository, a development override or a plugin that was never approved still
waits for review, and the full-access switch still gates trusted workers.
The update preview now carries what grew, so the Update dialog lists new
shortcuts, commands, panels and events as well as capabilities. The consent
copy says updates that don't ask for more access install without asking.
* plugins: match the full-access test to the shorter setting name
* plugins: update catalog plugins automatically when an update asks for nothing new
Adds "Update plugins automatically" to Plugin settings, on by default. The
setting is pluginUpdatePolicy ('auto' | 'manual') so later policies can be
added without a migration.
At startup (after a short delay) and every 12 hours, packaged Orca refreshes
the catalogs and, for each enabled, approved catalog plugin with a newer
release, installs it in place when it comes from the same repository and
grows no access; the approval carries over and the worker reloads. A release
from a non-official catalog installs only after it has been listed for 12
hours, timed from when this Orca first saw it (stored locally because
catalogs carry no listed-at time), so takedowns can land first. An update
that grows access or moved repository is not installed: the current version
keeps running and the plugin shows "Update needs review", whose Review
update button opens the existing update review with what is new. Plugins
updated this way show a quiet "Updated to vX" chip, and each pass shows at
most one toast. Manual Update and Update all are unchanged.
* plugins: clear code-quality findings in the update approval and auto-update code
* plugins: give an app theme that leaves --sidebar unset a visible sidebar edge
Orca draws no line between the left sidebar and the main area; the sidebar's
slightly different surface is the edge. A theme that omitted --sidebar (like
the Dusk sample) had it filled from --background, so the sidebar matched the
main area and the edge vanished. An unset --sidebar is now mixed 8% toward
the theme's foreground. The in-repo sample theme sets --sidebar explicitly
and the theme smoke test checks it reaches the sidebar.
* plugins: treat an unknown update policy as manual, not auto
* plugins: auto-update only pinned releases, and only the release that was held
* plugins: start the auto-update hold clock before the catalog refresh, and check every 6 hours
* plugins: refresh the kill list right before auto-installing, and skip the install if that fails
* plugins: refuse an unpinned full-access install while full access is off
* plugins: an automatic update re-checks inside the install lock that the plugin is still installed
* plugins: compare the full repository path, so a GitLab subgroup move counts as moved
* plugins: time out the kill-list fetch and retry 15 minutes after a failure
* plugins: drop one unreadable kill-list entry instead of the whole list
* plugins: keep language packs off the orca.yaml and notebook trust prompts, certificate warning and site permission prompt
* plugins: compare whole capability declarations on update, and cover swapped command actions and shortcuts
* plugins: log automatic updates so headless and remote hosts record them
* plugins: say that automatic updates can change what a full-access plugin does
* plugins: pin and document the nested-frame WebRTC residual in plugin panels
* plugins: delete the unused PluginReviewBody
* plugins: drop the dead repositoryMoved parameter and the predecessor wrapper
* plugins: declare the plugin policy settings type once
* plugins: show what main found an update changes instead of recomputing it in the renderer
* plugins: move update approval and update policy into the catalog folders
* test(plugins): expect the workspace.removed event name in the lifecycle test
* plugins: rename structural helpers for their role, type the update identity read, and give plugin system settings their own group
* i18n(plugins): drop retired plugin strings from the Portuguese catalog
* plugins: build the hello-orca status line with a template string
* plugins: install catalog plugins from a directory of a shared repository
A catalog source may name a 'path' inside its repository. Orca downloads the
pinned commit as before but materializes only that subtree, so contentHash
covers the plugin's own files and sibling commits never change it. A changed
path counts as a moved repository and needs review. validate:plugin accepts a
subdirectory and prints its source path; the frozen v1 export skips such
entries.
* plugins: offer the full access setting on a full-access plugin's page
The page offered Install & enable even with full access off, then failed with a generic error.
It now shows the card's 'Turn on in settings' action, names the real reason when main refuses,
and drops a stale install error once the full access setting changes.
* plugins: say a content-only plugin couldn't load its files, not that it crashed
Language packs and other data plugins have no code or logs, so a load failure now reads
"Couldn't load its files" on the page and the row instead of "Its code kept crashing".
* plugins: leave Settings before running a built-in action from a plugin page
Built-in actions such as Open Board and Go Back are disabled while Settings covers the app,
so Run on the plugin page always failed. Run now closes Settings, commits that synchronously
so the dispatcher sees the app view, then runs the action.
* plugins: refuse terminal:send on panel plugins and never list it on panel approvals
Panels get no host method that types into a terminal, yet a panel's approval listed
"Type and run commands in your terminals". Format 2 manifests now fail validation when a
profile below trusted-worker asks for terminal:send, and approvals, the access section and
update review drop that line for format 1 panels that still declare it.
* plugins: say "catalog" in user-facing copy, not "marketplace"
The menu said "Catalog sources…" but the dialog it opens said "Marketplace sources" and
asked for orca-marketplace.json. Plugin copy now says catalog in every locale, names
orca-catalog.json (still accepting the older file), and the author guide matches the UI.
Internal identifiers and settings keys are unchanged.
* test(plugins): run a built-in action from its plugin page end to end
* plugins: concise copy pass across plugin UI
Update review shows one line per plugin and only what's new for updates
that need approval, with the rest behind a See all access disclosure.
Consent, Can access, dialogs, settings menu and empty states drop restated
titles and filler; safety facts (new access, full access = files/network)
stay visible where the user decides.
* plugins: keep See all access on Button and Collapsible primitives' own spacing
* plugins: separate light and dark theme slots so packs pair and mix
Plugin app themes now fill a Light theme or Dark theme slot by their base. Orca paints the
slot for its current mode, so under System it swaps live with the OS. Appearance shows both
pickers grouped by plugin; install fills the matching slot(s) and Switch back restores them.
A legacy single selection migrates into its base's slot.
* plugins: installed carousel and card grid, category badges, In use state; load language packs that cover protected copy
* fix(theme): let plugin themes colour menus and dialogs
Menus, popovers, selects, hover cards, sheets and dialogs painted a fixed
glass tint (dialogs rgb 23,23,23 in dark mode), so a plugin theme's
--popover was ignored and a true-black theme still showed grey dialogs.
The tint now lives in --floating-surface / --dialog-surface, which a
plugin theme replaces with its --popover.
* plugins: name the app-theme slot a pack fills, not its terminal colours
* plugins: page the installed row by whole cards; e2e follows the card menu
* plugins: hide the installed row's scrollbar and draw kind art instead of initials
The installed carousel pages with its arrows and snap points; the native
scrollbar under it only added a stray bar. Format 1 catalog listings (the
official catalog until catalog v2 publishes) carry no release types or
images, so their cards fell back to a two-letter monogram. Art now reads
the kind from catalog categories, and the last fallback is a plugin glyph.
* plugins: reserve official publishers to Orca's catalog and pin installs to their catalog
Reserved publishers (stablyai, official, anthropic, openai, github, orca*; case-insensitive)
and orca-* ids now install only from Orca's official catalog: a Git URL, local folder or any
other catalog is refused, and a third-party catalog listing one is refused whole. The rule lives
in one import-free module the directory indexer can vendor; validate:plugin uses it too and
warns when publisher differs from the origin remote's owner.
A marketplace install never replaces one recorded from a different catalog; switching means
remove and reinstall. Docs state the publisher == repository owner policy (enforced by the
official and community catalog CI, not a new runtime field).
* plugins: label trust by catalog source and note other catalogs listing an install
The chip beside a plugin now says where trust comes from: the Official mark for Orca's catalog,
otherwise the catalog name and the owner parsed from its Git URL (github.com/acme,
gitlab.com/acme/tools), never manifest text; Dev · unverified for development folders and
Unverified for Git URL installs. An installed plugin's page says which other catalogs list it.
* test(plugins): give update review's Git-backed steps a loaded-runner timeout
Install and update review each fetch a plugin over Git. On a loaded machine that
took 25-30s with or without the publisher checks, past the 10s expect default,
so the test read as stalled on Installing…
* test(plugins): give the row-art fixture the entry's catalog source fields
* test(plugins): say why the panel WebRTC test needs a longer timeout
* feat(plugins): dismissible Alpha notice on the Plugins settings page
Shows "Alpha: The plugin interface may change. Expect nuances." under the
Plugins title until dismissed; dismissal persists in UI state
(pluginsAlphaNoticeDismissed). Localized in all locales, with unit and e2e
coverage for show-by-default and dismiss-across-reload.
Co-Authored-By: Claude <noreply@anthropic.com>
* plugins: stop shipping Orca Navigation Shortcuts and retire stale bundled installs
Removes the bundled copy and its fallback-catalog listing. On startup, bundled
bootstrap now uninstalls any previously bundled plugin this release no longer
ships, so existing users don't keep a protected entry they cannot remove.
Removal code moves to plugin-removal.ts to keep plugin-install.ts under the
line limit.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(plugins): concurrent saves of one image no longer fail the update review
Each save now writes its own uniquely named temp file and treats a rename
failure as success when a concurrent writer already produced the same
content-addressed file. A cache failure now only drops the image from the
preview or catalog refresh instead of failing it.
* fix(plugins): an update keeps unchanged machine recipes off the review's New list
Recipes always counted as new because their commands live in files the
manifest diff cannot see. Main now reads what each recipe can run (id,
checkout mode, commands) from the installed tree and the preview's staging
tree, and only a recipe that runs something new asks for review. An
unreadable file still counts as new.
* plugins: app themes color code in the editor via VS Code-shaped tokenColors
Theme files gain optional tokenColors (TextMate scope -> foreground/fontStyle).
The derived Monaco theme maps them onto Monaco's token names, the plugin-syntax
legend and raw TextMate scopes; unreadable colors are dropped.
* test(plugins): theme smoke checks tokenColors color the editor and revert
* i18n: retire translated entries for plugin strings this change rewords or removes
* plugins: add the custom editors contribution point
A plugin can now declare contributes.customEditors to open files of given
types in the editor tab, beside Source. The editor runs in the same
sandboxed, no-network panel frame and only exchanges the document's text
over a scoped postMessage channel; Orca keeps the buffer, dirty state,
saving, external-change banner, read-only tabs and SSH files.
The Editor | Source toggle and the 'first scene after load is the
baseline' approach follow community PR #27413.
Co-authored-by: Roughriver74 <115543510+Roughriver74@users.noreply.github.com>
* plugins: list custom-editor plugins with panels in the plugin list
* plugins: name an editor-only plugin's access 'Adds an editor'
* plugins: keep the Editors category label for custom-editor plugins
* plugins: restyle plugin frames in place and keep file paths out of editor frame names
A theme change used to remount panel and custom editor frames, which reloaded
the plugin and lost its state (Excalidraw undo, unsent edits). The host now posts
orca-panel-theme and the shell updates the --orca-* tokens and the html class in
place. Custom editor frames are named with a random id: window.name is readable
inside the frame, and the old name carried the file's absolute path.
* plugins: let custom editors open binary files as bytes (contentKind)
A custom editor can now declare "contentKind": "bytes" (with "readonly": true)
to receive the file's raw bytes instead of its text, for formats such as
spreadsheets. Orca pages the bytes from the host that loaded the tab (local,
SSH or a paired runtime, through the existing stat + readChunk calls, so no
wire change), refuses files over 16 MiB with a "too large to open" message,
re-sends on outside changes, and never applies a bytes editor's edits. The frame
gets a transferred ArrayBuffer and the matched suffix, never a path.
Documents are now versioned: { version, readOnly, content: { kind, ... } }.
Text edits may name a baseVersion; an edit against a replaced document is
refused with an orca-editor-edit-rejected conflict. Text documents keep the
legacy text field and unversioned edits still apply, so existing editors work.
"readonly": true on any editor makes the install review say "Opens .x files in
Orca" instead of "Opens and edits".
* plugins: suggest catalog custom editors for files Orca already opens
The file-type suggestion only offered a plugin when a file opened as plain text
or as the binary placeholder. It now also offers a catalog custom editor for a
file Orca shows with a language (an .excalidraw file opens as JSON): the editor
asks main with the `editor` purpose, which matches only release file types the
listing's contributions name as custom editors, and only when no installed
plugin's editor handles the type. Binary files such as .xlsx keep the existing
path, since release fileTypes already include custom-editor types. The banner
reads "A plugin adds an editor for .x files: Name"; Not now and Don't suggest
work per type as before.
* fix(plugins): an update that lets a custom editor edit, take over opening, or change content kind asks again
* fix(plugins): one unreadable catalog summary item no longer hides the whole summary
* fix(plugins): plugin editors never open Orca-core file types by default, and join Markdown, CSV and notebook view toggles as options
* fix(plugins): catalog releases list editor file types as data instead of parsing the display summary
* fix(plugins): custom editor edits must name their base version; drop the pre-release text field
* fix(plugins): a custom editor edit Orca refuses keeps the tab dirty and blocks the save instead of vanishing
Rate-limited edits are held and applied before the next save; oversized ones are reported to
the frame and the user. Every save, from any trigger, first flushes plugin editor frames with a
bounded wait and refuses to write while a frame holds edits the buffer lacks.
* fix(plugins): run custom editors as network-isolated guests and save only on real key presses
Editors see file contents, so they now run as <webview> guests in their own in-memory partition
instead of iframes of Orca's renderer. The session routes everything through a dead SOCKS proxy
(loopback included), refuses every non-editor request and permission, and each guest gets
disable_non_proxied_udp, no popups and no navigation. An Electron test proves fetch, WebSocket,
images and TURN-over-TCP all fail from the editor and from its srcdoc and javascript: child
frames, while the same page in a plain session reaches every listener. Electron 43 still resolves
<link rel=dns-prefetch> names outside the session; the test pins that residual and the docs say so.
Save chords now come from main's before-input-event on the guest, which page code cannot
synthesize; the shell's keydown forwarder and the orca-editor-keydown message are gone. Guests
also run in their own renderer process.
* fix(plugins): enforce a read-only custom editor in main, not just the tab
Main reads readonly from the installed manifest (bytes editors always count) and drops every
edit such a guest posts before it reaches the renderer. The tab host also refuses them and tells
the editor its document is read-only, even on a writable tab.
* test(plugins): the editor-suggestion catalog fixture lists editorFileTypes
* plugins: custom editors edit and save binary files; drop readonly and the isolated guest
Bytes editors now post `{ baseVersion, content: { kind: 'bytes', bytes } }` full
replacements (a transferable ArrayBuffer). The tab keeps the unsaved bytes beside
the text drafts, marks itself dirty, and the normal save pipeline (frame flush,
Cmd+S, close prompt) writes them: locally through a new `fs:writeFileBytes`
atomic replace guarded by the loaded bytes' SHA-256, and on SSH-served or paired
hosts by uploading chunks with `files.writeBase64Chunk` and swapping them in with
the new capability-negotiated `files.replaceWithUpload`. Older hosts are refused
before anything is written. A stale baseline is a conflict: the edit stays
unsaved and the external-change banner offers Reload or Overwrite. Source stays
the binary placeholder.
Per the product decision, every custom editor may edit: the `readonly` manifest
field, its main-side enforcement and re-approval rule are gone, and an editor
that only views simply never posts edits. Editors run in the normal sandboxed
plugin frame again instead of a network-isolated webview guest; the frame's save
chord is honored only while it carries real user activation. Consent now reads
"Opens and edits .ext files in Orca. It can read the files it opens."
* plugins: reserve agentHarnesses and hooks instead of agents; rename agents:read to agent:read
* plugins: syntaxes and custom editors share one file matcher (extensions with the dot, plus filenames)
* plugins: title for themes and syntaxes, when for commands (format 1 names rewritten on parse)
* plugins: add the editor catalog type for custom editors
* plugins: official means listed by the official catalog, not an orca- id
* plugins: one envelope protocol and window.orca for workers, panels and editors
Workers, panels and custom editors now share one internal envelope
({orca: 1, kind: req|res|evt|cancel}) instead of three message sets.
Frames get a frozen window.orca from the shell (api, host.call with
AbortSignal cancel, host.has, on, and document helpers in editors);
ready/hello carries the api, the surface's methods and the theme.
Editors gain host calls through their own session.
The host API table is keyed by method with typed params/results (no
handler casts), per-method surfaces and a numeric since minor; every
params schema is strict. Errors are {code, message, retryable,
retryAfterMs?} with cancelled/timeout/conflict/not_permitted/too_large
reserved and unknown codes read as action_failed. Event payloads are
typed with a closed agent-status enum, and the list entry type is
shared by main and preload.
* plugins: orca.document.onDidChange hands a late subscriber the current document
Editors that subscribe after their bundle loads (Excalidraw) missed the
document that arrived first and stayed blank.
* plugins: custom editor documents up to 64 MiB, with a large-file note past 16 MiB
The cap covers text and bytes on every route; reads and SSH or paired-host
writes are already chunked, so only the shared cap moves. Past 16 MiB the
tab shows a small, non-blocking note that the editor may take a moment.
* plugins: delete dead props and branches left by removed rows, logs toggle and access retry
* plugins: one status word per state (a crashed plugin reads Stopped everywhere) and drop unused plugin locale keys
* plugins: contribution rows use the manifest point names, so the policy table is the one source of catalog types
* test(plugins): assert the Use now line and page behavior, not Tailwind classes
* i18n: add the custom editor large-file note to the English catalog
* plugins: fold the loose shared plugin modules into contributions, frames, images, capabilities, events, languages, installation and catalog folders
* plugins: custom editor tab icons and contributes.newFiles templates
A custom editor may declare an icon; the tab and its hover card show it and the
editor title instead of "Editor", falling back to the plugin icon. contributes.newFiles
declares untitled file types (title, extension, optional UTF-8 template and icon) offered
in the tab bar + menu, its search, the command palette and the plugin page, created at the
workspace root through the Markdown untitled-file flow. The install toast's Try it creates
one for plugins that declare them.
* test(plugins): hidden e2e for a plugin new file from the + menu and its editor tab icon
* plugins: turn the plugin system on by default with a one-time migration
Saved false from the old default flips on once (pluginSystemDefaultedOn guard);
a later deliberate false is respected. The Turn on plugins off-state is gone,
and the official catalog seed is deferred off the startup path (and skipped
offline), seeding on demand when the marketplace is opened.
* plugins: move the card menu Disable/Enable directly above Remove, without an icon
* plugins: show the Alpha notice with the warning banner tokens
* plugins: show each category's icon in the filter dropdown
* plugins: seed drawn fallback art per plugin so two listings never look identical
* plugins: show manifest covers for catalog releases published without images
The official catalog's newest Midnight, Nord, OLED and Dusk & Ember releases
were regenerated without an images block (release-entry only kept images the
author pasted), so their cards fell back to drawn art. A catalog that keeps its
plugins in its own repository now borrows the manifest's images from the
catalog commit, checked like declared images, and the validator's printed
release entry includes them so regenerated catalogs keep their covers.
* plugins: drop the unused Turn on plugins strings
* settings: find the Plugins page by plugin, mod and extension searches
* plugins: remove the Allow full-access plugins setting
Full-access (trusted-worker) plugins now need only their own per-plugin
approval: main no longer gates install, consent, enablement or runtime on a
global switch, and the settings menu item, the Turn on in settings card and
page states, and the stored key are gone. The consent now says plainly what
full access means. Kill list, official review and publisher checks are kept;
docs note an enterprise block policy may come later.
* i18n: retire translated entries for plugin strings this change rewords or removes
* test(plugins): prune low-value plugin tests
Drop tests that asserted CSS classes, DOM structure, internal call counts,
copy, or duplicated coverage; merge overlapping e2e file-type suggestion
specs. Keep security, consent, data-integrity, compatibility and main
journey coverage.
* test(plugins): stop git auto-maintenance racing marketplace fetch teardown
* test(plugins): import the panel session token schema from the frame bridge
* feat(plugins): open orca://plugins install links at the plugin's page
orca://plugins/<publisher.id>?catalog=<official|community|git URL> opens
Settings -> Plugins at that plugin; it never installs. Plugins off shows
Turn on plugins first, an unknown catalog asks before it is fetched, and a
malformed link only toasts. Reuses the skill-share deep-link path (open-url,
second-instance argv, sidecar handoff) with repeat/burst dedupe, and
registers orca:// on packaged Windows, which NSIS leaves unregistered.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(plugins): show the linked catalog URL on its own line
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(plugins): follow main's moved plugin files and language-pack coverage field
* fix(plugins): keep a plugin disabled through its update and give format 1 event handlers worktreeId
* fix(plugins): keep held editor edits across view switches, ignore stale editor entry reads, share bytes across split panes, and meet the low-evidence lint
* refactor(editor): keep the file content loader under the line limit
* fix(plugins): keep a bytes draft's baseline across reloads, cover plugin new-file menu rows, and move render-time ref writes into layout effects
* refactor(tab-bar): keep the create-menu controller under the line limit
* refactor(tab-bar): keep the create-menu controller under the line limit with the plugin new-file case
* test(plugins): turn plugins back on through settings in the install-link journey
* fix(wsl): import the atomic plugin file writer from its new folder
* fix(plugins): save bytes custom-editor edits from Save-and-close and the overwrite banner
* test(plugins): park the Linux-only bytes editor e2e failure as a follow-up
* fix(plugins): follow main's new language-pack tests to the moved artifact module
* test(i18n): give main's new plugin language-pack fixture its coverage
* plugins: manifest v2 ships in 1.4.245, since 1.4.244 released without it
* fix(i18n): import the plugin language-pack artifact from its folder in the shared i18n instance
* fix(plugins): drop syntax loads that land after dispose and restore terminal overrides on Switch back
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Roughriver74 <115543510+Roughriver74@users.noreply.github.com>
|
||
|
|
dc4a990c4a |
test(e2e): background work never starts a stopped WSL host distro (E9 guard) (#35580)
* test(e2e): background work never starts a stopped WSL host distro (E9 guard) A desktop on the fake WSL transport keeps a WSL-host project and a local one. With the distro stopped, a window of background activity elsewhere (window focus/blur/reveal, workspace switches, linked issue/PR cards, a streaming chat in the local workspace, Settings panes and Tasks, account switches) must start nothing; opening a terminal in the WSL workspace then starts it exactly once. createGitProject returns the real path so the helper also works where tmpdir is a symlink. * test(e2e): actually render each Settings pane in the E9 background window openSettingsTarget alone only set the navigation target, so no pane mounted and none of its reads ran. Open Settings, wait for each pane's section to mount, then close it. A repo pane that boots the distro on mount now fails the guard. * test(e2e): fail the host-mode E9 guard early on a missing repo or connect log; state its scope |
||
|
|
c14c99bb49 |
feat(wsl-host): a paired phone reaches the desktop's WSL host and never starts its distro (E6) (#33911)
* feat(wsl-host): a paired phone reaches the desktop's WSL host and never starts its distro (E6)
Behind ORCA_INTERNAL_WSL_HOSTS and the Experimental switch. The desktop relay
lists its WSL hosts to phones. Every relayed call (resolve, call, watchChanges,
status.get) passes a never-start check, and a WSL host serves a phone only
while it already runs.
- WslHostPhoneGate holds the phone's view. The call check reuses E9's
focusReachability, so with no bridge in this process it refuses without a
running-list read. A host shows as "stopped" only on a confirmed stop
(liveness's distro-stopped, or a running list read by the check); anything
else gets a neutral "isn't available" message. Hosts are hidden from phones
while the Experimental switch is off or a Remove is pending.
- The relay host list sends optional `stoppedOnDesktop` only for a confirmed
stop. The phone badges those rows "Start on computer"; older peers ignore
the field.
- The paired-server rows producer carries WSL hosts like any server, so the
main-computed sidebar feed a phone reads has their rows.
- The paired-phone e2e drives a WSL host project end to end and asserts a
stopped distro is never started.
* fix(wsl-host): keep the phone's no-start check off non-WSL servers, and a stale stop off a ready host
- status.get runs the no-start check only for a WSL host, through a
check-only helper. SSH-managed and paired servers reach the status owner
exactly as on main: no reconnect, no redeploy, and the manual-disconnect,
coalescing and repair handling stay in place. The preparation option is
stripped before the probe.
- WslHostPhoneGate drops a 'stopped' read when a ready status arrived while it
ran (a per-host ready generation), and clears a recorded stop when a check
finds the host answering.
- A phone asking about a host that is switched off or being removed gets copy
that says so, not "open one of its projects".
* test(wsl-host): the real no-start helper leaves SSH-managed and paired servers untouched
* fix(wsl-host): tie a phone's confirmed WSL stop to that host's status, and label a host not connected
- A stop a phone's check confirmed is stored with that host's own status
object and holds only while that status is current. Another host's change no
longer clears it. Any status of its own (ready, a disable's closed, a failed
Remove's closed) does. A read never records a stop over a ready status, so a
read shared with one begun before ready can't. Removed hosts drop their
entry. The generation map and status listener are gone.
- The relay sends optional `unavailableOnDesktop` for a WSL host this desktop
isn't connected to and doesn't know is stopped. New phones badge it "Open on
computer"; older ones still show Connecting.
- The relay list reads the WSL host records once per poll (reachAll).
* refactor(wsl-host): one records read per phone check; note the gate's status identity compare
* test(wsl-host): read the phone's host flags as booleans in the paired-phone e2e
toMatchObject({ stoppedOnDesktop: undefined }) requires the key to be
present, and the desktop omits an unset flag, so the ready poll could never
match. The poll now compares relay plus both flags read as booleans.
* test(wsl-host): expect the neutral refusal once main's fake drops a stopped distro's bridge as closed
Main's fake connector (#34573) now publishes 'closed' when a stopped distro's
bridge drops, not liveness's 'distro-stopped'. So the phone's check reads the
stop under a ready status and doesn't claim it. The phone gets the neutral
copy and unavailableOnDesktop; the confirmed-stop copy stays unit-tested.
* test(wsl-host): the paired-phone e2e expects the confirmed stop again, and checks nothing booted the distro
Main's fake now publishes 'distro-stopped' when it drops a stopped distro's
bridge (#34624), as liveness does, so the phone gets "isn't running" and
stoppedOnDesktop. The spec also checks distros.json still reads 'stopped' at
the end: the fake boots a distro by rewriting it.
* test(wsl-host): the startup reconcile suite stubs the phone gate built beside the service
The reconcile still runs before the connector exists; the suite only lacked the new
setWslHostPhoneGate export on its service-instance mock.
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
|
||
|
|
b47f12abd5 |
test(e2e): keys typed into a new remote terminal before its first prompt reach the shell (#35312)
* test(e2e): keys typed into a new remote terminal before its first prompt reach the shell Add a headless paired-host spec that types into each new remote terminal after it binds while the host shell's rc file is still running, then requires the whole command to run. Drop the managed-SSH helper's wait for a prompt before typing, so those specs assert the same guarantee. * test(e2e): prove the rc gate held, and that the early-typed command ran exactly once The tty echo of the typed command must precede the rc file's own prompt, the command's output must appear exactly once, and the rc wait outlasts the bind wait. Throw if the host has no isolated HOME. * test(e2e): drop the early-typed echo-position check; keep the gate and exactly-once proofs The check that the typed line's tty echo precedes the rc file's prompt failed on Linux CI 2 of 2 (run 40763469331): the pane began with the prompt and the typed line followed it, while the command still ran exactly once. macOS echoes it during the rc. Where the echo lands depends on when the host's line discipline sees the bytes, which this test cannot pin; it is not evidence of loss. What the test keeps proving: the keys were typed while the rc file still waited (release file absent), the rc ran (its own PROMPT appears), and the command ran whole, exactly once. * test(e2e): name the early-typing test for what it proves Rename it to say every key typed before the first prompt is delivered exactly once, and drop the header's claim about how the tty keeps type-ahead. |
||
|
|
f7a114af29 |
fix(wsl-host): a terminal on a stopped distro offers Start, and New Terminal starts it (#35168)
* fix(wsl-host): a terminal on a stopped distro offers Start, and New Terminal starts it * fix(wsl-host): a Start whose reconnect fails toasts and returns false * fix(wsl-host): hide a pane's error toast only where the Start card replaces it * test(wsl-host): give the terminal Start e2e's timeout and no-boot window their reasons * test(wsl-host): await the pre-stop New Terminal so its user-act boot can't land in the no-boot window CI saw 2 extra fake connects right after the first stop. Instrumented runs traced every boot after a stop to the Start flow's two calls (wslHosts:connect, then the runtimeEnvironments connect, logged as a pair) and the renderer stack of the second pair to openNewTerminalTabInActiveWorkspace. In CI the spec clicked New Terminal, then waited only for the first .xterm. That was the auto-created terminal, so it wrote the stop while its own New Terminal was still in flight. That terminal then started the distro as the user act it is. No background path booted anything. The spec now runs the tab bar's New Terminal action and awaits it before the stop. The no-boot assertion is unchanged. * test(wsl-host): narrow the tab group id before opening the pre-stop terminal |
||
|
|
448ef93938 |
test(e2e): retry the PTY write spy's main-process evaluates on transient CDP failures (#34912)
The spy already retried its install through retryTransientMainEvaluate, but its reads, clear and delay setter did not, so a 'Resulting promise was garbage collected' (playwright#33737) failed a passing Windows WSL paste test. |