mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 17:37:40 +00:00
83ec1c09dd5077a6dff8bb3c94de0d32d0b6ac3b
199
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
45b433671e |
fix(recipes): show credentials recipe scripts inherit, add opt-in passEnv allowlist (#40757)
* fix(recipes): warn which credentials recipe scripts inherit, add opt-in passEnv allowlist Recipe lifecycle scripts run locally with Orca's full environment. Keep that default (provider CLIs and git auth rely on it) but name the credential-like variables in Settings and let a recipe opt into passEnv so only listed variables plus a safe base set reach its scripts. * fix(recipes): fail closed on a malformed passEnv instead of dropping the recipe Dropping the recipe let a stored snapshot or a same-id plugin recipe run with the full environment. Keep it with an empty allowlist and a diagnostic, match base variable names exactly outside Windows, and make the warning copy apply to any recipe source. * fix(recipes): import user-agent-platform from its new app-shell location |
||
|
|
5f3b2fa4bf |
feat(artifacts): allow artifact publishing by default for new profiles (#40948)
New profiles default artifactSharingEnabled to true. Existing users are unchanged: stored settings win over defaults on load, and a stored profile saved before the key existed loads as false instead of inheriting the new default. The gate still requires an explicit true, sign-in is still required, and web clients still mirror the host (their local fallback no longer inherits the desktop default). showArtifactsButton is unchanged. |
||
|
|
c2e6ebbf0b |
feat(cli): read, message and wait on agent chats with orca chat list/read/send/wait (#40836)
* feat(cli): read and message agent chats with orca chat list/read/send Carried over from #33115 (squashed onto current main; conflicts with chat rename resolved). * feat(cli): wait for a chat to settle, read text from stdin, refuse paired hosts chat send --wait and chat wait poll the history's working flag until the chat is idle or waits on a question, keeping a queued message pending until it runs. chat read is one history fetch and returns a cursor. Unattached and paired-host refusals say what they mean. * fix(cli): settle a held queued message, skip subagent rows, resolve chat list --worktree * fix(cli): show chat errors, keep waiting through queue handoffs, return the whole settled turn * fix(cli): settle any queued message the host will not send, show grouped questions and only answerable prompts * test(cli): drive chat tests through a real client and fake timers * fix(cli): describe chat --session, --wait and --state in command help * fix(cli): report chat wait in chat list's states, reject unknown --state, flag truncated reads * docs(cli): say chat wait settles on the chat's own turn; no truncated flag on held * fix(cli): chat rename help asks for a session id, not a handle --------- Co-authored-by: YangNuoCheng <42427439+YangNuoCheng@users.noreply.github.com> |
||
|
|
6dfb4dc60d |
feat(cli): add orca tab annotations so agents can read a tab's unsent notes (#40873)
Prints the notes the user left on a browser tab and has not sent, the same text the tab's Copy button gives (--json returns them). Reads the saved session, so it works for closed-and-restored tabs; SSH hosts reach it through the desktop browser bridge. A page drawn by a paired desktop reports that its notes stay there. |
||
|
|
9ef5e48f09 |
Plugins: add editor.readTypography and editor.typography.changed (#40736)
* feat(plugins): add editor.readTypography and editor.typography.changed Plugins that render code next to Orca's editor had to open the private profile database and reimplement Orca's font rules to match it. Host API 1.6 adds editor.readTypography (no capability; worker, panel and editor frames): the font family and CSS stack, size with editor zoom, weight, line height in px, ligatures, word wrap and minimap that the file editor resolves now. editor.typography.changed carries the same values after a settings write or an editor zoom changes them; it is the first event that needs no capability. The pure resolution (editor typography, editor zoom, monospace font stack) moves to src/shared so main and the renderer use one implementation. * fix(plugins): keep editor typography resolution from throwing in main A hand-edited profile with a non-string font family made the shared resolver throw, which the main-process watcher would surface at startup and on every settings write. Font values are now type-checked, the watcher catches and logs, and it reads live settings so a write without listeners cannot leave the event payload stale. Over-long font families are cut to the schema bound instead of failing every read. Regenerates the testing runtime. |
||
|
|
1bdadc903b |
fix(skills): load Orca browser guidance for ordinary web tasks (#39916)
* docs: load Orca browser guidance for ordinary web tasks Extend the Orca CLI skill description to include local and external page opening, reading, testing, and captures while working in Orca. Preserve explicitly chosen browser tools and the Computer Use boundary. Regenerate discovery/install bytes and append the new digest. Fixes #39880 * fix: route existing Edge windows to desktop browser control * docs: preserve configured desktop-control tool precedence * docs(skills): scope orca-cli browser trigger to page work and keep the Computer Use rule Drop "reading" so doc lookups stay on fetch tools, say plain HTTP/API calls don't need the skill, and restore the original Computer Use sentence and guide body, which the issue didn't ask to change. * docs(skills): list Edge among existing browser windows in the orca-cli guide The wider page trigger makes "screenshot my open Edge tab" load orca-cli, and the guide named only Chrome and Safari as windows that go to desktop control. --------- Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com> |
||
|
|
bd56be7146 |
feat(orchestration): mail an agent on a paired server with send --on; its reply comes back by itself (#40106)
* feat(orchestration): mail agents on a paired server with send --on, replies come back by themselves * fix(orchestration): gate --on on the carrying Orca, ack retried deliveries, refuse payloads and federated workers * chore(orchestration): annotate peer-mail row casts and drop a wall-clock wait in its test * chore(orchestration): name mail-between-servers codes server_mail_unsupported and mail_requires_server_pairing * docs(cli): list --on in the orchestration reply usage * fix(orchestration): name --environment, the flag on main, in agent mail refusals and the guide * chore(orchestration): mark the two deliberate agent-kind branches mail between servers needs * docs(cli): leave --on out of the reply usage; it is accepted only to refuse it * fix(orchestration): keep peer conversations to peer ids, survive resets and re-pairs, keep pulling on a registry error - A server takes only peerconv_ conversation ids, so a paired computer cannot name another Orca's dispatch in the relay. - A replayed reply after a mail reset is acknowledged, not retried forever; reset tasks keeps replies waiting to be pulled. - A re-paired server starts a new conversation instead of refusing every later send and reply. - A failed registry read keeps the pull loop retrying. - Drop the two ast-grep-ignore lines that only #40193's rule needed. * fix(orchestration): worker-start --on runs on the caller's own Orca, like send --on An inherited ORCA_ENVIRONMENT sent worker-start --on to that server, so the --on command the agent refusal suggests did not work. One rule now keeps send, reply and worker-start with --on on the caller's own Orca. * fix(orchestration): refuse reply --on on both sides of a conversation between servers The side that opened the conversation still took --on when it named the right server; the reply usage says --on is accepted only to refuse it. |
||
|
|
f358eb6a7d |
Plugins: add workspace.rename and project names in workspace.list (#40197)
* feat(plugins): add workspace.rename and project names in workspace.list Plugins that name workspaces had to read Orca's private runtime token and call worktree.set over the runtime socket, bypassing capability consent. workspace.rename (workspace:write, worker only, host API 1.5) does the same update as a sidebar rename. workspace.list rows gain the project name so plugins can prefix names without reading the runtime's repo list. * fix(plugins): harden workspace.rename against twin folders and hidden characters Folder renames require a unique folder id, so twins on two hosts are not both renamed, and fail when no folder has the id. Names refuse C1, bidi and zero-width characters, which could make a label read as another workspace's name. * fix(plugins): workspace.rename matches a sidebar rename for folders and reports kept names A folder rename also cancels a pending first-agent-message rename, so the automatic title cannot replace the plugin's name. A rename Orca does not apply (during a WSL move) is a conflict instead of a silent success. workspace.list's project is optional, so mocks written for host API 1.4 still validate. More invisible characters are refused. |
||
|
|
02ad6d9671 |
feat(cli): add orca vm env doctor to check that an environment can run agents (#40120)
* feat(cli): add orca vm env doctor to check a workspace environment Checks required CLIs (git plus what the repo manifests imply), agent CLIs and their sign-in, Git fetch and a dry-run push, the orca.yaml setup script (optionally re-running it with Orca's runner), and free disk. Pass/warn/fail with --json; checks live in src/main/environment-doctor for runtime reuse. * fix(env-doctor): ship the doctor modules in the packaged CLI and share the check formatter * fix(env-doctor): run Git probes in the C locale so folder detection is locale-independent |
||
|
|
1a60595845 |
fix(orchestration): record orchestration as the origin of nested workers on connected servers; lead the guide with new-child (#40091)
worker-start --on <server> --worktree new-child now tells the server that orchestration picked the parent, so the server records the child's lineage as orchestration, as a local child is, instead of cli. Older coordinators omit the field and keep cli. The guide now shows new-child first and new-top-level as the no-parent choice. |
||
|
|
f36751f79f |
Revert "feat(cli): create workspaces on environment recipes (#40108)" (#40184)
This reverts commit
|
||
|
|
862d315575 |
feat(cli): create workspaces on environment recipes (#40108)
* feat(cli): create workspaces on environment recipes `orca worktree create --recipe <id>` creates the workspace on a new environment from one of the repo's environment recipes, and `orca vm recipe list` shows which recipes it accepts. The desktop app on the provisioning computer runs the same main-side provisioning the composer uses (write-ahead record, per-step timeouts, cancellation), registers the project on the environment's Orca server, then creates (orca-worktree) or adopts (provisioned-root) the workspace there. Named progress steps ride on long-poll keepalive frames, so the CLI prints them to stderr; older CLIs ignore them. A failure after the VM exists destroys it through the shared cleanup and returns recipe_workspace_create_failed with the failed step, the recipe failure code and whether the destroy finished. Ctrl+C aborts the request and destroys a started environment. Paired devices cannot start a recipe create. Hosts advertise worktree.recipe-create.v1 only when the desktop wires the recipe service, so orcad and older hosts are refused before anything runs. Based on #39228 by jutaz, a port of #28439. Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> * fix(cli): report the VM outcome when connecting fails; record no cross-host parent * fix(vm-recipes): destroy the VM when recording its environment fails; reset exitCode in CLI tests * perf(types): keep recipe orchestration out of the runtime's type graph --------- Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com> |
||
|
|
bf7dfff664 |
Keep Session History responsive on large histories: move session search SQLite to worker threads (#38945)
* Move session search SQLite into dedicated workers * test: spawn the session search test worker with the shared worker helper * fix: pass only drain promises to the channel's drain wait * Repair session search failure and lifecycle boundaries * Stop indexing tool output and reclaim existing rows * test: say why the session search worker tests need a longer timeout * Bound search cleanup and preserve failure and digest semantics * Use the database row type for tool purge batches * test: drop the same-connection mid-page write case now that each page reads one snapshot * test: prove a mid-page delete from the writer can't change that page's hits * Repair transcript cancellation cleanup and search test runtime admission * fix: cancel active transcript finalization and enrichment waits * fix: close transcript handles when cancellation wins delivery * fix: preserve scan cancellation errors across parser waits * test: prove cold session search bypasses an active writer batch * fix: preserve search continuation through background tool cleanup * fix: preserve search pages during orphan reclamation * fix: bound typo repair posting visibility probes * fix: preserve exact search terms when visibility is inconclusive * test: drop orphan-reclaim cursor staleness case superseded by frozen continuation * Bound session search work before ranking candidates * Preserve the limit notice for empty search windows * Bound session eligibility lookups and reuse FTS scoring statistics * Index session scopes for population and candidate searches * Derive search status from the live index after clear * Preserve disabled search status during settings transitions * Share planned expressions between spelling probes and search * Keep identifier fragments out of spelling presence checks * Report search initialization through its pending transition * Bound spelling vocabulary work with the search posting budget * Preserve search fallback while bounding distinct vocabulary seeks * fix(session-search): drain removals before the worker queue fills; keep aborted close waits from failing teardown * fix(session-search): hold writer commands when the worker queue is full instead of stopping the writer * chore(ratchets): baseline the session search worker's one-shot entry check |
||
|
|
0b1efd9b90 |
fix(vm-recipes): record each VM before create runs so a quit or crash can't leak it (#39241)
* fix(vm-recipes): record each VM before create runs so a quit or crash can't leak it Orca now saves a "provisioning" record for a recipe VM before running its create command, and updates it when create finishes. If Orca quits or crashes mid-create, or create fails without returning a result, the VM stays listed in Settings > Cloud VMs as Failed with its instance id, so the user can run Cleanup (destroy gets the instance id) or remove it from the list. On startup, provisioning records with no create running are marked as interrupted. Records without a recipe result live in a separate file that older builds never read, so downgrading keeps working. Records also store the repo path so Cleanup, Copy command, suspend and resume still work after the repo is removed or re-added under a new id (#17293). * fix(vm-recipes): keep no runtime row when create is cancelled or rejected before its script starts * fix(vm-recipes): harden write-ahead records from review - Never overwrite a provisioning-records file this build cannot read; refuse new records instead. - Remove the provisioning-records file when empty instead of rewriting it on every store write. - Only fall back to the saved repo path while it still defines the same recipe. - Don't let Cleanup or Attach act on a create that is still running or never returned a result. - Show Provisioning before Cleanup disabled; stamp running records with the save time. * fix(vm-recipes): keep new store code off direct sync fs calls and render-path translate * fix(vm-recipes): detect a missing provisioning-records file without a type assertion |
||
|
|
47b4238cbc |
feat(vm-recipes): optional per-step timeouts for recipe lifecycle commands (#39238)
* feat(vm-recipes): optional per-step timeouts for recipe lifecycle commands A recipe in orca.yaml can set timeoutSeconds (one number, or a map of create/suspend/resume/destroy). When a step runs past its limit, Orca stops the whole process tree the same way Cancel does and reports a recipeTimedOut failure naming the step and the limit. Recipes that do not set timeoutSeconds keep running with no limit, exactly as before. Saved runtime records keep a recipe snapshot that older builds parse strictly, so the snapshot leaves timeoutSeconds out; suspend, resume and destroy read the current limit from the repo's orca.yaml instead. Suspend and resume exit failures now go through the failure catalog with the same English text. * test(vm-recipes): fire the grandchild timeout only after the grandchild exists * fix(vm-recipes): only reuse orca.yaml timeouts for the same recipe a runtime was created from |
||
|
|
3fe350eaed |
Create a worktree per repository from an empty folder workspace (#39575)
A folder workspace with no worktrees now offers Create worktree for each repository, named after the folder workspace. If that branch name is already taken, the host refuses instead of picking another name, and the composer opens so you can choose. |
||
|
|
4fabde28b1 |
feat(cli): one enclosing-workspace rule, --environment local, copyable addresses, and --parent-environment (#39733)
* feat(cli): one enclosing-workspace rule, --environment local, and copyable workspace addresses current/active and cwd inference now pick the innermost workspace of either kind (worktree or folder workspace); at equal depth the caller terminal's own workspace wins, otherwise the choice is refused as ambiguous. --environment local names this machine's own Orca over an ambient ORCA_ENVIRONMENT or pairing code. worktree ps/show/current print an environment: line and an address: line (JSON environment, address, addressUnavailable, parent) that always carries its --environment, and name a parent's environment only when it is verified. * test: answer the folder catalog read in agent launch cwd tests * feat(cli): worktree rm refuses current/active and names the selector to pass Removal needs an explicit workspace, as git worktree remove needs a path. The refusal runs before rm decides between a worktree and a folder workspace, and reports what current resolves to now (one selector, the ambiguous choices, or none) in text and as invalid_argument data. * fix(cli): keep the remote-environment guidance when rm refuses current * fix(cli): surface folder-catalog failures for omitted targets; no address for a duplicated folder parent * fix(cli): surface a worktree-list failure for omitted browser and terminal targets too * test(cli): folder rm refuses current/active before the folder removal path * fix(cli): refuse a cwd owner whose folder host can't be derived instead of skipping it * fix(cli): compare cwd owners by filesystem identity, refuse every equal-path tie, surface worktree-list failures Paths on the caller's own filesystem compare by realpath (reusing resolveRealPathSync), so /tmp and /private/tmp aliases find the deeper owner in both the folder prefilter and ranking; other hosts' paths stay lexical. Equal-depth owners with different repo registrations now refuse without a caller instead of picking by catalog order. An omitted target no longer swallows worktree.list method_not_found; only the optional folder reads fall back. * fix(cli): read the realpath helper from shared so the packaged CLI ships it * refactor(cli): move the catalog row type and unresolved-owner refusal out of the selection/catalog cycle * fix(cli): resolve every caller-filesystem workspace path, not only basename matches A workspace registered through a differently named symlink was skipped by the basename gate. Containment now realpaths cwd and each row on the caller's own filesystem once per command, shared by the folder prefilter and ranking; folder hosts are derived first so another host's paths are never resolved locally. * test: answer the folder catalog read in the ambiguous orchestration-check caller test * feat(cli): --parent-environment names where a worktree's parent lives worktree create and worktree set take --parent-environment <local|saved id|name> next to --parent-worktree. The parent is resolved in that environment only, and sent to the child as a verified cross-store ref after the child's cross-machine capability check. Without the flag, the parent stays in the child's environment; active/current always mean this machine's own Orca. Preflight failures happen before any change: environment_not_paired, environment_unavailable, LINEAGE_PARENT_NOT_FOUND / LINEAGE_PARENT_AMBIGUOUS naming the searched environment, and incompatible_runtime with data.environment and data.requires. * fix(cli): parent lookup errors name and list the environment searched LINEAGE_PARENT_AMBIGUOUS and LINEAGE_PARENT_NOT_FOUND now always carry data.environment and a listing command for the environment the parent was looked up in, for parents in another environment and in the child's own. Steps inherited from the runtime listed the caller's default route instead. * docs(cli): a local address names the Orca that printed it |
||
|
|
a55de38395 |
feat(cli): set and rm folder workspaces through the folder workspace RPCs (#39670)
* feat(cli): set and rm folder workspaces through the folder workspace RPCs worktree set and rm on folder:<id> (or a path:/name: selector that matches a folder) now call folderWorkspace.update and folderWorkspace.delete after the runtime confirms the folder id is unique. Flags with no folder meaning are refused before any change, a missing method reports incompatible_runtime, and worktree activate refuses folder workspaces as not supported yet. * test: read mocked method names without a cast * fix(runtime): refuse shared folder ids inside folder update and delete The CLI's show preflight could not make the id-only folder RPCs safe: an older show could select one of two same-id rows, and a twin added during teardown was deleted too. folderWorkspace.update/delete now take requireUniqueId, which refuses a shared id before any side effect, and delete removes only the row it checked. Hosts advertise folder-workspace.unique-id-mutation.v1; the CLI requires it and reports incompatible_runtime otherwise. * fix(runtime): refuse a folder delete when a twin appears during teardown Two rows that share a folder id share every record keyed by it, so delete can't keep one row's sessions while removing the other. After the awaited terminal teardown, delete checks the id again before any cleanup or removal and refuses with the duplicate-id error; only the stopped terminals remain as an effect. Removal by row identity is no longer needed and is dropped. * fix(cli): give only the repair step for a duplicated folder id The generic ambiguity recovery told agents to pass folder:<id>, which can't name one of two folders sharing that id. |
||
|
|
f341558b82 |
feat(cli): match folder workspaces by path: and name:, keep same-id ps rows apart (#39637)
* feat(cli): match folder workspaces by path: and name:, and keep same-id ps rows apart Adds one runtime matcher for worktrees and folder workspaces. With the new matchFolderWorkspaces opt-in (advertised as workspace-selector.folder-match.v1), path: and name: also match folder workspaces; branch:, issue: and identity: stay repo-backed. Several matches refuse with each choice's kind, host, path and selector; a folder id shared by two folder workspaces refuses with the repair step. The CLI resolves path:/name: through it, so terminal, file and ports commands reach a folder workspace, and create/set parents record a folder parent. Explicit ambiguous parents report LINEAGE_PARENT_AMBIGUOUS. worktree ps now keeps rows that share an id on different hosts apart, with their own host, identity, metadata and activity; activity whose host can't be proven attaches to neither. * test: let the cross-version ps harness pass the host-qualified summary lookup * fix(cli): read each ps row's own host session; qualify folder selector help * fix(runtime): refuse unscoped duplicate folder ids; hand lineage the matcher's typed result Unscoped folder:<id> refuses a duplicated id even when only one copy's host is derivable; a host-scoped lookup still picks that host's copy. A wsl: hook stamp counts as local host evidence. The lineage controller receives the worktree-or-folder candidate directly instead of re-deriving the kind. * docs(cli): guide the ambiguity fallback through truncated ps and id: selectors * fix(cli): report an ambiguous parent by its own choices; cover per-host sessions * fix(cli): send parents to the runtime parent resolver as typed; translate WSL paths for folders too Parent selectors skip the CLI's show-based folder lookup, so worktree.create and worktree.set classify them with parent rules: a folder spanning hosts is a valid parent, and ambiguity reports LINEAGE_PARENT_AMBIGUOUS. Caller-distro Linux path translation now also matches folder workspaces. * chore(rpc): import the computer-use recovery data directly instead of through an alias * fix(runtime): report a missing set parent as LINEAGE_PARENT_NOT_FOUND, as create does worktree set and worktree create now share one explicit-parent error conversion: several matches give LINEAGE_PARENT_AMBIGUOUS and none give LINEAGE_PARENT_NOT_FOUND, so a missing parent is no longer reported as a bare selector_not_found that could mean the child. |
||
|
|
51f3c956ed |
feat(plugins): let plugins ship web fonts for the terminal, editor and interface (#39416)
* feat(plugins): let plugins contribute web fonts to the font pickers Plugins declare font families under contributes.fonts (WOFF/WOFF2 only). Install checks each file's signature against its extension and caps file size, family count and plugin total; main never parses a font. Files are served over the plugin image scheme only while the plugin is enabled, typed and nosniff. The renderer registers each family under a name that carries the plugin key, so a plugin font cannot shadow an installed or built-in font, and it applies only once the user picks it. Disabling or uninstalling removes the faces; uninstalling also resets font settings that named them. Refs #38607 * fix(plugins): harden plugin fonts and re-measure editors when they load - Refuse WOFF/WOFF2-wrapped font collections by checking the flavor bytes. - Check dev folders' font files at discovery, not only at install. - Re-check family, weight and style from the plugin list in the renderer. - Track loaded families (case-insensitively) from document font loads, so the code editor re-measures and terminals, previews, the SSH terminal and the dashboard popout re-apply only when their own font changes. - Register plugin fonts in the dashboard popout window. - Give dev-folder font URLs their change count so edits reload. - Keep monospace fallbacks unless the chosen family is exactly that font. * fix(terminal): keep every fallback only for plugin font families System font choices keep their existing fallback list unchanged. * fix(plugins): leave the dashboard popout's plugin list alone; add the font row string Registering fonts there started the plugin auto-update watcher in a window with no toaster, which could consume update notices. Adds the new contribution-row string to the English catalog and the fonts list to the RPC test manifest. |
||
|
|
f308486115 |
Show Source Control for folder workspaces (#38831)
* Separate editor tab placement from content ownership * Show scoped Source Control sections for attached worktrees * Preserve active diff refresh and validate section catalogs * Complete folder section test worktree metadata * Use contextual types for scoped Source Control actions * Preserve optional scoped action parameters * Preserve editor ownership through restore, mirroring and workspace removal * Retire Source Control drafts only after confirmed owner removal * Limit section work to visible expanded repositories * Keep editor follow-up actions and bulk closes in their invoking views * Track the consolidated editor order writer in its owning module * Use complete typed fixtures for repair contracts * Preserve live editor placement during layout readback * Pass projected editor placement directly to serialization * Read attached worktree lineage from shared graph module * Retain inferred owner checks and scope placement retirement * Preserve selection in untouched workspaces during purge * Exercise editor placements in existing launch and lifecycle fixtures * Preserve shared buffer prompts and editor strip order * Pause inactive section context subscriptions * Keep section recovery and file actions in the folder workspace * Describe attached Source Control in folder workspace CLI help * Attribute Git metadata signals once per dispatch * Watch mounted source control sections outside the warm budget * Resolve section watches only for served filesystem roots * Restore restart-stable editor identity across SSH opens * Apply section terminal routing to explicit Chat choices * Include cross-store descendants in folder workspace panels * Keep cross-host recovery on its existing workspace route * Start cross-host section agents in their workspace without navigation * Update memoized Source Control labels on language changes * Remove unused terminal close-to-right implementation * Suspend inactive Source Control body observers * Retain base ref query while section observation pauses * Cover retained base ref search across section visibility * Resolve note menu ownership from the retained snapshot * Preserve section agent working directories and background placement * Keep Source Control sections active while their overlays are open * Read current settings when Source Control commands execute * Adapt editor and browser test stores to view subscriptions * Preserve bound store hooks for ordinary app views * Trust agent starts outside the placement workspace * Trust the section worktree through transient launch ownership * Extract editor follow-up file actions from the panel * Fail section launches when trust capability lookup fails Preserve explicit unsupported-host fallback, propagate lookup failures to the existing launch error path, and let the existing transport retry refresh rejected capability probes. * Follow the moved pane launch test in web configs * Preserve section file ownership during refresh and close * Share tab order removal across editor close paths * Verify companion editor close through the real store * Close all workspace split copies for legacy mobile file requests * Keep unmatched mobile close requests within their workspace * Reuse the agent menu render snapshot * Keep attached folder roots scoped to their resolved host * Apply repository trust decisions to the launch trust owner |
||
|
|
555bd481bc |
Let multi-repo folder workspaces parent and nest workspaces, including on other machines (#38904)
Multi-repo folder workspaces can parent workspaces on this machine and on paired servers, and their children nest under them in the sidebar and on the phone. Task parents are inferred at creation instead of on every lineage refresh. |
||
|
|
e0005f5cbf |
Attach existing worktrees to folder workspaces from the CLI (#39018)
* feat(cli): attach existing worktrees to folder workspaces worktree set accepts --parent-worktree folder:<id> (hosts advertise worktree.set.folder-parent.v1), keeping each worktree to one parent in the store. --parent-worktree active/current resolves to a folder workspace from its terminal or enclosing directory, and worktree create without --repo under a folder workspace lists the folder's Git repositories with a ready command. * fix(cli): report folder parents and keep typed flags in folder repo choices worktree show/set report a folder parent; the missing-repo error lists --repo choices to add to the user's command and names the Attached worktrees panel. Load and import repairs skip malformed rows and only touch imported worktrees, an import keeps a worktree's existing parent, a twin-owned folder parent warns, and folder ambiguity keeps its choices. * fix(persistence): settle one parent per imported worktree before writing An Orca server migration import now decides each touched worktree's parent before any write: an explicit folder parent replaces an inferred worktree parent, any other disagreement refuses the import. --parent-worktree active in a folder terminal still lists the folder's repositories. * fix(persistence): let a folder parent beat hydrate's inferred worktree parent Load repair and import reconciliation share one rule: an inferred worktree parent loses to a folder parent when the folder was chosen explicitly or the worktree parent carries hydrate's orchestration stamp. Import tests now run payloads through the manifest parser and cover a conflict that appears after staging. * fix(cli): list folder repos when active resolves to the enclosing folder worktree create without --repo used only the terminal's env to find the folder, so --parent-worktree active run outside an Orca terminal fell back to the generic missing-repo error. Use the parent create already resolved. |
||
|
|
b9a4b5fd2f |
fix(plugins): re-review any plugin whose catalog moves it to another repository (#36643)
* fix(plugins): drop a plugin's approval when its catalog moves it to another repository * plugins: revokePluginConsent refuses when the plugin service is not running * cli: orca plugin install/update ask again when a plugin moves to another repository, for every plugin kind |
||
|
|
be3b87f3ac |
cli: add orca plugin install, update, uninstall and catalog list/add/rm (#36647)
* cli: add orca plugin install, update, uninstall and catalog list/add/rm * plugins: escape the invisible-character regex so the orcad bundle stays ASCII * plugins: split approval re-run helpers and plugin RPC binding to stay under max-lines |
||
|
|
f0bfce8fce |
fix(automations): accept Antigravity model and effort extra arguments (#39161)
Antigravity automations refused --extra-agent-args, so unattended agy jobs could only use the model and effort from agy's global settings.json. Allow --model and --effort through the existing allowlist; permission, mode, and other flags stay refused. Part of #35234 (STA-12678). |
||
|
|
345c326a91 |
feat(cli): rename a chat with orca chat rename (#38719)
Fixes #38556 |
||
|
|
a9ba59c944 |
Nest workspaces under parents on other machines (#38740)
* feat(lineage): store cross-store parent links beside same-store lineage (inert)
A workspace's parent can live in another Orca store. Save that link in the
child's store under a new top-level key, crossStoreLineageByChildKey, so older
builds' same-store cleanup never reads it. Nothing writes records yet.
- Types, load normalization (malformed entries dropped one by one), section label.
- Store get/set/remove by child; a child keeps at most one parent record.
- Every maintenance path acts by the child only: deletion and missing-worktree
pruning, repo removal and deregistered-repo residue, identity migration,
profile project transfer, WSL move projection and UNC drive conversion, and
the orcad migration dormant payload (export, validation, import, subtraction).
* fix(lineage): gate cross-store links on host capability; one parent per child
- Migration stage/commit carrying crossStoreLineage requires the new
orcad.migration-cross-store-lineage.v1 capability; older hosts are refused
before staging instead of silently dropping the links. Empty arrays are omitted.
- Payload validation and destination prepare reject a child that has both a
cross-store and a same-store parent, through one shared conflict check.
- Saved entries stay on disk as written; the map is Record<string, unknown> and
readers go through validCrossStoreLineage. Re-keying moves unreadable entries unchanged.
- Tests: literal expectations; drop touched mock-call and work-count assertions.
* test(lineage): drop clone and save work-count assertions from project group removal test
* feat(lineage): resolve cross-store parents into the sidebar parent map (inert)
- One resolver: a saved record nests its child under the single visible
row whose store reports the parent's installationId and whose instance
matches; copied installs, unknown stores and stale instances stay standalone.
- getSidebarLineageParentsByIdentity merges resolved cross-store parents with
same-store edges before cycle breaking; a valid same-store edge wins.
- Workspace delete collects descendants only from the parent's own store.
- Store identity: paired stores from their verified status hostDescriptor;
this store from the published descriptor, else host-installation.json.
- Nothing passes a view or writes records yet, so the sidebar is unchanged.
* fix(lineage): import WorkspaceKey from workspace-scope after main move
* fix(lineage): resolve sidebar parents once over complete rows; keep unowned rows' delete rule
- resolveSidebarLineageParentIdentities resolves same-store edges and cross-store
records once over every visible store's unfiltered rows, then drops cycles.
Ancestor injection and nesting reuse that map, so a filtered-out twin still
makes a parent ambiguous.
- Removed, retired or refusing paired servers leave the view: their records stay
saved and their children standalone. Offline servers keep their last-known id.
- A row with no owner is unknown, not ours: it never resolves, and delete only
excludes descendants whose store is known and differs from the parent's.
* fix(lineage): refuse UNC rekey collisions and transfers giving a child two parents
The UNC drive conversion rekeys cross-store child keys through the shared
collision merge, so a UNC key and its drive key with different records throw
instead of one silently overwriting the other. Profile project transfer runs the
shared child-key conflict check before writing the target.
* feat(lineage): write, carry and nest cross-machine parents
- Capability worktree.lineage.crossMachine on the child's store; the CLI
refuses before any request when the server lacks it.
- worktree.set / worktree.create accept crossStoreParent
{ installationId, workspaceKey, instanceId } and write only
crossStoreLineageByChildKey (refused when it names this store, or the
child has no identity). Remove Parent clears both.
- worktree.crossStoreParentRef: the parent's own store names it with its
installationId; reparent refuses a parent whose chain already reaches
another store. Same-store Set Parent refuses the same.
- worktree.ps rows and lineage lists carry the records; same-store lineage
fields stay null so older readers show the child standalone.
- The desktop sidebar resolves parents over its own and paired stores'
records (PR 2's resolver) at the visible-worktree and row-plan call sites.
- CLI: active/current or an inferred terminal parent against a server is
sent as a cross-store parent.
* fix(lineage): read worktree rows through the record selector; mark the test runtime cast
* fix(lineage): hydrate every store, fence refreshes, honest CLI fallback
- Each host's catalog hydration fetches its lineage snapshot, so this
desktop's identity and records load whichever store is focused.
- Cross-store records join the per-child request-start fence: a stale
lineage list can't restore a removed record or override a newer one.
- A failed inferred cross-store parent sends noParent instead of
forwarding the selector a server could match to a same-store twin.
- Inferred cross-store creates record env-workspace/inferred capture.
- The writer states its trust contract; the chain rule runs at the mint.
* feat(lineage): cross-machine parents on the phone, pickers, chat resume and labels
- Phone: the list nests a child under a parent on another machine, from the
records rows already carry and the store identities its host verified
(status.get descriptor; relayed servers' installationId on the host list).
- Set Parent popover, context menu and the composer's parent picker offer
parents in other visible stores. The parent's own store names it
(worktree.crossStoreParentRef); the window checks it against that store's
verified installationId and the child store's capability before any write.
Remove Parent and Open parent cover cross-machine links.
- Native chat resume ancestors follow resolved cross-machine parents.
- Host sections keep a nested child under its parent and keep its own
machine label.
- Main sidebar feed resolves cross-store parents (rows carry records; desktop
facts and paired-host facts carry identities); paired web windows read
their host's installationId; reveal without an occurrence plan resolves
them; `worktree create --agent` names a parent on another machine.
* test(lineage): type the mint test's parent row through unknown
* test(lineage): give the cross-machine tests' partial-row casts their SAFETY reasons
* fix(cli): worktree set names a parent on another machine
* feat(lineage): name the machine of parent candidates on another machine
* fix(lineage): Set Parent and Remove Parent act on the clicked row's own host
* fix(lineage): phone resolves parents over every row before the repo filter
* fix(lineage): chat resume nests by host-qualified identity across machines
* fix(lineage): local create refuses a same-install parent before checkout and shares the RPC recorder
* fix(lineage): name parent machines without a focus read; keep create's probes synchronous
* fix(lineage): chat resume keys offers by their own machine; only cross-machine parents leave a section
* fix(lineage): name an older parent server before asking it for a cross-machine ref
* fix(lineage): an app-picked parent on another machine records as manual
* fix(lineage): chat resume keeps base grouping; only resolved cross-store parents move a chat
* revert(lineage): drop chat resume from cross-machine parents; it groups by machine as before
* refactor(lineage): CLI builds cross-machine parents; explicit only
- Drop worktree.crossStoreParentRef and its reparent chain walk: the CLI
builds the ref from this desktop's installationId (worktree.lineageList
now reports it) and the parent row it reads. Cross-machine chains are
allowed; same-store cycle validation and same-install refusal stay.
- No inferred cross-machine parent: remove crossStoreParentInferred and
the fallback states. Against a server, this machine's terminal, cwd and
env context is never sent; the CLI prints how to nest explicitly.
* refactor(lineage): build cross-machine parent refs from verified ids; pickers hide only loops; one desktop install id source
* refactor(lineage): refuse moving a linked workspace instead of carrying the link
Orcad migration and profile project transfer now refuse, before any staging or
write, when a workspace in the move has a cross-store parent record (raw entries,
readable or not). Remove the carry machinery: the dormant crossStoreLineage
field, its runtime capability and destination gate, import/subtract/claim code,
transfer carry and the two-parent conflict checker. Also drop the unused
removeCrossStoreWorkspaceLineage.
* docs(lineage): describe cross-store parent refs without the removed mint RPC
* test(lineage): drop the RPC call-list assertion from the cross-store ref test
* fix(lineage): refuse linked moves before any write and for shared-repo children
- Migration refusal passes the child's own host stamp to the scope matcher and
refuses an unstamped key whose shared repo id the move includes, so such a
child can't move while its link stays behind.
- Profile transfer checks the read-only source snapshot before pending-move
recovery or storage migration; the payload check stays as the final guard.
* fix(lineage): refuse a linked profile move before the profile lookup can restore the index
* fix(lineage): startup hydration of other stores loads only cross-machine links
* fix(lineage): list the child's own machine first in the parent picker
* fix(lineage): keep profile argument errors ahead of the linked-move preflight
* fix(worktrees): let the first listing replace a restored server workspace stub
A restored active server workspace starts as a session stub with no head.
If git status fills in its branch before the first listing lands, the
listing merge took that as a concurrent branch switch and kept the stub,
dropping the catalog row (instance id, lineage, provenance). The workspace
then showed standalone until the next listing.
* fix(worktrees): accept a headless row's listing only when it confirms git status
A stale listing could otherwise roll back a branch switch git status saw on
an empty-head row (e.g. an SSH fallback row) during the first connected listing.
* feat(lineage): CLI nests a create on another machine under the caller workspace
- No parent flag and no --no-parent against a server: the caller's workspace
on this machine (env, else cwd) is sent as an inferred cross-store parent,
the way --parent-worktree active builds it. The host records it as
inferred from environment or cwd.
- A server without worktree.lineage.crossMachine, or a caller workspace that
can't be linked, still creates unnested and prints one note.
- An inferred parent falls away for folder targets, as same-machine folder
creates record none.
* fix(lineage): CLI cross-machine inference reads the caller terminal and suppresses fallbacks
- The caller terminal's workspace joins env and cwd as an inferred parent,
with same-machine precedence: env and terminal must agree, cwd only alone.
- A fallback (old server, unlinkable or unresolved caller, ambiguous cwd)
prints one note and sends noParent, so the server's own create-time
inference can't nest what the CLI reported as not nested.
* feat(sidebar): drag a workspace onto one on another machine to nest it
Dropping a workspace on a workspace from another machine now sets the
parent through the same cross-machine path as Set Parent: same eligibility
(loops, older servers), same refusal messages. Drop targets carry host
identity so the child's own copy is the one written.
* refactor(lineage): this machine's Orca resolves the caller parent for a create on another machine
- New read-only worktree.resolveCallerParent runs the same-machine create
resolver over the caller's env, terminal and cwd context, so stale
contexts are skipped and only validated parents can conflict, and returns
the cross-store ref or a reason.
- The CLI's own precedence and terminal lookup are removed; it keeps the
capability gate, one note with noParent on any fallback, and silence with
no Orca context.
* feat(orchestration): remote worker-start --worktree new-child nests under the coordinator's workspace
worker-start --on <server> --worktree new-child creates the server's worktree
under the coordinator's workspace on this machine, using the same verified
cross-machine parent ref as the CLI's caller auto-nest. A server without
cross-machine parents still starts the worker, top-level, with a warning in
the receipt. Guide, CLI help and docs describe it.
* fix(lineage): resolveCallerParent reads this store's identity without creating it
- Uses the published host descriptor's installationId, else the existing
host-installation.json; never creates or repairs it. Missing identity
returns a reason, so the CLI creates unnested with its note.
- Drops the read-only wording: parent resolution does the same catalog
upkeep a same-machine create does.
* fix(sidebar): validate every cross-machine parent before a multi-select drop writes
A drop of several workspaces builds every cross-machine parent ref first, so an
older server's refusal leaves the whole selection unchanged. Drops the touched
preview-timing test cases.
* refactor(orchestration): build the remote new-child parent ref with the shared caller resolver
Orchestration still picks the caller workspace; resolveCallerParentForAnotherStore
verifies it and builds the ref, and both read the installationId the same way.
Drops the copy and mock-call tests.
* fix(lineage): narrow the inferred source with a guard instead of casts
* fix(lineage): a composer parent picked on another machine nests normally once the destination is that machine
The retained host-qualified pick is classified against the current destination:
same host gives the ordinary parent fields, another store the cross-machine ref.
Also corrects two stale comments.
* perf(lineage): read only the requested child's cross-store entry
* perf(lineage): request each store's lineage list once at startup
* perf(lineage): cap optional caller-parent inference at 3 s and skip a timed-out local Orca
* perf(lineage): return cached sidebar parents when selector inputs are unchanged
* fix(lineage): snapshot selector inputs without a type assertion
* Route startup lineage and the sidebar lineage memo through their owners
|
||
|
|
f660d8c47d |
feat(plugins): add permissioned desktop appearance publication (#38524)
* feat(plugins): add permissioned desktop appearance publication * docs(plugins): add one-line API comments for appearance provider * chore(plugins): regenerate declarative testing kit for appearance API --------- Co-authored-by: Matthew Wilkinson <wilkinson.m@outlook.com> |
||
|
|
9bd6272fdf |
refactor(tooling): organize build, CI, and test owners (#38130)
* refactor(tooling): organize test runtime and maintenance owners * test(tooling): preserve relocated runtime fixture dependency edges * refactor(tooling): preserve xterm routing owner checks * ci(tooling): include routing owner in sparse checkout * test(tooling): preserve copied workflow dependency closures * fix(tooling): normalize hashed JSON assets in release parity * fix(tooling): distinguish asset aliases from literal references * fix(tooling): frame normalized asset reference payloads * fix(tooling): normalize decoded JSON asset references * refactor(tooling): organize build, CI and release owners * fix(tooling): align moved generator and workflow path contracts * fix(tooling): update generated plugin bundle owner banners * test(tooling): create relocated mobile verifier fixture directories * test(tooling): copy headless detector dependency closure * test(tooling): align native batch policy fixtures with owner path * fix(tooling): link moved reliability command to historical evidence * fix(tooling): preserve nested sandbox owners and canonical guide source * fix(tooling): target release version owners in checkout fixture |
||
|
|
9658ec48ad |
fix(automations): accept Pi model and thinking extra arguments (#38020)
* fix(automations): accept Pi model and thinking extra arguments * fix(automations): keep Pi provider pins and refuse unpinned inline keys * fix(automations): match Pi value options to its argument parser * fix(automations): refuse Pi model overrides beside unscoped inline keys * test(automations): cover Pi's last-provider-wins key pin * fix(automations): refuse any Pi custom Command text with --api-key * fix(automations): drop the Pi inline-key pin guard Pi already sends an unpinned inline key to the chosen model's provider and warns; the user typed both the key and the model, so Orca does not refuse it. |
||
|
|
7854cb61b1 |
Delete the legacy orchestration takeover guide (#38013)
* fix(automations): say the run's worktree was deleted; document plain run-use recovery * revert(automations): drop the deleted-worktree wording change (not reproducible) * docs(orchestration): list Tasks on recovery and note run-use drops other Runs * docs(orchestration): delete the legacy takeover guide; keep orchestration docs to the normal flow |
||
|
|
f138493be3 |
fix(browser): a split tab create joins a browser pane already beside the caller (#38006)
* fix(browser): a split tab create joins a browser pane already beside the caller * fix(browser): the joined page is the pane's visible tab * fix(browser): a split with an unknown caller still splits beside the active pane |
||
|
|
7f885c19a6 |
fix(skills): rename computer use to orca-computer-use (#37659)
* fix(skills): rename computer use to orca-computer-use * test(skills): resolve rename fixture after main cleanup |
||
|
|
ec8b2e2055 |
Read one full Linear ticket for planning and plain tickets for queues (#37656)
* docs(linear): use plain ticket reads for queues * docs(linear): preserve selected queue ticket identity |
||
|
|
3a714906a0 |
plugins: keep status bar plugins' workers running while enabled (#37630)
A plugin with a worker and status bar items is now started when enabled and kept warm, like a plugin with hooks, through one shared resident-worker predicate and warmer. |
||
|
|
eb55a5a6d3 |
feat(browser): --expect-url refuses a browser command when the page is at another URL (#37575)
* feat(browser): guard page commands with an expected URL * fix(browser): refuse an empty --expect-url and check it on dialogs and the forwarding desktop * fix(browser): recheck the expected URL right before keys go out * refactor(browser): drop duplicate session type, dialog alias and per-capability sidecar fields * chore(browser): satisfy the changed-code gates for the expected URL guard |
||
|
|
34fa209fe1 |
fix(orchestration): native chats get each orchestration message whole instead of a check pointer (#28567)
* fix(orchestration): steer mail notices into a busy native chat's running turn A native-chat coordinator's mail notice always queued as a card until the whole turn ended, so a coordinator busy in a long command never saw its workers' reports. Agents that take a message mid-turn (Claude, Codex, Pi) now get the notice at once; agents that would cancel their turn for it (ACP) still queue it. * fix(orchestration): drain mail that arrives while a notice is pending * fix(orchestration): native chats get each orchestration message whole instead of a check pointer Each mail message is sent to a native-chat agent as its own chat message, with the sender, type, subject, body, payload and exact reply command, and is marked read once the chat accepts it. Heartbeats are marked read, never sent. Mail an unacknowledged check batch holds stays with that batch. * fix(orchestration): keep the at-most-once gate's mail-lane assertions, exhaustive sender switch * Preserve native mail compatibility and drain delivery backlogs * Drain native mail with a finite ordered pass and scoped operation ownership * Bound mail formatting and honor accepted queue handoffs * Run the native mail tests that open SQLite in the Node runtime project * Preserve live mailbox ownership and recover full reports by id * Use a typed runtime client in inbox compatibility test * Preserve historical mail evidence and scope the test clock * Map historical structured-send evidence to the current test command * fix(orchestration): settle mail handoffs per message and recover interrupted consumers * Hold native chat mail until the chat is idle, as terminal mail waits A mail send admitted into a running turn cancels that turn for agents that cannot take a message mid-turn (ACP: Grok, OpenCode, OMP, Antigravity): the second of two reports cancelled the first before the agent saw it, and the first report cut off the turn carrying the person's answer. Mail now waits while the chat is working or a prompt waits on the person, for every agent, and goes out at the idle edge, one message per turn, oldest first. * test: cover idle orchestration report turns * fix: preserve independent mail authorization through grouped delivery * fix: preserve routed mail identity and private inbox state * test: bound mailbox query work on repeated delivery * fix(orchestration): consolidate terminal mail imports * Validate mailbox query rows and type delivery fixtures * Keep host forwarders typed and inline single-use mail evidence reader * Declare the mail handoff store method boundary * Preserve mailbox contracts across typed boundaries * Retain existing main cleanup row boundaries * Fix mailbox handoff fixtures and helper mail transfer * Name the mailbox fixture constructor type * test: complete mailbox dialog pane identity * Keep structured mail ordering and ownership current at claim * Bound mailbox preparation and immutable cohort selection * Consolidate structured mail contract fixtures * Consolidate duplicate mailbox imports * Fix mail handoff type contracts and deterministic test fixtures * Repair journal forwarding and align mail contract fixtures * Fix mailbox corpus message type inference * Correct personal provenance in ACP backlog fixtures * Correct ACP mail contract measurement and epoch wake fixtures * Retain full ACP contract diagnostic arguments * Restore reliability gate coverage and consolidate mail fixtures * Preserve unknown alias release coverage * Route native reports through the durable chat queue * Preserve exact legacy mail holds in queue lineage proof * Use ordinary queued messages for worker reports * Use semantic queue and check completion for report delivery * Record bounded queue recovery work and request cleanup proofs * Preserve report creation evidence and bounded source wakes * Preserve report source work and check ownership * Use ordinary report acceptance and incremental original history * Retire completed mail opportunities with their current owner * Retire routed source debt and complete joined mail contracts * Exercise Run typed peek through the command transport * Require the queued report submission in creator coverage * Restore database callback API and align queue contract fixtures * Fix empty legacy tab selection in restart fixtures * Keep relation heading assertions scoped to each report * Native chats receive each orchestration message whole, through the chat's own queue Each orchestration message to a chat session becomes one ordinary chat message carrying the whole message, sent with the chat's queue like a person's message: it waits behind running work or a question and the agent is handed one per turn. A per-message record keeps the send's operation id, so a restart finds the card instead of sending twice; the message is marked read once the agent is handed it, and a check that takes it first deletes the waiting card. A message too large for one chat message keeps today's pointer to check. Terminals are unchanged. * Test that chats get each message whole, queued like a person's message * Repeat a report the agent may not have taken only after a later turn or /clear A send the agent rejected or left unanswered stays unread for check and is handed over again only once a later turn ran or a /clear replaced its context, so edges alone never restart an agent that fails on every start. A send whose record a rewind dropped is sent again, and a send that throws is retried on the session's next journal edge. Tests follow chats getting each message whole. * Hand a chat orchestration mail only while it is still owed A queued mail card now runs only while its message is unread in its mailbox and that mailbox still belongs to the chat: the queue asks at handover and drops a stale card without a turn (abandoned or settled Dispatch, Run taken over by another chat, mail a check or reset took). Cleanup after check, moves, run-use, abandon, reset and worker release deletes those cards visibly and never holds the action up; mail still owed goes to the mailbox's current owner, and Orca's own deletion is never read as the person's. A send that may have reached the agent is never sent again; check keeps it. A send the agent proved it never got is sent once more, under a new id, only after a later turn or /clear ordered after that failure. A send recorded but never admitted is admitted under its own id. Each outstanding send is read by key, never by scanning the chat's history. A refusal no longer loses its retry when an edge arrives mid-send, and a coordinator refused for queue room gets its mail when the queue frees room. A chat worker's follow-up now takes its short Task first and then each moved message whole, with no check needed. The guide says a working worker gets mail when its turn ends. * Let the chat's host answer what became of each mail send, and let the person's cards pass mail Orca cannot decide on The chat's host now answers for each send by its id: the card first, then the send itself, then a gone card's handoff found by key, and only then the admission receipt, which alone can prove nothing was admitted. A receipt whose journal detail is gone is in doubt however old its id, so a renewed id can no longer send the same message twice. A rejected send is repeated once only after a different turn was actually handed over and accepted, or a /clear was made, after the rejection; the queue's admission cursor no longer stands in for that. No answer walks the conversation's history. The mailbox reserves each send and stamps the message delivered in one write before the host call, so a crash after admission never leaves it selectable again. A refusal before admission releases that exact reservation; every retirement and release is checked against the current attempt, and a record an older build saved without a stamp is repaired as it retires. A person's Delete consumes an oversized pointer's mail too. Who holds a mailbox is read from durable facts: a Run moved to a terminal, a released worker, another host or an ended chat makes a waiting card stale, so it is withdrawn without a turn and its mail released for the real owner. Only a fact that cannot be read holds a card; the person's own cards behind it go on, later mail stays behind it, and selection and the handover check use the same rule. When the owner can be read again the queue is woken. A Task or a person's edited card never opens the mail database. An explicit Send of such a card now says what happened. Parked mail is indexed by chat, wakes only that chat's mail, ignores streamed tokens, and drops the chat's journal watch with its last mailbox. Canonical session identity is reused per session store revision instead of rebuilt from every record on each check. Main's account-switch worker test now reads "unread and still owed". * Let the queue alone decide which card goes next, and wake a terminal given back its mail The queue now owns one rule for what can be handed over next, installed once on each chat's queue and read by the drain, the final handover check, queue publication and scheduling alike. Mail whose owner cannot be read keeps its place; the first of the person's own cards behind it goes instead. Held cards stay held, a returned, paused or edited card behind it still stops the queue, and later mail, from any mailbox, stays behind it. The rule walks only the queue's live cards, never its history. When nothing can be handed over nothing is published as next, so the chat reads as idle and /clear works; when the owner becomes readable again the queue is published and looked at again. Choosing and publishing the next card only reads custody; settling a stale card stays with the handover. Mail a chat gives back after its Run or worker moved goes through the runtime's own delivery, so a terminal owner is pointed at it. A chat's journal watch now lasts as long as it has mail parked, through its own redrives, so a publication that changes nothing the mail waits on starts no pass. Session identity is cached until a record joins, leaves or is cleared, not rebuilt after every admission. An explicit Send of mail whose owner cannot be read says Orca couldn't read the chat's saved state rather than that it restarted. * Find the person's next card past undecidable mail by walking only as far as it must, and ask mail authority only once nothing else stops a send * Say plainly when Orca can't confirm queued mail is still this chat's, and that the person can try again * Let parked mail's own watch be the only journal subscription for mail, and stop saving a send fence nothing reads * Count the queue's order reads with plain index getters instead of a reflected proxy * Read saved mail sends column by column, and build test fixtures as the types they stand for * Keep main's words for every other refused queued Send; only undecidable mail says its message wasn't sent * Let replay read the queue's handoff links, keep the host's last mail answer where the type can see it, and drop the removed test from the send gate * Keep the queue's possible next cards in order as each one changes, reuse the last pick until the queue moves, and look up a send by its id * Ask whether one chat's tab closed instead of listing every open tab to find it * Settle a mailbox's earlier mail only when something it waits on moved, republish a chat once per pass, clean up only the mail a check, abandon or move touched, and act on a chat's status only when it changes * Date the scaling test's extra tabs by the coordinator's recorded lease instead of the wall clock * Keep nothing in memory for a mailbox a cleanup finds with no owner and no send left, unless a pass on it is still running * Ask about a report whose send threw before handing over newer mail, under the id it was reserved with |
||
|
|
36f17a04a7 |
plugins: Box layout container for components panels (catalog 4) (#37420)
- Box (ui.catalog 4, since 1.4.248): direction, gap/padding/paddingX/ paddingY/margin on the gap scale, align, justify, wrap, grow, shrink, width/height/min/max (px up to 4096 or whole percents), columns, scroll, border (true or a tone), radius, background (theme surfaces or tone tints). Strict props: hex colours, CSS lengths and unknown props are dropped with a warning like other components. - Renderer maps props to theme tokens through data attributes; sizes reach inline style only as validated px or percents. - Typings, docs, skill references, gallery Layout tab; orca/testing finds Boxes and summarizes danger or warning Boxes. |
||
|
|
cb031c4517 |
fix(plugins): merge disk writes into a custom editor's unsaved edits (#37343)
* fix(plugins): merge disk writes into a custom editor's unsaved edits A write to the file on disk while a custom editor tab had unsaved edits never reached the editor: the buffer kept the edits, Orca showed its Reload/Overwrite banner, and the session's merge never ran. Now a frame whose document session has merge announces it (editor.merges), and Orca sends it the new disk text with the text the edits started from (editor.document with ancestor). The session merges, posts the result, and the tab stays unsaved with it; the banner is skipped. Without merge the banner decides as before. * test(editor): an explicit save under the changed-on-disk banner keeps the edits * fix(plugins): make the outside merge exact, and narrow it to where it is - The host settles a merge only on the session's edit made against the merge's own document version, and always commits that result to the buffer (even when it equals the disk text); silence past the 1 s flush deadline, a remount or a throwing merge leave the banner and the suspended autosave in place. - Orca stamps exactly the disk snapshot the acknowledged merge used and records it as the next ancestor; a write that landed meanwhile puts the conflict back for its own merge. - The ancestor is the tab's disk text recorded while clean and advanced on acknowledged merges, and must match the tab's disk baseline. - Only a local file in one merging editor view, with no other tab on its buffer, takes this path; anything else gets the banner. - Frame events keep reaching their handlers after the merge capability. * fix(plugins): move nothing on a failed disk merge; advance the saved text on success A merge that throws now leaves the session's document, baseline and version untouched, so the user's next edit goes out against the old version: Orca refuses it and keeps the banner instead of taking it as the merge's acknowledgement. After an acknowledged merge the tab's saved text moves to the disk text it used, so typing back to the old ancestor no longer looks clean. * chore(plugins): regenerate the testing bundle on main |
||
|
|
5846caf2ba |
plugins: editor.save.before hook (format on save, or refuse the save) (#37347)
* plugins: editor.save.before hook (format on save, or refuse the save) Explicit saves of text files from an editor tab run plugins' editor.save.before in main before the write (local, SSH, WSL and folder workspaces all save through that one renderer path). A plugin can return changed text or deny with a reason, shown in the save error. The buffer takes the hook's text only if it is unchanged since the hook started; edits made meanwhile stay dirty. Autosave, restart saves and bytes documents are not hooked, and with no live plugin listing the hook the save path adds no await. Co-Authored-By: Claude <noreply@anthropic.com> * test(plugins): editor.save.before text reaches the visible Monaco model The hook writes its text into the tab's draft, which reaches the model through the same content-sync bridge as Reload from disk. A model-level test covers the formatted text showing, the next keystroke editing it, and edits typed during the hook staying in the model. Co-Authored-By: Claude <noreply@anthropic.com> * plugins: editor.save.before review fixes: flush held typing, update the surviving view, keep the denial - After the hook answers, pending view text (rich Markdown's serialize timer) is flushed before deciding whether the buffer still holds the hook's input. - The hook's text goes to whichever view of the buffer record is still open, so closing the saving view keeps a sibling view in step with disk. - The save-request bridge passes Errors through whole, so the toast shows the plugin and its reason instead of a generic failure. Co-Authored-By: Claude <noreply@anthropic.com> * chore(plugins): regenerate after rebasing the save hook on main --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
999160b3db |
feat(plugins): commands[].replaces lets a mod take over a built-in action (#37316)
* plugins: commands[].replaces lets a worker command take over a built-in action A worker command with replaces: <action> (the declarative action list, engines >=1.4.248, needs main) runs in place of that built-in from its shortcut, plugin aliases and the sidebar menus; a failed or silent (2 s) worker falls back to Orca's own. The install screen names each replacement, the plugin page has a per-action switch (settings.pluginReplacementsOff), and when two plugins replace one action the one installed first wins and the other's log says so. Update review counts replaces as new access. * fix(plugins): narrow replaced action ids before looking up their titles * plugins: harden command replaces after review - Consent includes the replaced actions, so adding replaces to a dev folder needs a new approval; CLI approval and update review name each takeover. - Shortcuts main intercepts (Tasks, Workspace Board, history), search with a selection and floating maximize now go through the replacement too. - A worker that only starts after the 2 s fallback no longer runs the command as well: main refuses to start it past the deadline. - A workspace-only command does not replace an action without a workspace. - An update keeps the plugin's first install time, so it keeps its takeover. - Drop the commands.run promise until Orca offers it. * plugins: commands.run always runs the built-in, never a replacement A5b's commands.run dispatches with the 'plugin-host' source; the app dispatcher now builds handlers that run Orca's own action for it, so a plugin that replaces an action and calls commands.run cannot loop. Docs and schema describe wrapping the built-in with commands.run; regenerated. |
||
|
|
3e52963a9a |
docs(plugins): fix custom-editor authoring papercuts from dogfood (#37337)
- shot --act: say edits only dirty the tab; end with Cmd/Ctrl+S to save - manifest: compound suffixes like .sketch.json open by default - cli.md: list plugin check's exit codes, including plugin_check_failed - workflow: how to run and stop the dev app from a source checkout - plugin create --help: real descriptions for --template/--publisher/--id/--name - recipes: declaration file for vendored ESM libraries |
||
|
|
2fb3a0975e |
feat(plugins): workers can open files and run built-in actions (#37323)
* feat(plugins): add editor.open and commands.run for full-access workers Both ride the existing plugin view request channel (the one plugin open and plugin shot use) to the one main window's renderer; headless serve and a missing window answer unavailable. editor.open takes a path that stays inside the workspace (Git worktrees and folders) and opens it as a tab without switching what the person sees. commands.run takes only the built-in contributes.commands action list and dispatches Orca's own handler, never a plugin replacement. Both need workspace:write. workspace.list now also lists project-group folder workspaces. * fix(plugins): open folder workspaces and host-naming ids through Orca's window workspace.open of a project-group folder asks the window to show it (setActiveFolderWorkspace), since the runtime activates Git worktrees only. editor.open resolves the identity: ids workspace.list now returns. commands.run documents that it must call the raw built-in, never a replacement wrapper. * plugins: regenerate the testing bundle and skill guides on the rebased host actions Generated files only (lint-staged's oxlint refuses a commit with no lintable files). Co-Authored-By: Claude <noreply@anthropic.com> * chore(plugins): regenerate the testing bundle on main --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
544577fe02 |
feat(plugins): workers can list and open workspaces, create and read terminals, launch agents (#37312)
* feat(plugins): let full-access workers act on workspaces, terminals and agents Host API minor 3 adds worker-only rows: workspace.list (workspace:read), workspace.open (workspace:write), terminal.create (terminal:send), terminal.read (terminal:read, at most 2,000 lines) and agent.launch (agent:launch). Each dispatches the runtime RPC method the orca CLI calls, in process with the CLI's identity, so it runs on the host that owns the workspace (local, WSL or SSH) and covers folder workspaces. The new capabilities arrive in 1.4.248; typings, docs and skill references are generated from the table. * fix(plugins): make workspace host actions safe to revoke, cancel and target - Each runtime effect re-checks the plugin's approval right before the runtime acts (a dispatcher beforeInvoke hook, after its own waits), and a worker's cancel or exit now aborts the call's signal through to the runtime. - agent.launch starts the agent's CLI in a background terminal and returns its handle at once; a prompt is delivered afterwards through the runtime's own reuse-terminal path, so the host call never waits for the composer. - workspace.list adds project-group folder workspaces and returns ids that name their host (identity: keys), so twins on two hosts are never ambiguous. - terminal.create passes presentation background; terminal.read counts a runtime-limited read as truncated. workspace.open refuses folders as unavailable until a window-side open lands. * plugins: keep both API extensions and host-call tracking under the line limits after rebasing on the hooks Worker-only status bar and workspace methods spread into PLUGIN_HOST_API through one module, the in-flight host call map moves into PluginWorkerHostCalls, and bindPluginRuntime builds the runtime RPC so main-process-plugins.ts keeps its size; regenerated docs and typings. Co-Authored-By: Claude <noreply@anthropic.com> * chore(plugins): regenerate after rebasing on the editor recipe and shots * chore(plugins): regenerate after rebasing on the plugin shot recipe --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
3b5eed8ca4 | docs(plugins): point the editor and status bar recipes at plugin shot (#37332) | ||
|
|
f908d2f40a |
feat(plugins): plugin shot --editor to screenshot and drive custom editors (#37302)
* plugins: orca plugin shot --editor, and plugin open --editor opens the file's folder plugin open --editor now opens the file in the workspace that holds it, matching its real path too (/tmp vs /private/tmp), and otherwise adds the file's folder as a folder workspace instead of failing with no_workspace. plugin shot <dir|key> --editor <file> [--theme] [--width --height] [--act] loads the editor afresh in a hidden tab, waits for it to get its document and ask for it (a new editor.subscribed frame event), captures the editor's guest with the panel shot's capture path, and sends --act clicks, drags and keys as real input via sendInputEvent. It exits 1 with the frame's errors when the editor throws, is blocked by its content policy, or never asks for its document within 5s; theme and size are put back. New RPC method plugins.shotEditor so older hosts fail cleanly. * plugins: shot --editor never changes the author's file With --act the shot copies the file into a temporary folder, shoots the copy in a temporary folder workspace, then closes its tab and removes the workspace and folder; --in-place acts on the file itself. Without --act it opens the real file, leaves its buffer alone and closes the tab if the shot opened it. Afterwards Orca shows the workspace it showed before. Regenerates the skill's CLI reference. * plugins: fix editor shot typecheck (refusal next step, RPC test mock) * plugins: editor shot targets its own guest, flushes before reload, scopes cleanup per capture - Main captures the exact guest WebContents the shot's tab mounted, not the first with its URL. - An open editor's pending edits are flushed before the shot reloads it; the shot fails if not. - --act --in-place keeps the acted tab and its unsaved edits. - end-capture undoes only its own capture (per-capture id), so overlapping shots don't clash. - The file's workspace lookup includes local folder workspaces. * plugins: shot --status-bar/--window, key acts focus the editor guest, panel shot selects a workspace - Editor --act keys first give the guest's <webview> DOM focus and refocus its target, so a canvas that keeps focus no longer drops later keys; never webContents.focus(), which focuses the window. - orca plugin shot <dir|key> --status-bar | --window [--theme]: captures Orca's status bar or the whole hidden window (plugins.shotChrome) with the existing capture helpers. - With no workspace showing, a panel shot selects this machine's most recent workspace in the hidden window instead of failing. * plugins: a shot's end restores only its own capture overrides * plugins: regenerate the testing runtime with the editor subscribed signal * plugins: editor capture refusals go through one CLI-message helper * fix(plugins): give the chrome shot refusal a next step |
||
|
|
591f2acbc8 |
docs(plugins): add a rich-editor recipe and list frame theme variables in the skill (#37306)
recipes.md gains "A rich editor with a library" beside the hooks and status bar recipes: an isolated-frame custom editor that vendors its library behind an import map, syncs through orca.document.session with a merge by id, and tests that sync with mockEditorHost. host-api.md lists every --orca-* frame variable and what it paints, generated from the frame token allowlist. |
||
|
|
fa7c3f95fe |
feat(plugins): check custom editors and test them with mockEditorHost (#37293)
* feat(plugins): check custom editors statically and add mockEditorHost orca plugin check now follows each custom editor entry (local script src, inline module scripts, relative imports), transpiled and resolved as the frame loader does, and fails at file:line:column on syntax errors, missing files, refused imports, string eval/Function and files over their size cap, with no running Orca. The check ships in the test hooks bundle. orca/testing gains mockEditorHost: it runs the frame shell's real window.orca (document API and session) over an in-memory text or bytes file, with edits, replace, conflictNext, flush, setTheme and dispose. Typings, docs and the skill guide cover both. * feat(plugins): warn on editor eval and check editors in dev watch editor_eval comes from a lexical scan that can misread rare code, so it is now a warning that does not fail orca plugin check. dev watch --check runs the editor check beside the panel check and reports it under editors. * fix(plugins): check editors by the frame protocol's rules; mock blocks lost saves The static editor check now reads files through the loader's contained reader (symlinks out of the plugin are refused), runs only JavaScript script types, honors the page's import map for native modules, classifies files by the protocol's content types (JSON imports, extensionless HTML entries), decodes escaped script URLs, and uses the protocol's caps: 10 MiB entry, 1 MiB transpiled module, 16 MiB checked dependency. mockEditorHost refuses an oversized edit before reading it and then rejects flush() until a later edit lands, as Orca blocks the save. * test(plugins): type mockEditorHost's frame API instead of reflecting on it * fix(plugins): keep main's case-spelling check and hook typings through the rebase The rebase onto main resolved plugin-artifact-validation.ts and orca-testing.d.ts to B4's side; this puts back main's exact-path-spelling check and hooks typings beside B4's contained reader and mockEditorHost types, and regenerates the testing bundle. |
||
|
|
7989c05ad3 |
feat(plugins): agent tool-call hooks (Claude Code can block or rewrite) (#37303)
* plugins: agent.tool.before and agent.tool.after hooks; Claude Code PreToolUse blocks
The hook server runs plugins' tool hooks after recording status. Claude Code's
POSIX hook script now asks for an answer on PreToolUse (X-Orca-Hook-Decision),
waits at most 8 s (Orca answers within 6 s) and prints the decision: a deny
with the plugin's reason, or updatedInput without approving it. Timeouts,
errors and an unreachable Orca print {}, so the call proceeds. Other events
still print {} before posting. Every other agent, Windows scripts and SSH/WSL
relays only observe or are not hooked yet (per-agent table in the
agent-hooks README).
Co-Authored-By: Claude <noreply@anthropic.com>
* plugins: verify PreToolUse answers against the real Claude CLI; 204 at once when no tool hook listens
A real-CLI test (ORCA_REAL_CLAUDE_CLI_TEST=1) shows Claude Code 2.1.316 runs
updatedInput sent without permissionDecision, still asks for approval of the
rewritten call, and refuses a deny. With no plugin listing a tool hook, the
server answers 204 before any await and runs no chain.
Co-Authored-By: Claude <noreply@anthropic.com>
* test(claude): type the real-CLI PreToolUse answer
* plugins: harden agent tool hooks (partial replies, fenced posts, OpenClaude, Amp/Copilot/Cursor)
- Drop a failed curl's partial body and print only a complete PreToolUse decision.
- Run tool plugins only for posts status ingestion accepted; name the owner's terminal.
- Enable PreToolUse decision mode only for Claude Code, not CLIs reusing its script.
- Decode Amp tool.call/tool.result, Copilot envelope/implied events and Cursor shell/MCP calls.
Co-Authored-By: Claude <noreply@anthropic.com>
* plugins: regenerate the testing bundle on the rebased tool hooks
Generated file only (lint-staged's oxlint refuses a commit with no lintable files).
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
|