* feat(wsl): run Git for Windows for a WSL project on a Windows drive
A project on C:\ whose runtime is WSL ran every Orca Git command through wsl.exe on
/mnt/c: ~300x slower than Windows Git, and blind to Windows-side edits. The project's
WSL runtime preference gains an optional `git: 'windows-host'`. With it, Orca's Git
(and where new worktrees go) is Windows; terminals, agents, accounts and hooks still
resolve to WSL, so nothing else changes. Older builds drop the field and go back to WSL
Git.
The conversion checks first, then the caller saves the returned preference through the
normal project update:
- Git for Windows must exist.
- New worktrees must not be set to go inside the distro.
- No linked worktree may have a Linux-path link. WSL Git made those; Windows Git sees
them as prunable, and Orca's prune after a worktree removal would delete their
metadata.
- Optionally writes core.autocrlf=true into the repo when Windows Git uses it, so WSL
Git in the project's terminals stops seeing CRLF changes. Never core.checkStat.
IPC is refused off Windows and with the internal WSL hosts gate closed.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(wsl): mock the drive-project IPC in the core handler registration test
Co-Authored-By: Claude <noreply@anthropic.com>
* test(wsl): pin WSL Git for a drive project that never chose Windows Git, and record which Git ran
* fix(wsl): base-ref lookups and the remote-identity sweep run Git where the project's runtime does
* fix(wsl): route base-ref and remote-identity reads by runtime only with WSL hosts on
These reads ran host Git on main. Routing them into a WSL-runtime project's
distro is part of D1c, so with the WSL hosts gate closed they run host Git
exactly as before.
(cherry picked from commit 2ed82987dc5b82c3a86ea7e03ce05e9efc3e77fb)
* refactor(ipc): register the filesystem handlers in one call, keeping core registration under its line cap
The optional commit-message resolvers pass straight through, so the call is the same with or
without them. #34059 left this file at the 300-line cap and the WSL drive-project wiring adds to it.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wsl): skip folder repos in the Windows Git check, and read worktree links with the prune guard's reader
Folder repos run no Git, so rev-parse on them always failed the preview. The link reader and
the WSL-authored test now come from worktree-prune-guard.ts; the copy's startsWith('/') wrongly
refused //wsl.localhost links, which Windows Git writes itself.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(wsl): the remote-identity sweep checks the distro a drive project's Git runs in, so it never boots a stopped one
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* plugins: app and terminal theme contributions
Manifests can contribute themes (public CSS tokens over a light or dark
base) and terminal themes (an ANSI palette), each at most 16 KiB. App
themes must set --background and --foreground; omitted tokens are derived
from them (surfaces copy the background, muted text, borders and accents
mix the foreground into it), and values must be colors (no keywords,
lengths, calc, var or url). Both load through the shared artifact-pack
registry with the plugin's display name and a content revision, reach the
renderer over IPC and are re-validated there. Catalog releases can declare
app-theme and terminal-theme, and marketplaces stop hiding theme listings.
docs/reference/plugin-themes.md documents the format.
* plugins: resolve a selected plugin terminal palette on every host
Selecting a plugin terminal theme saves a copy of its palette in settings
(terminalPluginPalettes). The shared lookup reads it, so main, headless
serve and relays answer terminal color queries and native chat matches the
terminal without the plugin loaded; a malformed snapshot falls back to the
default theme.
* plugins: one Theme list with plugin themes, painted safely
Appearance keeps the System/Dark/Light control until a plugin offers a
theme; then Theme becomes one list with plugin themes after a divider,
labelled with the publisher when names collide. Choosing one stores its
base in theme and remembers the earlier built-in choice, which comes back
while the plugin is off or after it is uninstalled; a plugin update that
changes the base re-syncs theme. It also offers the plugin's terminal
colors in one click.
The renderer paints only values CSS parses as colors, checks every
text/surface pair, ring and border against the effective set (plugin
values over this mode's built-ins) and repeats until nothing changes, so
dropping one pair cannot expose another. The applied theme is cached with
its id and revision, painted before first render, and dropped as soon as
settings show it no longer applies. Main bounds the new settings on every
write and load, and uninstalling a plugin clears its theme choices and
palette copies. Terminal themes appear under Plugins in the picker with the
plugin's name and are passed to lookups instead of read from a store.
* plugins: type the theme settings normalizer input; let the store own its normalization
* fix(plugins): check text contrast on the editor surface and clear terminal overrides when adopting a theme's terminal colors
* fix(plugins): reject theme colors the canvas probe silently ignores
* fix(mobile): scope workspace setup permissions to the responding host
Changing hosts can expose the previous desktop runtime settings and setup approvals. Own published data and setters by host and client.
* fix(mobile): keep an earlier selection's settings callbacks retired when the host is picked again
Ownership compared client and host id, so A -> B -> A made the first A's Save callbacks match again. Each selection now gets its own owner object.
* fix(mobile): own the workspace runtime context by host, not client object
Any server's relay change rebuilds every scoped client, which wiped the same host's settings and approvals.
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
- Editor conflicts: localize conflict-kind labels and hints, and build the
banner, rename note and snapshot time as complete messages instead of
joining English state labels with a translated fragment.
- PR file viewed checkbox: separate Mark/Unmark sentences instead of
injecting raw English verbs into '{{value0}} {{value1}} as viewed'.
- Quick Open ripgrep hint: one sentence with an embedded <code> element and
an interpolated reason instead of three fragments.
- Usage breakdown: session/turn/event counts use CLDR plural keys, so Russian
reads «1 сессия • 21 ответ» instead of «1 ответов».
Refs #34783
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Vyacheslav Scherbinin <14369958+gentslava@users.noreply.github.com>
* fix(i18n): localize provider failures and remaining shared UI copy
Translate Linear/Jira failures at the renderer boundary while preserving
English errors and adding optional stable codes for existing clients.
Localize host status, source-control metadata, discard confirmations,
native dialogs, and catalog gaps across all six shipped locales.
Inventory and reproduction paths contributed in #32207.
Co-authored-by: Seiji Kohara <9543980+seijikohara@users.noreply.github.com>
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
* test(i18n): assert stable task provider failure codes
* test(i18n): exercise goal notice fallback with an older language pack
* fix(i18n): address provider error and live title review findings
Handle missing remote error text, type provider codes and keep codes intact
through connection tests and optimistic edits. Fix the remaining Linear
load fallback and redundant translation calls, apply Japanese wording
corrections, and refresh native titles on language changes.
Co-authored-by: Seiji Kohara <9543980+seijikohara@users.noreply.github.com>
* fix(i18n): finish provider and shared-copy localization for all locales
- Translate the branch's new keys into de, ru, tr and zh-Hant (added to main
after this branch was cut), with Russian few/many forms.
- Use whole sentences for file deletion failures and the mixed batch notice
instead of inserting a 'Recycle Bin'/'Trash' word, and count keys for the
batch titles.
- Translate the workspace/activity options filter count (was a shared
'N filter(s)' literal) at the renderer call sites.
- Use _one/_other families for MCP server counts, untracked-file discard copy,
resume-chat counts, discard file counts and visible host counts.
- Localize PR/MR card status labels, the unsupported-agent hint, Linear title/
description update failures, the Linear 'showing first N' notice and the
Linear Connect button.
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
---------
Co-authored-by: Seiji Kohara <9543980+seijikohara@users.noreply.github.com>
Co-authored-by: Evgenii <413011+smwbev@users.noreply.github.com>
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(i18n): re-render memoized translated UI on language and catalog changes
Memoized components and useMemo/module caches that call translate() kept the
previous language after a switch or a plugin language-pack reload, because
react-i18next only re-renders components that subscribe themselves.
Add useUiLanguageRevision() (language + catalog revision via
useSyncExternalStore), call it in the 34 memoized translating components, key
translated useMemo results and module caches on it, and add a ratchet so new
memoized translating components must subscribe.
Fixes the composer pickers reported in #34783.
Co-authored-by: Vyacheslav Scherbinin <14369958+gentslava@users.noreply.github.com>
* fix(i18n): drive the language revision from the resource version
Tests that mock @/i18n/i18n have no i18n instance, so subscribe through
translation-resource-version (now also bumped on languageChanged) and give
useSyncExternalStore a server snapshot for renderToString tests.
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
Co-authored-by: Vyacheslav Scherbinin <14369958+gentslava@users.noreply.github.com>
* 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.
* Add repeatable Google cookie clearing for browser profiles
* Bind Google cookie clearing to its successful import target
* Repair cookie-clear contract test boundaries and positive flows
* Correct cookie-clear test fixture typing
* test: use checked runtime bindings in browser profile RPC fixture
* test: provide page registry to sidecar forwarding fixture
* fix: use selected browser profile owner for cookie clear menus
* test: provide confirmation context to link materialization fixture
* test: classify cookie clear session channels
* refactor: consolidate browser command property guards
* test: update cookie clear fixture for merged registry API
* feat: move Google sign-in recovery to browser settings
* Freeze Settings Google cookie clearing intent and refresh availability
* Restore baseline browser import disclosure coverage
* Pass the selected browser profile into cookie settings
* Localize Google cookie settings search keywords
* Update cookie restart fixture policy exports
* Keep localized browser search results visible
* fix: make Google cookie clear a red right-aligned setting that explains when to use it
* Explain why Google cookies are handled separately in the clear row caption
* fix(wsl-mover): add-host copy says bridge projects move automatically, in every locale
* fix(wsl-mover): add-host copy scopes the move to this distro and keeps Windows-drive projects here
* test(wsl-mover): sweep every locale's old 'until you move them' wording
* perf(explorer): reuse watcher child indexes by listing identity
* test(explorer): trim child index reuse tests to reuse and invalidation
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* plugins: bind worker and panel approval to exact package bytes
Consent for any plugin that runs code (a v2 sandboxed-ui or trusted-worker
profile, or a v1 manifest with a worker or panel) now names its installed
content hash, so an update cannot swap code under an old approval. Shipped
v1 installs re-prompt once. Data packs keep their fingerprints, and dev
trees stay unbound so a save doesn't re-prompt. The re-review notice is one
short line.
* plugins: integrity-check reviewed bytes before every worker spawn
The content verifier cached its first check, so bytes swapped between a
crash and its restart still ran. The controller now hands the manager one
uncached verifyBeforeSpawn hook that runs before every spawn, including
crash restarts, and replaces the cached first-start check, so nothing is
hashed twice and a running worker is reused without hashing. It is an
integrity check, not a sandbox: Node still reads files after it. Approval
is re-asserted at the same points, so a revoked plugin stops restarting
instead of counting as a crash, and cancellation does not wait on a hash.
* plugins: restart a running worker on its updated code
A refresh that changes a running worker's spec used to stop it and wait for
the next command or event. Reconcile now restarts it once on the new spec
after every stop, through the same approval and integrity path, and skips
the restart if a newer reconcile or dispose has taken over. Idle workers
stay lazy.
* test(plugins): re-review a dev copy that takes over an approved install
Approval of worker and panel plugins now names their exact bytes, so
switching the demo plugin from its installed copy to the dev folder asks
for review again; the journey approves the dev copy before using it.
* fix(plugins): admit worker restarts against current reviewed spec
* test(plugins): say why the worker refresh tests read the clock and wait out a backoff
* fix(plugins): refuse custom Git remote helpers in plugin downloads and test smudge filters for real
* fix(plugins): keep crash restarts through refresh pauses, stop workers before awaiting refresh on shutdown, and narrow inherited Git protocol allowlists
* test(plugins): shrink the flaky-test baseline for the worker controller test
Picks up the GHSA-5jr9-983r-c8x4 nesting-regex ReDoS fix (26.4.4), the
placeholder-injection fix for interpolated values (26.5.4), and
react-i18next's useTranslation resubscribe/stale resolvedLanguage fixes.
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* perf(orcad): spawn the terminal daemon as soon as the login env lands
orcad started its terminal daemon only after the secret store, profile and hook server were up.
The daemon (and every PTY) inherits process.env, which startup changes only through the
login-shell env adoption, so it now spawns as soon as that resolves, in parallel with the stores
and the hook server, and startup awaits it where it did before. A cleanup waits for an in-flight
spawn to settle before disconnecting. The login-env adoption and its logging move into
adoptWslHostLoginEnvironmentLogged.
* fix(orcad): observe the daemon startup promise where it is created
An early abort may never reach the await, so a future change that makes the spawn reject must
not surface as an unhandled rejection.
* 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
A windowed host answered OSC 10/11 for every terminal with its own window's
theme, so a Codex started from a dark client on a light-appearance host baked
a light input area. On such a host the launching client's colours and palette
now travel to the PTY owner as launcherColors and launcherAttributes. That
owner becomes the terminal's only theme responder: it answers OSC 10/11/12,
OSC 4 and ?996n with the launcher's theme (plus anything the app set) and
strips them, so neither the host's hidden-pane responder nor a viewer answers
with another theme. The startup query scanner gains these queries for pinned
terminals only; without launcherColors they pass through as before.
Terminals no client launched keep following the host-wide theme, and a
windowless host still follows its clients' later pushes. Older owners drop the
optional fields and behave as before.
terminal.setViewerColors also accepts an optional full appearance, so a
windowless host's hidden panes answer OSC 4/12 and ?996n like the client. A
colours-only update that contradicts the kept palette drops it rather than
mixing two clients' themes.
Fixes#34340
* test(wsl): copy whole orcad startup profiles out of the lane distro
A guest command's output is capped at 1 MiB, which truncated orcad's own CPU profile. The lane
now reads each profile in 512 KiB base64 chunks.
* test(wsl): refuse a lane file read that did not come back whole
execCommand keeps only the tail past its output cap; the chunked read now throws unless it got
exactly the file's size.
A failed agentSession.currentRequests read marked its version as tried for good, and the live read only reopened the subscription once per version. Two slow or dropped reads in a row left a pending approval or question without controls on remote desktop, web and phone clients until the decision changed.
The reader now re-reads a version whose read failed in transit, with the stream's reconnect backoff, and stops only when the answer breaks the contract or the host refuses for good. The transcript subscription is no longer reopened for a decision-read failure.
* Keep inactive tabs clickable when active dock crowds the strip
* Fix narrow tab dock state after drag cancellation
---------
Co-authored-by: m4air <m4air@Mac.localdomain>
* Recover brief Linear read transport failures
* Preserve safe diagnostics across runtime Linear reads
* Match existing attachment metadata in read contract
* Use a checked runtime in Linear CLI integration tests
* Keep Linear CLI integration coverage in the backend test graph
* Use integration test ownership for Linear CLI recovery coverage
* Observe empty Linear recovery traces before the first sink write
* Keep removed chat rows out of coalesced updates
* test: bound destructive history burst work
* test: verify removed history through transcript projection
* test: count retained row reads with typed getters
* feat(editor): built-in syntax highlighting for .env files
.env, .env.* and *.env files now open as a dedicated dotenv language with
comment, key, export, value, quoted-string and ${VAR} colouring instead of
INI. .envrc opens as shell, since it is sourced as a shell script.
* fix(mobile): map dotenv to the ini grammar for mobile highlighting
* fix(editor): keep quotes after the first dotenv value character literal
* fix(mobile): stop bundle work after caller cancellation
* test(mobile): use a type import for the fflate mock
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* plugins: download Git sources without checkout, within a protocol allowlist and size cap
Plugin and marketplace sources were a real clone/checkout, so user hooks,
smudge filters and core.hooksPath ran, insteadOf rules could reach any
transport, and nothing bounded the download. Now a --no-checkout depth-1
clone (or exact-commit fetch) runs with an empty hooks path, only the https
and ssh transports, and Orca writes the commit's exact blobs from ls-tree +
cat-file --batch. Symlinks, submodules, .git aliases, colliding portable
paths and SHA-256 repositories are refused. A size watcher stops the whole
Git process tree once the pack outgrows an approximate cap.
The exact argv lives in shared code and joins the real-Git compatibility
matrix, so the Git 2.25 lane runs it. Tests reach fixtures over an SSH
shim, since file transports are now refused.
* plugins: manifest v2 declares an execution profile
data < instructional < sandboxed-ui < trusted-worker. A v2 manifest is
strict and fails when it carries contributions beyond its profile; v1
manifests keep loading with the least profile inferred from what they
declare.
* plugins: pin exact catalog releases in orca-marketplace.v2.json
A v2 catalog entry carries the release it vouches for: commit, content
hash, version, profile, minimum Orca and contribution types. Preview and
install fetch that commit directly and refuse bytes that differ. The v1
file stays strict and frozen for shipped clients; v2 entries strip unknown
keys, and entries this client cannot install are dropped at parse time.
Catalog fetches read only the index blobs under their own download cap,
so a catalog repository is not held to one plugin's limits. Release-bearing
snapshots are cached under a new key, so an older build never reads them
and simply refetches.
readMarketplaceJson and parseMarketplaceFile from #30612 are replaced by
parsePluginMarketplaceIndex: catalogs are now read as Git blobs, so the
on-disk JSON read has no caller left.
* test(plugins): serve marketplace e2e fixtures over SSH
Plugin downloads now refuse the file transport, even through an insteadOf
rewrite, so the fresh-profile marketplace journey reaches its fixture
repositories through the GIT_SSH_COMMAND shim the unit tests use.
* test(plugins): give the Git compatibility plugin source its own identity
* test(plugins): record the plugin fixture's executable bit in the Git index on every platform
The hook relay's bridge-terminal presence borrowed the Codex-home helper; both now call a
neutral isWslTerminalSpawn, so a Codex-only change can't alter relay presence.
Co-authored-by: Claude <noreply@anthropic.com>
* fix(sidebar): prefetch the pressed workspace instead of switching to it
Rows are dragged to reorder them, so a press must not switch. Press activation
from #34594 is removed; a plain mouse press now starts the hover warm mount
immediately, and the click switches as before.
* fix(sidebar): start the press prewarm a task later and skip modified presses
---------
Co-authored-by: m4air <m4air@Mac.localdomain>
* fix(browser): expire abandoned extension menu snapshots
* Keep menu snapshot expiry cases in a focused host suite
---------
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
* fix(preflight): skip probing agents disabled in Settings
Background worktree-startup detection now passes settings.disabledTuiAgents
(which it already held for agent selection) into detectInstalledAgents, so
disabled agents are neither probed nor reported. The preflight:detectAgents
and preflight:refreshAgents handlers keep probing every agent so Settings →
Agents still reports real install status.
Fixes#34635
* test(preflight): cover disabled agent detection forwarding
* fix(preflight): skip disabled agents in background inventory
* fix(preflight): restore native inventory after settings changes
---------
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* perf(chat): typeset each unchanged formula once instead of on every streamed update
A streaming paragraph or list re-parses on each revealed prefix, and every
complete formula in it went through KaTeX again, as did every formula on a
virtual-row remount. Keep a bounded cache of typeset results keyed by what
the typesetter reads (tag, math classes, formula text), hand each tree its
own copy, and remember failures so invalid formulas still show their source.
* test(chat): import the typeset module type at the top of the math test
* fix(chat): evict the oldest cached formula without a type assertion
* fix(chat): type the readable math fallback without an assertion
* Cache immutable math results with bounded retention
* fix(watcher): prune nested ignored dirs on macOS and bound the flush fan-out
macOS was the only platform still watching nested node_modules/.git/dist/build
churn: the darwin branch passed the first 8 ignore dirs as plain @parcel/watcher
`ignore` entries, which the daemon resolves to `<root>/<dir>` only, and built
`ignoreGlobs` from the *remainder* of the list. Nested copies were therefore
pruned by neither layer, while Linux/Windows already got the full
component-anchored regex. Build the glob from the full list; the 8 plain paths
stay as-is because FSEventStreamSetExclusionPaths silently drops every exclusion
past its cap.
The resulting storms then hit an unbounded amplifier in the main process:
flushBatch stat'd every coalesced path with Promise.all (up to 5,000 in flight
against a 4-thread libuv pool), and scheduleBatchFlush could start another flush
for the same root while the previous one was still awaiting stats. Bound the
fan-out to the same limit the watcher child already uses and serialize per root,
keeping one flush running plus at most one queued so bursts coalesce instead of
multiplying. A queued flush is delayed, never dropped.
Fixes#11218
Co-authored-by: Orca <help@stably.ai>
* fix(watcher): share one stat budget process-wide and fence flushes on teardown
The per-batch cap multiplied by watched root, so N roots ran 8N stats; extract
the child's limiter and have both consume it. Teardown now fences and drains a
root's flush machinery so a queued flush cannot start, or emit, after close.
Also stop the queued flush from dropping a newer trailing timer's handle.
Co-authored-by: Orca <help@stably.ai>
* fix(filesystem): abort queued metadata when WSL watcher stops
* test(filesystem): satisfy watcher stat casting quality checks
---------
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
A mic tap opened capture, and with it the OS permission prompt, before
anything asked the host whether it could transcribe; the setup sheet only
appeared after the host refused dictation.start. The session screen now
gates the start on the setup read it already does, opens the setup sheet
when setup is missing, and hands the next tap back to the host and re-reads
when the sheet closes. A host that never had a model selected now offers
the mic. The sheet's switch uses MobileSwitch.
Fixes#35203
* fix(agents): preserve turn verdicts and monitoring in secondary views
* fix(agents): publish accepted native status changes to dashboard
* fix(agents): suppress equal rebuilt status notifications
* test(agents): explain proxy read forwarding in perf fixture
* test(agents): type production status fixtures completely
* test(agents): stabilize status fixture formatting
* Align web session test mocks with status transactions