* fix(terminal): observe foreground at the physical PTY owner
* fix(terminal): keep existing inventory, inspection and display semantics around master-group foreground
Review round 1 fixes for the physical-owner foreground observation:
- Stop and liveness verification keep complete-inventory proof: the router's
scoped listProcesses({ptyIds}) is owner resolution again (absent = []).
Only the launch guard's old-owner fallback asks for an established
target's owner via an internal targetOwnerOnly option.
- Degraded daemon mode routes foreground observations and target reads to
the established owner, so an unreachable unrelated daemon cannot refuse a
known terminal there either.
- Display and name refreshes read the master's foreground group but take
member rows from the shared single-flight process-table snapshot; no
per-terminal ps per refresh. Recognized agent names skip the confirm scan
again, and builds without the native accessor keep the existing reader.
- Ordinary inspections keep their first-match routing; strict owner and
incarnation checks apply only to foreground decisions. The unused
foregroundOnly preload/IPC/RPC surface is removed.
- Local inventory forwards only the target scope, never caller deadlines.
- An interpreter running an agent script counts as that agent, as before;
a blank argv row no longer voids a terminal capture outside the
foreground group.
- Bump the packaged compatibility contract to daemon protocol 55 and move
the node-pty accessor above the process getter's doc comment.
* fix(terminal): keep the node-pty patch hunk well-formed and drop redundant foreground tests
Remove two stray context lines from the src/unixTerminal.ts hunk so its body
matches its header (strict patch parsers reject the mismatch), and update the
lockfile patch hash. Prune foreground tests whose rows repeat branches the
parity table already covers.
* fix(terminal): index the shared snapshot by TTY once and keep observation age nonnegative
Display refreshes filtered the whole shared process table per pane, so
work grew with panes times processes. Group each snapshot by normalized
TTY once, memoized by array identity, and look each pane up directly;
the scaling contract now counts row TTY reads at N and 10N panes.
Both foreground observation producers clamp capturedAgeMs at zero, so a
wall-clock step back during the read no longer yields an envelope the
validator rejects and the launch guard refuses.
* test: move foreground-observation compat tests into the protocol compatibility suite
Main removed daemon-pty-adapter-steady-state-compat.test.ts; the merge restored it with only this branch's block. Reuse the suite's existing inspection adapter helper so no new type assertion is added.
* fix(cli): keep inferred worktree creation in the caller project
* Fix caller checkout ranking and creation guidance
* Share caller-host containment preparation across CLI selections
* Correct Windows CLI fixture syntax and snapshot command
* Match worktree fixture output to typed execution hosts
* Regenerate bundled workspace placement guidance
* Refuse ambiguous workspace ownership and preserve launch replay
* Scope runtime filesystem mocks to their aggregate tests
* Preserve launch proof semantics under strict test diagnostics
* Keep launch proof imports within their compiler project boundary
* Consolidate journal cleanup test imports
* Adapt launch fixtures to the current host settings contract
* Keep the CLI error formatter under the file-size limit
Move the selector-ambiguity workspace-choice check into selector-ambiguity-recovery.ts, which already owns that error's recovery text. Behavior is unchanged.
* Expect main's concise orchestration output in the workspace-choice CLI tests
Orchestration commands now print the one-line failure on stderr and the workspace choices and next steps on stdout (or compact JSON plus the stderr line with --json), and print concise success fields.
---------
Co-authored-by: Orca QA <orca-qa@users.noreply.github.com>
* test: remove 462 low-value test declarations
* Shrink flaky test pattern baseline after audit896 test removal
* Remove two empty hook-only suites after audit896 test removal
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(emulator): show a dead Android preview as disconnected so Connect restarts it
When the scrcpy session ended, the video registry dropped its subscribers silently and a later subscribe was a no-op, so the pane kept saying Connected over a blank 'Stream disconnected' screen with no way to retry. The registry now tells subscribers the session ended, the IPC relays it on the stream error channel, and the pane marks the session disconnected so the toolbar's Connect button restarts scrcpy.
* fix(emulator): retry a lost Android preview by AVD name and keep stale errors off new streams
* fix(emulator): keep a live emulator serial and fall back to its AVD name only once it is gone
* fix(emulator): keep the AVD target across failed reconnects and reused serials
* fix(emulator): reboot a vanished emulator by AVD name only when the host no longer finds its serial
Replaces the pre-attach device refresh: the live serial always goes first, and the AVD name is tried only after the host answers emulator_device_not_found.
* refactor(emulator): read the host error code plainly in the AVD fallback
* refactor(emulator): type the attach result without a cast and derive WebCodecs support in render
* fix(emulator): type the fallback test's attach result and allowlist the WebCodecs diagnostic
The PR tab now leads with the PR's identity, one row per merge gate
(checks, unresolved threads, approvals, conflicts) that opens the screen or
sheet that resolves it, a changes card and a collapsed description. Close,
Unlink, Auto-merge, Edit title and Copy link move into the ⋯ menu.
Checks and Comments become pushed screens: failures open with their
annotation and Fix / Rerun / Open / Log on the failure, running checks
next, passed folded; comments filter by Unresolved / All / Hide bots with
Resolve and Reply on each thread and a comment box at the bottom.
Merge opens a sheet that lists only the methods the repo allows, starting
on its default. Reviewers move into a sheet with search to add and remove.
Every Create PR entry point opens one sheet: title and description seeded
from the branch's commits (shared seed rule in src/shared, GitHub's own
default), Write with AI, base picker and draft. It pushes first when
needed, works for all five providers and lands on the PR tab for GitHub.
* feat(mobile): one next-step bar under both Source Control tabs
Changes and Pull request are the only segments. A bar at the foot of both
shows the branch's one next action: the commit box, push or pull, create
the review, resolve or fix with the workspace's agent, merge when ready,
merge, or why it can't. Commits opens as a pushed screen.
* fix(mobile): keep Merge reachable and show bar failures on both tabs
* test(mobile): expect the two Source Control segments in the page render test
* Route hosted review refreshes to their owning host
* Route remote review operations to their owning host
- Refresh the correct hosted review after remote git operations
- Scope comment mutations and AI acknowledgements to the owner cache
* Route legacy paired SSH reviews through their server owner
- Recover proxied runtime owners for older SSH worktree listings
- Preserve direct and ambiguous host routing safeguards
* Preserve review ownership across remote workspace operations
- Route checks, comments, and linked-review clears through the selected repository owner
- Reject ambiguous or mismatched host context to prevent cross-machine mutations
* Keep check detail tabs scoped to their remote owner
* Preserve remote worktree ownership across reconstructed check tabs
* Preserve direct SSH check tabs when proxy listings overlap
* Scope PR refresh ownership state and safely roll back comment mutations
- Preserve linked-review clear scopes beyond cache eviction and clean them up on expiry
- Handle failed or refused comment reactions and thread resolutions without stale optimistic UI
* Preserve remote review ownership when SSH copies overlap
* Fix review routing for overlapping remote repository hosts
- Preserve server-owned review refreshes when a direct SSH copy exists
- Fail comment mutations and refetches safely when ownership becomes invalid
- Resolve check and sidebar data through the workspace’s owning host
* Relax cache-sensitive test expectations
* Route check refreshes to runtime owners and isolate restored requests
* Scope reconstructed check detail tabs by execution owner
* Fix review refresh ownership for shared remote hosts
- Prefer explicit execution owners when matching worktrees.
- Avoid repeated tab scans when restoring check details.
* Fix hosted review polling for workspaces on multiple hosts
* test: trim redundant review ownership scenarios
* Preserve rich Markdown viewport through bare focus returns
* Retire viewport ownership on editor remount
* Complete no-op navigation and body Tab coverage
* Keep patch metadata keys separate from dependency snapshots
* Retire the viewport before root detach callbacks
* Give the engine writer fixture its native selection
* Keep native focus navigation current in Markdown
* fix: leave smooth Markdown scrolling to native focus cancellation
* Cover focus wrapper removal and routed Markdown writers
* Type the viewport scroll spy and mark the focus-recovery wait as deliberate
* Scope Markdown viewport wheel and touch guards to the editor scroller
* feat(mobile): GitHub threads, viewed sync and line comments on the diff screen
Committed files of a GitHub pull request now show its review threads under
their lines with Reply and Resolve, take their viewed state from GitHub and
sync the checkbox and Viewed · next file back through setPRFileViewed. A tap
or a long-press drag picks lines and opens a sheet that sends the note to
the workspace's agent through the existing send path, or posts it as a
review comment. Threads and GitHub comments appear only while the local
branch is at the PR head, the same contents desktop shows them on;
otherwise the file says to push. openDiffForFile takes an optional line for
a thread's Open in diff.
* test(mobile): use a type import for the line-mutations recording adapter
* fix(mobile): name the staged or unstaged side in the jump sheet's file labels
The Commits list now stops where the branch left its base. It groups
commits into Not pushed (hollow dots, with Push) and On origin, ends at
"Branched from <base>" with Update branch, and loads more past 50. A
commit opens its own page: message, author, date, pushed state, files
with +/-, and Copy SHA / Open on GitHub in the menu.
Older hosts ignore the new params, so the list falls back to the full
history without groups or the base marker.
The review screen becomes the one diff screen from the approved design.
It walks the Changes section the file came from (uncommitted, staged or on
the branch) or one commit's files, so 'N of M' and next/previous stay in
that list. The title opens a jump-to-file sheet built on the shared
source-control tree, with search and viewed boxes. Unchanged runs fold the
way desktop's diff does. The bar's main button is Stage · next file for
uncommitted files and Viewed · next file otherwise; Discard and Unstage move
to the menu. Filter chips, hunk jumps and Stage Reviewed are gone.
openDiffForFile also takes { kind: 'commit', commitOid, filePath }, read
through git.commitCompare and git.commitDiff.
* fix(browser): stop the paired tunnel refusing a heavy page's connections
The client capped a tunnel at 32 streams and the server refused opens past
16 pending connects, so ja.aliexpress.com (77-105 concurrent connections)
lost requests with ERR_SOCKS_CONNECTION_FAILED. Size the stream cap to
Chromium's 256-socket pool on the client, server and SOCKS listener, drop
the pending cap the stream cap already bounds, and raise the open rate to
1024 per 10 s above the measured 302.
* fix(browser): fail only the stream that overflows the tunnel receive budget
More streams per tunnel make the shared 32 MB receive budget reachable, and
a denied claim closed the whole tunnel as if the server sent invalid data.
Fail just that stream, as the server session already does.
* fix(browser): release a failed stream's claims before reporting it, update tunnel gate text
* fix(browser): keep room in the tunnel memory budget for a failed stream's Error frame
Application claims now stop 64 KiB and 64 claims short of the host and
process caps, so the Error frame for a stream failed by a full receive
budget can still be queued instead of closing the whole tunnel.
Source Control rows used to open a file three ways: the review screen, a
desktop editor tab the session then switched to, or a text-only branch
drawer. Every row now calls one openDiffForFile entry point that pushes the
review screen. The drawer, the session tab reveal and their handlers are
gone; Open in Session stays in the review screen's menu.
Main's page code is 9,414,296 of 9,437,184 bytes, and the Source Control
redesign branches add 7-31 KB each. The phone contract allows 10 MiB per
asset and 32 MiB in total, so the fence was our own budget, not a phone
limit; 9.5 MiB keeps it under the per-asset ceiling.
The queue card's invisible full-text line-count probe overflowed its two-line
row and stretched the queue's scroll range far past the real rows. Clip it to
the card text.
The queued-message editor drew Save and Cancel labels inside 38pt round icon
controls, so translated labels spilled over each other. They are now pills that
hug their label and truncate only when the row runs out of room.
* fix(mobile): show workspace images in session Markdown tabs
* fix(mobile): show workspace images restored by undo or paste
* fix(mobile): keep session image loader current and inside the workspace
* fix(mobile): classify entity-encoded image URLs by their decoded scheme
* refactor(mobile): classify editor images with the shared Markdown href router
* test(mobile): expect workspace image markup in the code-block selection check
- orca plugin check mounts the plugin's worker (main) on the same mock host
as each panel, so plugin.request reaches its orca.panels.handle handlers
as in Orca; a worker that fails to activate or deactivate is an issue
named after its file. In orca/testing, a worker mounted on a host answers
that host's panel requests unless `requests` stubs the name.
- Check scenarios: <entry>.check.ts (e.g. src/panel.check.ts) exports
defineCheck({ name: { ...mockHost options, persisted, theme, events } });
check renders the panel once per scenario and labels each result.
- RelativeTime (catalog 3, since 1.4.247) and { type: 'relative', at } Table
cells: Orca ticks them (each second under a minute, then less often), so
plugins never poll. Inline inside Text; test kit reads them as drawn.
- Typings, docs, skill guide, generated references; gallery shows it.
* feat(plugins): dev emit also reaches the plugin's open panels
orca plugin dev emit now publishes through the panel bridge to that dev plugin's open panels
that subscribed with orca.on, under the same approval and capability rules as the worker, and
reports delivered.panels. The bridge's publishEvent takes an optional pluginKey filter and
returns how many panels heard it. A panel-only plugin no longer needs a worker; an event
nothing listens for is refused.
* docs(skills): trim the plugin authoring guide; details move to references
The main guide drops from 299 to 121 lines: the decision table, build-less rules, core loop
(create → dev watch --check --shot → read the PNG → test → check → release-entry), approval
and top gotchas. Test/check and orca/testing (panels and workers), dev watch events, shot,
open and dev emit move to a hand-written references/workflow.md; the panel/worker/data and
agent status recipes to references/recipes.md, each with a read-when row. The guide test now
also scans hand-written references for commands and caps the main guide at 150 lines.
* plugins: components catalog 2 (forms, tabs, table, tree, markdown, code, images)
Adds 18 components to TSX components panels, drawn with Orca's own
primitives and gated by ui.catalog 2 / ui.has() (Orca 1.4.247):
Textarea, Checkbox, RadioGroup, Slider, Field, Tabs/Tab, Collapsible,
Toolbar, Grid, a virtualized Table with sort, selection and pull-based
paging, a keyboard Tree with lazy children, Markdown (sanitized, links
through the checked open path), CodeView (Orca's highlighter), Image
(header-checked plugin files read by main), KeyValue, Callout and
Skeleton, plus a tooltip prop on Button and IconButton.
Value controls share the edit protocol; handlers get plain JSON event
args, including small objects ({ keys }, { key, expanded }). The test kit
gains matching actions and hides unselected tabs and closed collapsibles;
a components-gallery example and e2e cover the catalog end to end.
* plugins: worker test harness, host refusals in tests and check
- orca/testing gains mountWorker(main, { host, events, commands }): it calls
the default-exported activate(orca) with the orca object Orca itself builds
(createPluginWorkerOrcaApi, moved to shared so the kit reuses it), backed by
mockHost. emit() checks payloads against Orca's event schemas and only
delivers subscribed events; command(), request() (the worker's
orca.panels.handle, as a panel's plugin.request), posts, logs, refusals and
deactivate(). Storage and settings share the mock host's in-memory store.
- orca plugin test loads a worker main's module graph as Orca's worker host
does (.ts/.mts transform, Node resolution, no runtime orca import).
- mockHost records refusals (capability_denied, not_permitted, ...) even
when plugin code catches them; panel.refusals exposes them and
orca plugin check reports them as warnings. Check dedupes repeated issues.
- Typings, docs and a generated references/testing.md skill reference; the
reference generator reads the split orca typings.
* feat(plugins): orca plugin open and shot; dev watch --shot
- orca plugin open <key> [--panel|--editor] shows a panel in the right sidebar or a file in the
plugin's custom editor, by changing renderer state only (no focus or window raise).
- orca plugin shot <key> [--panel] [--theme] [--width] [--out] [--json] waits for the panel's
current code to draw, then crops webContents.capturePage to the panel (html guests included),
with background throttling off while hidden. --width and --theme are temporary in-memory
overrides; the PNG returns base64 (5 MiB cap), so --environment works.
- dev watch --shot <dir> writes a PNG per panel after the load and each good reload.
- The authoring skill's loop is now dev watch --check --shot → read the PNG → plugin test.
* fix(plugins): shots never disturb a visible Orca
- shot --theme is skipped while the Orca window is on screen (themeApplied: false with a
themeReason); the override applies only to a hidden or minimized window.
- dev watch --shot opens the first panel (or --shot-panel <id>) once, then shoots it with
ifShown: if the user moved the sidebar away it emits one shot_skipped instead of switching.
* fix(plugins): dev loop dogfood fixes; orca plugin dev emit
- dev watch: approval re-run command drops watch-only flags and old --approve; a folder added
by a refused load is owned by the next approved load (Ctrl-C unloads it); check events
carry the plugin's status (no green while pending/errored); reloaded prints before that
reload's logs; --json errors are one NDJSON line.
- Errors: log, banner and check share source-mapped positions (a line-1 prelude hands sucrase
mappings to the components runtime); check dedupes issues and locates syntax errors;
Orca runtime frames and the error module's bogus location are dropped from logs.
- .orca/types tsconfig sets preserveSymlinks (tsc 7 loaded typings twice under /tmp).
- Templates' READMEs use dev watch.
- orca plugin dev emit <dir|key> <event> [--data] sends a test event to a dev plugin's worker
through the real delivery rules (plugins.devEmit).
* test(plugins): fixed timestamp in the dev emit test
* fix(plugins): shot captures an html panel's guest itself
On Linux the main window's capturePage leaves a <webview> guest blank. The renderer now reports
the guest's rect, and main captures the guest's own webContents and draws it over the window
capture at that rect (raw bitmaps, nativeImage only). Components panels are drawn by the host,
so the window capture alone stays right for them.
* refactor(plugins): keep plugin-service and main-process-plugins under max-lines
After rebasing onto #37013 both files crossed 300 lines. The guest log sink moves into the
desktop view binding (bindPluginDesktopViews), and plugin-service tightens emitEvent and its
event-delivery imports.
* 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.
Tokenize srcset like the HTML parser: read each URL up to ASCII
whitespace, strip trailing separator commas, and skip descriptors
(including parenthesized commas) before the next candidate.
Fixes#36955
Co-authored-by: Neil <neil@stably.ai>
* feat(plugins): build-less TypeScript workers
A worker's main may be .ts/.mts. The plugin host installs module.registerHooks scoped to the
plugin folder: .ts files are transpiled with the frames' sucrase options (lines kept, inline
source map, source maps on), relative imports fall back to the frames' candidate files, and a
value import of the type-only 'orca/worker' fails with a clear error. Needs engines.orca
>=1.4.246.
* feat(plugins): components panels hot reload with their state
- In dev folders a save swaps only the hidden guest: keyed memory atoms are handed to the new
guest (ui.retain → ui.hydrate memory), dropped when an atom's version changes.
- A save that fails to load keeps the last good render and shows an inline file:line:col
error banner; the next good save clears it. A subtle Reloaded mark follows a reload.
- Transpile and import errors carry line and column; dev worker restarts keep storage.
* feat(plugins): orca plugin dev watch
One command for the inner loop: refreshes .orca/types, dev-loads the folder, follows its frame
and worker logs (plugins.getLogs gains an optional cursor), prints reloads (optional
devChangeCount on list entries) and status changes, and unloads on Ctrl-C. --json streams
NDJSON events for agents.
* feat(skills): orca-plugin-authoring bundled skill guide
A guide for agents to build Orca plugins end to end (decision table, build-less rules, the
dev watch loop, test/check, validate, release-entry, approvals, gotchas) with references
generated from the component catalog, host API table, event schemas, manifest schema and CLI
specs, checked for drift. Fixes the components template's Reset to set(count, 0).
* feat(plugins): orca plugin dev watch --check; test kit details in the authoring skill
- --check runs orca plugin check after the load and after each reload (one at a time; saves
made meanwhile fold into one rerun) and prints each panel's render or errors inline, as a
`check` event with --json. Local folders only, since it runs the plugin's code here.
- The orca-plugin-authoring guide's Test and check section now documents orca plugin test and
check from #36969 exactly (JSON results, exit codes, test placement, the orca/testing kit and
its common mistakes), and the loop uses dev watch --check.
* refactor(plugins): move the components renderer's timing and helper constants to their own module
* feat(plugins): orca/testing kit, `orca plugin test` and `orca plugin check`
- `orca/testing` mounts a components panel in plain Node (node:test, vitest, bun) with the real
runtime and Orca's own tree validator: find by text/role/label/testId, press/type/submit/toggle/
select that resolve once the panel settles, tree() snapshots, errors (with stacks) and warnings,
persisted state (with stored() for migrations), emit/setVisible/rerender, and unmount running
setup cleanup. It re-exports node:test and strict assert so tests type-check without @types/node.
- mockHost refuses what Orca refuses with the same codes (surface, capability from the manifest,
params, a gesture method without a press), checks configured results against the host API, and
records calls.
- `orca plugin test [dir]` discovers *.test.ts(x) and runs them with node:test through Node module
hooks that resolve `orca` like the guest's import map and transpile/resolve sources exactly as
Orca's build-less loader, or with the plugin's own vitest via a generated config.
- `orca plugin check [dir]` validates, then renders each components panel once and reports what it
threw (file:line), layouts Orca would refuse, and props it would drop.
- The kit, hooks and register entry ship minified beside orca-runtime.mjs and are unpacked from asar;
typings land in .orca/types/orca-testing. The components template and hello-tsx get sample tests.
- ui.error carries an optional stack; a new runtime starts every atom from its initial value; the
hydration fallback timer is cleared once hydrated.
* plugins: run plugin test/check on a system Node or Orca's own, and warn they are unsandboxed
* test(plugins): run the shipped example plugin tests from the unit suite
* feat(window): working background opacity and blur on macOS, Windows and Linux
One window material model (opaque / translucent / blurred): macOS vibrancy without transparent, Windows 11 22H2+ acrylic, Linux transparent windows. Terminals paint their translucent background once, the transparent WebGL frame clears before drawing (#6491), and Reduce Visual Effects drops modal/backdrop blur and honors prefers-reduced-transparency.
* perf(window): drop hidden macOS vibrancy while a theme image covers the window
* refactor(settings): move Reduce Visual Effects into its own setting and search files