Carry the terminal identity worker alongside chat SQL workers and adopt provider aliases at the committed SQL cache boundary. Keep worker release and automation consumers on their relocated owners, preserving asynchronous journal reads and authority checks.
Retain main test deletions; none of the 47 deleted tests had branch-owned changes. Port incoming ACP fixtures to the asynchronous resume contract.
Validation: the standard merge hook, whole-merge lint, tc:node, e2e typecheck ratchet and changed-quality passed in gate825. All 120 tests in 14 owning files passed on Node and configured Bun. O1 diagnostics are isolated on their separate local branch and absent from this merge.
* Give terminal agents a lasting Orca Agent ID
Terminal agents now get an Orca ID (orca_session_id:<agent>_<uuid>) derived
from their own conversation id on the host that runs them, so it stays the
same across worktree sleep/wake, app restart and a hand-run resume in any
pane. The terminal pane menu gets Copy Agent ID beside Copy Session ID, and
worktree ps --json agent rows carry orcaSessionId. Messaging a terminal
agent by that ID is refused with a message naming its pane until terminal
delivery lands.
* Name terminal agents at row admission and fix review round 1
- Perf: a row's Agent ID is resolved once, when its provider key changes at
admission (legacy rows via the status adapter's prepareRow hook, tmux rows at
canonical commit) and carried on the row as runtime-only agentIdentity.
Snapshots, publications and internal notifications only copy it; no key
serialization, cache lookup or database access per walk. Drops the pane FIFO
cache.
- Refusal: the identity service keeps a reverse index id -> rows, kept exact by
the adapter's rowChanged hook; a terminal refusal reads only matching panes
and names only confirmed running ones (no resume seeds, exited or
unconfirmed restored rows).
- Retry: a read-only identity file is lookup-only and never mints; any store
failure backs off all SQLite work for 30 s; a Copy click retries once.
- Menu: Copy Agent ID shows for a live pane only when its host stamped an ID,
and for a sleeping pane only when this app owns it on macOS/Linux.
- SSH: a sleeping record keeps its connection; a foreign (non-WSL) one resolves
no ID.
- Renderer keeps an existing ID only for the same agent, owner and provider key
including the Pi transcript locator.
- tmux-selected terminal rows carry their ID at every snapshot seam and in Copy
resolution; structured chat rows stay excluded.
* Keep Agent ID work out of notifications and reach Copy wherever a host can answer
- Internal status/provider notifications walk rows without Agent ID work:
canonical (tmux-selected) rows are decorated only for outputs that carry
the id (snapshots, live emit, ps, Copy). The tmux publish body is now
publishTmuxSelectedStatus so tests drive the production path.
- A row this host can name but has not yet (failed or pending link) is
published with orcaSessionId: null; older hosts omit the field. The
renderer offers Copy Agent ID on a live row whenever the field is present,
and the click retries through terminal.agentId.
- Hosts advertise terminal.agent-id.v1. A sleeping pane offers Copy Agent ID
when its owner is this app on macOS/Linux, or a remote owner that advertises
the capability on a known non-Windows platform, and its record names no
foreign connection.
- "Running in pane" places require that this runtime observed the row; a
saved status, Done included, is history.
* Guard the pane menu subscription and stop offering Copy where it can never succeed
- A settled read-only miss (no link in a newer build's identity file) no
longer publishes orcaSessionId; only a resolved id or a pending failed link
does, so Copy Agent ID is offered only where a click can succeed.
- Render contract for the per-pane menu selection: another pane's or host's
status change re-renders no unaffected pane; a pane's own stamp flips its
availability.
* Move terminal agent identity SQL into a worker thread
Main's blocking-SQLite ratchet forbids the synchronous identity store, so
(per the decider ruling) agent-identities.db is now owned by one lazy
worker-thread entry per hook-server owner, desktop and orcad alike.
- The schema, open/version handling, mint/link transaction and read-only
behaviour move unchanged into agent-identity-worker-entry.ts; main keeps
only the key type, path and an async client over WorkerThreadRequestQueue.
- Admission stays synchronous: a new key is published pending (null), one
request per exact key is shared by every row and click, and the committed
answer re-stamps the current rows still pending on that key (legacy and
tmux-selected) as identity-only replays. Replies are fenced by store
generation, key and current subscription; failures back off 30 s and a
Copy click retries once.
- terminal.agentId and the terminal-ID refusal are async: Copy waits for the
pending lookup and revalidates the pane; send/task routing resolves the
terminal recipient (awaiting the store's has() on an index miss) before
any synchronous routing or effects.
- The renderer treats the host's row naming a conversation as authoritative
for its id, so a settled miss clears a pending null, while ID-less local
updates keep it.
- Packaged for desktop and orcad; registered as a worker entry, no baseline
growth.
* Own identity demand per key, publish settled ids as projections, recheck authority
Implements the second decider ruling for the identity worker:
- One owner-level demand table replaces the per-key promise backlog and the
settled-row scan: each exact key a current row or caller needs has one
record (identity, places, waiters); the pump sends the worker one operation
at a time, only for keys still needed, so a healthy burst completes and
detached keys are never sent. Operation deadlines start at dispatch; a
caller's wait expiring never drops a row's demand.
- One failure gate for lookups and membership: after a failure nothing is
sent for 30 s except one coalesced Copy attempt; a single owner wake
retries while rows still wait, and cancels with the last demand or close.
- The retirement barrier outlives a client: a replaced worker must exit
before another starts; a different store path is a different authority.
- Settlement re-stamps the stored row and publishes a projection only: window
readers get the row without its hook event (no agent-state record) and
session.tabs is woken by a row touch; no enriched subscriber, plugin event
or freshness heartbeat runs again.
- Copy and terminal membership check the owner generation after their waits.
A known chat is decided by the chat store alone; send, peer mail, reply and
assignee admission resolve the terminal recipient before reading the facts
they act on, recheck the sender after the wait, and group send reselects
its audience and mailboxes after each wait before writing.
* Scope identity answers to their store authority, expire Copy grants with callers, index provider aliases
- One synchronized authority token before Copy/reverse fast paths, compared after their awaits;
answers carry their authority and an ended store turns rows, tmux subjects and the reverse
index pending together. Status path changes sync the authority outside admission.
- A failed operation reschedules the pump so a queued click gets its attempt; grants belong to
live waiters and a click joining a running attempt earns none.
- Provider-native ids resolve through a commit-maintained alias index at the record store.
- Group fan-out no longer classifies authoritative candidates; @idle rereads statuses with
current candidates before the final synchronous selection.
- Hook-server unit fixtures use an in-memory identity client; a real worker load/stop failure
check covers the worker boundary.
* Pick a shared provider alias's owner among its owners only
The alias index keeps the store's listing order (readable, then unreadable) as derived ranks, updated from the draft's appended keys on commit, so a duplicate alias no longer walks the history per lookup.
* Ask a remote pane's host for its Agent ID by the host's own pane key
Copy Agent ID on a web-terminal surface sent the client's mirrored pane key, which the execution host does not know, so it answered null.
* Keep focus where the user moved, recover a missed identity re-stamp, ack peer-mail replays first
Copy Agent ID refocuses its pane only when focus is unclaimed or still in the pane; a carried pending row takes its key's settled answer; an already-delivered peer-mail retry is acknowledged before recipient preparation.
Keep main owner relocations and deliberate test deletions, carry SQL
journal readers to their surviving owners, and preserve the native chat
title generation ruling. Move SQL publication, startup failure and
durable shutdown assertions into the surviving owning suites.
Validation: standard merge hook, full Node typecheck, code quality,
anti-slop, flaky and e2e typecheck gates pass; owning suites pass on
Node and the configured Bun entry (23 files,119 tests each).
O1 diagnostics work remains uncommitted and excluded from this merge.
Preserve the SQL journal authority while adopting main's consumer relocations, account holds, context usage and deliberate API/test removals. Move retained SQL regression assertions to surviving owners and keep the retired conversation title owner deleted.
The P7 costs remain small measured overhead: warm work lookup p50 rises by 0.167 us (3.542 to 3.709 us; ratio 1.047, 60/80 pairs slower), and empty / two subscribers / changed writer acknowledgment p50 rises 5.5% (0.259459 to 0.273833 ms; paired interval excludes parity) on a writer path P7 does not change. Completion improves from 1.546834 to 0.657125 ms.
The 232-commit consumer audit and local validation receipts are recorded in the lane evidence. O1 diagnostics work remains excluded from this merge.
* Move local usage services into a supervised backend process
* Own usage recovery and worker retirement lifetimes
* Preserve answered usage data during background refresh
* Run independent usage scans concurrently in the backend
* Limit backend startup paths to the delegated usage service
* Show usage failures through backend recovery
* Include usage failure strings in the English catalog
* Keep usage update details beside refresh failures
* Resolve usage freshness failure from the final producer snapshot
* Retain the forced refresh completion requirement
* Keep managed backend failures out of application crash reports
* Preserve usage recovery boundaries across backend reconnects
* Match the backend RPC cancellation signal in the usage seam proof
* Avoid serializing backend requests before port delivery
* Keep receiving request validation in the boundary schemas
* test: align usage transport coverage with renderer project
* fix: preserve unknown usage state and renderer retirement
* fix(usage): revalidate tracking before scan admission
* fix(usage): retry failed backend startup on demand
* test(usage): isolate stale backend ownership checks
* build: fail the React Compiler ratchet on stale uncompiled-list paths
- A listed path that no longer names a renderer source (a rename or split) fails the ratchet, so the file can't silently start compiling.
- The build and the ratchet read the lists through one parser that drops trailing notes, resolved from the repo root rather than the current directory.
* build: resolve uncompiled lists from import.meta.url and check listed paths on disk
- electron-vite's config bundle rewrites import.meta.url per file but not import.meta.dirname, so the repo root came out wrong and desktop builds failed with ENOENT.
- A listed path is stale only if no renderer file exists there; the scan's test-name filter no longer flags shipped files like notification-test-delivery.ts.
* build: require uncompiled-list entries to name the exact file the build matches
A ../ segment, a directory or a different letter case passed the existence check, but the build's exclusion matches only the exact path, so the file still compiled.
* build: reject backslashes in uncompiled-list entries
On Windows path.join turns a backslash into a separator, so the entry passed the check while the build's forward-slash match missed it.
The browser-extension preload was a main-build Rollup input, so it could be
split into shared CJS chunks that a sandboxed preload cannot require. Build it
with the other guest preloads as a self-contained bundle, and share the
one-byte unminified output options between the preload build and sandboxed
bundles so the extension preload stays one-byte in V8.
Co-authored-by: Neil <neil@stably.ai>
* feat(cli): add orca vm env doctor to check a workspace environment
Checks required CLIs (git plus what the repo manifests imply), agent CLIs
and their sign-in, Git fetch and a dry-run push, the orca.yaml setup script
(optionally re-running it with Orca's runner), and free disk. Pass/warn/fail
with --json; checks live in src/main/environment-doctor for runtime reuse.
* fix(env-doctor): ship the doctor modules in the packaged CLI and share the check formatter
* fix(env-doctor): run Git probes in the C locale so folder detection is locale-independent
* Move session search SQLite into dedicated workers
* test: spawn the session search test worker with the shared worker helper
* fix: pass only drain promises to the channel's drain wait
* Repair session search failure and lifecycle boundaries
* Stop indexing tool output and reclaim existing rows
* test: say why the session search worker tests need a longer timeout
* Bound search cleanup and preserve failure and digest semantics
* Use the database row type for tool purge batches
* test: drop the same-connection mid-page write case now that each page reads one snapshot
* test: prove a mid-page delete from the writer can't change that page's hits
* Repair transcript cancellation cleanup and search test runtime admission
* fix: cancel active transcript finalization and enrichment waits
* fix: close transcript handles when cancellation wins delivery
* fix: preserve scan cancellation errors across parser waits
* test: prove cold session search bypasses an active writer batch
* fix: preserve search continuation through background tool cleanup
* fix: preserve search pages during orphan reclamation
* fix: bound typo repair posting visibility probes
* fix: preserve exact search terms when visibility is inconclusive
* test: drop orphan-reclaim cursor staleness case superseded by frozen continuation
* Bound session search work before ranking candidates
* Preserve the limit notice for empty search windows
* Bound session eligibility lookups and reuse FTS scoring statistics
* Index session scopes for population and candidate searches
* Derive search status from the live index after clear
* Preserve disabled search status during settings transitions
* Share planned expressions between spelling probes and search
* Keep identifier fragments out of spelling presence checks
* Report search initialization through its pending transition
* Bound spelling vocabulary work with the search posting budget
* Preserve search fallback while bounding distinct vocabulary seeks
* fix(session-search): drain removals before the worker queue fills; keep aborted close waits from failing teardown
* fix(session-search): hold writer commands when the worker queue is full instead of stopping the writer
* chore(ratchets): baseline the session search worker's one-shot entry check
* Rotate the server pairing identity when ORCA_INSTANCE_ID changes
* Back up replaced identity files, keep the recorded id on reset, keep staged files once the rotating marker is published
* Add identity-reset files to the sync fs baseline and document the backup folder
* Report a reset honestly after finishing an interrupted rotation; keep first backups and the newest one
* fix(runtime): move the local RPC socket to a short path when userData is too long
A long userData path made the local RPC socket path exceed the Unix
sun_path limit (104 bytes on macOS, 108 on Linux), so listen failed with
EINVAL and the CLI could not reach the runtime. Reuse the terminal
daemon's relocation: resolveDaemonUnixSocketPath moves the socket to a
private /tmp/.orca-daemon-<uid>/<hash> dir, the server creates and
verifies that dir before listening, and the orphan sweep covers it.
The CLI and the browser sidecar check the dir is private to this user
before they send the auth token, as the daemon client does.
* fix(runtime): verify the relocated socket dir before sweeping it; probe relocated holder sockets
Check that the relocated /tmp/.orca-daemon-<uid>/<hash> dir is private to
this user before the orphan sweep lists or unlinks anything in it, and skip
that dir when the check fails. The orcad stale-lock reclaim now also scans
the relocated dir for the holder's runtime socket, so a live holder there
is probed and its lock is not reclaimed.
* fix(runtime): ship the socket-dir check with the packaged CLI; keep main sync fs flat
The CLI imports daemon-socket-endpoint-path, but electron-vite replaces
out/main, so packaging lost the module and the installed CLI crashed.
Add it to the CLI main entries and unpack it with its mode constants.
The lifecycle sweep and the stale-lock reclaim now use async fs for the
relocated dir, so the main sync-fs count stays at its baseline.
---------
Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local>
The queue's one ordered list now runs over the storage interfaces: the
SQL side reads live rows from the typed current-card table in
(position, message id) order, and the released-position, candidate and
lineage ports leave the projection. Old saved queues decode only at
open, in memory, and the writer's open converts them as main's does.
* fix(speech): run the on-device recognizer in its own process
A native crash in sherpa-onnx took Orca down with it, and a decode stuck
in native code could not be stopped. The recognizer now runs in an
Electron utility process (a forked child under orcad), is killed when a
stop or cancel goes unanswered, and a dead process ends the dictation
with an error instead of a silent stop.
* fix(speech): let a loading model finish when its dictation is canceled
* fix(speech): never leave a speech child behind or crash main on its fatal error
* refactor(speech): drop the teardown message now that terminate kills the process
* fix(speech): fork the orcad speech child through process-host with a typed request
Journal modules now live in main's owner folders; the projection modules keep their imports
through the moved paths, and tests main retired stay retired.
Also from the first review: worker tests bundle their entries instead of production spawn code
running TypeScript sources; restore drops its unused profiling and selector options; a persisted
reopen stamps cards and restores the lineage frontier in restore's order.
* feat(chat): shared contract for forking a chat from a response
Adds the create-time fork source, the host fork capability, the agent fork
level, the forked-from record relationship and the forked-from divider row.
* feat(chat): advertise each agent's fork level and a chat's fork support
* feat(chat): carry a fork source through chat launch, reload and retry
A launch with forkFrom {sessionId, throughItemId} keeps it on the create call,
the saved launch record, reload, retry and its holders, sends no new-chat
options, and is refused before create on a host that does not advertise forks.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(chat): fork a native chat from a finished response on desktop
Finished root responses offer "Fork from this response" where the host and
agent can fork: disabled while support is unknown or a fork is opening, opened
in a new tab right after the source, with one toast naming the agent on
failure. The forked-from row draws as a divider linking to its source.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(mobile): fork a chat from a response in the message actions sheet
The sheet offers "Fork from this response" with the desktop's eligibility and
host capability, creates the fork through the phone's chat create, and draws
the forked-from divider with a link to the source chat.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(chat): a fork create replays only as the same fork
* Add native conversation copy adapters
* Create native chat forks with derived source markers
* fix(chat): offer a fork only on rows that show the agent's own message
A displayed row can be a tool call or a status projected as a plan while
reading as a response; both clients now check the journal row's own kind.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(chat): open phone and paired-desktop forks right after their source
The phone names its source tab as the create's placement and the host takes
that tab's group; a paired desktop sends the address captured at the click
when the fork has no tab of its own yet.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(chat): float a mid-turn response's fork action instead of adding a line
The action on a response the turn continues past hangs from a line of no
height, as the reply controls hang into the gap, so tool-heavy turns keep
their spacing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(chat): follow the chat's own fork verdict on both clients
The options read already says whether the installed agent forks; an observed
no hides the action, an unanswered read keeps it disabled, and yes enables it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Preserve native copy boundaries and rewind behavior
* Preserve imported fork tips and serialize create replays
* fix(mobile): open a fork's source through the session's own chat opener
The forked-from link now asks the controller's existing opener for the source
by history id, so it follows that opener's host, selection and reveal rules
instead of navigating on its own.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Project fork markers from touched journal groups
* Retain fork group restoration for delayed readers
* fix(chat): keep a mid-turn response's fork in its own right gutter
The floated action covered the start of the next row. It now sits beside the
response's last line, in a gutter as tall as the prose, so it adds no line and
never reaches the following row.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Preserve native fork chain boundaries and durable streamed copies
* Place phone forks beside their source in window publications
* fix(tabs): adopt a host's new tab where the host placed it
First adoption put every unseen tab at the end of its group, so a fork the host
published after its source landed last. A new tab now follows its nearest host
predecessor when that tab is here; tabs already adopted keep the user's order.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(chat): reserve the fork gutter on every root response from the first frame
The gutter came and went with the fork offer, so prose reflowed when a turn
finished or support resolved. A pane that draws forks now keeps it on all root
responses, and the fork sits only there, not also beside Copy.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Return Codex copies without automatic provider renaming
* Resolve chat placement once at the current layout owner
* Preserve chat publication when saved opens are skipped
* Retry chat opens when queued placement changes
* Bound stale chat placement retries
* test: expect the OpenCode reader's imported fork tip
* perf(chat): keep the fork offer stable while a chat streams
Every stream commit made a new forkable-id set, so the fork context changed and
every offered response re-rendered. The set is reused while its members hold,
and rows get an action object that changes only with support or pending.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix: keep the fork params and Claude fork worker inside main's new lint limits
* Test fork copy and source refresh scaling
* fix: merge duplicate imports and stringify the OpenCode fork tip id for main's lint rules
* Keep fork placement behind session tab projection boundaries
* test: annotate the Claude copy test's hoisted account homes instead of asserting
* fix: add the fork action and forked-from strings to the English catalogs
* test: give fixtures the fork copy their agents declare; add the forked-from string to the boot catalog
* test: keep registry fixtures consistent with the fork copy their agents declare
* fix(orcad): ship the Claude fork worker with the server; update tests for fork fields
* Test saved fork selections through import and first send
* Preserve ordinary chat publication while saving placement
* Show fork beside the copy button on phone chat responses
Long-press opens text selection on every current phone, so the actions sheet that held fork never opened. The fork button now sits next to each response's copy button.
* Keep the phone fork slot fixed and offer it on every forkable response
The fork slot is now held by the row's own kind, as desktop's gutter is, so finishing a turn or learning the host's support never moves the timestamp. Responses with no copyable text (a visual only) still get fork, and each button re-renders only when its own offer changes.
* Follow main's moved runtime modules in fork code and tests
* test: build the phone response-actions fixture without type casts
* Let the phone read the host's agents so its fork action can turn on
Phone QA found the fork button always disabled: the phone asks the host which agents can fork, and the host refused that read from paired phones.
* Retry the phone's agent-list read, and read again after a reconnect
A read lost to a dropped connection or a timeout left Fork disabled until the chat was reopened.
* Own the phone's agent-list retry timer in its own effect
CI's effect-cleanup check could not see a timer set inside the read's callback; each retry is now a state change with an effect that sets and clears one timer.
* Give each phone connection its own agent-list retries
A count left over from an earlier connection could leave a new one with no retries, so one failed read kept Fork disabled after the transport moved.
* Scope the phone's agent-list retries to each spell of discovery
When the host's fork support dropped and came back on the same connection, the earlier failures carried over, so one more failure got no retry. Each stretch of discovery now owns its reads, failures and retry timer.
* Keep the forked-from source link reachable by screen readers
The divider's separator role and row label hid the source chat button inside it; the rules are now decorative and the text and button read normally.
* Keep fork names owned by adopted chat records
* Use the fork icon for Fork from this response
* Show the phone meta actions only when a row has one
An empty actions group still shifted the time by the icons' edge margin on rows with no copy, fork or rewind.
* fix(chat): put Fork beside Copy in the response's hover row
The fork button sat alone in a right gutter far from the other row actions.
It now joins the response's existing hover controls next to Copy, where those
controls show, and the gutter is gone.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(chat): keep a finished turn's actions on its last words and hold the Fork slot
A turn whose last prose was followed by tool or thought rows showed no Copy
and no Fork anywhere until it was collapsed. The actions now belong to the
turn's last prose row, decided when the transcript's rows are built, and keep
the gap below it whole so they never cover the next row. Root responses also
keep an empty Fork slot when not offered, so resolving support never moves
the row's other actions.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(chat): give a turn's actions only to a reply with words
An image-only reply after the turn's text took the response actions but could
not draw them, so the text lost Copy and Fork. Slot construction now picks the
turn's last reply by the same words the row draws and copies.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* fix(chat): let an image-only response hold a turn's actions when its text is folded
A collapsed turn that ends in an image hides its earlier text, so no drawn row
could show the response actions and Fork vanished. Each turn's actions now go
to its last drawn response with words, else its last with images. Copy and its
context-menu target appear only where there are words to copy.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Fix Claude fork cuts after local commands
* Extract the conversation copy input contract
* Preserve caller results at Claude fork boundaries
* test: check the copied fork for the wake answer without a type assertion
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* feat(browser): save and fill passwords in Orca's browser (experimental)
Off by default under Settings > Experimental > Saved passwords.
* fix(browser): secure saved passwords and fix login lifecycles
* fix(browser): keep the guest preload self-contained so saved passwords load
The shared uuid import split into a chunk the sandboxed preload can't require, so the
whole preload failed on every page. Element tokens now come from crypto.getRandomValues.
* fix(browser): fill a saved login on mouse press so clicking a row works
Pressing Orca's UI blurs the page field, which closed the list before the click landed.
* feat(browser): manage saved passwords from a Passwords section in Settings › Browser
Replaces the Manage passwords dialog with an inline section: save and Touch ID
switches, import menu, a searchable list grouped by site with last-used times and
hover actions in a capped scroll box, delete confirmations, and an Add/Edit dialog.
* feat(browser): turn saved passwords on for everyone instead of behind Experimental
Drops the experimental flag, its Experimental toggle and the badge; the Passwords section in
Settings › Browser now shows on desktop for the local host without opting in. With no toggle,
the guest disable message and the apply-to-open-pages step had nothing left to trigger them.
* fix(browser): refuse protected password actions when Touch ID is set up but unavailable, and keep fills on the matched page
Touch ID lockout or a closed lid made canPromptTouchID() false, which counted as a Mac without
Touch ID, so show, copy and protected fill went through unchecked. Enrollment from bioutil now
tells the two apart. A fill also kept no hold on the page across the Touch ID prompt, so a page
that navigated meanwhile got the password; it now goes only to the frame and origin it was matched for.
* fix(browser): keep a browser profile when its saved logins can't be deleted
Profile deletion removed the profile first and only logged a failed vault delete, so the
encrypted vault could stay on disk with nothing left to retry it. The vault now goes first,
and the profile stays (deletion reports failure) when it can't.
* 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): build-less TS/TSX plugins, typings and authoring tools
- Plugin frames transpile .ts/.tsx/.mts/.jsx on load (sucrase on a shared worker thread with a
2 s budget, cached in main), resolve relative imports to exact files, and refuse bare
package imports by name. Components and html panel/editor entries may be .ts/.tsx.
- orca plugin types writes typings for the components orca module, window.orca, worker
activate(orca), host.call and events into .orca/types, from one host-typings generator.
- orca plugin create --template components; templates omit publisher and target 1.4.246.
- orca plugin release-entry, dev inspect and restart; validate:plugin checks named files.
- Guest console errors reach orca plugin logs; dev workers restart on edits; the dev watcher
ignores .git, .orca and node_modules; Git and folder installs cannot replace catalog installs.
- examples/plugins/hello-tsx, docs, and the plugin-buildless-tsx e2e spec.
* ci: run the Windows parity probes with one tsgo checker
tsconfig.node peaks near 22 GB with tsgo's default four checkers (each holds its own types)
and about 16 GB with one; the 16 GB Windows runner paged the native probe past its 900 s
timeout once this branch's package.json change triggered the job. One checker gives the
same diagnostics (verified locally with --parity-only); the timing benchmark is unchanged.