mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 01:27:35 +00:00
90742fc22cd2d23e695268d14958da9911ff2da8
322
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
edc0373fcd |
plugins: Plugin Alpha (#35470)
* i18n(plugins): drop retired plugin strings from the Portuguese catalog
* i18n: keep the empty project group in the Spanish and French catalogs
* i18n: retire translated entries for plugin strings this change rewords or removes
* plugins: syntax contributions
A plugin can contribute up to 16 syntaxes: a TextMate grammar, optional
language configuration, and the file extensions and names it claims.
Main validates every grammar when the plugin is approved (shape, scope,
size, nesting) and lists only the file associations. A language's
grammars cross IPC only when a matching file opens, and includes must
resolve inside the same plugin. Catalog releases can declare syntax.
* plugins: highlight files with plugin syntaxes
Files Orca shows as plain text use a matching plugin syntax. Its grammar
compiles once in a worker that stays warm between edits and runs under
core's per-line limits; a worker that stops reporting progress or crashes
is terminated, the language stays plain, and the plugin card says so.
Tokens reach Monaco as semantic tokens, so Monaco asks only for models
shown in an editor, keeps one request per model, and keeps painting the
previous colors, shifted by edits, until the new pass lands. Plugin
languages borrow ids from a pool of fixed Monaco languages, counted by
the editors using them; a language no editor uses moves its models back
to plain text, and the least recently used idle slots are reused first.
* plugins: Gleam syntax example pack
An official-style data plugin with the upstream Gleam TextMate grammar
(Apache-2.0, provenance and license alongside) and language
configuration. A test installs it through the production inspection and
loads it through the syntax registry.
* plugins: list themes, icon themes and syntaxes in the marketplace preview
The preview's Includes line named only language packs, commands,
shortcuts, VM recipes, panels and events, so a theme or syntax pack read
as "Manifest metadata only".
* fix(plugins): a syntax failure belongs to one revision, not the syntax id
A grammar that failed in revision A kept the plugin card flagged after revision B
replaced it. Failures are now keyed by id@revision, matching the runtime slots,
and dropped when the installed list no longer contains that revision.
* chore(plugins): format the Gleam example grammar
* plugins: import the Monaco editor API, not the full bundle, from the syntax runtime
* plugins: type the syntax engine against the Monaco API it uses
* plugins: suggest a catalog plugin for files Orca can't open
When a file shows as plain text or as a binary Orca can't display, and a
cached catalog lists a release whose fileTypes include its extension, the
editor offers it: View plugin opens the marketplace preview (never an
install), Not now hides it for the session, and Don't suggest remembers
the extension. Suggestions come only from cached, verified catalogs, skip
kill-listed releases and anything an installed (even disabled) plugin
already handles, and can be turned off in Plugins settings. A release's
fileTypes must match its manifest's syntax extensions.
* fix(plugins): scope the file-type suggestion's Not now to the file type
The editor stays mounted when its file changes, so a single hidden flag
suppressed the suggestion for the next file type too. Track which file
type was hidden instead.
* plugins: type the plugin-owned settings normalizer inputs
* plugins: update the preview-request callback ref after render, not during it
* test(plugins): smoke specs for themes, syntaxes and file-type suggestions
Three end-to-end specs join the demo and marketplace journeys:
- an app theme and icon theme apply from Settings and fall back when the
plugin is disabled;
- a plugin syntax highlights an already-open file, re-highlights it after a
grammar update, and lets go when disabled;
- a v2 catalog release with fileTypes is suggested for an unknown file,
View plugin opens its preview without installing, and Don't suggest is
remembered.
The marketplace spec's Git fixture helpers move to a shared helper.
* test(plugins): say why the file-type suggestion e2e needs a longer timeout
* test(editor): install Monaco's cancellation guard in the owner view-state test
The test mocks monaco-setup, which skips the guard production installs, so
a disposed editor's pending word highlight surfaced as two unhandled
"Canceled" rejections once plugin syntaxes added a render. The run
passed but reported errors.
* plugins: plugin app themes recolor the code editor
When a plugin app theme is active, every Monaco surface (editor, diffs,
notebook cells, code excerpts, automation prompt) uses a theme derived
from the colors the document is actually painted with: editor background,
text, line numbers, cursor, selection, current line and widgets. Syntax
colors stay the built-in light or dark ones; if text would fall below
4.5:1 or a syntax color below 3:1 on the plugin's editor background, the
editor keeps its built-in theme. Colors are resolved to hex through the
browser's own parser, so color-mix() and other CSS color forms work. The
theme is redefined when the plugin updates or the mode changes, and the
editor returns to the built-in theme when the plugin theme is deselected,
disabled or removed.
* refactor(plugins): one module per contribution point and a single points table
The manifest's contributes object, the execution-profile derivation and the
catalog type list now read one PLUGIN_CONTRIBUTION_POINTS table instead of
three hand-kept lists.
* refactor(plugins): express id and path rules as patterns
Plugin ids and relative paths now validate with a regex first, so a generated
JSON Schema can carry them as `pattern`. The predicate only adds what a
pattern cannot (reserved names, Windows device names), and a bad value
reports one issue instead of two.
* plugins: document every manifest and catalog field in the schema
Each field now carries a description, examples and the Orca release that
first reads it, and each contribution item has a named fragment id. Manifest
v2 accepts an optional $schema key for editor completion, and the catalog
gains an authoring schema built from the same field definitions.
* plugins: generate published JSON Schemas and author references from zod
pnpm generate:plugin-schemas writes schemas/plugins/orca-plugin.schema.json,
schemas/plugins/orca-marketplace.v2.schema.json and the matching reference
pages under docs/reference from the runtime schemas. A test fails when the
committed files drift, when a field lacks a description or since-version,
when a documented example does not validate, and when the schema and the
runtime disagree on bundled manifests or known-bad inputs.
* plugins: report every manifest and catalog mistake with its path
Manifest and catalog validation now lists up to eight distinct problems as
`contributes.themes[0].label: must not be empty` instead of zod's first raw
message, and rewrites parser wording (required, unknown keys, allowed
values, limits) into what the author should change.
* plugins: say which Orca a newer plugin or catalog release needs
A manifest the strict schema rejects is pre-read for engines.orca and
manifestVersion first, so a plugin built for a newer Orca reports
"requires Orca >=X (this is Y)" instead of unknown-key noise. A catalog
release whose minimumOrca is above this build stays listed but is refused
before anything is downloaded.
* plugins: version the published schemas and pin v2 fields to a real release
Schemas move under schemas/plugins/v2/ so a later breaking format can
publish beside them without changing what a pinned URL means, and the
example plugin authors copy carries its own copy for offline completion.
Fields new with manifest v2 cite one constant, PLUGIN_MANIFEST_V2_SINCE
(1.4.232, the release after the latest tag), and a test fails once a tag at
or above it ships without manifest v2. The reference documents format 1 as
legacy.
* plugins: open review when enabling a plugin that was never approved
Dismissing the review dialog records keep-disabled without consent. Turning
the plugin's switch back on then only cleared the disable, so it returned
to "Needs review" with no dialog. Enabling now opens the review whenever
the result is still pending.
* plugins: release details for the plugin detail page
Catalog releases may carry a license, repository and homepage (https only),
an updatedAt date and a short plain-text changelog; an invalid value is
dropped so it never hides the plugin. Manifests may declare license and
homepage. Marketplace listings flatten name, version and those details, and
installed plugins report license, homepage, repository and the version a
rollback would restore.
The JSON lint-staged step no longer fails a commit whose only staged JSON
files are generated schemas the formatter ignores.
* plugins: fold in the schema review
- Parity runs both ways: documented examples also pass their zod field,
bundled manifests pass both the schema and the runtime, and manifest and
catalog negatives (traversal, oversize, wrong types, duplicates) fail in
both. A table lists every rule only the runtime can enforce, and each is
named in the description of the field it constrains.
- The published files carry the format in their names
(orca-plugin.v2.schema.json, orca-marketplace.v2.schema.json); $id stays
on main until the v2 release, and a test demands the release tag once it
exists.
- The v1 since-value is 1.4.160, the first release that read plugins, and a
test pins it to the tags. engines.orca documents that format 2 needs at
least the release that ships it.
- v2 catalog sources strip unknown keys like the rest of the entry, and the
v2 runtime schema is derived from the one authoring definition, whose
plugins field documents the duplicate-id rule. Contribution types and
categories declare uniqueItems; fileTypes items come from the file-type
schema itself.
- Issue messages no longer depend on zod's English: a missing field is told
from the input, and every pattern carries its own message. Unknown-key
lists show five keys plus a count, and each line is capped at 200
characters.
- A prerelease host (1.5.0-rc.1) now ranks below its release, as in semver.
* plugins: read the rollback version on demand, not while listing
The plugin list is rebuilt at startup and on every plugin change, and each
installed plugin cost a directory read to find the version a rollback would
restore. That moves to plugins:getRollbackVersion, which the detail page
calls when it shows the action, and a test pins the list build to zero
filesystem calls.
* plugins: v1.4.232 shipped without manifest v2, so v2 fields cite 1.4.233
The release-tag check caught it: v1.4.232 was cut from main before this
stack landed.
* plugins: list installed plugins while the plugin system is off
With the system off the service discovers nothing, so plugins:list returned
an empty list and the settings page could not show what is installed. The
client list now reads the install tree on demand in that state and projects
every plugin as disabled; nothing is activated or started, and startup with
the system off still does no plugin I/O. Older clients that hid the list
while off are unaffected.
Also for the plugin page: plugins:getInstalledManifest returns one installed
plugin's parsed manifest on demand, marketplace installs report the catalog
ref beside its URL, and the listing type declares the release record it
already carried.
* plugins: final schema decisions for catalogs and versioning
Catalog
- The catalog is orca-catalog.json with a required catalogVersion: 2; a
client that sees a higher version refuses with "update Orca to browse
this catalog". New clients read it first and fall back to the frozen
orca-marketplace.json, which export-legacy-plugin-catalog.mjs generates.
- Parsing is tolerant at every level: unknown keys are stripped, unreadable
entries and releases are skipped, over-limit lists are trimmed, a repeated
id keeps the first copy, invalid display-only fields are dropped.
pnpm validate:plugin reports each of those as an error for authors and CI.
- Entries list releases newest first; Orca offers the first whose
minimumOrca it meets, and shows "Needs Orca X" only when none fits.
Versioning
- engines.orca is the only gate and must cover the newest since-version of
every field and enum value used (capabilities, events and built-in actions
now carry per-value since tables). The check is part of the v2 schema, so
validation, catalog checks and installs all enforce it.
- pluginApi is optional in format 2 (defaults to 1) and refused on data and
instructional plugins. Format 2 rejects unknown keys at every level,
including engines, author and every contribution item.
- contributes.agents is reserved for coding-agent definitions and must be
empty in format 2 until their format exists.
- Plugins are gated against the newer of the app version and the newest
since this build defines, so development and local builds, whose package
version only moves at release, read the fields they introduce.
The policy is written into the generated references and pinned by tests.
* plugins: one-click install for content-only plugins, and the verified profile on the list
installMarketplacePlugin takes an optional enableIfData. Main then turns the
plugin on in the same step only when the installed, verified manifest is
execution: data, approving exactly the fingerprint it just installed through
the normal consent path; anything else comes back needsReview: true, whatever
the renderer sends. Older hosts ignore the field and leave the plugin pending.
Installed plugins now report their verified execution profile, so the plugin
page never infers "content only" from the absence of a worker.
* plugins: images and contribution summaries for plugin pages
Manifest format 2 gains cover and screenshots (alt text required), and its
icon must be a square PNG or WebP. Images are checked at install from their
headers only: static PNG, JPEG or WebP, per-kind pixel and byte limits, at
most 4096 pixels a side and 8 MB in total, so nothing is ever decoded to
decide trust.
Catalog releases may carry images stored in the catalog repository and
pinned by SHA-256, a summary of what they add, and the capabilities they ask
for, so a listing can show the plugin completely before anything is
downloaded. All three are dropped when unreadable; the summary and
capabilities must match the manifest exactly at install. pnpm validate:plugin
checks each image's hash, size and format against the repository files.
* plugins: serve plugin and catalog images from verified bytes
Images reach the renderer only as orca-plugin-image URLs, which main serves
with nosniff and the type it read from the header:
- catalog images are read from the catalog repository at the fetched
commit, kept only when their hash, size and format match, and cached by
SHA-256; a listing references only those;
- preview images are cached by hash before the staging tree is deleted;
- installed plugins' images are named by plugin, install hash and slot and
re-checked on every read, so listing plugins still reads no files.
Listings, previews and installed plugins carry an images field the plugin
page can render without fetching anything else.
* plugins: catalog theme palettes, and one-click never approves a dev override
Catalog releases may list up to four theme palettes (hex colors only) so a
listing can draw theme cards before install; they are display-only and
dropped when invalid. One-click enable now also refuses when a development
override shadows the installed plugin, since those are not the bytes the
user just chose.
* plugins: one-click approves only the fingerprint the user saw
installMarketplacePlugin takes an optional expectedFingerprint, the
preview's consentFingerprint. With enableIfData, main now approves only
when the installed fingerprint equals it, so bytes that changed between
preview and install stay pending for review instead of being enabled. The
release commit is already pinned by resolvedCommit. Older hosts ignore the
field.
* plugins: gate manifest v2 on 1.4.242 and publish schemas under docs/schemas
v1.4.240 shipped without manifest v2, so the first release that reads it is 1.4.242.
The root-directory guard refuses a new top-level schemas/ folder.
* plugins: read unvalidated schema input through a typed object guard and break the image validation import cycle
* plugins: one place decides an installed plugin's status word
Pull the status ranking, label and enabled/needs-review checks out of the settings row so the
coming list rows and detail page read the same words. No visual change.
* plugins: one list entry shape for installed and catalog plugins
PluginListEntry joins an installed plugin to its catalog listing (or stands for a listing alone),
and matchesPluginSearch is the one search both lists use. No visual change.
* plugins: usePluginCatalog owns catalog loading, refresh and preview
Sources, listings, refresh, the install/update preview and the outside preview request move out
of PluginMarketplaceBrowser into one hook the coming list and detail page share. The browser
keeps only its view state. No visual change.
* plugins: one plugin list with fixed slots, a plugin page, and inline states
- Installed plugins first, then one group per catalog (verified/unverified · owner or URL), capped
at 6 rows with Show N more; every plugin appears once
- Rows: the name opens the plugin page and covers the row; status, action, switch and ⋯ are
fixed-width sibling slots in Tab order. Update {version} is the action when a catalog has a newer
release; Stopped offers Restart with a red mark on the switch; Blocked offers Remove…
- Plugin page in the same pane: what it adds (commands with platform shortcut chips, panels,
recipes, contribution summary), what it can access, logs, and info. Back link, Alt+← or ⌘[
return focus to the row
- States inside the list: skeletons, a catalog that fails only affects its own group, no results
with Clear search, nothing installed. Plugins off keeps the installed list visible, dimmed
- Add plugin ▾ (folder, Git URL) replaces Install plugin; Plugin system stays at the top
- Catalog listings now expose their release (name, version, minimum Orca, types) to the renderer
* plugins: filter by category and catalog, one review for Update all, Needs newer Orca
- Filter popover (category, catalog) next to search; search and filters show every match
- Update all opens one review: updates that ask for new access are expanded with what's new, the
rest are one line, any can be unticked; installs run one at a time
- A catalog release that needs a newer Orca says so and disables Install, in the row and the page
- Installing from a plugin page shows a review with only access and source, since the page just
showed what it adds
* plugins: plugin page uses the manifest name; Off status word; official isn't a category
* plugins: catalog sources live in the Add plugin menu
* plugins: search takes its own row when the list is narrow
* plugins: release notes, license and links on the plugin page; roll back names its version
* plugins: fix list review findings
Plugin page owns the pane (back link and plugin header only); Adds to Orca names
every contribution; access never reads as 'nothing' when the check failed; filter
kinds have readable names; Update all is reachable, fetches once per open and
routes updates needing review; installed plugins join their own catalog;
attention-first order; paused list while plugins are off.
* plugins: readable category names on the plugin page
* plugins: Update all keeps its set; reviews queue; updates only from the plugin's own catalog
* plugins: name what an off or unreviewed plugin adds from its manifest; join catalogs by url and ref
* plugins: Needs Orca checks use the version plugins are gated against
Main gates plugins on pluginHostVersion, the newer of the app version and the
newest since-version the build reads. The plugin page compared releases to the
raw app version, so a development or local build showed Needs Orca for plugins
it would install.
* test(plugins): e2e journeys follow the redesigned plugin list
The page offers "Turn on plugins" while the system is off, catalog rows share
the installed rows' data-plugin-key, the review action is "Review", and an
enabled plugin reads "On".
* plugins: describe access from the verified execution profile, never from "no worker"
A commands-and-shortcuts plugin's page said "Content only. It has no code that runs."
because the page treated "no worker" as "no code". A worker plugin without capabilities
read "runs in a sandbox". The page now classifies from the catalog release's execution
profile (install refuses bytes whose manifest differs), the fetched manifest, or the
installed manifest's profile from the plugin list's `execution` field. Unknown stays
"Reading…" or "Couldn't read", never content only. The review dialog uses the same
profile, and an older host that omits it is reviewed as instructional.
* fix(plugins): read revision-scoped syntax failures on detail pages
* plugins: use the Blocks glyph for icon themes in the plugin page
* plugins: update latest-value refs after render in the update dialog and page navigation
* i18n: retire translated entries for plugin strings this change rewords or removes
* plugins: one action to install, inline consent, and a picture-first catalog
Settings > Plugins no longer opens a confirm dialog and then a review dialog.
- Content-only catalog plugins install from their card or page in one click; main
turns them on only when the verified manifest is data. Undo stays in place for 10s.
- Plugins that run code or instructions show "If you install <Name>, it can:" on the
host security surface above one Install & enable, which stays off until the access
rows are read, and approves exactly the fingerprint shown. Review of an installed
plugin happens on its page too (Enable / Keep off); Remove stays in its menu.
- The catalog is a grid of cards drawn from what each plugin is (its theme colours once
installed, a code sample, keycaps), with the name as a stretched link and one action.
- The page pins the listing it opened, says "Newer version available" instead of
swapping rows, and previews are prefetched only on hover intent, capped per visit.
- The plugin system switch, file suggestions, catalog sources and development folders
move into a header menu; amber text uses a contrast-safe token.
* plugins: give the reworded no-access line its own key so English shows the new copy
* plugins: pin installs to the release shown, warn by what a plugin carries, disclose replaced shortcuts
- The page pins the listing it opened; a preview of any other release (commit, catalog
commit or execution profile) leaves Install & enable off and shows "Newer version
available". One-click installs from a card refuse the same mismatch.
- Warnings are the union of the verified profile and the contributions: a panel that
also adds commands gets the instructions warning, never "bounded" or "own files only";
unknown contributions over-warn. Access rows follow the same rule.
- Shortcuts that replace one of yours are named in the consent before install, from the
manifest or the catalog summary; the shortcut list itself stays in Adds to Orca.
- Pages paint from the catalog summaries, capabilities and theme palettes, and show the
cover (or the card's art) as a hero, with screenshots in a strip and lightbox.
- Installing fills a reserved status line and keeps its action row (Undo, Use now), so
the page doesn't move; the settings scroller keeps a stable gutter.
- Row art names the plugin type instead of initials, rows drop the "Needs review" word,
the content hash moves into the menu, and card art is tinted and coloured.
* plugins: catalog covers on cards
* plugins: Review reopens its page after Back; hero art and stable status line follow what an installed plugin carries
* test(plugins): e2e journeys review and install on the plugin page, with no dialogs
* plugins: install exactly the release shown, classify from the full manifest, polish the page
Code review:
- A page or card arms Install only when the preview matches everything the listing showed
(catalog commit, release commit, content hash, execution); any change, including a
catalog-only refresh, reads "Newer version available". One-click installs send the
preview's fingerprint as expectedFingerprint, so main turns on only those bytes.
- Install stays off while a catalog refresh is in flight.
- Trust uses the full verified preview manifest when present; a capped catalog summary
counts as unknown and gets the stronger warning.
- The installed-manifest read is keyed by plugin and installed revision, so a same-key
update never pairs old contents with the new fingerprint.
- A failed Undo shows its error on the card or page and keeps Undo to retry.
- The security-surface test now covers the inline consent instead of the removed dialog.
Visual:
- Lightbox: close button clear of the image, "1 of N" with previous/next and arrow keys,
content scrolls on short windows, focus returns to the opening thumbnail.
- Keycap art shows the plugin's own first shortcut, larger, with the platform's keys.
- The hero fills the content column; a screenshot identical to the cover isn't repeated.
- "Change in Shortcuts" is a link; the chip says "Adds commands" (or "Runs a worker",
"Adds a panel", "Content only"); the disabled button says "Reading what it can access…".
- A content-only plugin's action row keeps fixed slots, so its note doesn't move on install.
* plugins: keep the decision above the fold, route suggestions to the page, final review fixes
- The page shows the decision (Install, the consent, Enable) before the picture, and the
picture is capped and cropped from its centre, so the button is in view at 1280x800 and
900x700. Nothing grows after first paint.
- The consent gives no access verdict while the plugin is still being read.
- A file-type suggestion opens the plugin's page instead of the old install dialog; that
dialog now serves updates only.
- A theme plugin reserves its "Use now" line from first paint; the action slot and its
button share one width.
- The file-suggestion toggle reports a failed save; a failed Undo is reported once, on
the card or page that offered it.
- Cards show a plain trust chip ("Content only", "Adds commands"); the local and bundled
group reads "Bundled & local".
- Install error copy moves into the protected plugin namespace, and the new consent
components join the language-pack security pins.
- Dead code goes: the keybinding consent preview (its conflict helper stays), its strings,
trustRunsNothing and the access-only preview plumbing.
* test(plugins): the file-type suggestion opens the plugin page, not a dialog
* plugins: the install decision sits top-right beside the name; no plugin on/off switch in the UI
- Plugin page: Install (content only), Install & enable (disabled until its access is read),
Enable / Keep off (installed, waiting for review) and the installed switch share one slot
top-right of the title. The consent sits directly under the header with no button of its
own; the "Can't reach anything outside its own files" note sits on the line under the
publisher, which every state reserves, so nothing moves between states.
- Removed "Turn off plugins" from the ⋯ menu and the "Turn on plugins" button from the off
state. The setting and all gating stay: off now comes only from policy, and the page says
so without a switch.
- e2e journeys turn plugins on through the setting and use the page's one button.
* plugins: restore Turn on plugins, drop Undo, add Remove to installed card menu
Plugins stay opt-in, so the off state keeps its Turn on button; only the
menu's Turn off item stays removed. Installed catalog cards get a sibling
more-actions menu with Remove (immediate, inline error) and Turn off/on,
inside a fixed-width action slot so the footer doesn't shift.
* test(plugins): installing a theme plugin never changes the active theme
* fix(plugins): confirm card removal before deleting data
* fix(plugins): pause review queue when leaving plugin page
* fix(plugins): disclose execution changes before updating
* refactor(plugins): share single and bulk update review
* refactor(plugins): share installed card and row actions
* test(plugins): cover confirmed removal and shared update review
* feat(plugins): offer icon and terminal themes after install
* test(plugins): capture settled review dialog screenshots
* fix(plugins): make installed contributions discoverable and actionable
* fix(plugins): label card-install toast Try it and mark terminal-theme Use now buttons
The toast action opens the plugin page rather than applying a theme, so it
always says Try it. Terminal themes often share their app themes' names, so
their Use now buttons carry a terminal icon. Update the update-review e2e for
the Use now accessible names.
* fix(plugins): apply a theme plugin's themes when the user installs or enables it
Installing (card or page) or enabling a plugin that adds themes now applies its
app theme (matching the current light/dark mode), icon theme and terminal theme
at once, with a 'Now using' toast whose Switch back restores the previous
selections. Updates, startup discovery and catalog refreshes never apply.
Co-Authored-By: Claude <noreply@anthropic.com>
* plugins: call toast actions through a typed button in tests; key card art by stable names
* i18n(plugins): drop retired plugin strings from the Portuguese catalog
* test(plugins): say why the update review e2e needs a longer timeout
* i18n: retire translated entries for plugin strings this change rewords or removes
* refactor(plugins): organize main plugin files by responsibility
* refactor(plugins): group shared plugin schemas and contracts
* refactor(plugins): organize renderer plugin surfaces
* plugins: keep the plugin service under the line limit after the folder moves
* refactor(plugins): move the JSON object guard beside the manifest schemas
* test(plugins): move the flaky-test baseline entries with the worker tests they count
* test(plugins): point the panel lifetime test at the reorganized plugin folders
* plugins: reserve skills, mcpServers, taskSources, connections and settings contribution keys
Format 2 accepts each key only as an empty list, so the points can ship later as additive
minors without a new manifest format.
* plugins: freeze host API v0 with a generated reference and refuse unknown pluginApi majors
The method table now carries a summary and an optional deprecatedSince, and renders
docs/reference/plugin-host-api.md with the stability and deprecation policy. A manifest
naming a newer host API major fails with "update Orca" instead of "must be 1".
* plugins: name the bad release in catalog validation and re-ask on any execution profile change
validate:plugin now reports each unreadable release with its reason (for example a tag
instead of a full commit SHA) rather than a count. The consent fingerprint includes a
declared non-data execution profile, so a data pack that becomes instructional no longer
keeps its one-click approval. Tests pin that catalogs drop non-SHA releases, that a
repository cannot load or approve a plugin it carries, and that added capabilities or a
changed profile always need re-approval.
* plugins: add the author guide, theme token list, v2 examples and a printed catalog release entry
docs/reference/plugin-authoring.md walks write, load a development folder, validate and
publish. The theme token table is generated from the public token set and its fallbacks.
hello-orca and hostile-panel move to manifest format 2. validate:plugin on a plugin
repository root materializes HEAD the way install does and prints the release entry to
paste into orca-catalog.json.
* plugins: name the host API type renderer and reserved contribution fields for their role
* plugins: gate the bundled example plugins on 1.4.240
* plugins: reserve orca, orca-*, official, anthropic, openai and github publishers
* plugins: rename storage/secrets to storage:own/secrets:own and gate events by domain capability
events:subscribe and the events.subscribe host method are gone; workspace events need
workspace:read and agent status needs the new agents:read. Format 1 manifests keep their old
names, rewritten on parse.
* plugins: move samples and fixtures off the now-reserved orca-samples publisher
* plugins: name the public surface workspace, not worktree
Events become workspace.created/removed with workspaceId and a kind field, agent status
carries workspaceId, and command context/keybinding when use workspace. Format 1 names are
rewritten on parse, v1 workers still receive worktree.* handlers, and clients treat any
non-global context from older hosts as workspace-scoped.
* plugins: rename the instructional execution profile to declarative
* plugins: move agents into the reserved contribution keys
Format 2 keeps contributes.agents empty like every reserved point; format 1 entries, which
Orca never read, are dropped on parse so they stay inert and bind no content.
* plugins: skip unknown theme tokens and icon slots at runtime, refuse them in validate:plugin
A token or slot added in a later release no longer fails the whole theme on older Orca.
validate:plugin now parses each theme, terminal theme and icon theme strictly. App themes
accept an optional schemaVersion 1.
* plugins: inject panel design tokens as --orca-* custom properties
* plugins: accept a closed, documented list of panel icons
Format 1 panels keep any icon name: a known one in either Lucide spelling is canonicalized,
an unknown one is dropped and shows plug, as before.
* plugins: make catalog release types optional and derive them
Every required release field is permanent for old clients, and types repeat what contributes
and execution already say. Printed release entries no longer include it.
* plugins: strip unknown kill-list and consent fields instead of refusing them
A strict kill list froze old clients on their cached list as soon as a later list added a
field, silently stopping revocation; a strict consent request would refuse a newer client's
optional review field.
* plugins: check only the shape of a panel action in the renderer
The host's capability gate already refuses methods panels may not call. Filtering against the
client's own method list blocked every panel method a newer host added on older clients,
including remote and SSH ones.
* plugins: read a leading >=x.y.z from engines.orca leniently in the compatibility pre-read
* plugins: derive content-bound approval from the contribution policy table
Each point now declares bindsContent, replacing the hand-kept list in the consent
fingerprint, so a new point such as mcpServers cannot swap bytes under an old approval by
being forgotten.
* plugins: name the host API "Host API 1" and add a stability section to the author guide
The guide now lists what is stable and what is experimental: the agent status payload, the
worker process model, language-pack keys, validate:plugin output beyond its exit codes,
settings:own and manifest format 1. Secrets copy now says encrypted file, not OS keychain.
* plugins: make the hello-orca sample speak in plain words
The worker command returns a sentence instead of a JSON object, and the panel labels
terminals by position instead of their opaque ids.
* plugins: give plugins short branch names, not refs/heads/...
* plugins: panels can no longer type into terminals; workers only (D3)
terminal.sendText with Enter runs shell commands locally or over SSH, which
the sandboxed-panel tier's "limited" consent copy did not convey. The
capability copy now says so, and the sample panel no longer types.
* plugins: put full-access worker plugins behind a second setting, off by default (D2)
Trusted workers are unsandboxed Node, so the plugin system switch alone no
longer lets them run. With "Allow plugins that run code with full access"
off, main refuses to install a full-access catalog release, approve or enable
one, and keeps installed workers stopped with an error naming the setting.
The catalog card says "Full access · turned off in settings" and links to
the switch; the worker chip now reads "Full access".
* plugins: bind dev-folder approval to the folder it was given for
A dev plugin's consent fingerprint now includes the folder's canonical path,
so approving one dev folder no longer approves another folder whose
manifest claims the same key and capabilities. The development dialog now
says edits inside an approved folder run without another review.
* plugins: close WebRTC as an outbound channel from panels
CSP has no WebRTC directive, so a panel could reach a STUN/TURN server it
controls despite connect-src 'none'. The panel shell now locks
RTCPeerConnection to undefined before plugin code runs, and the main window
that hosts panels gets the same WebRTC IP-handling policy as doc preview
guests. DNS-prefetch hints remain the residual doc preview already accepts.
* plugins: stop language packs relabelling trust copy outside plugin settings
Protection covered only plugin copy under settings, so a content-only pack
could rename the catalog's Official badge, the file-type suggestion banner,
or swap Allow and Deny on agent approvals. Those components are now
protected whole, the same way the plugin security dialogs are.
* plugins: refuse Git URLs with a dash-led user or host, or a '..' host
ssh reads a leading '-' as an option, and the scp form is not normalized, so
'stablyai/../evil' read as the official owner. The shared URL check used by
the catalog schema, validate:plugin and every install path now refuses these,
and provenance parsing refuses '..' path segments.
* plugins: flag an update whose catalog moved it to another repository
An update whose catalog now points at a different repository showed the new
URL without saying it changed. The update review now names the old and new
repository and leaves that update unticked, so it installs only once the
user opts in.
* plugins: sample worker returns a readable toast; sample panel shows no internal ids
Hello Orca's ping returned raw JSON, which the command toast printed as-is,
and its panel showed the full ref name. It now returns a sentence and shows
the plain branch name.
* plugins: move runtime policy checks and catalog types out of files over the line limit
* plugins: refresh the plugin safety list every 6 hours while plugins are on
Revocations previously reached a session only at launch or when plugins were
turned on, so a long-running Orca kept running a revoked plugin.
* plugins: main sends an update from a moved repository to review
The update dialog left such updates unticked, but main still accepted a
one-click approval for them. Main now compares the installed and new
repository itself and always answers needsReview.
* plugins: label the plugin system Alpha instead of Experimental
Settings badge, nav entry badge, search/description copy in all locales,
and plugin docs' stability sections. Setting keys are unchanged.
* plugins: trim the Plugin settings menu to titles and a short full-access hint
* plugins: reserve statusBarItems and sidebarCards and list planned contribution points
Both keys are rejected when non-empty, like the other reserved points. The
manifest and authoring references gain a Planned contribution points list
built from one table. Also moves the Alpha note on the host API page into its
generator so the schema/doc parity test passes again.
* plugins: an update that asks for nothing new keeps its approval
Before, any catalog update to a declarative, sandboxed-ui or trusted-worker
plugin changed its consent fingerprint (it binds the package bytes), so the
plugin turned off and waited for review after every Update. Only content-only
(data) plugins kept running.
Main now reads the approved version before installing and, when the update
comes from the same repository and adds no capability, no higher execution
profile, and no new command, shortcut, panel, event or VM recipe, records the
new fingerprint so the plugin stays on. Anything that grows access, a moved
repository, a development override or a plugin that was never approved still
waits for review, and the full-access switch still gates trusted workers.
The update preview now carries what grew, so the Update dialog lists new
shortcuts, commands, panels and events as well as capabilities. The consent
copy says updates that don't ask for more access install without asking.
* plugins: match the full-access test to the shorter setting name
* plugins: update catalog plugins automatically when an update asks for nothing new
Adds "Update plugins automatically" to Plugin settings, on by default. The
setting is pluginUpdatePolicy ('auto' | 'manual') so later policies can be
added without a migration.
At startup (after a short delay) and every 12 hours, packaged Orca refreshes
the catalogs and, for each enabled, approved catalog plugin with a newer
release, installs it in place when it comes from the same repository and
grows no access; the approval carries over and the worker reloads. A release
from a non-official catalog installs only after it has been listed for 12
hours, timed from when this Orca first saw it (stored locally because
catalogs carry no listed-at time), so takedowns can land first. An update
that grows access or moved repository is not installed: the current version
keeps running and the plugin shows "Update needs review", whose Review
update button opens the existing update review with what is new. Plugins
updated this way show a quiet "Updated to vX" chip, and each pass shows at
most one toast. Manual Update and Update all are unchanged.
* plugins: clear code-quality findings in the update approval and auto-update code
* plugins: give an app theme that leaves --sidebar unset a visible sidebar edge
Orca draws no line between the left sidebar and the main area; the sidebar's
slightly different surface is the edge. A theme that omitted --sidebar (like
the Dusk sample) had it filled from --background, so the sidebar matched the
main area and the edge vanished. An unset --sidebar is now mixed 8% toward
the theme's foreground. The in-repo sample theme sets --sidebar explicitly
and the theme smoke test checks it reaches the sidebar.
* plugins: treat an unknown update policy as manual, not auto
* plugins: auto-update only pinned releases, and only the release that was held
* plugins: start the auto-update hold clock before the catalog refresh, and check every 6 hours
* plugins: refresh the kill list right before auto-installing, and skip the install if that fails
* plugins: refuse an unpinned full-access install while full access is off
* plugins: an automatic update re-checks inside the install lock that the plugin is still installed
* plugins: compare the full repository path, so a GitLab subgroup move counts as moved
* plugins: time out the kill-list fetch and retry 15 minutes after a failure
* plugins: drop one unreadable kill-list entry instead of the whole list
* plugins: keep language packs off the orca.yaml and notebook trust prompts, certificate warning and site permission prompt
* plugins: compare whole capability declarations on update, and cover swapped command actions and shortcuts
* plugins: log automatic updates so headless and remote hosts record them
* plugins: say that automatic updates can change what a full-access plugin does
* plugins: pin and document the nested-frame WebRTC residual in plugin panels
* plugins: delete the unused PluginReviewBody
* plugins: drop the dead repositoryMoved parameter and the predecessor wrapper
* plugins: declare the plugin policy settings type once
* plugins: show what main found an update changes instead of recomputing it in the renderer
* plugins: move update approval and update policy into the catalog folders
* test(plugins): expect the workspace.removed event name in the lifecycle test
* plugins: rename structural helpers for their role, type the update identity read, and give plugin system settings their own group
* i18n(plugins): drop retired plugin strings from the Portuguese catalog
* plugins: build the hello-orca status line with a template string
* plugins: install catalog plugins from a directory of a shared repository
A catalog source may name a 'path' inside its repository. Orca downloads the
pinned commit as before but materializes only that subtree, so contentHash
covers the plugin's own files and sibling commits never change it. A changed
path counts as a moved repository and needs review. validate:plugin accepts a
subdirectory and prints its source path; the frozen v1 export skips such
entries.
* plugins: offer the full access setting on a full-access plugin's page
The page offered Install & enable even with full access off, then failed with a generic error.
It now shows the card's 'Turn on in settings' action, names the real reason when main refuses,
and drops a stale install error once the full access setting changes.
* plugins: say a content-only plugin couldn't load its files, not that it crashed
Language packs and other data plugins have no code or logs, so a load failure now reads
"Couldn't load its files" on the page and the row instead of "Its code kept crashing".
* plugins: leave Settings before running a built-in action from a plugin page
Built-in actions such as Open Board and Go Back are disabled while Settings covers the app,
so Run on the plugin page always failed. Run now closes Settings, commits that synchronously
so the dispatcher sees the app view, then runs the action.
* plugins: refuse terminal:send on panel plugins and never list it on panel approvals
Panels get no host method that types into a terminal, yet a panel's approval listed
"Type and run commands in your terminals". Format 2 manifests now fail validation when a
profile below trusted-worker asks for terminal:send, and approvals, the access section and
update review drop that line for format 1 panels that still declare it.
* plugins: say "catalog" in user-facing copy, not "marketplace"
The menu said "Catalog sources…" but the dialog it opens said "Marketplace sources" and
asked for orca-marketplace.json. Plugin copy now says catalog in every locale, names
orca-catalog.json (still accepting the older file), and the author guide matches the UI.
Internal identifiers and settings keys are unchanged.
* test(plugins): run a built-in action from its plugin page end to end
* plugins: concise copy pass across plugin UI
Update review shows one line per plugin and only what's new for updates
that need approval, with the rest behind a See all access disclosure.
Consent, Can access, dialogs, settings menu and empty states drop restated
titles and filler; safety facts (new access, full access = files/network)
stay visible where the user decides.
* plugins: keep See all access on Button and Collapsible primitives' own spacing
* plugins: separate light and dark theme slots so packs pair and mix
Plugin app themes now fill a Light theme or Dark theme slot by their base. Orca paints the
slot for its current mode, so under System it swaps live with the OS. Appearance shows both
pickers grouped by plugin; install fills the matching slot(s) and Switch back restores them.
A legacy single selection migrates into its base's slot.
* plugins: installed carousel and card grid, category badges, In use state; load language packs that cover protected copy
* fix(theme): let plugin themes colour menus and dialogs
Menus, popovers, selects, hover cards, sheets and dialogs painted a fixed
glass tint (dialogs rgb 23,23,23 in dark mode), so a plugin theme's
--popover was ignored and a true-black theme still showed grey dialogs.
The tint now lives in --floating-surface / --dialog-surface, which a
plugin theme replaces with its --popover.
* plugins: name the app-theme slot a pack fills, not its terminal colours
* plugins: page the installed row by whole cards; e2e follows the card menu
* plugins: hide the installed row's scrollbar and draw kind art instead of initials
The installed carousel pages with its arrows and snap points; the native
scrollbar under it only added a stray bar. Format 1 catalog listings (the
official catalog until catalog v2 publishes) carry no release types or
images, so their cards fell back to a two-letter monogram. Art now reads
the kind from catalog categories, and the last fallback is a plugin glyph.
* plugins: reserve official publishers to Orca's catalog and pin installs to their catalog
Reserved publishers (stablyai, official, anthropic, openai, github, orca*; case-insensitive)
and orca-* ids now install only from Orca's official catalog: a Git URL, local folder or any
other catalog is refused, and a third-party catalog listing one is refused whole. The rule lives
in one import-free module the directory indexer can vendor; validate:plugin uses it too and
warns when publisher differs from the origin remote's owner.
A marketplace install never replaces one recorded from a different catalog; switching means
remove and reinstall. Docs state the publisher == repository owner policy (enforced by the
official and community catalog CI, not a new runtime field).
* plugins: label trust by catalog source and note other catalogs listing an install
The chip beside a plugin now says where trust comes from: the Official mark for Orca's catalog,
otherwise the catalog name and the owner parsed from its Git URL (github.com/acme,
gitlab.com/acme/tools), never manifest text; Dev · unverified for development folders and
Unverified for Git URL installs. An installed plugin's page says which other catalogs list it.
* test(plugins): give update review's Git-backed steps a loaded-runner timeout
Install and update review each fetch a plugin over Git. On a loaded machine that
took 25-30s with or without the publisher checks, past the 10s expect default,
so the test read as stalled on Installing…
* test(plugins): give the row-art fixture the entry's catalog source fields
* test(plugins): say why the panel WebRTC test needs a longer timeout
* feat(plugins): dismissible Alpha notice on the Plugins settings page
Shows "Alpha: The plugin interface may change. Expect nuances." under the
Plugins title until dismissed; dismissal persists in UI state
(pluginsAlphaNoticeDismissed). Localized in all locales, with unit and e2e
coverage for show-by-default and dismiss-across-reload.
Co-Authored-By: Claude <noreply@anthropic.com>
* plugins: stop shipping Orca Navigation Shortcuts and retire stale bundled installs
Removes the bundled copy and its fallback-catalog listing. On startup, bundled
bootstrap now uninstalls any previously bundled plugin this release no longer
ships, so existing users don't keep a protected entry they cannot remove.
Removal code moves to plugin-removal.ts to keep plugin-install.ts under the
line limit.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(plugins): concurrent saves of one image no longer fail the update review
Each save now writes its own uniquely named temp file and treats a rename
failure as success when a concurrent writer already produced the same
content-addressed file. A cache failure now only drops the image from the
preview or catalog refresh instead of failing it.
* fix(plugins): an update keeps unchanged machine recipes off the review's New list
Recipes always counted as new because their commands live in files the
manifest diff cannot see. Main now reads what each recipe can run (id,
checkout mode, commands) from the installed tree and the preview's staging
tree, and only a recipe that runs something new asks for review. An
unreadable file still counts as new.
* plugins: app themes color code in the editor via VS Code-shaped tokenColors
Theme files gain optional tokenColors (TextMate scope -> foreground/fontStyle).
The derived Monaco theme maps them onto Monaco's token names, the plugin-syntax
legend and raw TextMate scopes; unreadable colors are dropped.
* test(plugins): theme smoke checks tokenColors color the editor and revert
* i18n: retire translated entries for plugin strings this change rewords or removes
* plugins: add the custom editors contribution point
A plugin can now declare contributes.customEditors to open files of given
types in the editor tab, beside Source. The editor runs in the same
sandboxed, no-network panel frame and only exchanges the document's text
over a scoped postMessage channel; Orca keeps the buffer, dirty state,
saving, external-change banner, read-only tabs and SSH files.
The Editor | Source toggle and the 'first scene after load is the
baseline' approach follow community PR #27413.
Co-authored-by: Roughriver74 <115543510+Roughriver74@users.noreply.github.com>
* plugins: list custom-editor plugins with panels in the plugin list
* plugins: name an editor-only plugin's access 'Adds an editor'
* plugins: keep the Editors category label for custom-editor plugins
* plugins: restyle plugin frames in place and keep file paths out of editor frame names
A theme change used to remount panel and custom editor frames, which reloaded
the plugin and lost its state (Excalidraw undo, unsent edits). The host now posts
orca-panel-theme and the shell updates the --orca-* tokens and the html class in
place. Custom editor frames are named with a random id: window.name is readable
inside the frame, and the old name carried the file's absolute path.
* plugins: let custom editors open binary files as bytes (contentKind)
A custom editor can now declare "contentKind": "bytes" (with "readonly": true)
to receive the file's raw bytes instead of its text, for formats such as
spreadsheets. Orca pages the bytes from the host that loaded the tab (local,
SSH or a paired runtime, through the existing stat + readChunk calls, so no
wire change), refuses files over 16 MiB with a "too large to open" message,
re-sends on outside changes, and never applies a bytes editor's edits. The frame
gets a transferred ArrayBuffer and the matched suffix, never a path.
Documents are now versioned: { version, readOnly, content: { kind, ... } }.
Text edits may name a baseVersion; an edit against a replaced document is
refused with an orca-editor-edit-rejected conflict. Text documents keep the
legacy text field and unversioned edits still apply, so existing editors work.
"readonly": true on any editor makes the install review say "Opens .x files in
Orca" instead of "Opens and edits".
* plugins: suggest catalog custom editors for files Orca already opens
The file-type suggestion only offered a plugin when a file opened as plain text
or as the binary placeholder. It now also offers a catalog custom editor for a
file Orca shows with a language (an .excalidraw file opens as JSON): the editor
asks main with the `editor` purpose, which matches only release file types the
listing's contributions name as custom editors, and only when no installed
plugin's editor handles the type. Binary files such as .xlsx keep the existing
path, since release fileTypes already include custom-editor types. The banner
reads "A plugin adds an editor for .x files: Name"; Not now and Don't suggest
work per type as before.
* fix(plugins): an update that lets a custom editor edit, take over opening, or change content kind asks again
* fix(plugins): one unreadable catalog summary item no longer hides the whole summary
* fix(plugins): plugin editors never open Orca-core file types by default, and join Markdown, CSV and notebook view toggles as options
* fix(plugins): catalog releases list editor file types as data instead of parsing the display summary
* fix(plugins): custom editor edits must name their base version; drop the pre-release text field
* fix(plugins): a custom editor edit Orca refuses keeps the tab dirty and blocks the save instead of vanishing
Rate-limited edits are held and applied before the next save; oversized ones are reported to
the frame and the user. Every save, from any trigger, first flushes plugin editor frames with a
bounded wait and refuses to write while a frame holds edits the buffer lacks.
* fix(plugins): run custom editors as network-isolated guests and save only on real key presses
Editors see file contents, so they now run as <webview> guests in their own in-memory partition
instead of iframes of Orca's renderer. The session routes everything through a dead SOCKS proxy
(loopback included), refuses every non-editor request and permission, and each guest gets
disable_non_proxied_udp, no popups and no navigation. An Electron test proves fetch, WebSocket,
images and TURN-over-TCP all fail from the editor and from its srcdoc and javascript: child
frames, while the same page in a plain session reaches every listener. Electron 43 still resolves
<link rel=dns-prefetch> names outside the session; the test pins that residual and the docs say so.
Save chords now come from main's before-input-event on the guest, which page code cannot
synthesize; the shell's keydown forwarder and the orca-editor-keydown message are gone. Guests
also run in their own renderer process.
* fix(plugins): enforce a read-only custom editor in main, not just the tab
Main reads readonly from the installed manifest (bytes editors always count) and drops every
edit such a guest posts before it reaches the renderer. The tab host also refuses them and tells
the editor its document is read-only, even on a writable tab.
* test(plugins): the editor-suggestion catalog fixture lists editorFileTypes
* plugins: custom editors edit and save binary files; drop readonly and the isolated guest
Bytes editors now post `{ baseVersion, content: { kind: 'bytes', bytes } }` full
replacements (a transferable ArrayBuffer). The tab keeps the unsaved bytes beside
the text drafts, marks itself dirty, and the normal save pipeline (frame flush,
Cmd+S, close prompt) writes them: locally through a new `fs:writeFileBytes`
atomic replace guarded by the loaded bytes' SHA-256, and on SSH-served or paired
hosts by uploading chunks with `files.writeBase64Chunk` and swapping them in with
the new capability-negotiated `files.replaceWithUpload`. Older hosts are refused
before anything is written. A stale baseline is a conflict: the edit stays
unsaved and the external-change banner offers Reload or Overwrite. Source stays
the binary placeholder.
Per the product decision, every custom editor may edit: the `readonly` manifest
field, its main-side enforcement and re-approval rule are gone, and an editor
that only views simply never posts edits. Editors run in the normal sandboxed
plugin frame again instead of a network-isolated webview guest; the frame's save
chord is honored only while it carries real user activation. Consent now reads
"Opens and edits .ext files in Orca. It can read the files it opens."
* plugins: reserve agentHarnesses and hooks instead of agents; rename agents:read to agent:read
* plugins: syntaxes and custom editors share one file matcher (extensions with the dot, plus filenames)
* plugins: title for themes and syntaxes, when for commands (format 1 names rewritten on parse)
* plugins: add the editor catalog type for custom editors
* plugins: official means listed by the official catalog, not an orca- id
* plugins: one envelope protocol and window.orca for workers, panels and editors
Workers, panels and custom editors now share one internal envelope
({orca: 1, kind: req|res|evt|cancel}) instead of three message sets.
Frames get a frozen window.orca from the shell (api, host.call with
AbortSignal cancel, host.has, on, and document helpers in editors);
ready/hello carries the api, the surface's methods and the theme.
Editors gain host calls through their own session.
The host API table is keyed by method with typed params/results (no
handler casts), per-method surfaces and a numeric since minor; every
params schema is strict. Errors are {code, message, retryable,
retryAfterMs?} with cancelled/timeout/conflict/not_permitted/too_large
reserved and unknown codes read as action_failed. Event payloads are
typed with a closed agent-status enum, and the list entry type is
shared by main and preload.
* plugins: orca.document.onDidChange hands a late subscriber the current document
Editors that subscribe after their bundle loads (Excalidraw) missed the
document that arrived first and stayed blank.
* plugins: custom editor documents up to 64 MiB, with a large-file note past 16 MiB
The cap covers text and bytes on every route; reads and SSH or paired-host
writes are already chunked, so only the shared cap moves. Past 16 MiB the
tab shows a small, non-blocking note that the editor may take a moment.
* plugins: delete dead props and branches left by removed rows, logs toggle and access retry
* plugins: one status word per state (a crashed plugin reads Stopped everywhere) and drop unused plugin locale keys
* plugins: contribution rows use the manifest point names, so the policy table is the one source of catalog types
* test(plugins): assert the Use now line and page behavior, not Tailwind classes
* i18n: add the custom editor large-file note to the English catalog
* plugins: fold the loose shared plugin modules into contributions, frames, images, capabilities, events, languages, installation and catalog folders
* plugins: custom editor tab icons and contributes.newFiles templates
A custom editor may declare an icon; the tab and its hover card show it and the
editor title instead of "Editor", falling back to the plugin icon. contributes.newFiles
declares untitled file types (title, extension, optional UTF-8 template and icon) offered
in the tab bar + menu, its search, the command palette and the plugin page, created at the
workspace root through the Markdown untitled-file flow. The install toast's Try it creates
one for plugins that declare them.
* test(plugins): hidden e2e for a plugin new file from the + menu and its editor tab icon
* plugins: turn the plugin system on by default with a one-time migration
Saved false from the old default flips on once (pluginSystemDefaultedOn guard);
a later deliberate false is respected. The Turn on plugins off-state is gone,
and the official catalog seed is deferred off the startup path (and skipped
offline), seeding on demand when the marketplace is opened.
* plugins: move the card menu Disable/Enable directly above Remove, without an icon
* plugins: show the Alpha notice with the warning banner tokens
* plugins: show each category's icon in the filter dropdown
* plugins: seed drawn fallback art per plugin so two listings never look identical
* plugins: show manifest covers for catalog releases published without images
The official catalog's newest Midnight, Nord, OLED and Dusk & Ember releases
were regenerated without an images block (release-entry only kept images the
author pasted), so their cards fell back to drawn art. A catalog that keeps its
plugins in its own repository now borrows the manifest's images from the
catalog commit, checked like declared images, and the validator's printed
release entry includes them so regenerated catalogs keep their covers.
* plugins: drop the unused Turn on plugins strings
* settings: find the Plugins page by plugin, mod and extension searches
* plugins: remove the Allow full-access plugins setting
Full-access (trusted-worker) plugins now need only their own per-plugin
approval: main no longer gates install, consent, enablement or runtime on a
global switch, and the settings menu item, the Turn on in settings card and
page states, and the stored key are gone. The consent now says plainly what
full access means. Kill list, official review and publisher checks are kept;
docs note an enterprise block policy may come later.
* i18n: retire translated entries for plugin strings this change rewords or removes
* test(plugins): prune low-value plugin tests
Drop tests that asserted CSS classes, DOM structure, internal call counts,
copy, or duplicated coverage; merge overlapping e2e file-type suggestion
specs. Keep security, consent, data-integrity, compatibility and main
journey coverage.
* test(plugins): stop git auto-maintenance racing marketplace fetch teardown
* test(plugins): import the panel session token schema from the frame bridge
* feat(plugins): open orca://plugins install links at the plugin's page
orca://plugins/<publisher.id>?catalog=<official|community|git URL> opens
Settings -> Plugins at that plugin; it never installs. Plugins off shows
Turn on plugins first, an unknown catalog asks before it is fetched, and a
malformed link only toasts. Reuses the skill-share deep-link path (open-url,
second-instance argv, sidecar handoff) with repeat/burst dedupe, and
registers orca:// on packaged Windows, which NSIS leaves unregistered.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(plugins): show the linked catalog URL on its own line
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(plugins): follow main's moved plugin files and language-pack coverage field
* fix(plugins): keep a plugin disabled through its update and give format 1 event handlers worktreeId
* fix(plugins): keep held editor edits across view switches, ignore stale editor entry reads, share bytes across split panes, and meet the low-evidence lint
* refactor(editor): keep the file content loader under the line limit
* fix(plugins): keep a bytes draft's baseline across reloads, cover plugin new-file menu rows, and move render-time ref writes into layout effects
* refactor(tab-bar): keep the create-menu controller under the line limit
* refactor(tab-bar): keep the create-menu controller under the line limit with the plugin new-file case
* test(plugins): turn plugins back on through settings in the install-link journey
* fix(wsl): import the atomic plugin file writer from its new folder
* fix(plugins): save bytes custom-editor edits from Save-and-close and the overwrite banner
* test(plugins): park the Linux-only bytes editor e2e failure as a follow-up
* fix(plugins): follow main's new language-pack tests to the moved artifact module
* test(i18n): give main's new plugin language-pack fixture its coverage
* plugins: manifest v2 ships in 1.4.245, since 1.4.244 released without it
* fix(i18n): import the plugin language-pack artifact from its folder in the shared i18n instance
* fix(plugins): drop syntax loads that land after dispose and restore terminal overrides on Switch back
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Roughriver74 <115543510+Roughriver74@users.noreply.github.com>
|
||
|
|
3094a4ae7b |
fix(i18n): code Create project failures and keybinding diagnostics (#35626)
* fix(i18n): code Create project failures and keybinding diagnostics * fix(i18n): localize conflict titles and interpolate create-project copy in one pass --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
0976872b9e |
feat(wsl): let a cached remote policy close the WSL hosts gate (kill switch, remote half 2/2) (#35529)
* feat(wsl): let a cached remote policy close the WSL hosts gate (kill switch 2/2) A cached remote policy of "block" now closes an internal gate the launch environment opened, for the whole run. It reuses the closed-gate path that already exists: with saved hosts or moves the gate becomes serve-only, so moved projects keep working while nothing new is added or moved. With nothing saved it is closed. A missing, unreadable or "allow" policy changes nothing. Main stamps windows so preload agrees, the download runs only on Windows with the internal gate open, and telemetry reports the block. Co-Authored-By: Claude <noreply@anthropic.com> * feat(wsl): report the applied WSL hosts policy and keep the way back under a block Telemetry reports the cached policy applied at launch as allow, block or missing (omitted when the internal gate left it unread). Tests pin that a block keeps Remove host, the way back and unfinished-move recovery, refuses new hosts and moves, and that a mid-run download applies only next launch. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
3a68805eee |
fix(wsl): Settings CLI status, CLI repair, interop health and link checks never boot a stopped distro (E9) (#35412)
* fix(wsl): Settings CLI status, startup CLI repair, interop health and link checks never boot a stopped distro (E9) - cli:getWslInstallStatus: opening Settings takes a settled running read and shows a refreshable "not running" status instead of starting the distro; the refresh button passes wakeWslDistro. - Startup CLI repair re-reads each listed distro (settled) right before its repair spawns and defers it otherwise, so a distro stopping mid fan-out is not restarted. - Interop health: stop-triggered checks no longer trust the stop event's list; every check takes a settled read, and again before the root repair. - shell:pathsExist (chat link and terminal hover existence) refuses a stopped distro's UNC path instead of statting it; callers already retry an unverifiable answer. * docs(wsl): note the missing-kernel availability probe as the known E9 exception * fix(wsl): shell:pathsExist refuses only the stopped distro's path, not the whole batch One UNC path in a stopped distro no longer fails the host paths checked with it; the renderer treats that path alone as unverifiable and retries it. |
||
|
|
8c3551bde3 |
fix(wsl): background Git, GitHub and GitLab reads never start a stopped distro; explicit opens may (E9) (#35410)
* fix(wsl): keep background git and GitHub reads from booting a stopped distro Git history, diff and status-follower reads, GitHub issue/work-item/check polls, chat link existence checks, the composer's create-base prefetch, the worktree-root fan-out and the Settings/Automations orca.yaml previews now refuse or skip a stopped WSL distro instead of starting it (E9). * fix(wsl): explicit opens may start a stopped distro; more polls gated (E9) Folds the parallel G1-G6 work into this branch and splits background reads from user acts: - An explicit open runs as a user act for its distro and may boot it: showing a diff tab or its Retry, showing Commits or its Refresh, opening the checks panel or entering its tab, checks Refresh, a check action, and linking or creating a PR. Main takes a wakeWslDistro flag on git:diff, git:branchDiff, git:commitDiff, git:history and gh:prChecks and runs those reads under runAsWslUserAct. - Polls, timers, refreshes after Git actions, prefetches and fan-outs stay background and are refused while the distro is stopped. - Also gated: the hosted-review card poll for every provider, the GitLab checks-panel poll (background flag), and the composer's open-time orca.yaml check (Create re-checks in the foreground). - Pollers keep the data they already show on a refusal: the issue on a card, the checks list, an open diff and loaded submodule children, and stop logging it. * docs(wsl): note that a hosted-review poll's stopped-distro refusal is still logged (E9) * fix(wsl): Settings re-asks orca.yaml once a stopped distro runs; drop link-check gating (E9) - Link existence checks (shell:pathsExist / pathExists) are no longer gated here: answering "missing" cached chat and terminal links as absent and toasted "File not found" on markdown link clicks. The pathsExist refusal lives in its own PR, which throws instead. - Settings no longer sits on "checking" forever: a repo whose distro refused the background check is re-asked on window focus, on visibility, and after 10 s, until it answers. An unverifiable distro is now marked (wsl-distro-unverifiable) and treated as unread too, instead of being stored as "no orca.yaml". - The sidebar issue poll and the Tasks list and count refuse with "Open a terminal in it to start it", since their Retry is itself a background read; the checks panel keeps "Retry", whose Refresh is a user act. * fix(wsl): Tasks Refresh, interactive review refresh and manual PR lookups may start a stopped distro (E9) - Tasks: a Refresh, Retry or search, or Tasks opened on a single repo, passes wakeWslDistro through gh:listWorkItems and gh:countWorkItems (IPC only; the RPC twins and web routes drop it). A multi-repo open stays background. Their refusal says "Retry" again; only the sidebar issue poll says "Open a terminal". - hostedReview:forBranch wakes for an interactive request (the checks panel's manual Refresh), so GitLab, Bitbucket, Azure DevOps and Gitea reviews with nothing cached can load. - gh:prForBranch, the renderer's fallback when refreshPRNow is missing, is gated like the other card polls; a manual lookup wakes, matching refreshPRNow's manual-only rule. The fallback call moves into its own module, built from the refresh candidate. * fix(wsl): only an explicit Refresh starts a stopped distro for review status (E9) hostedReview:forBranch woke on admissionTier 'interactive', but the visible-review scheduler sends 'interactive' for the selected card on a timer, so that poll restarted a stopped distro every interval. The wake is now an explicit wakeWslDistro flag (desktop IPC only). The card refresh helper sets it, since every caller follows a user act (the checks panel's manual Refresh, or a review created, linked or edited), and the manual Refresh also wakes its pre-refresh git status. admissionTier is back to priority only. * fix(wsl): an explicit review Refresh never joins a refused poll (E9) fetchHostedReviewForBranch let a forced card Refresh join an in-flight forced scheduler poll, since the join only compared force. On a stopped WSL distro that poll is refused, so the click got the refusal. The in-flight entry now records the wake, and a waking request joins only a waking flight; a poll may still join an explicit Refresh. |
||
|
|
9babef2866 |
fix(wsl): background preflight and agent detection never boot a stopped WSL distro (E9) (#35411)
* fix(wsl): background preflight and agent detection never boot a stopped WSL distro (E9) Integration checks (git/gh/glab --version and auth status) and agent detection ran inside the focused workspace's WSL distro on every mount, poll and status-bar render, and wsl.exe starts a stopped distro. They now take a settled running read first and refuse (WSL_DISTRO_STOPPED or WSL_DISTRO_UNVERIFIABLE) when it is not running. Window focus/visibility, retry buttons, agent refresh buttons, a runtime choice in Settings and first-run onboarding pass wakeWslDistro, which runs the check as a user act on that distro only. Running distros behave exactly as before. * fix(wsl): a focus wakes only a focused WSL workspace's distro; end-to-end preflight gate test A focus with a native workspace active sends no wake. Ports the real running-list preflight case from #35395 and adds user-act scoping cases. * test(wsl): model the running gate in the preflight RPC suite and cover a stopped distro Windows CI runs the real gate, so the WSL detection case must state that the distro runs. * fix(wsl): an agent refresh click never joins a background refresh it would be refused with Store the wake flag with each in-flight refresh, as preflight.ts does, so a status-bar or Agents refresh click during a mount refresh reaches main as a user act. Note why the RPC project branch stays ungated. * fix(wsl): a refused background check waits for the distro, and an agent picker wakes it A preflight or agent detection refused for a stopped WSL distro was final: once the distro came up, nothing re-ran it, so the tab-bar + menu offered no WSL agents (real-WSL golden). Now a refusal is deferred until the distro is next confirmed running (deferUntilWslDistroRunning), and main tells renderers to re-ask. Opening an agent-launch picker (tab-bar +, composer, continuation dialog, source-control action dialog) whose list was refused retries it as a wake, never joining a background probe. * fix(wsl): an open agent picker wakes a refused list once, and never retries real failures The picker wake fired whenever the list read 'failed', so a woken probe that failed again (pending -> failed) re-fired it: an endless wsl.exe loop while the picker stayed open, and repeated probes for native failures too. It now fires at most once per open per target, and only when the last probe was an E9 refusal (distro not running/unverifiable), matched by the gate's message. * fix(wsl): forget agent-inventory refusals when the inventory or its project contexts are cleared |
||
|
|
bfbdcd7e80 |
feat(wsl): run Git for Windows for a WSL project on a Windows drive (D1c-2) (#33090)
* 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> |
||
|
|
5018241866 |
feat(plugins): app and terminal themes in one Theme list, painted safely (#30719)
* 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 |
||
|
|
bb1b05e3bd |
Clear Google cookies from a browser profile, as often as you need (#34158)
* 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 |
||
|
|
8e9a08b543 |
fix(preflight): skip probing agents disabled in Settings (#34832)
* 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> |
||
|
|
045f8c8266 |
feat(files): show images and PDFs from the byte-range preview path, local and remote (#35165)
* feat(files): show images and PDFs from the byte-range preview path, local and remote ImageViewer and PdfViewer read an orca-media:// URL instead of base64 when the editor opens a file: images load by URL, and pdf.js reads PDFs by range, so a large PDF no longer arrives whole through files.readPreview or pages into memory first. The grant mints only for the editor's viewers; diffs, git blobs, markdown images and the paired web client keep base64. - Minting an image checks its header with the base64 path's rule, so an image proven too large to decode safely never reaches the decoder. - orca-media gains fetch and CORS privileges, and range responses expose Accept-Ranges and Content-Range, so pdf.js can read by range. - Grants report the file size the viewer used to estimate from base64. * fix(files): read PDFs by real range, check served images, keep old hosts' previews - pdf.js fetches ranges only over http(s), so an orca-media URL was read whole; a small range transport now hands it bytes=a-b reads from the grant, and a failed range fails the preview instead of hanging it. - A file can change after mint, so the raster header is checked again on the bytes each image request serves (the same handle locally). - A paired host without files.readChunk falls back to files.readPreview for images and PDFs, as before; only audio and video need the update. * fix(files): mint no local document grant for a renderer gone mid-mint The local image/PDF mint is async now (authorize, open, header check), so a renderer that closed meanwhile could leave a grant no teardown drops. It binds the renderer lifetime first and refuses to mint once it's gone, as the remote mint does. * fix(files): keep the 50 MB cap for URL images, and probe remote headers incrementally An <img> decodes the whole file, so image grants keep the base64 path's 50 MB cap; PDFs, now read by range, don't need one. A remote header probe reads only each wider step's new bytes instead of re-reading from the start. A replaced image of a different size resets its zoom. * fix(files): tear down a PDF load whose range failed, and read 256 KiB ranges A failed range only showed the error and left the pdf.js task, its worker and pages alive; it now destroys that load first. pdf.js asks for one readChunk-sized range at a time instead of 64 KiB, and a Range preflight gets its CORS answer instead of 405. * fix(files): read PDF ranges over IPC so orca-media needs no fetch or CORS orca-media had gained supportFetchAPI and corsEnabled, and its responses sent Access-Control-Allow-Origin: *, so pdf.js could fetch ranges. That let any default-session frame holding a token read the bytes. pdf.js now reads a PDF grant's ranges through fs:readPreviewRange, which main answers only for the renderer that minted the token. The scheme is back to element-load privileges (standard, secure, stream), responses carry no CORS headers, and preflights get 405. Grant bookkeeping moves to preview-grant-registry.ts. An e2e spec proves an orca-media URL can't be fetched from the app page or read from another session. * ci(e2e): route the byte-range preview sources to the viewer specs that exercise them Changes to the orca-media grant path, the image/PDF viewers and the PDF range transport now run the PDF reload, rebuild and find specs, the remote large-file open, media playback and the partition-isolation spec. * fix(files): stop PDF range reads on abort, abort remote reads with the window, fix the CI route - A closed or reloaded viewer schedules no further pieces of a merged range, and a remote range read stops when its window goes away. - A URL without a size is an error rather than a fetch the scheme refuses. - The PR guard job's sparse checkout and its admission test include the new route module, and the route now also covers the mint handler, preload bridge, editor surfaces, scheme registration and read client. * fix(files): classify linked previews by their target, keep range reads off stopped WSL distros A local image or PDF reached through a link is classified by the file it resolves to, at mint and on every read, and a re-mint after the link is retargeted gets a fresh grant of the new type. A paired host's document whose first bytes are another kind defers to files.readPreview, which classifies the target there. Lazy local reads go through the non-waking WSL guard, as fs:readFile and fs:readFileChunk do. |
||
|
|
808aaee3f6 |
fix(wsl): hide the sidebar setup-script card while the repo's distro is stopped (#35163)
A background hooks:check refused for a stopped WSL distro now says so (unavailable: 'wsl-distro-stopped'). The setup-script prompt maps it to a distro-stopped state: the card hides instead of showing 'Couldn't verify…' with a Retry that cannot succeed, and focus re-inspects, so the card returns once the distro runs. An unverifiable distro stays a retryable error. |
||
|
|
c58591e56d |
fix(wsl): refuse render-driven hook checks on a stopped distro instead of booting it (#35155)
hooks:check takes an optional background flag. The sidebar setup-script prompt and the setup guide's progress probe, which run on render, pass it: on a stopped or unverifiable WSL distro the check answers status 'error' without opening orca.yaml over \\\\wsl.localhost, which would boot the distro. Launch preflight and settings, user acts that start the distro anyway, are unchanged. |
||
|
|
f231d1cde6 |
feat(files): play remote audio and video through one byte-range preview path (#35038)
* feat(media): read remote media ranges through the paired runtime Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(media): stream remote media through orca-media grants Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(editor): play video and audio from remote runtime workspaces Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(media): surface update-required for remote media and cancel in-flight chunks Probe files.readChunk once per environment and pairing revision before minting a grant so older servers show the update message. Closing a media stream now aborts the in-flight remote chunk. Also validate the IPC address, fix extension-only names, and tighten the preview return type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(files): one classifier decides which viewer opens a file Local reads, files.readPreview on hosts, git blob previews and the desktop's remote binary handling each kept their own image/PDF extension table, and media had another. file-preview-kind.ts is now the one table: image, PDF, audio or video, with the MIME type. AVIF, which only local reads knew, previews on hosts and in git diffs too. * perf(runtime): give byte-range reads their own small call lane files.readChunk (media streams, paged files, downloads) now runs in a two-call lane per environment, so a playing video or a download never holds the slots terminal input and workspace calls use. * feat(files): stream previews from paired runtimes by byte range Generalises the remote media grant into one byte-range preview path: an orca-media:// grant keyed by environment, worktree, path and pairing revision, streamed over files.stat/readChunk. Audio and video use it now; the shared classifier decides which viewers do. - One files.stat at mint replaces the readChunk probe: it proves the host serves range reads and that the path is a file, so an old host or a missing file fails in the tab, not as a silent player error. - A burst of range requests shares one stat (reused for 1s), so seeking costs one round trip less on a slow link; later requests re-stat, so a growing recording keeps playing. - Removing a paired runtime revokes its grants; a re-paired one answers 410 and drops the grant. - Only readers that render bytes mint a stream; baseline checks don't. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * fix(files): prove chunk reads at mint, and let a reload report the new size Hosts from v1.4.5 answer files.stat but only v1.4.111 and later answer files.readChunk, and no capability names it, so minting reads one byte, cached per pairing, and an older host fails in the tab with the update message. A re-mint seeds the grant with its fresh stat, so a reload never reuses an older size. A renderer gone mid-mint mints nothing. Preview chunks time out after 20s so a stalled one frees its lane sooner. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * fix(files): resolve preview hosts in the pairing registry's own directory The remote preview reader looked environments up under the canonical user-data path, while the pairing IPC writes the registry under app.getPath('userData'), which can differ in casing on case-sensitive installs. Both now use one getter. A chunk-read verdict is cached only when a pairing revision pins it, so it can't outlive a re-pair. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * fix(files): read the pairing registry from one directory everywhere Doc previews resolved paired servers under the canonical user-data path, the same casing mismatch the media reader had. They and every other main caller that names the registry directory inline now use getRuntimeEnvironmentRegistryRoot(), so it has one source. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * fix(files): pin an unpinned preview grant to the pairing it was minted on A renderer that hadn't loaded the environment's pairing revision yet sent none, and every later chunk read went unguarded, so a re-pair under the same environment id would let the old URL read from the new host. Main now pins the registered revision at mint. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * refactor(files): route the remaining pairing-registry readers through the one getter AI-vault host scans, the settings runtime-environment preference, skill capability checks and the mobile relay host list named the registry directory inline. They now use getRuntimeEnvironmentRegistryRoot() too; callers that also use the directory for other storage keep their own path. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> * refactor(files): write new pairings through the same registry root The ephemeral VM pairing writer named the registry directory inline; it now uses getRuntimeEnvironmentRegistryRoot() like every reader. Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> --------- Co-authored-by: Sahil Sharma <128581847+SahilSharma0810@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2747079f94 |
fix(wsl-mover): ask before quitting while a WSL project move runs (#34860)
* fix(wsl-mover): ask before quitting while a WSL project move runs A plain quit (Cmd/Ctrl+Q, closing the window) during a move gave no warning: the next launch recovers safely, but the move is lost. While main reports a move running, the window's close guards now ask "A project is moving to its WSL host. Quit anyway? The move will be undone at next launch." Behind the internal WSL hosts gate: the guard registers only with it open, and main answers false with it closed. An intentional restart and an unanswered question never prompt. * fix(wsl-mover): the quit prompt's running check gives up after 2 s The close request is acknowledged before the guards run, so a hung wslMove:isRunning would block quitting for good. The guard now treats no answer within 2 s as no move running, like a failed ask. * test(wsl-mover): give the flag-off host test the confirmation dialog the quit guard reads Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
ad8d35eb59 |
feat(wsl): serve saved WSL work behind a closed hosts gate (gate states, kill switch 1/2) (#34683)
* feat(wsl): serve saved WSL work behind a closed hosts gate (serve-only) The WSL hosts gate gains three states. A closed gate with a saved WSL host or a committed move becomes serve-only: saved hosts stay listed and reachable, committed rewrites, retention, interrupted-move recovery and the way back keep running, and the preload API is exposed through a stamped window argument. Adding hosts and starting moves still need the open gate. With nothing saved the gate stays closed exactly as before. * fix(wsl): stamp serve-only into the dashboard popout and Space windows too They load the same preload, so without the argument they hid saved WSL hosts' status and Connect in serve-only. One helper now supplies the argument for every window on the shared preload. * fix(wsl): reviewer follow-ups for the serve-only gate - Refuse wslHosts:add unless the internal gate is open here, so this PR is safe on its own. - Promote on any move journal entry, so recovery can reset an in-flight move whose host record is gone. - List unfinished moves in serve-only. - An unreadable WSL deployment store fails closed in serve-only too, through a shared serving flag main sets at startup. - Report the gate state in wsl_usage_snapshot as an optional field. |
||
|
|
f173998203 |
feat(wsl-host): a chat on a stopped WSL distro says so and offers Start (#34681)
* feat(wsl-host): a chat on a stopped WSL distro says so and offers Start * fix(wsl-host): a chat's Start never cancels a pending WSL host Remove |
||
|
|
1eaaf85e9f |
Land the WSL project mover dark (merges only after verify-15b, the flag-off audit and green CI) (#34059)
* test(orcad-migration): pin the SSH manifest through the real dormant collectors Co-Authored-By: Claude <noreply@anthropic.com> * refactor(orcad-migration): read the dormant-state export through a source-kind scope A local-WSL scope lives on host local and owns only its projects, so host-wide matches stay an SSH whole-host rule. SSH bytes are pinned by the collector golden. Co-Authored-By: Claude <noreply@anthropic.com> * feat(wsl-mover): export a local WSL move's signed manifest with its dormant state (D1b-3c) Collects the scoped projects, their groups and every dormant-state kind through the local-WSL export scope, rewrites UNC paths to the distro's, and returns blockers for anything the collectors can't carry instead of dropping it. Automations move disabled, as the wire requires, and come back as a list to re-enable on the host after commit. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): reset an interrupted move to zero, or finish it once the host proves a commit Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): abort a move by its identity when its manifest is too large for a request Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): cap a new move's manifest below the request limit, and move forward on a by-reference commit only once the host flushed it Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): remove only the newest move of a distro, so its chain stays readable Co-Authored-By: Claude <noreply@anthropic.com> * feat(runtime): clients read a migrated pane's scrollback from its host (D1b-6d-1) * fix(runtime): hold a remote pane only when its host is known to serve scrollback, and never read bytes in render (D1b-6d-1) * fix(runtime): route the scrollback read by the tab's own host, never the focused one (D1b-6d-1) * fix(runtime): resolve the scrollback host through resolveOwner and use the shared RPC error check, after main moved both (D1b-6d-1) * feat(wsl-mover): a moved project's existing chats stay listed and resumable on this computer (D1b-7a) * fix(wsl-mover): moved-project chats go through the layout owner instead of writing layout directly (D1b-7a) * test(wsl-mover): run the moved-project chat runtime test in the Node runtime (D1b-7a) * test(wsl-mover): read the hidden local row through main's per-host hidden-repo API (D1b-7a) * feat(wsl-mover): rewrite the desktop's routing and seed the host's session after a move (D1b-7c) Registers the main-side desktop rewrite stores ui-routing, session-globals and host-session-seed. Adds a +2 main layout-writer baseline line for wsl-move-main-rewrite-stores.ts: these are one-shot, ledgered move rewrites, and no LayoutCommand can set focus or seed a runtime host's partition. * fix(wsl-mover): finish the main rewrite before the window loads, keep one copy of each moved tab, and copy instead of move (D1b-7c) * feat(wsl-move): rewrite renderer stores for moved projects and keep their UI through catalog prunes (D1b-7d) Registers the renderer-side desktop rewrite stores quick-open-history, file-view-preferences and notebook-environments. The renderer copies each moved workspace's entry to its WSL host key, marks it applied in the same storage, and records the ledger entry; main requests a storage flush first and accepts only the main window. Committed moves are re-listed for re-application at every startup. Catalog prunes keep filters, hook trust and setup-script dismissals of moved repos. * fix(wsl-move): import the migration manifest types from main's orcad-migration folder (D1b-7d) * fix(wsl-move): import wslUncPathToLinux from shared wsl-paths in the manifest exporter, where 7d moved it (D1b-7d) * feat(wsl-mover): rewrite a moved project's orchestration history on the desktop (D1b-7e) Settled local worker dispatches and their worker-terminal rows in a moved project take the WSL host's worktree id, in one ledgered, idempotent store. Chat workers, live rows, federated attachments and JSON receipts stay as written; automations keep their unchanged local copy (the scheduler only advances it). Per-table dispositions for orchestration.db. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): hold the orchestration store while a worker in scope is live; skip federated rows (D1b-7e review) Co-Authored-By: Claude <noreply@anthropic.com> * feat(wsl-mover): copy in-app browser logins into the WSL host on a move (D1b-7f) A committed WSL move now copies each in-app browser profile's cookies once into the WSL host's stable route partition (owner decision 3a), merging without overwriting what the host jar holds and never touching the source. Where that is infeasible (no deployment link so no stable partition, the destination is not a WSL host or is gone, or the partition name is held by another identity) the host starts fresh and the move journal records why (3b). Registered as the ledgered browser-cookies rewrite store; it runs only once browser sessions and an app window exist. WSL_MOVE_DESKTOP_REWRITE_REGISTRY_COMPLETE stays false. * feat(wsl-mover): retain moved source rows, reconcile them on start, and plan delta moves (D1b-8) * fix(wsl-mover): keep the retained mark out of the WSL move manifest (D1b-8) * feat(wsl-mover): the move driver runs a WSL move end to end, with production gate facts and journaled restore folders One entry point (and preview/start/cancel/listUnfinished IPC for D1b-9) plans the move, gates terminals on the hook server's agent status, the close-tab process probe, running automation runs and live dispatches, pauses and proves exit, stages, sends blobs, commits only from blobs-transferred (#29825), and finishes on the desktop. Any failure resets to zero or goes forward when the host committed. Restore folders and the automations to turn back on are kept in the journal; the host turns those automations back on after commit, retried until it confirms. A real-PTY test pauses daemon shells, and runs on a real distro in the WSL orcad lane. * feat(wsl-mover): move dialog with preview, blockers, progress and result behind the internal WSL hosts gate (D1b-9) * fix(wsl-mover): move dialog hides instead of blocking, follows runs after a reload, and lets a start settle an unfinished move (D1b-9 review) * fix(wsl-mover): word an unfinished earlier move as still finishing (D1b-9) * test(wsl-mover): type the e2e's fake move state instead of reading it through Reflect (D1b-9) * WIP(wsl-mover): 7f-2 registry complete, coverage proof, startup re-apply (D1b-7f-2) * test(wsl-mover): registry-complete lifecycle, stale-focus restart, unload re-apply (D1b-7f-2) * fix(wsl-mover): share the session focus write so the re-apply adds no layout writer (D1b-7f-2) * fix(wsl-mover): redo additive rewrites once at a stale window's unload; behavioural coverage proof (D1b-7f-2 review) * test(wsl-mover): the IPC record test now finishes the rewrite with the registry complete (D1b-7f-2) * fix(wsl-mover): fence worktree-less spawns by cwd and re-prove terminal exit before commit (R46, WIP) * test(wsl-mover): pin the commit re-proof, browser jar identity and repeated move generations (R45, R46, R47) * fix(wsl-mover): fence any spawn by its folder and name the re-proof's reason (R46 review) * fix(wsl-mover): a terminal in a known folder outside the move never blocks it (R46 follow-up) * test(wsl-mover): kill the real move driver at every point against a real host store; abort a reset move's leftover stage on reconnect Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): carry unsaved drafts into the moved project; round-trip every fixture through the real export, driver and host import Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): reset a move waiting on a distro that is proven unregistered; test updates mid-move (R41), lost distros (R38) and two desktops (R39) Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-mover): list the D1b-10 real-SQLite mover tests Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-mover): type the fault test's journal hook without a cast Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): reset for a lost distro even when its kept host fails to connect, never for a renamed one; compare filled-in repo keys only where the source lacked them Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): carry markdown frontmatter visibility and closed-terminal-tab tombstones into the moved project Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-mover): read the persisted stage through a typed record, not Reflect Co-Authored-By: Claude <noreply@anthropic.com> * feat(telemetry): report how WSL moves end, by phase and reason code (R43) Co-Authored-By: Claude <noreply@anthropic.com> * fix(telemetry): report a pause refusal's reason, an outcome for a thrown run, and only real transport errors as unreachable Co-Authored-By: Claude <noreply@anthropic.com> * fix(agent-hooks): a WSL host's orcad never removes the hook entries the WSL bridge shares (R42) Co-Authored-By: Claude <noreply@anthropic.com> * fix(agent-hooks): a WSL host's Codex account-home launch with hooks off skips too; mark the R42 guard to drop with the bridge Co-Authored-By: Claude <noreply@anthropic.com> * feat(wsl-mover): "Use on this computer again" brings a moved project back as it was before the move Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): judge a bridge WSL pane's foreground inside its distro On Windows every live bridge pane's own process is wsl.exe, so the busy-terminal gate read every open WSL terminal as running a program and refused the move. Read the pane's terminal foreground process group inside the distro (processes carry ORCA_PANE_KEY): only shells means idle, anything else blocks, and an unreadable guest stays unverifiable. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): only the selected projects' session rows can refuse a WSL move The session eligibility check treated host local's whole partition as the move's, as the SSH conversion does. So an agent session or unsaved draft in any other project on this desktop, or in a project an earlier move retained, refused every later WSL move from that distro. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): sign the manifest as the journal and the host read it The digest was computed over in-memory rows. A value with toJSON (a Date on a row added this session) canonicalized to {} when signing but to its string once written to the journal or sent to the host, so the first move after adding a project reset with orcad_migration_manifest_digest_mismatch until a restart reloaded the row. Normalize through JSON before signing. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): carry a slept pane's scrollback from its daemon checkpoint The move sleeps every pane first, and a slept pane's history lives only in the daemon's checkpoint, never in a renderer snapshot. The export carried renderer snapshots only, so moved terminals opened empty. After Sleep the driver reads each paused pane's checkpoint (as cold restore would replay it) and the export carries it under the pane's own snapshot ref; the snapshot channel serves those bytes, checked against the signed hash. SSH conversions pass no reader and are unchanged. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): say why when a move can't be prepared, instead of a bare reset An export or journal failure after the pause (a digest mismatch, on awin) was rethrown and shown as "everything was put back" with no reason. Nothing is journaled yet at that point, so refuse with the error named instead. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): retry a renderer store main refused to record The renderer applied a store and wrote its marker, but ignored a refused ledger record (gated-off, failed, not-main-window), so a committed move stayed unfinished and refused every later move of the distro until the next app start. Log the reason and retry with backoff until it lands. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): a WSL pane is idle only when its shell has nothing else Review of #32343: reading only the terminal's foreground group let background jobs, nohup and disowned work, setsid daemons and a script waiting at read pass as idle, and the move's Sleep would end them. Scan the pane shell's subtree, its session and every process carrying its key; any non-shell process, or a shell running a script, blocks. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): never leave behind an agent whose key may be the selected project Review of #32343: scoping the session check to the selected projects let an unqualified key for a repo id another host also registers fall out of both the transfer and the refusal. Such a key now refuses. Adds tests that fail on the old code: another project's live agent with its tab open and its draft don't refuse, the same kinds of state in the selected project still do. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): refuse an unreadable slept checkpoint, prefer it, and spool it to disk Review of #32343: - A checkpoint behind an unreadable log (or an unreadable one) refuses with the pane named instead of carrying stale history. - For a pane the move just slept the checkpoint is the newest copy, so it wins over an older renderer buffer or snapshot. - Buffers spool to a per-move folder and only their hashes and sizes stay in memory; the snapshot channel reads them by offset. The folder is removed whatever the outcome. - A journal write that landed before it threw is reset, so no orphan record blocks the next move. awin's checkpoints were 310-615 KB, well inside the 5 MB per-pane cap, so nothing there is trimmed. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): retry a failed listing, never a record another window was refused Review of #32343: not-main-window can't clear by waiting, while a listing failure is transient. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): sign the manifest as the host parses it The likelier cause of awin's digest mismatch: the signature covered the exported objects, but the manifest parser keeps only the fields it knows, so a session field it drops (one a sleep can write) left the journal and the host hashing something else. Sign the parsed form, and warn when the parser dropped anything, since such a field does not move. Co-Authored-By: Claude <noreply@anthropic.com> * chore(wsl-mover): split the journal step out of the driver, and format The review fixes took wsl-move-driver.ts past the line limit; the export-and-journal step moves to its own module unchanged. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-mover): a slept pane passes the busy check; say what each move dropped or lacked Re-run on awin ( |
||
|
|
8d908764dc |
Revert "Keep same-machine folders with matching Git remotes in separate projects (#32272)" (#34662)
* Revert "Keep same-machine folders with matching Git remotes in separate projects (#32272)"
This reverts commit
|
||
|
|
917ef9c737 | feat(browser): install Chrome extensions from the Web Store into Orca's browser (#30940) | ||
|
|
f57d00f045 | refactor: group shared native-chat upgrade-tip audience (#34509) | ||
|
|
9802866ed5 |
fix(editor): Copy Remote URL links to the code the workspace is on, with the selected line range (#33597)
* fix(editor): Copy Remote URL links to the code the workspace is on, with the selected line range The gutter menu's Copy Remote URL always built the link on the default branch and dropped any multi-line selection. Prefer the HEAD commit when origin already has it, then the origin branch the current branch tracks, then the default branch; carry an optional end line through IPC, RPC and the git provider so a selection becomes a line range. * fix: pair remote file links with published repository refs * fix: prepare exact remote file fallback before publication scan * test: consolidate remote file URL integration coverage * test: document real-clock cancellation deadline proof * test: handle optional cancellation signal in assertion * test: reuse spawned child fixture across runtimes --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> |
||
|
|
2327180d12 |
feat(quit): add Quit and Stop All Sessions to the app menu and tray (#32153)
* feat(quit): add Quit and Stop All Sessions to the app menu and tray Quit keeps daemon sessions alive for warm reattach. The new item, placed directly above Quit in the macOS app menu and menu bar icon, the Windows File menu and tray, and the Linux File menu, asks for confirmation, runs Settings' Kill all sessions in the renderer, and quits only when every session stopped. Closing the tabs first means nothing reopens or resumes on the next launch. Serve hosts do not offer the item. * fix(quit): keep Orca open when Kill all cannot prove every session stopped - Kill all no longer reads a daemon generation that failed to list as "no sessions": a failed poll keeps the last confirmed remaining set, and a failed initial listing sets listingIncomplete. - Quit and Stop All Sessions stays open on an incomplete listing or a terminal tab opened during the sweep, logs why it stayed open, and reveals the window before the final quit. - Share the main-window message box helper, stub the request on the web client, and add Portuguese strings. - Cover the windowless path, request expiry, the in-flight guard, and failed listings in tests; bound the E2E exit wait. * fix(terminal): count Kill all per daemon generation within a time window - A poll updates only the daemon generations that answered, so one failing generation no longer hides the kills of the others. - Poll for 6.5 s of wall-clock time instead of 65 attempts, because a wedged generation fails each listing only at the request timeout. - Flag a sweep with no daemon provider as listingIncomplete. - Log the leftover-tab exit, share the one-shot window intent with Open Settings, and cover the sender check, the reveal before the final quit, and retries in tests. * fix(quit): stay open while a newer build's daemon is held - Set listingIncomplete while this build holds a newer protocol's daemon, whose sessions it can neither list nor stop. - Reuse getDaemonAdapters in Kill all, type the shared one-shot helper by its flag factory, and move the app-menu quit handlers next to the tray options so both serve/desktop splits are tested. - Cover a quit that outlasts the request expiry and a failed request pull, and fix the docs lead-in for the new quit-time case. * fix(quit): explain, without stopping anything, while a newer version runs terminals - Check the newer-version daemon hold before the confirmation and show an explanation instead, so Kill all no longer closes every tab and then refuses. listingIncomplete stays as the backstop. - Translate the explanation, describe listingIncomplete generically, and assert the single timed-out poll in the Kill all test. * fix(quit): explain before asking whenever Kill all cannot list every session - Show the explanation instead of the confirmation while the daemon provider is missing (still starting or failed) as well as while a newer version's daemon is held. - Name only the steps that work (wait for terminals to open, reopen a terminal opened in a newer version), avoid stating a hold as fact, and label the dialog's button through the catalog. * fix(quit): add the relaunch step to the explanation and align the ja wording * test(pty): keep a confirmed stop when its generation fails a later poll * test(quit): give the E2E timeout bump its reason * fix(quit): stay open when the daemon still lists a session after Kill all Kill all counts only the sessions of its first listing, so a session started since then, for example from the CLI or an automation before its tab reaches the renderer, would outlive the quit. Main now lists every daemon generation again before quitting, and quits only after a listing in which every generation answers and none lists a session. It polls within Kill all's 6.5 s window so the tab sweep's PTY shutdowns can finish; otherwise the renderer shows the existing error and Orca stays open. ui:quitAfterStoppingAllSessions becomes an invoke that answers whether main quits. * feat(quit): rename to Quit Completely with a macOS hover hint, and explain plain Quit in the confirmation * fix(quit): show progress while Quit Completely runs, and refuse at once when the daemon can't be fully listed --------- Co-authored-by: Neil <neil@stably.ai> |
||
|
|
a7c9d19048 |
fix(file-explorer): offer permanent delete when moving to Trash fails (#33956)
Offer confirmed permanent deletion when moving an item to Trash fails. Preserve authorization and workspace ownership checks, cancellation behavior, text-snapshot undo, remote compatibility, and all supported translations. Fixes #33944 Co-authored-by: nori <dosukoicrypto@gmail.com> Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
362104ca18 |
fix(wsl): background Git and the roots catalog never start a stopped WSL distro (E9) (#34231)
* fix(wsl): background Git and the roots catalog never start a stopped WSL distro git status ran on the UNC project root 0.45 s after a terminate, next to the explorer read; either boots the distro. Background Git (status, conflict operation, upstream status, branch compare, the upstream-ref watch) now asks the shared running gate first and refuses for a stopped distro, including host paths whose Git runs through wsl.exe. The authorized-roots rebuild skips a stopped distro's repo and leaves it dirty, and the detected-worktree scan fails as unavailable, so rows are kept and the next scan after the distro runs lists it. * fix(wsl): the active workspace's first status and a wake read's roots rebuild may start WSL - Drive-path projects whose Git runs through WSL had no wake path: the active workspace's first git:status after it becomes active now passes wakeWslDistro, so Source Control starts the distro; later polls stay gated. - A user act runs in an async scope naming its distro; gated work inside it (the authorized-roots rebuild an authorization miss triggers, the detected scan, the Git) may start that distro and no other. External worktrees on a stopped distro no longer fail a wake read with access denied. - After a user act wakes a distro, background reads stop trusting the older 'stopped' read and probe again. * fix(wsl): explicit WSL launches refresh the running read; wake only on tab change; gate the home probe - Any wsl.exe Git/CLI run (commit, push, fetch) or WSL terminal spawn for a distro last read as stopped records that it started, so background reads probe again instead of refusing for up to 60 s. - The active editor tab wakes only when the active tab changes; effect re-runs driven by git status or overview views read without waking. - The authorization roots' WSL home probe no longer runs wsl.exe in a stopped distro when the home is uncached. - The settle window no longer imports the orcad liveness module (it pulled main code into the web typecheck); a test pins it to EXIT_SETTLE_MS. * fix(wsl): deferred work and running-list listeners never inherit a user act A user act's async scope could leak into work it triggers indirectly: a drain of deferred tasks it caused, or listeners of a running-list probe started inside it. Both now run outside the scope, so only the act's own work may start its distro. * fix(wsl): keep shared modules free of main-only gate imports worktree-logic.ts and wsl-running-distro-cache.ts are also compiled by the web project, which cannot see main-only modules (AsyncLocalStorage, wsl.exe). getAllowedRoots now injects the gated home lookup into computeWorkspaceRootWithin, and the background gate's own cache subscriptions run outside the user-act scope instead of the cache knowing about it. |
||
|
|
fe82078909 |
fix(wsl): background file reads and watches never start a stopped WSL distro (E9) (#34222)
* fix(wsl): background file reads and watches never start a stopped WSL distro Any Windows touch of a \\wsl.localhost path boots a stopped distro. After a terminate, the dying explorer watcher's overflow refresh ran realpath on the project root 0.23 s later and booted the distro again. Background reads, stats and watch installs now ask a fresh running list first (shared, with a 5 s lease and a stop signal from the watcher exit and the hook relay link) and refuse when the distro is stopped. Opening the workspace and Retry still start it. A stopped watch waits for the distro and resyncs the explorer when it runs again. * fix(wsl): trust a confirmed running read for 60 s without a stop signal * fix(wsl): user acts wake; unverifiable is not stopped; settle after a stop - Opening a workspace, expanding a folder, opening a path (explorer, quick-open, links), the active editor tab's load and every Retry pass wakeWslDistro on readDir, readFile, stat and readFileChunk. Background reloads, restored-tab scans and watchers stay gated. - A failed running-list read is 'unverifiable', not 'stopped': the gate re-reads once past the failure backoff (once per failure window) and otherwise refuses with 'WSL didn't answer', never touching the path. - After any stop signal, a running read that started within EXIT_SETTLE_MS of it never counts, in isWslDistroRunning itself, so neither the watcher's own overflow refresh nor the hook relay's restart check can read a stale listing. - A confirmed read that sees a distro stop records a stop signal, resetting the 60 s lease. * test: user-opened stats now carry the WSL wake flag |
||
|
|
284411d893 |
fix(wsl-host): uninstall and startup release WSL holders; a partial Remove keeps the host pending (#33843)
* fix(wsl-host): uninstall and startup release the WSL distro holders Orca left running The detached wsl.exe holder outlives the app, so an uninstall left its distro, orcad and shells running. The uninstaller now runs Orca with --orca-uninstall-release-wsl-holders after killing the app and its daemon; it ends only the holders this profile recorded, each verified by pid, start time and command line, and keeps any it cannot verify. At startup the WSL host service now releases holders whose distro is no longer a host (a failed add or remove), and every holder while WSL hosts are off; a closed gate releases them too. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): a Remove that can't prove the server stopped keeps the host, pending A partial Remove dropped the host anyway, leaving a server whose live terminals block the next add's activation. Remove now drops the host only on a proven stop; otherwise it records a pending stop on the WSL record, keeps the host listed and says why (live or unverifiable). Remove again retries without ever booting a stopped distro (it says to start it); Connect or Add on the same distro keeps the host; a distro that is no longer registered finishes. Nothing reconnects a pending host on its own. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): E11 review — keep holders when records are unreadable; finish removals a stopped or renamed distro proves - Startup keeps every holder when the WSL host records can't all be read (unverifiable), and no longer re-adopts a pending host's holder. - Remove matches a renamed distro by GUID (isWslDistroRegistered), and a stopped distro finishes a pending Remove: the cold probe proves the stop. - Only the user's Connect or Add withdraws a pending Remove; other connects are refused, and re-adding respects startIfStopped. - Settings' Remove carries the kept result, so it warns instead of 'Removed'. - A holder record without a start time is never killed on its command line alone, except the one this process just spawned. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): E11 review 2 — a closed gate keeps live hosts' holders; stop a renamed distro by its current name - With the gate closed, a launch releases only orphan holders (no host record, or a pending Remove), under the same keep rule as startup; a user with no holder records costs one folder check, nothing else. - The keep rule re-reads host records per holder and keeps an Add in flight. - Remove resolves the distro's current name from its GUID and stops it there. - The uninstall command arms its exit timer first and exits 1 if setup throws; NSIS launches it only when a userData holder folder exists. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): never boot a host whose Remove is pending at the next launch Early wake built its host list from every record, so a host focused when its Remove ended pending was booted at each launch, undoing the stop's proof. It now skips pending records, and Remove forgets the host's early wake whatever the outcome. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): no wake for a pending host; the e2e fake stops an unbridged server like the real one - mayWake skips a host whose Remove is pending, so a due automation can't boot it (focus already couldn't). - The e2e fake connector read a host with no bridge as stopped. Since E9 a re-enable connects nothing, so Remove after off/on left the host's shells running. Like the real connector, it now reconnects the always-running fake distro to stop its server. - Status bookkeeping moves to WslHostStatusBoard, and the pending-host connect rule to admitConnectToPendingHost, to keep the service under max-lines. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
29a5f89b8a |
Keep same-machine folders with matching Git remotes in separate projects (#32272)
* WIP: same-host same-remote checkouts keep their own project id * WIP: claim the shared project id per checkout surface; drop the display-only clone split * WIP: index derived ids by repo in the hydration normalizer * Resolve workspace project affiliation from current checkout owners * fix: preserve concrete project ownership across catalogs and operations * fix: combine recent project selector imports * fix: enforce canonical catalog reads and preserve search continuity * fix: scope catalog lint exceptions to renderer files * Resolve project search ownership before native candidate limits * Combine duplicate session scope imports * fix: derive returned history row ownership on the host * Reconcile full session history replies by content * Require authoritative project catalogs for terminal snapshots * Preserve registered project claims and partial history results * test: check orphaned setup cleanup state without assertions * fix: align catalog callers and native search fixture contracts * test: check full repo shapes in runtime routing fixtures * Fix checked catalog inputs in compiler regression fixtures * Keep checked PTY fixture repos mutable * test: align catalog fixtures with canonical readers * test: check catalog and runtime fixture inputs * test: check catalog fixtures without outer assertions * test: follow persistence harness relocation * Adapt catalog test inputs to integrated main checks * Test History hashing across cached depth revalidation * test(settings): expect host-qualified setup removal * test: capture host split listings and scope relay recovery * ci: regenerate merge ref * test: type host-split listing diagnostics |
||
|
|
6e3c10c835 |
Honor browser preferences and modifiers for HTML preview links (#33622)
* fix(browser): honor preview link destinations and modifiers * Clarify the source browser provider contract * test(browser): check preview guest before reporting modifiers * fix(browser): report system link failures and cover preview routes * test(browser): combine HTTP link destination imports * refactor(browser): require source ownership for preview links * test(browser): type the forbidden Active Server getter * fix(i18n): retain required preview error catalog entry |
||
|
|
2e67ba5a64 |
perf(wsl-host): start booting only the focused WSL host early at launch (E9, replaces #33141) (#33924)
* perf(wsl-host): start booting the distros the last run had open work on as the app launches The WSL host connect can only start once the store has loaded, about 1.5-2 s into startup on a slow PC, and its first command then waits for the distro to boot. The service now remembers which distros had open work, and the next launch starts booting just those right after taking the single-instance lock. * perf(wsl-host): wake only the focused WSL host early at launch (replaces #33141's list) open work on, which conflicts with E9 (a launch boots only the focused host). Each focus entry now records just that host's distro for the next launch's early boot, and focusing a workspace off WSL (reported as a null focus entry), turning WSL hosts off, or a host that can't run clears it. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): the early-wake list is authoritative: deleted when off, forgotten on Remove Review of #33924: the early wake runs before settings load, so it can't read the WSL hosts setting. Turning WSL hosts off now deletes the list synchronously (emptying it if the delete fails; a missing or unreadable list wakes nothing), and removing a host drops it from the list. There is no pendingStop field on host records yet (E11); the existing registered-host filter covers removed records until then. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
2dd8207369 |
fix(wsl-host): boot only the focused WSL host, and keep a stopped one down (E9 A) (#33838)
* fix(wsl-host): boot only the focused WSL host, and keep a stopped one down E9 connect policy, part 1. A stopped distro now boots only for an explicit user action or when its host becomes focused: - Visible work is the active workspace plus workspaces focused earlier in this window that still have tabs. Saved tabs alone no longer count, so a launch with two hosts boots only the focused one. - After a confirmed stop (wsl --shutdown, WSL update) the host is parked. Liveness no longer reboots it even when it is visible, and polls get "<distro> was stopped" instead of a boot. Re-focusing the host, Connect, or the distro running again lifts it. - Liveness recovery always needs a confirmed-running distro, so a distro that stops mid-recovery is never booted again. Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-host): launch boots one of two hosts; polls never boot; lost contact never parks Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): only a focus entry or a user action boots a WSL host (E9 review) Review of #33838: - Re-focus never lifted a park: a host focused earlier stayed in the visible set, and the renderer skips unchanged reports. The renderer now sends a separate focus entry (focusHost) each time the user switches to a workspace on a WSL host, including the launch restore; only that, or Connect, lifts a park and may boot. - Runtime calls could boot: ensureForRuntimeCall connected any visible, unparked host. It now reads the host's reachability first: a confirmed-stopped distro parks at once, an unreadable running list refuses, and only a distro confirmed running is reconnected (for visible work). Visible work itself never connects anything. - Turning WSL hosts on no longer boots every visible host, and focus isn't recorded while they're off; the window re-reports its focused host instead. - Each window's visible work is kept apart and unioned, so one window can't drop another's. - wakeForAutomation/isConnected move to the automation PR, which uses them. Co-Authored-By: Claude <noreply@anthropic.com> * fix(wsl-host): a poll waits for liveness's verdict right after an exit (E9 re-review) Right after `wsl --shutdown` WSL can still list the stopping distro as running (the supervisor waits and re-reads for exactly this). A poll's cold probe then read 'unreachable', reconnected, superseded the pending distro-stopped verdict and booted the distro again. The supervisor now reports when it is settling (a verdict in progress, or a watch/holder exit within the last few seconds), and a runtime call refuses instead of reconnecting then; the verdict parks the host as before. Co-Authored-By: Claude <noreply@anthropic.com> * test(wsl-host): a new supervised entry starts with no recorded exit Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
0afedab10d |
fix(lifecycle): keep UI listener failures from vetoing the shutdown checkpoint (#21029)
A throwing ui-changed listener (e.g. webContents.send on a destroyed secondary window) propagated out of store.updateUI() during app:stage-before-unload-sync and cancelled the shutdown checkpoint, leaving the user unable to quit. notifyUIChanged now isolates each listener, the ui:stateChanged broadcast skips destroyed webContents, and the staging failure cause is returned to preload so the error toast names it. Fixes #20897 Co-authored-by: Neil <neil@stably.ai> |
||
|
|
a93f73c032 |
fix(terminal): skip an escape tail an abandoned hidden-output restore would print (#33905)
* fix(terminal): skip an escape tail an abandoned hidden-output restore would print (#33766) Main drops a hidden pane's renderer delivery after its model ingests the bytes, so the first chunk sent on reveal can begin inside an escape whose start was dropped. When the restore is abandoned, the renderer resets its parser and writes the queued chunks, and xterm printed the tail (';242m', the rest of a Codex OSC title). Main tracks each PTY's escape state over every accepted payload and labels the first delivery after a hidden or pending-cap drop with the escape it resumes inside (gapEscapeState). Only the abandon path strips that continuation; a successful restore keeps every byte so the snapshot's pending escape tail can complete. No label means no change. * fix(terminal): make the escape-continuation scan's switch exhaustive (#33766) |
||
|
|
c9eee6b54c |
fix(runtime-environments): every window sees a server saved from the CLI (#33930)
`orca environment add` writes the saved-server file directly. Main already watched that file but only repaired the Active Server preference, so every renderer surface listing saved servers (the Agent Session History host picker, host menus, the status bar) kept the old list until something else refreshed it. Main now tells every window when the file changes, and the renderer refreshes through the existing coalesced catalog refresher. Co-authored-by: Tian-yi Liang <tianyilt@qq.com> |
||
|
|
a66f6bf011 |
fix(agent-resume): keep a background agent launch's flags when it is resumed (#33776)
* fix(agent-resume): record a background agent launch's recipe so resume keeps its flags * test: narrow the reveal's notifier so the test needs no cast * refactor(agent-resume): one recipe registration path; skip adopted panes * test: add the launch-recipe listener to the remaining window mocks |
||
|
|
bfc633af8f |
Offer to resume chats after managed server updates (#28978)
* Guard managed server restarts with host work reservations * Protect legacy server update requests with host admission * Reserve chat-safe restarts in SSH and WSL server updates * Keep activation host fixtures within the module line limit * fix(orcad): preserve session queue timing during admission * Explain chat-safe update deferrals and superseded restarts * Clarify managed server Force upgrades and retry instructions * Separate chat entry delegates from conversation creation * Report child work through main's child evidence in the restart drain test * Drive main's snapshot-room tests through the restart reservation Main's room tests deployed over a serving incumbent with a census that has no chat work count and no restart admission, so the update deferred before the room probe ran. Give them the same idle census and slot admission as the other activation tests, and pin the probe before the reservation instead of before the recount it replaced. * fix(native-chat): an update keeps waiting on a chat start after its conversation is closed The restart check counted a start only while its conversation stayed open, so an idle close during a stalled start let a managed update through. Every tracked attach, create, start and open now counts as restart work in the same tracker that counts the session queue. * fix(native-chat): keep the structured session view within its line limit once formatted Main's copy sat at 400 lines only because one line was left unformatted; the merge's formatter pushed it to 401. Inlining the one-use question list keeps it at 400 with identical behavior. * fix(orcad): a recovery stop request stops the server; only an older client's empty request waits for idle Stopping a slot and restarting it for an older client's update were both an empty .orcad-stop-request file, so routing that file through restart admission let a crash recovery, stranded-setup release or rejected-candidate rollback leave the server running. New clients now write "stop-now" into the request (renamed in whole), which stops at once as before; an empty or unrecognized request takes the chat-safe restart, and a deferred restart logs why. Also gives the restart admission activation fixtures the now-required recount. * docs(orcad): say a directory at the stop-request path is refused, not restarted * docs(orcad): the plain stop request's comment states both of its meanings * style: format the restart admission files for the format check * test(wsl): count the incumbent's recount bridge after the reservation's * fix(orcad): a Windows stop request retries its rename while antivirus holds the new file Renaming the just-written stop-now request can briefly fail with EPERM, EACCES or EBUSY on Windows; the stop now retries those with the same bounded delays as record-publish instead of answering SIGNAL_FAILED and leaving the server up. * test(orcad): a real Windows host stops on the slot's stop-now request and relaunches * test(orcad): recovery stops a real server whose restart admission refuses * test(orcad): the recovery-stop cell tunnels over the cell's SSH connection * test(orcad): the recovery-stop cell names itself in the CI log * fix(settings): a deferred WSL update shows its full reason below the row * test(orcad): fixtures pass releaseIncumbentAdmission; the census test calls its own method * test(orcad): the capable-server census in the fence test reports idle chat work * Record server chat restart offers and desktop creation history * Offer interrupted chat recovery per managed runtime * Ship the remote chat resume action labels in the runtime catalog * Update removal contracts for desktop chat history cleanup * Scope remote chat recovery to each server occurrence * Preserve recovery choices and uncertain continuation outcomes * fix: preserve uncertain restart action outcomes * Fix restart recovery CI imports and fixtures * test: align resume assertions with unconfirmed outcomes * test: bound restart recovery work across scaled populations * fix(native-chat): title the remote resume dialog with the restart The dialog can appear out of nowhere when another desktop updates a shared server, so its title now says what happened: "<machine> restarted". |
||
|
|
1b0e56e385 | feat(browser): make Orca shortcuts, split focus and mouse back/forward work inside pages (#31859) | ||
|
|
eb499478da | feat(browser): show agent browsing live, with a jump to the page from chat (#33075) | ||
|
|
883b768bc7 |
A chat never starts writing a conversation a terminal is still writing, and restored panes respect open chats (#30930)
* fix(native-chat): one ownership index with link roles, and a chat refuses to start while a terminal writes its conversation Each chat link now carries its role (head or earlier) and key; Session History names the chat continuing a conversation first, duplicate adoption checks only head links in both the pre-commit check and the store transaction, and terminal resumes stay refused exactly as before. The terminal-writer check now also runs inside acquireOwner before the spawn, refusing with the typed pre-spawn reason conversationOpenInTerminal. * fix(native-chat): hold a terminal start Orca issues until its terminal reports it An in-memory registry of managed terminal starts per conversation, registered in the same step as the resume admission (terminal.send with a resume command, createTerminal with a command), bound to the PTY execution that runs it, and ended only when that terminal's hooks report the conversation or the execution is gone. A chat's agent start refuses while an entry may hold its conversation. * fix(terminal): an automatic pane restore never resumes a conversation an open chat continues Resume recipes built from a pane's saved facts (cold restore, deferred and late reattach, sleeping wake, host mobile materialization) carry resumeOrigin 'saved'. The execution host decides before any command is issued: while an open chat continues the conversation, or a chat may be writing it, the pane starts its plain shell with the started-fresh notice and its saved claim is forgotten; with unreadable records only a saved restore is refused and its record kept. An admitted resume registers its managed start in the same step, so the chat's agent start refuses until the terminal reports it or exits. Clearing the last saved record now reaches disk. * Fix saved terminal resume ownership and effective launch results * Preserve conversation case and clear refused cold restore identity * fix: publish effective terminal launch results on attachment * fix: preserve terminal launch callback and candidate ownership * fix: keep existing terminal attachments observational * fix: consolidate terminal launch imports * test: document snapshot runtime fixture boundary * fix: preserve terminal launch identity types * fix: accept reattach payload policy sessions * fix: preserve terminal result validation contracts * refactor: separate terminal create contract * test: document partial terminal runtime fixtures * test: align sleeping resume store fixture * Fix terminal create type contracts * fix: return the terminal main started to its waiting view * fix: register reattached terminals before publishing their handles * Check unavailable-resume test fixture types * Complete sidebar resume test store fixture * test: bound saved resume ownership and refusal work * Settle refused saved resume claims from actual launch results * Fix saved resume test type contracts * test(e2e): capture exact terminal parking diagnostics * test: verify parked terminal with fresh host inventory * Consolidate agent session imports in remote terminal transport * Clarify terminal conversation refusal guidance * Admit note-only saved conversations without hiding live writers * Retain terminal writer proofs through final admission |
||
|
|
82a3214049 |
fix(sleep): reopen a slept agent whose tab is gone in a fresh tab instead of stranding it (#33598)
A slept agent whose tab disappeared now resumes in a fresh tab (with --resume, through the existing duplicate/host guards) when its workspace opens, and main's stranded workspace-sleep record is then dropped (only if no tab still lists that pane), instead of the record sitting forever while the workspace opens a bare shell. Fixes #22657 |
||
|
|
9485e73207 | feat(browser): dock DevTools in the browser pane, with dock side, resizing and pop-out (#33003) | ||
|
|
0b28553093 |
feat(ssh): show saved port forwards that couldn't start, with why, and let you remove them (#33450)
* feat(ssh): list saved port forwards that couldn't start, with why, and let you remove them (#32484) A saved forward whose local port is taken, or that keeps failing, stayed saved but invisible, retried in the background with no way to remove it. The port-forward lists now show each saved forward that isn't open, with the last start error, and Remove deletes it by its mapping. * fix(ssh): a forward whose ssh exits after starting backs off like a failed start * fix(ssh): re-register the new forward channels, close a forward a restore reopened before removing it, and update IPC fixtures * fix(ssh): a flapping forward keeps its backoff streak until it stays up * fix(ssh): translate the saved-forward row, say Stopped for a forward that died, toast a failed remove, and reset backoff on manual edits * fix(ssh): keep saved forwards listed and removable while the host is offline; label the remove button; test the healthy-uptime reset * fix(ssh): mirror saved forwards from main with a stale-read guard, including hosts that never connect * fix(ssh): scroll the offline ports panel when saved forwards overflow it * test(e2e): give the saved-forward restart case's timeout its reason |
||
|
|
8e9f86b119 |
feat(managed-server): Update and Update anyway for a managed SSH server, keeping its running terminals (#33397)
* feat(managed-server): offer Update and Update anyway on a managed SSH server's row A managed SSH server only updated on connect, and every connect deferred while a terminal ran there. Its row now offers Update when this desktop bundles a newer build than the Orca that runs the host. When running terminals defer it, Update anyway restarts the server past them; the terminal daemon carries them across the restart. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(managed-server): Update anyway passes only counted live terminals and keeps Update's version admission Update anyway now sends the incumbent build it confirmed over; under the host fence it is refused if another desktop activated a build since, keeps the newer-host downgrade refusal, and never passes an uncounted terminal census. The offer also covers hosts activated before the Orca version was recorded, for the build this desktop already deferred there. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(managed-server): Update anyway also confirms a menu Update the row does not advertise Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(managed-server): the row shows one confirmation at a time Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * ci(e2e): route managed-server update sources to the Update anyway Docker spec Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
25b9ce5168 | feat(browser): show a hovered or focused link's URL in a bubble at the bottom of the page (#32978) | ||
|
|
76f0f35bad | feat(browser): speaker icon on tabs playing sound, with tab mute (#32981) | ||
|
|
b900d9843f | refactor(shared): colocate Jira rules and direct imports (#33164) | ||
|
|
785daec1e1 | fix(browser): show profiles changed outside the window in the profile menu without a reload (#32723) | ||
|
|
5dc197e5ec | feat(browser): history controls: Chrome-style Escape, removable suggestions, history view (#31846) | ||
|
|
7cafdb072b |
feat(ssh): Recover server for a managed host refused on a stale lock, and surface that refusal in seconds (#32951)
* feat(orcad): run --reclaim-stale-lock on a managed host's active slot The desktop can now dry-run and confirm the stale instance-lock recovery on a Linux managed host, serialized with launches, then start the server again and reconnect the way the restart action does. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * feat(settings): offer Recover server for a managed host refused on a stale lock When a managed orcad start names --reclaim-stale-lock, the SSH host row offers Recover server. The dialog dry-runs the check, shows the host's evidence, and clears the lock only after the user confirms no other machine sharing the home runs Orca. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * feat(mobile): point a host refused on a stale lock to the desktop's Recover server Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(settings): mount the Recover server dialog per opening A fresh mount starts each opening from a new check instead of resetting state in an effect. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(orcad): end the readiness wait once the host proves the launch exited A managed orcad refused at start (such as on a possibly stale instance lock) left the client waiting out the full readiness deadline. Each host-side wait now also checks the launch's PID file with kill -0 and ends early on a proven exit, so the caller reports the same pending readiness, with the orcad.log tail, within a poll. No PID, a denied probe or a reused PID keeps the old deadline. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(orcad): refuse a managed slot without --reclaim-stale-lock before running it An older orcad ignores the flag and starts serving in the foreground. The same remote exec now checks that the slot's server bundle names the flag and answers unsupported otherwise, without invoking orcad. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(settings): show the manual stale-lock command as literal mono text The rendered dialog ran the command into the sentence, so it was hard to read or copy. It now sits in its own mono block, like Details. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(settings): offer only a manual delete when the host can't reclaim, and format the lock's age An unsupported host was told to run the very command it lacks. Main now names the lock path for that case, and the dialog shows only a copyable rm of it with the shared-home caution. The lock's age uses the UI's relative-time formatter instead of a hand-rolled minutes count. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(orcad): pin a confirmed stale-lock reclaim to the record the user approved --yes reclaimed whatever record held the lock at that moment, so a lock a same-named machine wrote while the dialog sat open could be cleared. orcad now takes --expect-nonce and refuses unless the lock still holds it; the dry run reports the nonce, the desktop sends it back on confirm, and the managed slot gate requires a build that knows the pin. A reclaimed result carries the evidence it acted on. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(settings): keep the Recover server dialog open through its own reclaim The dialog's mount was gated on the status that offered it, and the reclaim clears that note before its answer arrives, so the result was never shown and the card kept the dialog marked open. Only the triggers are gated now; an open dialog keeps the server it opened for until the user closes it. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(settings): put the Recover server confirmation on the security surface It asks permission to run a remote command that clears an ownership lock and starts server code, which STYLEGUIDE puts on that surface. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(orcad): trust a gone launch PID only on the machine that launched it The PID file sits in a home other login nodes may share, so a wait exec that lands on another node read a starting server as exited. Both launch paths now record the launching machine's boot id and node name beside the PID, and the readiness wait ends early only when its own exec reads the same record. No record, a host without a boot id, or another machine keeps the deadline. The PID path is named once in the launch command so it stays within its sent-byte ceiling. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(orcad): keep a slot's unreadable stale-lock answer from offering a manual delete A slot that passed the gate but gave no JSON, or a status this client does not know, read as unsupported and offered rm of the lock. It now reads as no-answer, which points to the slot's own reclaim command, and unsupported is left to a slot without the command, a non-Linux host or no active version. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * style(settings): use the text-2xs step for the stale-lock command block Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(mobile): offer the desktop-recovery hint on the same refusal the desktop does Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * test(orcad): name the extra fields a fake stale-lock answer carries Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(settings): end the Recover server flow once the lock is cleared, and keep an unpinned reclaim manual After a reclaim whose restart failed, the dialog kept the old evidence, the enabled confirmation and manual recovery for a lock that was gone. It now shows only that the lock was cleared and why the server did not start, with Close. A slot that has the reclaim but not the nonce pin is now told apart from one without the reclaim, and is pointed to its own reclaim command rather than rm. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(orcad): keep a stale-lock reclaim's result when the restart after it throws A wake or tunnel rebuild that threw after the lock was cleared discarded the reclaimed result, so the caller skipped its reconnect and note clearing and the dialog kept a confirmation for a lock that was gone. The restart's failure now becomes the result's notRestarted reason. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * fix(orcad): report a reclaimed server as started when only its forward failed to follow A tunnel rebuild that failed after the wake started the server was reported as the server not starting. The rebuild now goes through followLaunchedServerPort, as other relaunches do, which warns and leaves the forward to the next connect. Also drops a caller test that only covered behaviour the fix did not change. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> * test(mobile): re-record the execution-target goldens for the recovery hint field The SSH gate's projected state gained `needsDesktopServerRecovery`, which is false for every recorded reply (no recorded host sends a managed server refusal). Re-recorded with `pnpm --dir mobile rpc:record` for the two pilot recordings and the four execution-target reply partitions; the only change is that field, plus the value pool reordering around it. Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> --------- Co-authored-by: Jesse Sanford <108698+jessesanford@users.noreply.github.com> |
||
|
|
861299e6cc |
refactor(ipc): remove unreachable runtime-environment provisioning and control-retry IPC (#32960)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> |