mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 01:27:35 +00:00
3d812eb9bf54c39e80098bb6ce55f8498a3d3c8c
85
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>
|
||
|
|
4e326e2371 | Show Orca publishing guidance only when the host has it on (STA-12225) (#34547) | ||
|
|
b35fb1ccfb |
fix(orchestration): route dispatched workers to the skill and stop heartbeat loops before worker_done (#34404)
The orchestration skill description only advertised coordinator work, so a dispatched worker never loaded it and built its heartbeat loop from the preamble alone. Neither the preamble nor the guide said to stop a background heartbeat loop before worker_done, so the loop outlived the task. Add worker-role triggers (heartbeats, ask, worker_done) to the description and stub, and tell workers in the preamble and guide to restart an expired heartbeat loop mid-task and stop it before worker_done. Fixes #26605 |
||
|
|
3816457631 |
fix(mac): declare Contacts, Calendars and Reminders permissions for terminal tools (#34401)
Hardened-runtime TCC refused EventKit and Contacts requests from terminal-launched tools without a prompt: Orca and its terminal host lacked the addressbook and calendars entitlements and the matching purpose strings. Declare them the same way camera, microphone and location already are; the terminal host inherits both. Fixes #12933 Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
6cb6d0d44d | Fix native chat hover colors for live theme changes (#33791) | ||
|
|
2a28fc7d4e |
[comment audit] Finish launcher and configuration comment review (#33513)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
7d6603aa17 |
[comment audit] Complete repository-wide comment cleanup (#33249)
* [comment audit] Align legacy failure-read counts with cached display * [comment audit] Condense shared provider lifecycle and browser recovery comments [skip ci] * [comment audit] Condense shared generation, path and preview comments [skip ci] * [comment audit] Condense host, file and Git contract rationale [skip ci] * [comment audit] Tighten Git lifecycle and provider contract comments [skip ci] * [comment audit] Clarify shared host authority and launch isolation [skip ci] * [comment audit] simplify local access mobile and native chat contracts [skip ci] * [comment audit] simplify native chat presentation and state contracts [skip ci] * [comment audit] simplify native runtime and provider contracts [skip ci] * [comment audit] simplify migration and orchestration contracts [skip ci] * [comment audit] simplify plugin trust and process capture rationale [skip ci] * [comment audit] simplify terminal delivery and remote compatibility rationale [skip ci] * [comment audit] clarify remote recovery and launch wire rationale [skip ci] * [comment audit] shorten shared RPC compatibility and runtime evidence comments [skip ci] * [comment audit] simplify secure storage shell startup and sidebar rationale [skip ci] * [comment audit] clarify sidebar, skill and SSH invariants [skip ci] * [comment audit] condense structured chat delivery and timing rationale [skip ci] * [comment audit] condense terminal replay and telemetry invariants [skip ci] * [comment audit] clarify launch permission and terminal delivery rationale [skip ci] * [comment audit] clarify workspace ownership and layout contracts [skip ci] * [comment audit] wait for fitted and painted SSH terminal links * [comment audit] clarify layout persistence and session ownership [skip ci] * [comment audit] clarify host routing and workspace lifecycle contracts [skip ci] * [comment audit] clarify startup persistence and app lifetime comments [skip ci] * [comment audit] clarify recovery and activity boundaries [skip ci] * [comment audit] condense activity and artifact invariants [skip ci] * [comment audit] condense automation authority contracts [skip ci] * [comment audit] simplify automation scheduling and history contracts [skip ci] * [comment audit] clarify browser chrome and annotation lifecycles [skip ci] * [comment audit] clarify browser routing and retained guest ownership [skip ci] * [comment audit] clarify browser recovery and document ownership comments [skip ci] * [comment audit] restore hosted runners required by native IME fixtures * [comment audit] shorten preview, palette and dashboard invariants [skip ci] * [comment audit] clarify terminal preview, dashboard and retention comments [skip ci] * [comment audit] clarify diff-note recovery and editor lifecycle comments [skip ci] * [comment audit] shorten rich-text and combined-diff ownership comments [skip ci] * [comment audit] shorten autosave, draft recovery and model ownership comments [skip ci] * [comment audit] shorten save-queue, notebook and Markdown constraints [skip ci] * [comment audit] shorten Monaco, PDF and rich Markdown safeguards [skip ci] * [comment audit] clarify rich Markdown source and selection safeguards [skip ci] * [comment audit] clarify editor loading and emulator stream lifetimes [skip ci] * [comment audit] trim emulator and feature tour narration [skip ci] * [comment audit] clarify floating workspace and GitHub cache ownership [skip ci] * [comment audit] trim provider controls and Linear filter explanations [skip ci] * [comment audit] clarify pairing and chat resume lifetimes [skip ci] * [comment audit] clarify chat delivery and transcript lifetimes [skip ci] * [comment audit] clarify session options and host-owned status [skip ci] * [comment audit] clarify draft durability and live-status precedence [skip ci] * [comment audit] Trim chat send and model ownership explanations [skip ci] * [comment audit] Shorten transcript ownership and send recovery comments [skip ci] * [comment audit] Simplify native chat composer and transcript hook comments [skip ci] * [comment audit] Shorten native chat scroll and structured session explanations [skip ci] * [comment audit] Trim workspace picker and onboarding commentary [skip ci] * [comment audit] Simplify pet rendering, review cache and quick open comments [skip ci] * [comment audit] Trim sidebar and session history explanations [skip ci] * [comment audit] Condense session resume and review checks comments [skip ci] * [comment audit] Shorten checks state and file explorer refresh comments [skip ci] * [comment audit] Trim plugin bridge and source-control action rationale [skip ci] * [comment audit] Trim source-control listing and review rationale [skip ci] * [comment audit] Shorten sidebar lifecycle and explorer safeguards [skip ci] * [comment audit] Condense Settings account and appearance rationale [skip ci] * [comment audit] Trim pairing and repository Settings explanations [skip ci] * [comment audit] Condense Settings search SSH and terminal safeguards [skip ci] * [comment audit] Shorten Settings voice and provider ownership comments [skip ci] * [comment audit] Condense Settings draft persistence and host-state rationale [skip ci] * [comment audit] Trim Settings hooks and sidebar setup rationale [skip ci] * [comment audit] Condense sidebar deletion and board-filter safeguards [skip ci] * [comment audit] Condense worktree cards, host ownership and Markdown contracts [skip ci] * [comment audit] Condense sidebar drag, folder and filtering contracts [skip ci] * [comment audit] Condense sidebar parity, sleep and host ownership contracts [skip ci] * [comment audit] Prune focus-read baseline after comment cleanup * [comment audit] Clarify sidebar visibility, board drops and agent evidence [skip ci] * [comment audit] Tighten sidebar listing, drag and reveal contracts [skip ci] * [comment audit] Clarify viewport geometry and skill update safeguards [skip ci] * [comment audit] Tighten skill inventory, usage and host status comments [skip ci] * [comment audit] Clarify usage ownership and resource kill safeguards [skip ci] * [comment audit] Tighten tab selection, rename and search contracts [skip ci] * [comment audit] Tighten tab-strip geometry and drag ownership comments [skip ci] * [comment audit] Tighten Tasks recovery, pagination and mutation comments [skip ci] * [comment audit] Tighten provider loading and terminal recovery comments [skip ci] * [comment audit] Tighten completion, cadence and PTY ownership comments [skip ci] * [comment audit] Clarify terminal restore and parked-pane boundaries [skip ci] * [comment audit] Tighten PTY startup and replay explanations [skip ci] * [comment audit] Clarify PTY identity and delivery ownership [skip ci] * [comment audit] Shorten remote reconnect and input replay rationale [skip ci] * [comment audit] Condense terminal parking clipboard and file link comments [skip ci] * [comment audit] Clarify IME ownership and trim trace history [skip ci] * [comment audit] Shorten pane recovery and parked watcher explanations [skip ci] * [comment audit] Condense snapshot replay and visibility recovery rationale [skip ci] * [comment audit] Shorten terminal parking and keyboard ownership rationale [skip ci] * [comment audit] Trim renderer lifecycle and menu rationale [skip ci] * [comment audit] Condense workspace cleanup ownership and settlement notes [skip ci] * [comment audit] Clarify renderer hook evidence and source ownership [skip ci] * [comment audit] Tighten IPC ownership and reconnect explanations [skip ci] * [comment audit] Trim renderer focus, paste and attention comments [skip ci] * [comment audit] Shorten scroll, locale and agent lifecycle comments [skip ci] * [comment audit] Trim agent launch, resume and ownership commentary [skip ci] * [comment audit] Shorten account, browser and editor comments [skip ci] * [comment audit] Clarify host-mirror waits, previews and input ownership [skip ci] * [comment audit] Condense launch recovery and editor tokenization comments [skip ci] * [comment audit] Condense workspace selection and terminal pane rationale [skip ci] * [comment audit] Condense terminal fitting and rendering recovery comments [skip ci] * [comment audit] Condense terminal input and host routing explanations [skip ci] * [comment audit] Condense ownership and sleeping-session recovery rationale [skip ci] * [comment audit] Condense structured launch and terminal link explanations [skip ci] * [comment audit] Condense terminal ownership and workspace file routing rationale [skip ci] * [comment audit] Condense session persistence and workspace activation rationale [skip ci] * [comment audit] Condense workspace routing and browser ownership rationale [skip ci] * [comment audit] Condense mirror recovery and layout authority rationale [skip ci] * [comment audit] Condense runtime transport and file safety rationale [skip ci] * [comment audit] Condense runtime graph and structured session rationale [skip ci] * [comment audit] Condense browser creation and remote tab recovery rationale [skip ci] * [comment audit] Condense snapshot authority and publisher recovery rationale [skip ci] * [comment audit] Condense frame, startup and provider cache rationale [skip ci] * [comment audit] Condense host twin and agent lifecycle rationale [skip ci] * [comment audit] Condense browser authority and editor cleanup rationale [skip ci] * [comment audit] Condense editor buffer identity and review cache rationale [skip ci] * [comment audit] Condense provider lifetime and repository ownership rationale [skip ci] * [comment audit] Condense reconnect, hydration and terminal retirement rationale [skip ci] * [comment audit] Condense recovery, reconciliation and persistence rationale [skip ci] * [comment audit] Condense cleanup ownership and listing admission rationale [skip ci] * [comment audit] Condense teardown ordering and terminal ownership rationale [skip ci] * [comment audit] Condense recovery ledger and web host-boundary rationale [skip ci] * [comment audit] Condense web reconnect and credential lifecycle rationale [skip ci] * [comment audit] Condense cloud rollout and assignment safety rationale [skip ci] * [comment audit] Condense relay session and database recovery rationale [skip ci] * [comment audit] Condense relay placement and protocol compatibility rationale [skip ci] * [comment audit] Condense build and packaging constraints [skip ci] * [comment audit] Condense CI gates and validation isolation rationale [skip ci] * [comment audit] Condense catalog identity and browser validation rationale [skip ci] * [comment audit] Condense mobile browser and frame-budget rationale [skip ci] * [comment audit] Shorten mobile route and browser test explanations [skip ci] * [comment audit] Condense editor and session seam test rationale [skip ci] * [comment audit] Trim session and terminal closure history [skip ci] * [comment audit] Shorten terminal browser and census explanations [skip ci] * [comment audit] Preserve root-only E2E diagnostic baseline * [comment audit] Condense mobile seam and HTML preview test rationale [skip ci] * [comment audit] Condense preview instrumentation and render harness rationale [skip ci] * [comment audit] Condense bundle contracts and native-build constraints [skip ci] * [comment audit] Shorten native packaging and CI routing rationale [skip ci] * [comment audit] Condense release tooling and benchmark constraints [skip ci] * [comment audit] Condense packaging and platform gate rationale [skip ci] * [comment audit] Shorten mobile route and history rationale [skip ci] * [comment audit] Condense mobile browser and component rationale [skip ci] * [comment audit] Shorten drawer and workspace-form rationale [skip ci] * [comment audit] Trim mobile review and editor-document explanations [skip ci] * [comment audit] Condense editor lifecycle and Markdown explanations [skip ci] * [comment audit] Trim mobile file, diagnostics and dictation commentary [skip ci] * [comment audit] Simplify mobile host-list and workspace-view explanations [skip ci] * [comment audit] Clarify mobile shell lifetime and bridge delivery constraints [skip ci] * [comment audit] Condense bridge stream, native request and audio rationale [skip ci] * [comment audit] Reduce bridge schema and page-client commentary [skip ci] * [comment audit] Tighten mobile page bridge contracts [skip ci] * [comment audit] Clarify mobile cache and session constraints [skip ci] * [comment audit] Condense mobile route and lifecycle rationale [skip ci] * [comment audit] Tighten mobile shell hook timing rationale [skip ci] * [comment audit] Clarify route handoff and notification compatibility [skip ci] * [comment audit] Clarify push registration and dictation cleanup constraints [skip ci] * [comment audit] Condense keyboard geometry and native media ownership rationale [skip ci] * [comment audit] Tighten mobile chat scroll and composer concurrency rationale [skip ci] * [comment audit] Condense mobile reply compatibility and upload ownership rationale [skip ci] * [comment audit] Condense optimistic echo and scroll ownership rationale [skip ci] * [comment audit] Tighten stream replay and queued session ownership rationale [skip ci] * [comment audit] Condense mobile composer and reply-schema constraints [skip ci] * [comment audit] Clarify mobile transcript recovery and session ownership [skip ci] * [comment audit] Clarify mobile queue and source-control compatibility [skip ci] * [comment audit] Condense storage and task launch constraints [skip ci] * [comment audit] Clarify task schemas and terminal document ownership [skip ci] * [comment audit] Tighten terminal input and viewport rationale [skip ci] * [comment audit] Shorten terminal and RPC recorder contracts [skip ci] * [comment audit] Condense recorder engine and connection contracts [skip ci] * [comment audit] Shorten host credential and relay recovery comments [skip ci] * [comment audit] Tighten pairing recovery and bundle transport rationale [skip ci] * [comment audit] Clarify RPC delivery and workspace catalog boundaries [skip ci] * [comment audit] Condense catalog and relay entry contracts [skip ci] * [comment audit] Shorten shutdown and SSH relay delivery contracts [skip ci] * [comment audit] Condense WSL relay and E2E regression rationale [skip ci] * [comment audit] Shorten cross-version harness and renderer fixture explanations [skip ci] * [comment audit] Condense paired-host and E2E lifecycle rationale [skip ci] * [comment audit] Shorten layout oracle and regression explanations [skip ci] * [comment audit] Condense paired recovery and ownership regression contracts [skip ci] * [comment audit] Shorten restart, sidebar and SSH lifecycle contracts [skip ci] * [comment audit] Condense terminal rendering and IME regression rationale [skip ci] * [comment audit] Shorten terminal recovery and benchmark contracts [skip ci] * [comment audit] Condense tooling and Windows lifecycle proof rationale [skip ci] * [comment audit] Condense workflow routing and release rationale [skip ci] * [comment audit] Condense mobile security and installer contracts [skip ci] * [comment audit] Shorten native rationale and stylesheet workarounds [skip ci] * [comment audit] Shorten Windows visibility probe rationale [skip ci] * [comment audit] Condense embedded release and signing rationale [skip ci] * [comment audit] Retain current main test behavior in final reconciliation [skip ci] * [comment audit] Complete final comment review across current source inventory * [comment audit] Handle consolidated audit reports before final CI * [comment audit] Preserve credential storage census detail [skip ci] * [comment audit] Scale broad changed E2E selections with verified timing shards * [comment audit] Align E2E assertions with browser close and settled session metadata * [comment audit] Match existing E2Es to current resource and windowing contracts * [comment audit] Observe the shared server outage notice in reconnect coverage * [comment audit] Make existing renderer probes measure settled tab and PTY work * [comment audit] Align palette E2E selector with task search * [comment audit] Refresh remaining palette search selectors * [comment audit] Keep selector correction within selected audit specs * [comment audit] Await emoji fixture settings inside renderer evaluation * [comment audit] Cancel fixture fit retries between terminal tests --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
5ee5765c44 |
fix: shimmer stale reference metadata without layout shifts (#32949)
* fix: keep stale linked-reference status inline * fix: shimmer stale reference rows without a clock * docs: compare row and shadcn text shimmer treatments * fix: shimmer only stale reference metadata * fix: remove obsolete row shimmer class --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
6768988ed6 |
Add Orca's own bundled-skill planner and installer (not wired in yet) (#31662)
* Add Orca's own bundled-skill planner and installer (not wired in yet) One planner decides what installing Orca's bundled skills does to each target folder; execute re-plans under per-path locks and runs only a plan whose digest still matches; a shared summary derives badge, wording and exit code. A copy counts as Orca's untouched one only when its SKILL.md bytes match a version some build shipped (resources/skills/released-digests.json, generated from git history and checked add-only). Nothing calls this yet; the npx path is unchanged. * Report left-alone folders as warnings and keep backups in the home A leave is no longer a failure: the outcome line says what happened plus "N left alone: <reason>", and the exit code is 1 only for a failed or changed op. Backups for every scope go to <home>/.agents/.orca-skill-backups on the executing host, so a project Replace never writes into the repo; moving there falls back to copy, verify, then remove across filesystems. * Escape non-ASCII characters in bundled-skill regex and wording The orcad bundle rejects a literal non-ASCII character in a regex. * Make bundled-skill test fixtures link folders the way the product does on Windows Directory links in fixtures are junctions on Windows, which need no Developer Mode; the one file-link fixture is skipped there. * Reject stale skill replacements when auxiliary content changes * Keep ordinary bundled skill classification shallow * Leave unreadable skill replacements alone without aborting plans * Bound bundled skill classification reads and parse names linearly * Keep workspace skill roots inside the resolved workspace * Compare workspace skill roots with native path semantics * Restrict bundled skill backups to their owner on POSIX |
||
|
|
acc6354363 |
Shrink feature tour animations without changing pixels or timing (#31012)
* Shrink feature tour animations without changing pixels or timing * Update README media links for lossless animation assets |
||
|
|
3d0973d0d4 |
A chat's visuals and sent images live as long as the chat (#30413)
* fix(native-chat): a chat's visuals folder lives as long as the chat A chat's scratch folder was deleted once the chat had gone 30 days unused, so an old chat's inline visuals turned into "Visualization unavailable" while the chat and its history stayed. The common pattern keeps a chat's files for as long as the chat and never deletes them on an "unused for N days" timer. The sweep now removes only folders no chat record maps to, plus leftover .expired folders older builds parked. Everything that existed only to make the age rule safe goes with it: the per-folder save lock and its expiry candidates, the session-lane idle check, the journal last-activity query, and the migration's fresh-window timestamp. The visuals skill no longer tells agents the folder is temporary. * fix(native-chat): an image sent in a local chat lives as long as the chat A local chat's pasted images lived in one paste folder that deleted every file older than 30 days, sent or not, so an old chat's images turned into label chips. Paired-server chats already keep pastes in the host's attachment store, where the send that names a file claims it for its chat and only unclaimed files are ever swept: the common pattern. A local composer paste now goes into this machine's own attachment store (starting the local chat host first), so its send claims it the same way. The old paste folder is no longer written or swept: messages sent before this change may name its files. Restored drafts still read it. An unclaimed upload now waits 30 days instead of one before the sweep takes it. A draft names its image by this path, so the window is how long an unsent draft keeps its image; 30 days is what local drafts had, and it outlasts the host's send-id window so a resent draft still finds its image. A chat folder an older build set aside as unused (<hash>.expired) goes back to its chat instead of being deleted. * fix(native-chat): a terminal-backed chat's pastes are never swept A terminal-backed chat has no journal, so no send claims its pastes and nothing can tell a sent one from an abandoned one. Its pastes therefore stay in the paste folder, which is no longer swept, rather than in the attachment store, whose sweep would take them after 30 days unclaimed. Only a local structured chat's paste (forStructuredChat) goes to the store, where its send claims it. * fix(native-chat): keep the attachment owner's literal kind for structured local chats * test(ipc): expect the local chat store option on the clipboard registrar * fix(native-chat): preserve attachment ownership and restore held files safely * fix(native-chat): settle restored image checks independently * test(native-chat): assert restored image outcomes without batching * Re-check draft images when the attachment sweep removes their upload A draft checks its pasted images once, when its composer comes back. Every chat in an open workspace mounts its composer at launch, so that check ran before the store sweep (60 s after host start, then every 6 h) deleted an expired unsent upload, and nothing checked again: the chip lost its picture with no Not kept feedback and Send stayed enabled. The sweep now reports each removal attempt; the main process forwards it to its window, and the draft store starts a fresh finite check for every loaded local draft image in that folder, mounted or not. A notice is a reason to check, never proof of absence. * Let the app effect remove the draft re-check listener it adds startNativeChatDraftLoad dropped the unsubscribe for the upload-removal listener, so each recovery through the root error boundary's Retry remounted App and added another listener. Return it so the effect's cleanup removes it. |
||
|
|
7ac2dcc7d4 |
feat(cli): let agents read and update Jira tickets safely (#28592)
Expose host-owned verified Jira reads and single-attempt writes through the CLI. Preserve site ambiguity checks, old-host capability refusal, atomic label changes, and uncertainty after failed writes. Refs #11986 and #26055. Co-authored-by: Dan Cieslak <dcieslak19973@users.noreply.github.com> Co-authored-by: kokbee <kok2209@gmail.com> |
||
|
|
9b1e83a7d8 |
refactor(native-chat): rename the chat visuals folder to the chat scratch folder (#28389)
* fix(files): never write through a dangling symlink A path that doesn't exist yet was authorized by walking up to the nearest existing folder. A dangling symlink fails realpath with ENOENT, so the walk stepped over it and approved the link's own path; the write then followed the link and created its target outside the allowed folders. The walk now continues from the link's target, and returns that real destination. * refactor(native-chat): rename the chat visuals folder to the chat scratch folder The per-chat folder agents write into is the chat's scratch space, not only a visuals folder. Its root becomes <state>/chat-scratch/<hash> (the hash is unchanged) and the agent variable becomes ORCA_CHAT_SCRATCH_DIR. The old ORCA_CHAT_VISUALS_DIR is never set and is still stripped from what every agent child inherits, Pi included. The visuals skill names the new variable and says the folder is temporary. * test(native-chat): keep the delivery test to the rename The launch parity snapshot already pins that every agent drops the pre-rename variable. * fix(files): refuse any dangling symlink in the missing-path walk Following a dangling link by hand resolved relative targets against the lexical parent, not the link's real folder: through a folder link the walk could loop forever or authorize the wrong file. Refuse instead: realpath can't say where a dangling link leads, but a write would follow it. * test(files): drop the loop case that duplicated the dangling-link refusal |
||
|
|
83056e5edb |
fix(skills): judge official skill updates by ownership, not snapshot matching (#27603)
* fix(skills): judge official skill updates by ownership, not snapshot matching Orca decided whether an installed official skill was pristine by matching its bytes against a shipped list of past snapshots, falling back to the skills CLI's lock hash. Copies installed between releases, CRLF copies, and installs whose lock recorded a sha256 hash all read "doesn't match the official version" and could not be updated (#26841), and older content could be labelled newer and never offered. Now an official skill is Orca's when the skills.sh global lock says it came from stablyai/orca, and it is current only when its listed files equal the bundled manifest (line endings and sidecars ignored); anything else is outdated. Install and update are one pinned `skills add .../tree/v<appVersion>` command, used by the in-app runner, `orca skills update`, and the Settings rails. The update dialog preselects Orca-owned rows and lists same-named skills from elsewhere unchecked. Removes the snapshot registry, release mapping, git-tree identity, lock trust and convergence logic, and the release-cut provenance step. * ci(skills): run the pinned-add round trip on a skills CLI that can fetch a commit * fix(skills): let orca skills update target the shared folder on a bare host Update became the same pinned add as install, so it inherited install's refusal when no agent is detected. That broke the bare-host update the old command guaranteed, and the built-CLI check (update --dry-run, no --agent) on CI runners. The in-app runner already fell back to universal; both now share one detectSkillsCliUpdateAgentKeys rule. Also brings the CLI skills docs off `npx skills update`. * refactor(skills): derive the update selection from the grouped rows The selection hook took the live and the retained inventory, re-derived Orca ownership from installations beside the grouping's own orcaOwned, and kept a separate display count. Groups already carry both eligibility and ownership, so the hook reads them once; the button's existing live-scan gate is the only authorization check. The unselected line is inlined into the headline. * refactor(skills): drop helpers the ownership design made redundant - isOwnerManagedSkillScope only negated into the participation check once plugin caches stopped participating; fold it in. - Eligibility re-checked resolvedPath/physicalIdentity, which observation already turns into 'inaccessible'. - The manifest verifier probed access() before a readFile that throws anyway. - orchestration-install-command.ts only forwarded one constant from the lib module its three importers already import. * i18n(skills): stop naming npx skills update in four skipped-copy strings The es/ja/ko/zh cantUpdateReason and tipDuplicate strings still named `npx skills update`, which Orca no longer runs for its skills. Say 'the update command' instead. * refactor(skills): inline the single-use pinned source URL helper orcaSkillsSourceUrl was exported but only called by the builder beside it. * fix(skills): let an update choice lapse when the install source changes The selection froze every checked name, Orca's preselection included, the moment the user ticked anything. A re-check that then attributed a name to another source kept it checked, replacing it without consent. Store only the user's explicit choices, keyed by name and lock source, and default to ownership otherwise. * fix(skills): label the empty update action 'Update skills', not 'Update 0 skills' The button stays whenever a row is updatable, so unticking every row (or a dialog with only non-Orca copies outdated) doesn't reflow the footer. At zero selected it stays disabled and reads 'Update skills' instead of a zero count. The label lives beside the dialog's other count copy. * fix(skills): let keyboard focus open the Not from Orca tooltip The source of a non-Orca copy is only in the tooltip, and its trigger was a plain span. Make it focusable like Orca's other tooltip-on-text triggers (tabIndex 0, cursor-help, the row primitive's focus ring), as in the agreed mock. * test(skills): hold the round-trip add equal to the shared install builder The CI round trip hardcoded its skills add argv, so it could drift from what Orca runs. A .mjs script can't import the TS builder (extensionless imports), so the argv moves into an exported roundTripAddArgs and a unit test asserts it is the builder's unattended add with the tag swapped for the PR commit. The script runs under the same main guard as the manifest generator. * i18n(skills): translate the skill row's location count and duplicate reason es, ko and zh still carried English for SkillUpdateRow.oneLocation and manyLocations, and es and ko for SkillFreshnessRow.skippedReasonDuplicate. * fix(skills): pin official skill installs to the build commit and skills CLI `skills add .../tree/v<version>` only works for stable and RC builds: hourly, daily and adhoc builds publish elsewhere, so stablyai/orca has no tag for their version and both install and update failed there. Every build is made from a commit that exists in stablyai/orca, so the build now stamps `git rev-parse HEAD` and the one shared builder pins to `tree/<commit>`, which equals the bundled skills by construction. Main, renderer, web and vitest get it as ORCA_BUILD_COMMIT (replacing ORCA_APP_VERSION); the tsc-built CLI reads it from the compiled out/package.json boundary. A missing or malformed commit fails the build or the command with a clear error instead of building a bad URL. The builder also pins the skills CLI (`npx skills@1.7.2`): 1.5.x cannot fetch a commit, and a bare `npx skills` can reuse a stale cache or resolve to another binary (#18687). The CI round-trip script reuses the same constant. * ci(skills): run the round trip on the shared pinned skills CLI version * docs(skills): document the commit-pinned skills add * refactor(skills): keep the pinned skills CLI version in the install builder skills-cli-version.ts existed only so the plain-Node round-trip script could strip-load a .ts file, which needed --disable-warning in CI. The version now lives beside the builder that uses it; the script keeps a literal, and the existing round-trip test already asserts its argv, skills@<version> included, equals the builder's. * refactor(skills): validate the build commit once, where it is resolved resolveBuildSourceCommit already refuses anything but a full hash, and both the define and the CLI's stamped package.json come from it. The builder's second check could only fire as a module-load throw in the renderer's command constants. Also drops the resolver's unused cwd parameter. * test: stamp a fixed build commit instead of running git in the vitest config Tests only interpolate ORCA_BUILD_COMMIT, so they need not read HEAD (or fail outside a git checkout) on every run. * refactor(settings): match only skills add in the Windows npx preflight Every official skill command is now the builder's skills@<version> add; no rail emits skills update any more. * fix(skills): fail an update that leaves a broken skill link behind Eligibility already skips names with a broken link before the run, so one afterwards is the run's own damage; report it instead of claiming success. * ci(release): refuse to tag when the skill manifest is stale The removed --release step implicitly checked the committed manifest against skills/. Keep that guarantee with a verify-only run; it writes nothing. --------- Co-authored-by: Orca Worker <orca-worker@localhost> |
||
|
|
a53967fc05 |
Native chat: add an inline visuals switch and simplify the skill (#26358)
* Native chat: let users turn off inline visuals for new chats * Native chat: keep inline visuals guidance light * Move inline visuals setting to Chat settings |
||
|
|
c785c986c2 |
feat(native-chat): teach chat agents to show inline visuals in their own folder (#26099)
* feat(native-chat): visual directive grammar and host read for a chat's visuals folder
A shared grammar for the ::orca-visual{file="..." title="..."} reply line,
the per-chat visuals folder location on the owning host, and the
agentSession.readVisual runtime method that reads one visual with lexical and
canonical containment, a 512 KiB bounded read and UTF-8 refusal.
* feat(native-chat): render chat visuals inline and in the right sidebar
Native-chat assistant replies render a ::orca-visual{...} line as the chat's
HTML visual in an opaque, scripts-only sandboxed frame: CSP first, the host
frame navigation guard registered before content runs, live theme without a
reload, fitted height, links opened in the viewer's browser only from a real
gesture, lazy mount, and one muted line when the visual cannot be shown.
Open in sidebar shows the same frame in the right sidebar, widened while it
is open and restored after.
* feat(native-chat): teach chat agents to show inline visuals in their own folder
Native-chat Claude and Codex sessions now get a per-chat visuals folder on
the host that runs them, write access to exactly that folder, its path in
ORCA_CHAT_VISUALS_DIR, and an Orca skill that teaches the ::orca-visual line.
- Skill ships as an unpacked plugin folder in desktop and headless builds.
- Claude: --plugin-dir via SDK plugins, behind the CLI version probe (now one
shared probe for every version-gated flag); folder added to
additionalDirectories beside the user's own.
- Codex: skills/extraRoots/set and the folder appended to the user's own
writable roots, between initialize and the thread open, under a 2 s budget;
unsupported, failed or hung setup opens the chat without visuals.
- A host sweep removes folders no chat record maps to, and folders whose
local workspace is provably removed; anything unproven is kept.
* test(native-chat): the visuals skill names only theme variables the frame sets
* fix(native-chat): visual CI fixes, shared height governor, live-turn streaming hold
Registers agentSession.readVisual from the methods index so the structured
method file stays under its line budget, replaces reflective reads with checked
narrowing, moves the pure height governor to src/shared for mobile, and holds a
half-written directive tail while the turn works (structured text rows carry no
running state).
* fix(native-chat): harden the visual read and link opening
Re-checks after the open that the chat's visuals folder is still the real
directory at Orca's path, reports unexpected filesystem faults by code without
host paths, and lets one click in a visual open at most one page.
* fix(native-chat): keep visual lines out of plain-text reply surfaces; review fixes
One shared helper drops visual lines (outside fenced code) from reply text where
it becomes plain text: the structured status summary that feeds the sidebar row,
dashboard, notifications, phone rows and handoffs, and AI Vault reply previews.
Review fixes: height also counts a pinned body's overflow, only the live
frontier row holds a half-written visual line, the runaway-height stop needs the
same step repeated, and any host refusal evicts the cached revision.
* fix(native-chat): review round 1 for chat visuals delivery and cleanup
- Visuals sweep: a workspace counts as removed only when no profile's
catalog holds it (chats and visuals are shared by every profile, catalogs
are not); a worktree in a known project is removed only when git no
longer records it; any unreadable profile decides nothing; one catalog
snapshot per run; a symlinked visuals root is never walked.
- The other-profile catalog reader moves out of window/ and also returns
project ids.
- A folder Orca itself inherited is stripped at the spawn layer for both
agents, not only from the launch overlay.
- Claude version probe: a probe that gave no version is never remembered;
the plugin check waits up to the probe's kill time so a slow first probe
no longer costs a chat its skill.
- Skill: kept out of Claude's / menu, filename and theme guidance matched to
the renderer, refused writes are not retried.
- Opt-in real Codex test for skill discovery and the writable root.
* feat(native-chat): ask the Claude CLI its version when native chat starts
The first chat after Orca starts usually finds the version known, so the
plugin and thinking-display checks answer at once instead of probing a
cold binary while the chat waits.
* fix(native-chat): resolve the visuals folder without the removed journal-paths helper
Main removed the per-chat journal paths and the journal database's state
directory; the visuals folder keeps the same sha256 layout on its own and the
read method uses the profile state directory the chat host is opened in.
* fix(native-chat): review round 2 fixes; copy a reply without its visual lines
Reply previews in Agent Session History drop visual lines per text part before
lines are folded; the frame adds a body's overflow only when the body really
overflows; fence tracking follows CommonMark closers and openers; the copy
button copies a reply without visual lines; a coded read fault keeps its cause.
* fix(native-chat): review round 2 for chat visuals delivery and cleanup
- Read git worktree records written relative to their own folder (git 2.48+),
so a worktree on an unmounted drive in such a repo is still kept.
- Skip the running profile by its own storage folder, not the profile index a
switch rewrites first; a profile never written to counts as empty, so the
workspace rule is not switched off by a profile that was never opened.
- Ask for readable thinking again once the plugin check has waited for the
version, so a slow first probe no longer drops it for the chat's life.
- Launch flag decisions move to their own module; tests use a typed record
fixture instead of casts.
* fix(native-chat): review round 3 for the visuals sweep and version check
- Resolve a relative git worktree record against its folder's real path, so a
project added through a link still matches and its worktree is kept.
- A profile with only backups of its data file is a lost file, not a fresh
profile: it still stops the workspace rule.
- The readable-thinking re-check reads what is known and never starts a
second version probe.
* fix(native-chat): update the frame's theme ref after render; read the visuals folder pair at once
* test(native-chat): declare agentSession.readVisual on the cross-version agent-session surface
* fix(native-chat): copying a reply keeps its code blocks and indentation
Removing visual lines now closes only the gap each removal leaves, instead of
collapsing blank lines across the whole reply and trimming its indentation; the
visuals folder is checked parent first again so a broken path answers the same
way every time.
|
||
|
|
7468e9cccb | release: v1.4.214 | ||
|
|
7ea01279cd |
feat(search): bundle ripgrep for local, WSL, and SSH search (#22396)
* feat(search): bundle ripgrep for local, WSL, and SSH search Ship @vscode/ripgrep-universal's prebuilt rg for all six relay platforms in every desktop artifact. Local and WSL searches spawn the bundled binary and drop the git ls-files / git grep fallbacks; SSH deploys upload the remote's binary once per ripgrep version and the relay prefers it over PATH rg. * fix(search): address bundled ripgrep review findings - Key the SSH ripgrep cache on the binary's content hash; a package bump is the only update step - glibc verifier: read arch tokens below the slice root and accept static ELFs (arm64 release blocker) - Ship ripgrep/PCRE2/musl license notices; bundle rg with orcad - Packaged builds never spawn a bare rg; report fd pressure as transient - SSH: install rg before sweep/GC, size-validate installs, back off instead of disabling on launch failure - Scope Dependabot to @vscode/ripgrep-universal; revert unrelated lockfile churn * chore(search): drop bundled-ripgrep reference doc; assert full packaging layout parity * refactor(search): one entry point for spawning the bundled ripgrep Local Quick Open, Quick Open path search, the Explorer name filter, and runtime text search each repeated the same three steps: resolve the bundled command, spread in the WSL distro, spread in the WSL shell expression. Fold that into spawnBundledRipgrep so one place owns the rule that a bare 'rg' must never reach spawn, and simplify the resolver's command/packaged checks. Restore the AGENTS.md ripgrep rule dropped alongside its reference doc in |
||
|
|
5610b11703 |
feat(ipynb): create a .venv when pip is locked out, and show ipykernel setup progress (#22710)
* feat(ipynb): set up ipykernel in a new .venv when pip is locked out, and show install progress in the dialog * fix(ipynb): drop the retired installFailed string from translated catalogs * refactor(ipynb): drive the setup dialog from one setup state; fix review findings - Kernel status now only describes the kernel; a single `setup` object (base, offer, phase, error) drives the dialog, replacing the extra statuses and the externallyManaged/setupError fields. - The picker's 'Create virtual environment…' opens the same dialog; success switches through selectEnvironment, so a running kernel is only replaced once the venv exists. - Async setup results are dropped when the dialog they belong to is gone (tab closed/reopened). - main verifies ipykernel imports after pip, reuses an existing .venv instead of re-running venv over it, and explains failures that printed nothing. - Windows copy command guards the install with if ($?); notebooks at a filesystem root get a correct .venv parent; 'Try again' shows for both retry paths. * fix(ipynb): close the setup prompt when another Python is picked |
||
|
|
8ba7f829ac |
feat(ipynb): run notebook cells in a persistent Jupyter kernel (#22581)
* feat(ipynb): run notebook cells in a persistent Jupyter kernel Replaces the fresh-process runner (which silently re-ran every earlier cell) with the user's own ipykernel, driven by a small bundled Python bridge over line-framed JSON. One kernel per open notebook: started on first Run, shut down when its tab closes or Orca exits (stdin EOF), and the kernel's own parent poller reaps it if the bridge dies. The header gains a kernel pill (workspace .venv/.conda recommended, PATH interpreters, Browse), Interrupt/Restart/Run all/Clear all, and a one-time missing-ipykernel dialog with Install. Outputs stream live per cell and are written into the document when the run finishes. * test(ipynb): cover the stalled-interrupt restart offer * refactor(ipynb): disable the kernel pill while settling; merge its classes with cn * refactor(ipynb): tie kernels to their renderer document and simplify the run flow - Main keys kernels per renderer, so a reload, renderer crash or closed window shuts them down, and two windows never share one notebook kernel. One close-driven cleanup replaces the separate exit and start-failure deletions. - The first run uses the nearest workspace env, else the first Python on PATH; the picker no longer opens itself, so its open state stays in the toolbar. Closing the picker brings the missing-ipykernel dialog back instead of dropping the queue, which also keeps a Browse pick's run. - Discovery marks the kernel starting, so a second run during it queues instead of starting a second kernel, and a tab closed mid-discovery no longer leaks one. - Running an nbformat 4.4 notebook gives its cells ids (upgrading to 4.5), so moving a cell mid-run cannot misroute its output. - The death notice drops stderr from before the kernel was ready (the unencrypted-TCP warning). - SSH and non-Python runs toast instead of writing a notice into the cell. - Windows conda envs are named after their folder. * fix(ipynb): install ipykernel into envs without pip uv-created venvs ship without pip, so Install failed with 'No module named pip' there. When pip is missing, bootstrap it with the stdlib's ensurepip and retry. The install moves beside the other interpreter probes, and the copyable install command comes from one helper. * fix(ipynb): address PR review comments on stream errors, old jupyter_client and the Windows venv hint - Swallow stdout/stderr stream errors on the bridge child, as spawnProcess requires, so a broken pipe cannot crash main. - The bridge exits (reporting the death) even when cleanup_resources is missing (jupyter_client < 6.1.5) or raises. - The install-failure hint suggests `py -m venv .venv` on Windows. * feat(ipynb): add Cancel to the missing-ipykernel dialog It does what Esc does: drops the cells waiting on the kernel. * fix(ipynb): recover from a rejected kernel start; quote the install command per shell - Discovery moves into start, so one catch turns a rejected listPythonEnvironments or startKernel into the usual failed start: the session returns to off with the error in the cell, instead of sticking at starting. - The copyable ipykernel command quotes the interpreter only when its path has whitespace, prefixing PowerShell's call operator on Windows. Install itself still spawns without a shell. * fix(ipynb): always shell-quote the copyable ipykernel install command Quote the interpreter path for every path, not only ones with whitespace, so paths with shell metacharacters like & copy as a working command. Single quotes are literal in POSIX shells and PowerShell; embedded quotes are escaped per shell, and PowerShell keeps its & call operator. |
||
|
|
9af6a3d798 |
fix(cli): report a denied runtime connection instead of a dead Orca (#22341)
* fix(cli): report a denied runtime connection instead of a dead Orca Inside Codex's macOS Seatbelt sandbox, connect() on the runtime socket fails with EPERM. The CLI dropped the errno and reported "Could not connect ... Restart Orca", appended "Orca is not running. Run 'orca open' first.", and `orca status` answered ok:true with `starting` (its pid probe also gets EPERM). An agent following that advice restarts a healthy app, which cannot help. EPERM/EACCES on the metadata read or the socket/pipe connect now fails with a CLI-local `runtime_access_denied` error: ok:false, non-zero exit, operation/systemCode/processState:"unverifiable"/retryable:false and nextSteps that say to re-run with escalated permissions and not restart. CODEX_SANDBOX only picks the wording. `orca open` stops before launching. The status pid probe is unchanged: a refused or missing socket proves the caller reached the endpoint, so a later EPERM probe is another uid and keeps #20098's `starting`. Missing, refused, stale-pid and timeout paths are unchanged. Adapted from the diagnosis and tests in #20487 (and #19605, #13583). Co-authored-by: lifeodyssey <zhenjiazhou0127@outlook.com> * docs(skills): tell agents runtime_access_denied means escalate, not restart The shared CLI-resolution block told every bundled skill to run `orca open` when a command says Orca is not running. Add the counterpart for the new access-denied code so sandboxed agents re-run with escalated permissions instead of launching or restarting Orca. Regenerated stubs and manifest. * refactor(cli): classify only a denied runtime connect, with a leaner error A denied metadata read was never observed under a sandbox, and it turned an unreadable user-data path (the Linux launch contract's root-owned HOME) into runtime_access_denied instead of "Orca is not running". Keep metadata reads as on main and classify only the socket/pipe connect. One helper now maps a socket errno to the error or null; the error data keeps only systemCode and nextSteps. Tests drop cases already pinned by status.test.ts. * fix(cli): give not-running advice when a denied socket belongs to a dead Orca A crashed Orca leaves its metadata and socket file behind, and a sandbox denies the connect with EPERM before the CLI can see ECONNREFUSED. The sandbox still reports ESRCH for a gone pid, so a denied connect now probes the metadata pid and falls through to the ordinary unavailable path when the pid is proven gone. isProcessRunning moves to its own module so transport and status share it. * refactor(cli): inline the runtime_access_denied code like other CLI error codes --------- Co-authored-by: lifeodyssey <zhenjiazhou0127@outlook.com> |
||
|
|
12d744f253 |
fix(skills): keep computer-use off filesystem and shell tasks (#21069)
* fix(skills): keep computer-use off filesystem and shell tasks STA-7615: "On my desktop create a folder" was matching computer-use because discovery copy said OS/window-level and neighboring skills advertised desktop UI. Scope the trigger to visible GUI with no CLI path, and exclude files/folders/git/shell. * fix(skills): prefer programmatic paths over computer-use State the last-resort rule in discovery copy instead of enumerating files/folders/git/shell. computer-use prefers shell, filesystem, git, HTTP, CLIs, and Playwright/CDP; neighboring skills route to Computer Use only when a visible window needs GUI control those cannot do. * fix(skills): stop advertising computer-use from orchestration Orchestration coordinates workers; it does not drive a GUI. Drop Computer Use and Playwright/embedded-browser routing from its discovery description so those tools are not pulled in from a coordination skill. * fix(skills): drop Playwright from orca-cli discovery orca-cli should not prescribe Playwright or CDP. Those tools may not be installed, and page automation is not this skill's job. * fix(skills): drop the page-only ban from computer-use discovery Page automation is a preference, not a prohibition. If Playwright or CDP is not available, a visible browser window is valid Computer Use. Keep the hard split for Orca's embedded browser (`orca-cli`) only. |
||
|
|
7b0701aefa |
chore: remove 20.7 MiB of duplicate and unused media (#20416)
* chore: remove duplicate and unused documentation media * chore: guard README local links and refresh tile-01 vendor metadata - Add config/scripts/check-readme-local-links.mjs: every local src/srcset/href in README.md and docs/readme/*.md must resolve to a tracked file. Runs in the ungated root_directory_guard job so docs-only diffs (which skip static_analysis) still catch a deleted docs-site or feature-wall asset the README embeds. - Refresh tile-01.recorded-at.json to what vendor-feature-wall-assets.mjs now emits for the tab-split source path. - Drop the pr-19217 evidence prose that cited the removed screenshots. * fix: accept single-quoted attributes in README local link check The parser only matched double-quoted src/srcset/href, so <img src='missing.gif'> was skipped and the guard passed a README that GitHub renders with a broken image. Regression test fails without the parser change. |
||
|
|
fb322046e8 |
skills: rewrite and trim the seven non-orchestration guides (#19128)
* skills: rewrite the seven non-orchestration guides to one outcome-first standard
Every guide leads with Result / Done / Safe failure, states conditions instead of case lists, keeps one done bar and one autonomy envelope, and loads references at the point of use via `skills get <topic> --full`. orca-cli drops from 424 to 260 always-loaded lines with three references; orca-per-workspace-env from 794 to 397 with five.
Defects fixed in shipped guides: `emulator camera` (no such command), iOS `permissions` (backend refuses it), Android pane described as in development, `relayGracePeriodSeconds: 0` documented as immediate teardown (it is unbounded), doctor `ok: true` hiding `warn`, an SSH exemplar setting both `jumpHost` and `proxyCommand`, a provisioned-root fetch from `origin`, and the Linear unconfirmed-write rule keyed on four verbs when ten emit it.
The resolver ladder, placeholder rule, and older-binary fallback shared by every installable SKILL.md now come from one skill-stubs/_shared/cli-resolution.md fragment composed by the generator, which also bundles per-guide references into --full. New guards: every ORCA invocation and flag resolves against COMMAND_SPECS, descriptions carry no angle-bracket tokens, reference routing is checked both ways, and an always-loaded size ratchet (300 lines) that guides may leave but never join.
* skills: address review on the SSH recipe and the parity guard
- ssh-host create script: route the bootstrap ssh through the chosen jump host or proxy command, refuse both at once, use StrictHostKeyChecking=accept-new instead of a blind ssh-keyscan append, and pass gh_token/project_root/repo_url/repo_ref to the remote bash via printf %q so a quote in a value cannot break out of the command.
- per-workspace-env envelope: the step-10 workspace test the user asked for is no longer forbidden by the same paragraph.
- linear guides: name the full verb, ORCA linear list-issues.
- parity guard: a prefix reference such as ORCA linear --help or ORCA emulator --webcam now has its flags checked against every command under that prefix; only an exact path or an explicit ... was checked before.
* skills: tighten prose in the seven rewritten guides
Shorter outcome spines, one idea per sentence, no restated rationale after a rule. No rule, command, or pinned phrase changes; 47 net lines fewer across the guides and references.
* skills: route orca-cli and per-workspace-env gates through --reference
Both guides told agents to load --full at a gate because the per-reference
selector did not exist when they were written. Now that main serves
`skills get <topic> --reference references/<file>.md`, load only the
named file and keep --full as the fallback for an older CLI, matching the
orchestration kernel.
* skills: drop outcome-spine boilerplate from the CLI-wrapper guides
The Result/Done/Safe-failure preambles and Next Action closers restated
rules the body already carries. Agents stop fine without them, and for
a CLI wrapper the command surface is the guide. Keeps the one substantive
rule computer-use's Done block added (never report unverified as success)
inside Action Rules. orchestration and per-workspace-env keep theirs:
those are multi-step workflows where the done bar is load-bearing.
(cherry picked from commit
|
||
|
|
b8311d509a |
Revert "skills: rewrite the seven non-orchestration guides to one outcome-first standard (#18724)" (#19126)
This reverts commit
|
||
|
|
15d0f8aedf |
skills: rewrite the seven non-orchestration guides to one outcome-first standard (#18724)
<!-- orca-pr-loc -->
<!-- Programmatic LoC summary. Do not edit by hand; rewritten on every commit. -->
| | Files | Added | Deleted | Net |
| :--- | ---: | ---: | ---: | ---: |
| Test | 6 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$544 | $\color{#cf222e}{\Huge{\mathbf{−}}}$49 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$495 |
| Prod | 36 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$1719 | $\color{#cf222e}{\Huge{\mathbf{−}}}$1703 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$16 |
<!-- /orca-pr-loc -->
## ELI5
Orca ships eight skill guides that agents read before running the CLI. Seven of them (everything except `orchestration`, which #16904 rewrites) were command catalogs that had drifted from the binary. This PR rewrites them so an agent reads the outcome, the done bar, and the safe-failure rule first, loads reference material only at the step that needs it, and never sees a command or flag the installed CLI does not define.
## What changed
- **Seven guides rewritten** to one standard: outcome spine first (Result / Done / Safe failure), conditions instead of case lists, one done bar, one autonomy envelope, references loaded at the point of use via `skills get <topic> --full`, every runnable invocation spelled `ORCA`. `orca-cli` is 424→260 always-loaded lines with three references (browser, automations, publishing); `orca-per-workspace-env` is 794→397 with five (provider-vercel, ssh-host, docker-ssh, windows-scripts, failure-modes).
- **Defects fixed in shipped guides:** `emulator camera` (no such command), iOS `permissions` (backend refuses it), Android pane described as "in development" (shipped in June), `relayGracePeriodSeconds: 0` documented as immediate teardown (it is unbounded), doctor `ok: true` hiding `warn`, an SSH exemplar setting both `jumpHost` and `proxyCommand`, a provisioned-root fetch from `origin`, the Linear unconfirmed-write rule keyed on four verbs when ten emit it. Linear and emulator descriptions dropped embedded commands and angle-bracket placeholders (651→329, 732→404 chars).
- **Generator bundles references.** `skill-guides/<name>/references/*.md` is appended to `--full`; `skills get` help says compact by default, full with references.
- **Stubs single-authored.** The resolver ladder, placeholder rule, and older-binary fallback shared by all eight installable `SKILL.md` files come from one `skill-stubs/_shared/cli-resolution.md` fragment composed by the generator. Projections were byte-identical before the content fixes.
- **Guards:** every `ORCA <cmd>` and flag in every guide and reference resolves against `COMMAND_SPECS` (this found the camera defect); descriptions ≤1024 chars with no angle-bracket tokens; reference routing checked both directions; an always-loaded size ratchet (300 lines) that guides may leave but never join. `orchestration` (440 lines on main) is recorded as an exception until #16904 lands its kernel.
## Relationship to #16904
Split out of #16904 so that PR carries only the orchestration guide. On main, `terminal send` has no `--wait-submit` / `--retry-request` and the orchestration kernel still carries the resolver ladder and worktree-selector rule, so this branch pins `accepted: true` for handoff receipts and leaves the orchestration pins where main has them. The merge in either direction is mechanical: #16904 rebased on this becomes a one-file `orchestration.md` change plus dropping the two exceptions.
## Standard
Compound Engineering's portable skill-authoring guidance (outcome spine, conditions not cases, pinned fragile commands with an ordered hatch, references at point of use). NVIDIA SkillEvaluator Tier 1 (`schema,pii,license,quality,unicode,lint`) was run on every guide; its deterministic checks pass, its template nudges (Instructions/Examples sections, 50–150 char descriptions) do not apply to Orca's stub architecture and were not applied.
## Testing
- `pnpm typecheck:tsc:cli` clean; `check:code-quality:changed` and `check:react-doctor:changed` 0 findings
- `pnpm verify:bundled-skill-guides` and skill-bundle manifest verify clean
- vitest over `config/scripts`, `src/cli/skill-guide-cli-parity.test.ts`, `src/cli/skills.test.ts`, `src/cli/specs/skills.test.ts`, `src/cli/help.test.ts`, `src/main/skills`: 240 files / 2,019 pass
- Live smoke on the built CLI of every `skills get <topic>` and `--full`, every emulator, linear, and vm verb named in the guides, and every projection's resolver, GNOME warning, and bounded fallback (done on the #16904 branch before the split; the guide bodies are identical here except the send-receipt vocabulary noted above)
## Deferred product decisions
Merging `orca-emulator` and `orca-emulator-android` into one skill with a platform branch; collapsing `linear-tickets` to a guide alias; a `skills get --reference <name>` selector so a gate table can load one file; a fresh-agent routing eval before trimming the `orca-cli` (1,015 chars) and `orchestration` descriptions, whose quoted triggers each fixed a routing misroute.
|
||
|
|
06a607a1d7 |
feat(orchestration): make multi-agent workflows durable (#16904)
<!-- orca-pr-loc -->
<!-- Programmatic LoC summary. Do not edit by hand; rewritten on every commit. -->
| | Files | Added | Deleted | Net |
| :--- | ---: | ---: | ---: | ---: |
| Test | 225 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$21666 | $\color{#cf222e}{\Huge{\mathbf{−}}}$2820 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$18846 |
| Prod | 348 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$17107 | $\color{#cf222e}{\Huge{\mathbf{−}}}$4706 | $\color{#1a7f37}{\Huge{\mathbf{+}}}$12401 |
<!-- /orca-pr-loc -->
## ELI5
Orca now treats orchestration like a durable control plane instead of inferring success from terminal keystrokes. Agents can tell whether a prompt was accepted or a turn started, replay an ambiguous request without sending twice, and recover coordinator mail after a crash. Completed workers can be inspected, released, or retained, and their panes no longer auto-resume as if the work were still running.
## What changed
- **Run receipts** from `run-create/use/current/show/list` are the row without routing plumbing (`home_database`, `coordinator_pane_key`) and without the duplicate `binding` object.
- **`terminal send` receipts are honest and idempotent.** `input_accepted` and `turn_started` are the only stages; `--wait-submit` observes without resending; `--retry-request <uuid>` replays the exact request against the same process incarnation. A transport timeout keeps the retry ID; only a different runtime answering strips it. Value-less or non-UUID `--retry-request` is rejected on the CLI and the SSH shim.
- **Mailbox delivery is committed before wakeup.** Pointer writes are staged in the DB before any PTY byte, replayed once after restart, and never emit a naked Enter. The watermark that parks concurrent deliveries is released with the DB reservation. Restart rescans pointer-pending and `dispatch:` mailboxes.
- **Lifecycle is a guarded transition graph** (`lifecycle-transition.ts`) with a table-driven test over every caller edge. Task reopen/overturn stays in the public contract. A PTY exit during `worker-stop` is the stop succeeding, not a failure.
- **Worker lifecycle CLI:** `worker-start` (`--spec` creates Task + attempt in one call), `worker-show`, `worker-read` (provider transcript first, bounded terminal fallback with a typed reason, local/WSL/SSH), `worker-stop`, `worker-abandon`, `worker-release`, `worker-retain`, `worker-list` (rowid-fenced pagination, fleet liveness, `attention`, literal `nextAction`).
- **Release is an explicit ownership table** (`decideWorkerTerminalRelease`): only an `owned` resource can be settled, the archive is mandatory where reachable, and an owner whose process is proven exited can always get out of `retained` via `archive_status: unavailable`. User-taken-over, external, and transferred panes stay retained.
- **Settled-worker resume fence** (folds in #17651): a settled dispatch whose pane is still open is fenced at settlement, on stop/abandon/exit, and at startup; lifted on release, retain, takeover, and pane reuse.
- **Liveness is `live` / `unverifiable` / `exited` only**, from execution-host evidence. Fleet projection reads the evidence clock, not the relay delivery clock. A host-certified exit outranks the worker's settled state. `unverifiable` never authorizes stop, abandon, retry, or release, in code or in the guide.
- **Federation:** structured reads negotiate by `method_not_found` so every shipped host keeps transcript-first output; exited remote workers are closed before being reported closed; epoch fencing holds across peer restart, downgrade, and pairing rotation; no per-second forced capability probe.
- **Schema v35:** repairs databases stamped v34 by the pre-fix branch (mailbox_handle default, index predicates), drops the write-only `lifecycle_transition_receipts` ledger and five never-read v31 identity columns.
- **Schema v36:** `dispatch:<id>` mailboxes get a real consumer generation on `dispatch_contexts` and `remote_dispatch_attachments`, bumped and fenced in the same transaction on every re-attach (manual inject, worker-start, federated attach). A stale worker whose Dispatch moved to another process now gets `consumer_fenced` instead of silently acking the new worker's Delivery. Run mailboxes already worked this way.
- **Schema v37:** `dispatch_contexts` records its creator (`creator_handle`, `creator_pane_key`), so a coordinator's context-only self-dispatch is bookkeeping rather than a nesting parent; before this, one self-dispatch made every later `worker-start` from that coordinator fail the depth cap. Pre-v37 rows keep counting (fails closed).
- **Dispatch-mailbox ownership is checked, not inferred.** A `check` from a process whose pane no longer holds the Dispatch, or whose last Attempt was abandoned/failed and moved to another terminal, gets `consumer_fenced` instead of an empty inbox that reads as "no mail yet". `--peek`/`--all` stay readable. A paneless caller still gets `stable_pane_required` with the rebind recovery.
- **Liveness certification is stricter:** a `process_exited` stage whose termination reason is `unknown` (a stop that was issued but never observed) projects `unverifiable`, not `exited`. Federated `worker-show` carries the execution host's verdict and host kind instead of a local guess. A live, ready worker with nothing pending has `nextAction: none` rather than pointing at the `worker-show` that produced it.
- **Wire:** `workerShow` keeps `dispatch.task_id` next to `taskId` for shipped CLIs. `ask --json` uses the standard `{ok, result}` envelope like every sibling verb.
- **Migration start-version detection** treats the two v32 recovery columns as versioned. Before this, every shipped database stamped below 32 resolved to the v6 floor and replayed the whole chain (the v23 backfill synthesized 68 phantom retained workers on a real v30 profile). Verified on a copy of a real 62 MB v30 profile: starts at 30, no row delta, integrity ok, 11 ms.
- **Skill guide** rewritten as a ≤200-line kernel plus seven references, to the outcome-first standard (Result / Done / Safe failure first, conditions not case lists, one done bar, references loaded at the point of use). The canonical loop uses `worker-start --spec`, names `worker-list` for completion accounting, documents `--retry-request` / `request-show` / `--wait-submit`, and requires positive evidence before any stall action. The other seven guides get the same treatment in #18724, split out so this PR stays orchestration-only.
- **`rpc/methods/orchestration-*`** (126 flat files) regrouped into `orchestration/{worker,federation,messaging,runs,gates}/`.
## Why
User reports showed the same boundary failures: false `agent_prompt_stalled` causing duplicate sends (#15180), coordinators unable to trust screen scrapes, cold-parked terminals receiving a pointer without the submit, settled workers accumulating as live tabs and auto-resuming after restart, and no way to tell a stalled worker from a working one.
## Linked issues
Fixes #15180. Fixes #17935 (orchestration skill description is 866 characters; a guard now caps every bundled skill at 1,024). Supersedes #17651 (fence folded in). Advances #16660, #16522, #14907, #13047.
## Review record
This PR was reviewed adversarially after revival: eight independent lenses (lifecycle, mailbox, send, worker, federation, transcript, complexity, live ergonomics), each required to prove findings with a failing test. That produced 16 proven blockers, all fixed with red-then-green regression tests, followed by two re-review rounds and a third fix wave that caught 3 regressions introduced by the fixes and 7 fixes that missed their target; all closed. A final pass (five lenses incl. a live built-runtime smoke, then a re-review of the fix wave) found and fixed seven more, chiefly the stale-worker mailbox steal, the self-dispatch depth wedge, and the unproven-exit certification. Three independent Codex (gpt-6-astra) passes followed: the first found nothing new, the second found and fixed 3 defects (task-status reachability, WSL-local host classification, peer-capability epoch), the third found and fixed 6 (production PTY controller never installed settled writes, ambiguous in-flight pointer failures allowed duplicate replay, SSH/relay deadlines cut off a valid `--wait-submit`, stop-vs-exit race during inspection, and two release-recovery paths for vanished or exited terminals). The full record (findings, proof tests, triage, declines with reasons) is archived outside the repo.
**Rework after the live smoke.** A first live cross-host run on the shipped adhoc build (this Mac, a paired Windows host on the same build, a paired Mac on 1.4.195, and an SSH host) found a P1: a running local worker read `unverifiable`/`missing_status` because the fleet snapshot rows lacked the terminal handle the matcher keyed on. A 59-row failure table over every bug fixed during review showed the same two classes recurring: a fact dropped in transit through optional fields, and two authorities for one fact. Two blind designs (Opus, Codex) converged on the same mechanisms, and the scoped tranches landed here with red-then-green seam tests from the real producer to the real consumer, faults injected only at the transport or hook-ingest boundary:
- **Settlement (data-loss class):** one three-valued `WriteSettlement` (`accepted | refused{reason} | unverifiable{reason, bytesHandedToTransport}`) from the SSH multiplexer through daemon client, providers, controller, to pointer staging. No boolean, no rejection-as-third-state. The two silent degrades that fabricated a handoff are deleted; a provider that cannot settle refuses before any effect. Pointer text and Enter share the contract; a partial flush is `unverifiable`, never `refused`.
- **Evidence identity (false-liveness class):** fleet agent-status evidence is a tagged union (`binding: worker | pane | unresolved{reason}`, `clock: observed | delivery`) minted once at ingest, so a hook row captured on one process incarnation can never bind to a later dispatch on the same pane. The matcher's `!worker.paneKey ||` defaults are gone. One host-scope parser replaces two.
- **Small pre-merge items:** `capability_unsupported` from an old peer is no longer relabelled `host_unavailable`; a producer census test asserts every agent-status consumer path projects a pane-only hook row as `live`.
Two ergonomics defects the second live run surfaced on a real database are fixed here too: a pre-v3 dispatch already marked `completed` projected as `outcome_unknown` / `requiresAction: true` forever (three copies of the outcome ladder disagreed on legacy rows; now one resolver, legacy `completed` reads `succeeded` with nothing to act on, legacy `failed` stays actionable on the failure), and an unscoped `worker-list` enumerated the entire database (now defaults to the Run bound to the calling terminal, `--run` overrides, and the receipt's additive `scope` field says which).
A third live round on the shipped adhoc build of `b082443e1f` (same four hosts) plus an unscripted run in the user's own prompt style (a plain Claude Code shell, `/orchestration`, three workers, zero errors, bound-Run default confirmed) found two more branch defects, fixed with red-then-green tests: a worker freshly started on a paired server projected `unverifiable`/`host_indeterminate` with `requiresAction` for ~3 minutes, including after its own `worker_done`, because the host's federation observation returned `missing_liveness_verdict` for any PTY the liveness register had not yet swept (the host now reads a connected pane it owns locally as `live`; disconnected or SSH-scoped panes stay `unverifiable`); and six pre-v3 completed rows still carried an `input` category because settling through the task-status path or `failDispatch` never closed the Dispatch's pending question threads (both paths close them now, and schema v38 closes threads already pending on settled rows). The guide's `worker-start` examples now show `--model sonnet`, since an omitted model inherits the launcher's default.
A Codex adversarial pass on the tranche diff found one real design hole (identity minted at read time instead of ingest, now closed) and two daemon settlement paths that threw instead of settling (fixed). Two `@ts-nocheck` runtime mixins on these paths were extracted into checked modules; the repo-wide `@ts-nocheck` count is unchanged at 171.
Deletions during review: ~1,900 lines (write-only ledger, unread columns, dead v1 archive path, test harnesses shipped in prod, duplicated liveness and state-machine copies, self-capability checks that were compile-time true).
## Testing
- `pnpm typecheck:tsc:node|cli|web` clean
- `pnpm run check:code-quality:changed` 0 findings; `check:react-doctor:changed` 0
- `pnpm verify:bundled-skill-guides`, `verify:skill-bundle-manifest`
- full `pnpm test` on the integrated head: 72,332 pass / 292 skipped; the only failures were three non-PR files (two zsh live-shell suites hit a node-pty spawn-helper ENOENT while a concurrent native rebuild ran, 44/44 in isolation; `release-checkout.unit.test.ts` is a known 30 s load timeout that passes in isolation on `origin/main` too).
- CI on
|
||
|
|
3e4fd4a7af |
Shorten orchestration skill description under the Agent Skills 1024-char limit (#18683)
* Shorten orchestration skill description under the Agent Skills 1024-char limit The folded description was 1038 chars, so spec-conforming installers such as SkillStar rejected the bundled orchestration skill. Drop the two clauses already covered elsewhere in the same description: "decomposing work across agents" (implied by "structured multi-agent coordination") and "automation of the browser embedded inside Orca" (restated by the locked `orca-cli` embedded-pages sentence). Every routing trigger asserted by orchestration-skill-guidance.test.mjs, the orca-cli handoff boundary, and the Computer Use boundary are unchanged. Result: 958 chars. Add config/scripts/skill-description-length.test.mjs, which parses every skills/*/SKILL.md frontmatter with `yaml` and fails on an empty or >1024 char description, so the regression cannot return. orca-cli sits at 1015 and is left as is. Fixes #17935 * Keep the embedded browser in the orchestration description's orca-cli routing Restores the word "browser" in the orca-cli sentence ("and the Orca embedded browser") so agents scanning for it still route embedded-browser control to orca-cli. Description is 985 chars, 39 under the spec limit. |
||
|
|
f37d2fec97 |
fix(linux): land the reviewed Linux packaging stack on main (#18100)
* fix(linux): give the CLI one entrypoint by extracting the AppImage once
* refactor(linux): trim AppImage CLI registration seams
* test(cli): assert registration lock serialization
* fix(linux): fence AppImage terminal shim mounts
* fix(linux): accept extracted AppImage runtimes with APPDIR only
* docs(linux): make headless AppImage extraction runnable
* refactor(linux): import bundled launcher directly
* fix(linux): reclaim superseded AppImage payloads and packaged symlinks
Pruning removed 3215 of 3216 files from a superseded generation and always
stranded resources/app.asar, leaking ~105 MB per version update. Electron's
asar shim reports a *.asar file as a directory, so the recursive remove tried
to rmdir a real file and failed with ENOTEMPTY; the .catch(() => {}) hid it.
Reproduced end to end on Ubuntu 24.04: 519M -> 623M across one update, and
519M again once the payload is actually reclaimed.
removeExtractedAppImagePayload holds process.noAsar for the removal, counted
so overlapping removals cannot hand the shim back early, and the prune site
now warns with the path instead of swallowing the rejection. All three
removal sites use it -- staging cleanup and displaced roots leaked the same
way.
Also reclaim symlinks left by a packaged deb/rpm install, which the
extracted-cache-only rule turned into a hard conflict on a deb -> AppImage
migration, and name the remedy in the conflict error.
* fix(linux): bound the CLI registration lock wait
`retries: 1000` caps the attempt count, not elapsed time, so at up to 1s per
attempt an IPC-driven registration could hang ~16 minutes against a wedged
holder with no feedback.
A legitimate holder is bounded by the extraction timeout, so wait that plus
slack and then fail with a message naming the lock file, rather than hanging.
`maxRetryTime` is forwarded verbatim to the `retry` package by proper-lockfile.
* fix(linux): stop re-extracting the AppImage on inode metadata churn
The extracted-payload cache key hashed ctime alongside dev/ino/size/mtime.
ctime moves on any inode metadata write -- `chmod +x`, which every AppImage
user is told to run, plus `chown`, an ACL or SELinux relabel, and a backup
restore -- none of which alter a byte of the payload.
Measured on Ubuntu 24.04: `chmod +x` leaves dev, ino, size and mtime
identical and moves ctime alone, so the key changed and the next launch paid
a full ~519 MB re-extraction and a multi-second stall to rebuild a payload it
already had, then pruned the old generation.
Key on content identity instead. An in-place content change moves mtime and
almost always size; a replacement moves the inode. The existing
replace-in-place test still passes.
* fix(linux): stop CLI commands from falling through to Chromium startup
* refactor(cli): remove redundant command membership check
* test(cli): cover command-named project selectors
* fix(cli): redirect the open-url command before startup
* test(linux): cover AUR serve wrapper flags
* fix(linux): tighten CLI launch detection
* fix(linux): respect CLI flag value boundaries
* fix(linux): strip injected Chromium switches from CLI args
* fix(linux): report a missing display instead of dying in uv_close
* refactor(linux): read display locks without a preflight race
* fix(linux): preserve unverified external displays
* chore: format reliability gate manifest
* test(packaging): split runtime resource checks
* fix(linux): fail serve when no display is available
* fix(linux): do not treat a lockless X socket as a dead display
An X server writes its lock beside its socket and both survive a crash
(verified against Xvfb under SIGKILL), so a socket with no lock was never
left by a crashed server. It is an endpoint published from elsewhere: a
container bind-mounting only /tmp/.X11-unix, WSLg, or a foreign PID
namespace. Declaring those dead made the desktop gate exit(1) on displays
that work, with no workaround, and the serve gate refuse to start.
Liveness now splits by ownership. A foreign DISPLAY trusts a lockless
socket; Orca's own :99 does not, because removeStaleDisplayArtifacts
unlinks the lock before the socket and so manufactures that state itself --
adopting it would resurrect the orphan-socket bug and stop the cleanup from
self-healing. The stale-lock rejection is unchanged.
Also correct four doc statements this behaviour falsified.
* fix(linux): fail closed when a stale socket blocks the Xvfb rebind
Readiness only checked that /tmp/.X11-unix/X99 exists. A stale socket we
could not unlink still exists after our own Xvfb refused to bind, so Orca set
DISPLAY to a dead server and Chromium died in Ozone init.
Measured on Ubuntu 24.04 against the pre-fix build: with a leftover :99
socket and no lock, serve exits 139 (SIGSEGV), the socket inode is unchanged
before and after, and no lock is recreated -- it neither cleaned up nor
respawned. To a user that is a crash, not a misconfiguration.
This is reachable in the documented topology, where orca-xvfb.service has no
User= and runs as root while serve runs as User=orca: /tmp is sticky, so the
orca uid cannot unlink a root-owned socket, rmSync fails, and Xvfb exits with
the display already active.
Readiness now requires the display to actually be live -- our socket plus a
lock naming a running process -- so the same state reports an unusable
display and exits 1 with the existing diagnosis.
* fix(linux): recognise abstract X sockets and inherited Wayland fds
Two display setups this gate could not prove were refused outright, and on the
desktop path that is app.exit(1) with no workaround.
An X server may bind only the abstract namespace (`@/tmp/.X11-unix/X0`), which
leaves no filesystem socket to stat. Abstract addresses are kernel-owned and
vanish the moment the owner exits, so an entry in /proc/net/unix is proof of a
live server -- no lock file needed and no stale entry possible. Verified on
Ubuntu 24.04, where 139 such addresses were present.
WAYLAND_SOCKET is an already-connected fd handed over by the compositor, so
there is no path to stat and WAYLAND_DISPLAY may be unset entirely. Its
presence is the display.
Both are consulted only after the filesystem-socket check fails, so no
existing verdict changes.
* fix(linux): never treat Orca's own display number as a foreign endpoint
Recognising a lockless X socket as live is correct for an endpoint published
from elsewhere -- a container bind mount, WSLg -- because an X server writes
its lock beside its socket and both survive a crash. It is wrong for
VIRTUAL_DISPLAY_NUMBER, because Orca's own teardown unlinks the lock before
the socket and so manufactures that exact state.
The managed branch was already strict, but a caller that sets DISPLAY=:99
explicitly takes the foreign path and skipped it, accepting a dead display
left by Orca's own interrupted cleanup. Route the managed number through the
strict probe on both paths.
Found by an adversarial audit of the asymmetry introduced earlier in this
branch; the documented systemd topology is unaffected because its Xvfb writes
a real lock.
* test(linux): add a packaged-artifact contract for the CLI launch paths
* test(linux): avoid buffered serve readiness detection
* test(linux): signal AppImage serve owner directly
* test(linux): tolerate readiness timeout boundary
* test(linux): add startup margin to shutdown oracle
* ci(linux): give package contracts timeout headroom
* fix(ci): route all Linux packaging contract changes
* test(linux): poll shutdown readiness without tail leaks
* test(linux): bound shutdown cleanup grace
* test(linux): assert on CLI output, not the harness's own control lines
run-cli-case.sh echoes `RESULT status=N case=<name>`, and the two cases named
*-skills asserted `expectOutput: 'skills'`. That substring was satisfied by
the case name in the harness's own line, so 2 of 8 cases asserted nothing
about the command -- gutting `skills` entirely would still have gone green.
Control lines are now excluded before matching, and both cases assert the
rendered help header, which only real help output produces. Verified on an
Ubuntu 24.04 host: 8/8 still pass against a stack-tip AppImage.
Also register the gate in reliability-gates.jsonc, which #15085 added a CI
Docker gate without. Red/green is recorded from a stock release AppImage
failing 4 of 8, three of them at status 133 (SIGTRAP).
* fix(linux): require static AppImage runtimes (#17319)
* test(linux): reject a wrong-architecture native binary at packaging time
Cross-building the arm64 slice on an x64 host silently packed an x86-64
`pty.node` -- the rebuild logged "Forcing native rebuild for linux-arm64" and
shipped the host's binary anyway. Every gate here inspects symbol versions,
which are perfectly valid on the wrong architecture, so nothing noticed.
Observed on a Raspberry Pi 5: the packaged app loaded, then failed with
"Failed to load native module: pty.node", and the launch contract reported
3 of 8 cases crashed rather than naming the cause. Swapping in the aarch64
`pty.node` took the same build to 8/8.
Compare ELF `e_machine` against the slice being packaged and fail with the
offending path. Checked before the glibc pass, because a wrong-architecture
binary's symbol versions are valid but meaningless and would send the reader
down the wrong path.
Release CI builds arm64 on a native runner, so this guards local and future
cross-builds rather than a shipped artifact.
* test(linux): judge per-arch vendored binaries against their own path
The first CI run of the architecture gate failed the x64 package job on
`@parcel/watcher-linux-arm64-glibc/watcher.node`. That binary is arm64 on
purpose: the package ships every architecture and its loader picks the match,
so its presence in an x64 build is correct.
Judge a binary against the architecture its own path names, falling back to
the slice when the path names none. That keeps the case this gate exists for
-- `bin/linux-arm64-*/node-pty.node` holding an x86-64 binary, which is what
shipped to a Raspberry Pi 5 -- while letting multi-arch dependencies through.
Dry-run over the real dependency tree flags nothing for either target arch.
* fix(linux): move deb/rpm update installation outside Orca (#17318)
* fix(linux): complete deb/rpm package metadata
* fix(linux): preserve CLI link during package upgrades
* docs(linux): document local RPM build prerequisites
* fix(linux): move deb/rpm update installation outside Orca
* fix(updater): preserve Linux recovery across stale events
* fix(updater): fence stale downloaded events by active target
* fix(updater): preserve active Linux package recovery
* test(linux): keep workflow order assertion in scope
* test(updater): assert stale recovery stays silent
* fix(updater): preserve Linux package recovery after checks
* refactor(updater): keep Linux marker message with status
* fix(linux): describe the right manual update path for deb/rpm hosts
A remote host installed from .deb or .rpm now reports
manual-service-update-required, and the guidance told the operator to
"update through the service manager that starts this server" -- which is
correct for unsupported-headless-serve but wrong for a package install,
where nothing about the remedy involves the service manager.
Say both, keyed on how the host was installed.
* docs(linux): document orcad update restart safety
* docs(linux): scope restart census omissions
* docs(linux): use absolute service CLI launcher
* fix(serve): validate in-process serve options before startup (#17683)
* fix(linux): stop offering updates a distro-managed install cannot apply (#17918)
Closes #17702.
The resources/package-type marker is authoritative but never checked against
the host, so any repackager that unpacks Orca's .deb -- AUR, Nix, a container
rebuild -- inherits `deb` verbatim. Install feasibility was then computed
after a ~165 MB download, so those users got check -> download -> a card
promising an install command -> a dead end.
Validate the marker against the host: a deb/rpm marker with no matching
package manager in the trusted directories means a package manager owns this
install. This reuses the exact lists and resolver that
buildLinuxPackageInstallCommand already loops over, so a false positive is
impossible by construction -- any host flagged here would have failed with
no-package-manager after the download anyway. The gate only moves that
verdict earlier. Verified across Debian 12, Ubuntu 24.04, Arch, Fedora 40 and
openSUSE Leap: no false positive on a real deb host, correct on every
repackaging host.
The release is still reported, because the user does want to know 1.4.194
exists and to update through their distro; only the download path is closed.
`externallyManaged` is an additive optional field on the existing `available`
status, so older paired clients decode it unchanged. downloadUpdate() refuses
authoritatively, since main owns this verdict rather than the card, and
unwinds any pinned-build state first -- a Linux pinned jump resolves to
'release', and stranding isPinnedBuildActive would silently kill every
background check for the rest of the process.
Note the fix the issue suggests cannot work: electron-updater builds a
PacmanUpdater whose doDownloadUpdate looks for a .pacman asset Orca does not
publish, then dereferences undefined.
* style(cli): restore prettier wrapping on install error copy
* test(linux): re-pin the child-process ratchets and the batch-shim allowlist after the merge
|
||
|
|
da4a83bd22 | fix(linux): give the CLI one entrypoint by extracting the AppImage once | ||
|
|
b44ef1e59d |
fix(skills): narrow computer-use discovery boundary (#17736)
* fix(skills): narrow computer-use discovery boundary * chore: remove merge-formatting noise * fix(skills): name browser page automation surfaces |
||
|
|
fa9b20cb41 | feat(skills): reland private bundle sharing safely (#14934) | ||
|
|
763b1febeb |
Revert "feat(skills): add private bundle sharing (#14401)" (#14913)
This reverts commit
|
||
|
|
757fae28d7 |
feat(skills): add private bundle sharing (#14401)
Co-authored-by: E2E Test <e2e@test.local> |
||
|
|
3246b73add |
Forward Unix launcher signals to orca serve supervisor (#14071)
* fix(cli): forward Unix launcher signals to serve * test(cli): retry incomplete listener state writes * test(cli): cover both Unix launcher termination signals * test(cli): cover macOS launcher signal oracle * refactor(cli): keep Unix launcher exec atomic --------- Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com> |
||
|
|
00f0c44a23 | release: v1.4.178-rc.2 | ||
|
|
c991bb27d3 | Add account-backed artifact sharing (#13012) | ||
|
|
97e4776dfe |
feat(plugins): Orca plugin system — kernel, content packs, panels, workers, marketplace v0 (experimental) (#8549)
* feat(plugins): Orca plugin system — kernel, content packs, panels, workers, marketplace v0 (experimental) Adds Orca's experimental plugin system behind a settings flag: a supervised kernel, declarative content packs (VM recipes, commands and keybindings, language packs), sandboxed iframe panels, forked worker hosts, and a Git-backed marketplace v0 with consent, provenance and kill-list enforcement. Theme, icon-theme and terminal-theme contributions are deferred to a follow-up pass. * fix(plugins): make unsupported marketplace listings unreachable by key findPlugin() backs preview/install/previewInstalledUpdate via requireListing(), so filtering only listPlugins() hid the catalog card while leaving the dead install path reachable one click later. * fix(plugins): fan Pi session-only status out to plugin subscribers The providerSessionOnly early-return in applyNormalizedStatus emitted to onAgentStatus (main-window fanout) but skipped enrichedStatusListeners, so plugins subscribed to agent.status.changed silently missed every Pi session_start event. Route both emit sites through one helper so a future early return cannot drop the plugin tap again. Co-authored-by: Orca <help@stably.ai> * plugins: drop dead code and hoist duplicated trust-boundary patterns Cleanup pass over the P1 diff, no behavior change: - Delete `readPluginTreeSnapshot`/`readSnapshotFile` and their types, plus the now-vestigial `directories`/`signal` plumbing in `collectFiles`. - Delete `resolveContainedPluginDirectory` (no callers). - Delete `plugin-content-load-pool.ts`; it reimplemented the existing `mapWithConcurrency`, whose index arg also removes the pairing wrapper in `buildPluginList`. - Hoist `PLUGIN_CONTENT_HASH_PATTERN` and `PLUGIN_COMMIT_PATTERN` into the install-lockfile module; 11 sites hand-rolled these identically. - Point the new reliability gate at the PR instead of gitignored docs paths, matching every other gate's link form. * fix(plugins): retry plugin state renames on Windows AV/EPERM locks Six plugin write paths (lockfile, provenance, current pointer, kill list, marketplace cache, staged install dir) did a plain rename, so an antivirus or indexer holding the target open surfaced as a failed install. The repo already retries this hazard for issue #1507, but only through a sync helper; these paths are all async. Adds one bounded async retry + atomic write used by all six, and trims a consent-provenance header that restated its own JSX. * test(plugins): cover the Windows rename retry path The retry loop shipped untested: both existing cases hit the non-retry path, and the temp-cleanup test passed identically with the `finally` removed. Mock `rename` to queue errno codes so CI can exercise locks it cannot provoke. Co-authored-by: Orca <help@stably.ai> * fix(plugins): pin bundled plugin resources to LF Windows CI checks out with autocrlf, so the byte-hashed launch tree arrived as CRLF and verify-packaged-plugin-resources rejected it — the packaged build could never pass on Windows. Reproduced locally: CRLF yields the exact CI error, LF verifies clean. Files are already LF, so nothing renormalizes. Co-authored-by: Orca <help@stably.ai> * test: guard the bundled-plugin LF pin against a CRLF checkout The byte-hash mismatch only surfaced in Windows packaging CI. Assert the .gitattributes pin and that a CRLF tree is rejected, so a regression fails on any platform instead of waiting for a packaged Windows build. Co-authored-by: Orca <help@stably.ai> * ci: trigger packaged-build check on bundled plugin resource changes The launch tree is byte-hashed during packaging, but no trigger path covered it — so the CRLF fix for that check would not have re-run the check. Add the resources, verifier and .gitattributes paths that can break packaging. Co-authored-by: Orca <help@stably.ai> * perf(plugins): rebuild the panel frame only when its baked theme values change The revision keys the panel iframe, so every bump destroys the sandboxed frame and its in-panel state. It counted root attribute mutations, but --workspace-sidebar-live-width is written every rAF of a sidebar drag, so dragging with a panel open blanked it ~60x/sec. Compare the two values the shell actually bakes in instead. Co-authored-by: Orca <help@stably.ai> * test: stop pinning a plugin name in the CRLF guard The CRLF case rewrites every launch file, so the reported mismatch is whichever plugin sorts first. P2 adds theme plugins that sort ahead of orca-navigation-shortcuts, which broke the assertion there. Co-authored-by: Orca <help@stably.ai> * style: drop stray blank lines left by the rebase resolutions Both sides of the agent-hooks and orca-runtime conflicts contributed a trailing blank, which oxfmt rejects. Whitespace only. Co-authored-by: Orca <help@stably.ai> * test(plugins): stop the startup budget failing on machine load P95 runs 16-34ms idle but exceeds the 50ms bound under full-suite parallelism, so the gate flaked. Widen it to catch an order-of-magnitude regression instead; the no-worker/no-plugin-code assertions are the real guarantee. Verified a 400ms regression still fails. Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai> |
||
|
|
3708c4f6ce |
fix(mobile): report interrupted native chat sends as delivery-unknown, not failed (#10021)
* fix(mobile): report interrupted native chat sends as delivery-unknown, not failed A terminal.send interrupted mid-flight showed a definite "Message not sent" even when the desktop may have already delivered the text. Three paths were misclassified as definite failures: - Logical relay/direct cutover: migrateTo rejects in-flight requests with LogicalClientCutoverError, which mapped to 'rejected'. Now maps to 'unknown' (held unconfirmed + transcript-echo verification; never retried since terminal.send is non-idempotent). - Suspend/close of a half-open session: the stable logical client blanket- rejected in-flight pendings with plain 'Client suspended'/'Client closed', preempting the physical layer's delivery-unknown marking. It now lets the physical close settle them, so post-write failures stay marked and pre-write failures stay definite. - Relay path: mobile-relay-rpc-session never marked delivery ambiguity at all (timeout, close, link failure). Post-write rejections are now marked; pending entries only exist after the frame reached the authenticated link. Permission, ask-answer, and cancel-Escape surfaces now show "unconfirmed — check chat before retrying" instead of a definite "not sent" on ambiguous outcomes (still not-accepted, never retried). Also consolidates a private copy of isLogicalClientCutoverError in worktree-create-retry. Co-authored-by: Orca <help@stably.ai> * chore(skills): regenerate skill-bundle manifest artifacts --------- Co-authored-by: Orca <help@stably.ai> |
||
|
|
41751dd90d | fix(runtime): route HUB-owned SSH worktrees through owning runtime (#9994) | ||
|
|
1a9e819c40 |
feat(skills): land remaining hybrid stubs (#9846)
* feat(skills): land remaining hybrid stubs * fix(build): exclude skill stub sources from packages |
||
|
|
ae12bb1292 |
fix(skills): preserve released history across new tags (#9778)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
f1c84d3858 | refactor(cli): split oversized command modules (#9775) | ||
|
|
a10a2ba53c |
feat(linear): add MCP-style save issue (#9670)
* feat(linear): add MCP-style save issue * fix(linear): harden save issue parity * fix(linear): close save issue contract gaps * docs(linear): bundle project discovery with save issue |
||
|
|
87af1c8673 |
feat(linear): add complete issue relations (#9674)
* feat(linear): add complete issue relations * fix(linear): harden relation reads and writes * fix(linear): classify ambiguous relation writes |
||
|
|
42a4f017b4 | feat(linear): add MCP-compatible issue listing (#9672) | ||
|
|
be066fe8e9 | feat(linear): expose issue activity history (#9667) | ||
|
|
1bebb24015 |
feat(status-bar): tooltips for Detailed vs Compact usage modes (#9693)
* feat(status-bar): add tooltips explaining Detailed vs Compact usage modes
The Detailed/Compact density picker in the usage popover named both modes
but didn't explain what they change. Add hover tooltips via a new optional
`tooltip` field on SettingsSegmentedControl's options (no behavior change
for existing segmented controls).
* reword usage tooltips + add zh/ko/ja/es translations
Detailed: drop 'in the status bar'. Compact: 'Condensed usage: only the
tightest window'. Translate both keys into all locales via the repo's
translate+repair policy.
* test(status-bar): wrap UsageRosterPanel renders in TooltipProvider
The new segment tooltips use Radix Tooltip, which requires an ancestor
TooltipProvider (present in the real app at App root). Wrap the test
renders to match, fixing 3 failures.
* i18n(usage-tooltips): fix zh/ja mistranslations of 'full usage'
The zh/ja 'Detailed' tooltips read as an imperative ('make full use of
bars/labels/percentages') instead of the intended noun ('full usage
shown with ...'). Correct to the usage-status noun, align ja Compact to
使用状況 (not 使用法/how-to), and drop a stray trailing period in es.
* chore(skills): regenerate skill bundle manifest for release-tag drift
New release tags cut since the manifest was last committed appended
orca-cli snapshots (releaseRevision 33→35). Append-only regen — released
history is preserved; only unblocks the verify:skill-bundle-manifest gate.
* i18n(usage-tooltips): polish zh Compact tooltip wording
The zh Compact tooltip read like an instruction ('only use the tightest
window'). Reword to a descriptive summary parallel to Detailed. Keep the
'tightest = highest-usage window' meaning (getTightestUsageSection picks
max usedPercent) rather than CodeRabbit's '最短/shortest', which would
misdescribe it as the shortest-duration window.
|
||
|
|
f8b430f725 |
feat(skills): ship orca-cli as a first-generation hybrid stub (#9238)
* feat(skills): ship orca-cli as a first-generation hybrid stub Convert the installable orca-cli SKILL.md from a full fat guide into a hybrid discovery stub: a safe CLI resolver, an `orca skills get orca-cli` pointer, and a bounded read-only fallback for pre-guide binaries. The version-matched command reference now lives only in the Orca binary (embedded guide table, served by `orca skills get`), so the distributed file can no longer drift from the binary that runs the commands. - generator projects STUB_TOPICS from skill-stubs/<name>.md, reusing the guide's own frontmatter so the routing/description surface is unchanged; the embedded full guide (bundled-skill-guides.ts) is untouched. - manifest regenerated: orca-cli releaseRevision 32->33 as an append-only snapshot; existing fat installs classify `outdated` and get the targeted `npx skills update` nudge (no in-app writes). - tests: command-guidance assertions repointed to the guide source (their home now), plus stub-projection + safety coverage. Only orca-cli converts; the other skills stay fat. Per notes/skill-freshness-design.md, the E.3 pointer-compliance spike and the E.5 RC window remain before any further thinning. allowed-tools is intentionally not added yet (frontmatter kept byte-identical to the guide). * fix(skills): distinguish guide lookup failures * chore(skills): refresh released skill mapping |
||
|
|
a6df23c762 |
Tighten orchestration worktree isolation policy (#9482)
* docs(orchestration): require true isolation for worker worktrees * docs(orchestration): deduplicate parallel worker guidance * docs(orchestration): clarify isolation exceptions * docs(orchestration): clarify checkout preference * Tighten orchestration worktree isolation policy guidance - Clarify that same-worktree workers remain orchestration children despite appearing as peers in the sidebar - Define new-worktree creation as required only for explicit requests or concrete filesystem/checkout conflicts, not convenience - Distinguish stacked worktrees from independent ones via --no-parent - Rename agent-first guidance to reflect conditional requirement * Release orchestration skill v25 with tightened worktree policy |