mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 17:37:40 +00:00
bc2fc4ea2bfd106d96fc80bd783fd0dad1fabc19
1265
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a82468b023 |
chore(deps): safely update vetted dependencies across workspaces (#41291)
* chore(deps): safely update vetted dependencies across workspaces * fix(deps): deduplicate rolldown to 1.2.16 for electron-vite tsc parity |
||
|
|
c9ef81809f |
test: remove 198 low-value test registrations (#41175)
* test: remove 198 low-value test registrations * ci: fail over unavailable Ubuntu package mirrors (#41174) * ci: fail over unavailable Ubuntu package mirrors * fix(ci): recover package retries across headless jobs * fix(ci): allow complete fallback package index downloads * fix(ci): recover dpkg locks and bound WebKit setup retries * fix(ci): run apt deadlines inside sudo sessions * fix(ci): invoke installed Playwright without root pnpm * fix(ci): allow large fallback dependency downloads to finish --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com> |
||
|
|
15cabe65ac |
fix(terminal): scope parking and output coverage to each workspace (#40331)
* perf(native-chat): project structured chat tabs per workspace bucket The shared chat-tab list was keyed on the whole unifiedTabsByWorktree identity, so every tab write anywhere (terminal title batches included) rescanned all tabs and handed every consumer a new list. Rebuild only the buckets whose identity changed and return the previous list while no chat tab changed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): reconcile chat status membership per changed tab The status bridge rebuilt every member and host group and captured every chat on any tab-map or owner-input change, and recaptured every chat on any launch notification. Membership now updates only the tabs whose identity changed; owner-input changes re-resolve only unstamped tabs, the only ones whose host depends on them; launch notifications name their session so only its tabs are recaptured (unaddressed ones still recapture all). The sleep and launch-directory companions of one projection land in one store write. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): guard whole tab-map triggers and hot-map listeners Add a count ratchet for identity comparisons of the whole unifiedTabsByWorktree/tabsByWorktree map in renderer code (counts may only fall), wired into pnpm lint, run-ratchets discovery and changed-check selection. Extend the advisory no-whole-hot-map-selector rule to inline store listeners that compare a whole hot map and to effect bodies that use one whole from getState(). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * revert(lint): drop the hot-map listener/effect extension The guard stays scoped to the repaired seams; no repository-wide rule change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): capture chat status on semantic tab changes; address tombstone retirement Focus, preview and order-only tab writes no longer recapture a chat's status: membership and the projection fences compare the fields the projection reads. Absent-tombstone retirement now names the sessions it retired, so no launch producer sends an unaddressed notification. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): keyed-record transition seam for tab maps and companion records Writers build next tab buckets and keyed companion records through replaceTabBuckets / replaceRecordEntries (or name the keys of a record they already built), which record exactly which keys and tab IDs changed against the produced record. Readers ask readTabMapChanges / readRecordChanges for an addressed delta; any unannotated link reads as a full resync. Adds subscribeTabTransitions and a store-observer installer registry. The chat-tab list and the status bridge now consume addressed deltas and keep the whole-list walk only as the cold path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): annotate every shared tab-map writer through the seam Shared tabsByWorktree/unifiedTabsByWorktree writers (tab, editor, browser, worktree, ssh, terminal create/close/navigation/title-batch/reconnect/ hydration, web-session mirroring and layout frames) now build or annotate their next tab buckets and companion records with the exact workspace and tab IDs they changed; full hydration, full frame builds and reconnect inventories are named full resyncs. Writers that copied every bucket for one tab (preview promotion, dirty-file preview clear, worktree removal filters, sleeping-record identity rename) now keep unchanged buckets. Replace the renderer-wide tab-map comparison ratchet with a narrow seam guard: the repaired consumers may walk a whole tab map only in named cold paths, and the pinned writer modules may not build raw seam records. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(store): name seam fields once; type seam records; record moved respawn writes Writers stop repeating tracked field names (centralized in seam-record-fields.ts), the seam takes a named KeyedSnapshot record type instead of casts, and the layout-writer baseline records the respawn helpers moved unchanged out of worktree-layout-lifecycle.ts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(store): drop seam field cast; record the seam field list in the layout-writer baseline Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): keep chat-tab list in source workspace order (C3/F1) Every source workspace keeps a projection slot, even without chats, and the seam reports when a write added or deleted a workspace key or moved a surviving bucket, so the incremental list never reorders first-match consumers; those transitions take the cold rebuild. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): keep projection and retirement debt awake (C2, F3) A member is owed from attach or semantic change, members without a host feed keep their own debt, and every reconciliation drains existing owed or retired work even when no new member changed, including a closed last chat whose feed is gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): stop inferring host-mirror companion IDs from visible tabs (C1) A host retraction can delete PTY or layout records for tabs neither inventory lists, so the mirror funnel marks its tab-keyed records full resync instead of advertising an incomplete addressed set. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): close indirect paths in the tab-map seam guard (C4) The guard now rejects ordinary callers of the bridge cold path, value imports the repaired consumers have not reviewed, and raw seam records built into a local binding without a seam helper annotating it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): drive real tab actions through the status bridge (F2) Close, session rebind with a late old-session tick, and a legacy owner change, through createUnifiedTab/setTabLabel/closeUnifiedTab, so the addressed reconciliation path is exercised. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: exempt seam field-name constants from the layout-writer ratchet; drop dead setters (F4) The seam's SEAM_*_FIELDS lists name fields without writing them, so the ratchet skips them and the raised baseline row is gone (renderer total 569, main 571). setStructuredChatSleptAt and the two launch-directory setters lost their last callers to the batched companion write. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): Map provenance and source-ordered change keys in the seam (PR A addenda) replaceMapEntries gives Map-typed fields (runtimeStatusByEnvironmentId) the same weak provenance and readRecordChanges protocol. Change keys compose forward through a chain, oldest write first, so added keys come out in source order (index keys first for records, as Object.keys orders them). A surviving key deleted and re-added, in one write or across a chain, and a record builder that moves a surviving key, read as a 'reordered' full resync. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): writers declare key order; seam reports ordered additions (N1c, N1a) The seam no longer scans both records to rediscover order on every annotation. replace* helpers know insertion order by construction; annotate* takes a declared order ('appended' by default, 'reordered' for a builder that moves keys, read as a full resync), verified only under test. Addressed changes now report keys, source-ordered added keys and deleted keys, so a reader holding its own key ranks places changes in O(changed). Worktree removal declares its editor-transfer records reordered. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): scope the chat-tab projection to chat-bearing workspaces (N2c) The projection keeps chat subsets only for workspaces that have chats, plus per-workspace source ranks that change only when a workspace is added or deleted. A focus, label or title write costs O(that workspace); the ordered list is materialized lazily, only for full-list readers, and keeps its identity while no chat changed. Workspace adds and deletes are addressed through the ranks instead of a cold rebuild. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): resolve aliases and require annotation before publication (C4) Any reference to a cold helper or Object enumerator outside its named callers counts, including aliases and callbacks; writer values are followed through local aliases and must be annotated before the write that publishes them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): scoped hydration keeps the warm chat list equal to a cold read (D1) Drives the real scoped hydrateTabsSession on early/later chats of one session: source order, list order and first-match precedence match a cold rebuild, including when the selection order differs from hydrated order. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): cache the chat-workspace order across chat edits (D1 item 5) The lineage keeps chat-bearing workspaces in rank order and only inserts or removes one when it gains its first or loses its last chat; a chat object change re-flattens the list without re-sorting. Full resyncs rebuild it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): the seam guard recognizes only construction helpers and cold marks (D1) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor(store): addressed provenance only from constructing helpers (D1) Remove annotateRecordReplacement/annotateTabBucketReplacement and their caller-declared order: only replace*/recordDraft/tabBucketDraft, which perform the construction, derive changed keys, additions and deletions from their operations (delete-then-reinsert reads as reordered); opaque reconstructions use markFullResync. Every former annotate caller is migrated: ordinary local writes build their records once through helpers or drafts with today's operations and order; scoped tab and terminal hydration, the reconnect inventory, host-mirror application and layout flush are full resyncs. Change readers move to keyed-record-change-reads.ts. Renderer layout-writer total 567 (main 571). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): type the hydration fixture without a cast Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): seam record writes define own entries, even __proto__ (N5c) replaceRecordEntries and drafts assigned through the inherited __proto__ setter, so a tab id '__proto__' lost its own PTY, layout and startup entries. Both now define an own data property, as the computed-key literals they replaced did; contract test included. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(terminal): build each createTab record once (N4c) createTab took ensureGroup's and insertSplitGroup's whole records and the orphan cleanup's seam records, then rebuilt them through the seam. It now takes the per-worktree group and split results and gives the orphan cleanup only the bucket it reads, so every seam record is constructed once with its ordered operations. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): record createTab's orphan-cleanup input view (renderer total 570, main 571) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor(terminal): split orphan cleanup so createTab cleans only companion caches (N6c) buildOrphanTerminalCompanionCleanupPatch holds the per-tab cache, tab-bar order and selection cleanup; buildOrphanTerminalCleanupPatch adds the seam record deletes on top, unchanged for reconciliation. createTab calls only the companion part with real state and deletes the seam entries through its single construction, so the stub input view and its layout-writer baseline rise are gone (terminal-tab-creation.ts back to 10). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(terminal): filter the orphan cleanup's kept bucket once (N7c) The full cleanup filters the workspace's tabs once and hands the kept bucket to the companion part, which takes its replacement active tab from it; createTab's companion-only call still makes its single find pass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * Scope terminal parking inputs and registries to workspace ownership * Guard parking ownership and cover background split output * Connect parking ownership to accepted tab transitions * Use accepted Map provenance and preserve parking owner order * Read paired parking capability deltas from the shared seam * Consume ordered additions from accepted record transitions * Expose first-tab and outside-owner views of terminal membership * Construct terminal binding and startup transitions at their writers * Construct shutdown and orphan cleanup transitions from ordered operations * Construct presentation and sleeping record transitions at their writers * Express semantic parking inputs and close annotation guard escapes * Keep replacement values typed from their source records * Construct sleeping session moves without changing nullable status records * Follow the constructing seam integer-key module * Adopt the separated transition reader module * Ratchet the cold parking compiler bailout improvement * Exercise parking fixtures through addressed inputs and live ownership * fix(tabs): keep removed worktrees' group entries deleted on removal The second emptied-group collapse in removeWorktreeLayout also visited removed worktrees and wrote their deleted groupsByWorktree entry back as an empty list, a delete-then-set the seam read as a reordered full resync. It now visits only surviving workspaces, so removal stays addressed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(tabs): closeEmptyGroup collapses through the shared builder again collapseGroupLayout takes the record builder, and the renderer passes the seam's replaceRecordEntries, so the per-worktree collapse publishes with provenance without new counted layout writes (tabs-group-actions back to 12). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(tabs): reconciliation names its draft fields once (2 + 4 <= 9) The written-field sets come from SEAM_ field-name constants instead of string literals, so the reconciliation split no longer raises the combined layout-writer count (tabs-reconciliation 2, tabs-reconciliation-batch 4, against the original 9). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(terminal): bound parking updates to changed ownership facts * fix(terminal): type parking ratchet entry descriptors * chore(tabs): publish reconciliation drafts with explicit field writes (N9c) Revert the SEAM_ field-name constants: the drafts are held under their own names and finishReconciliationDrafts publishes each written draft as an explicit unifiedTabsByWorktree/groupsByWorktree/activeGroupIdByWorktree/ layoutByWorktree property, so the counter sees every real write and the split totals 2 + 4 against the original 9, with no exemption. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(parking): follow merged module paths * Move parking assignment invalidation into the store observer * Limit parking assignment checks to changed tab rows * Separate tab row recording from provenance reads * Preserve uncertainty across skipped tab reinsertion * Keep root terminal watchers within workspace surfaces --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
9646b48fb8 | chore(i18n): guard startup and worktree localization (#40449) | ||
|
|
48f9eb037d |
chore(deps): bump tsrs to 0.22.0-ts7.1.0-beta (#40572)
0.23.0 is inside the 3-day minimumReleaseAge window, so 0.22.0 is the newest version installable without an exclusion. |
||
|
|
376cf18634 |
perf(native-chat): addressed tab-map transitions for chat membership (#40098)
* perf(native-chat): project structured chat tabs per workspace bucket The shared chat-tab list was keyed on the whole unifiedTabsByWorktree identity, so every tab write anywhere (terminal title batches included) rescanned all tabs and handed every consumer a new list. Rebuild only the buckets whose identity changed and return the previous list while no chat tab changed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): reconcile chat status membership per changed tab The status bridge rebuilt every member and host group and captured every chat on any tab-map or owner-input change, and recaptured every chat on any launch notification. Membership now updates only the tabs whose identity changed; owner-input changes re-resolve only unstamped tabs, the only ones whose host depends on them; launch notifications name their session so only its tabs are recaptured (unaddressed ones still recapture all). The sleep and launch-directory companions of one projection land in one store write. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): guard whole tab-map triggers and hot-map listeners Add a count ratchet for identity comparisons of the whole unifiedTabsByWorktree/tabsByWorktree map in renderer code (counts may only fall), wired into pnpm lint, run-ratchets discovery and changed-check selection. Extend the advisory no-whole-hot-map-selector rule to inline store listeners that compare a whole hot map and to effect bodies that use one whole from getState(). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * revert(lint): drop the hot-map listener/effect extension The guard stays scoped to the repaired seams; no repository-wide rule change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): capture chat status on semantic tab changes; address tombstone retirement Focus, preview and order-only tab writes no longer recapture a chat's status: membership and the projection fences compare the fields the projection reads. Absent-tombstone retirement now names the sessions it retired, so no launch producer sends an unaddressed notification. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): keyed-record transition seam for tab maps and companion records Writers build next tab buckets and keyed companion records through replaceTabBuckets / replaceRecordEntries (or name the keys of a record they already built), which record exactly which keys and tab IDs changed against the produced record. Readers ask readTabMapChanges / readRecordChanges for an addressed delta; any unannotated link reads as a full resync. Adds subscribeTabTransitions and a store-observer installer registry. The chat-tab list and the status bridge now consume addressed deltas and keep the whole-list walk only as the cold path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): annotate every shared tab-map writer through the seam Shared tabsByWorktree/unifiedTabsByWorktree writers (tab, editor, browser, worktree, ssh, terminal create/close/navigation/title-batch/reconnect/ hydration, web-session mirroring and layout frames) now build or annotate their next tab buckets and companion records with the exact workspace and tab IDs they changed; full hydration, full frame builds and reconnect inventories are named full resyncs. Writers that copied every bucket for one tab (preview promotion, dirty-file preview clear, worktree removal filters, sleeping-record identity rename) now keep unchanged buckets. Replace the renderer-wide tab-map comparison ratchet with a narrow seam guard: the repaired consumers may walk a whole tab map only in named cold paths, and the pinned writer modules may not build raw seam records. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(store): name seam fields once; type seam records; record moved respawn writes Writers stop repeating tracked field names (centralized in seam-record-fields.ts), the seam takes a named KeyedSnapshot record type instead of casts, and the layout-writer baseline records the respawn helpers moved unchanged out of worktree-layout-lifecycle.ts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(store): drop seam field cast; record the seam field list in the layout-writer baseline Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): keep chat-tab list in source workspace order (C3/F1) Every source workspace keeps a projection slot, even without chats, and the seam reports when a write added or deleted a workspace key or moved a surviving bucket, so the incremental list never reorders first-match consumers; those transitions take the cold rebuild. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(native-chat): keep projection and retirement debt awake (C2, F3) A member is owed from attach or semantic change, members without a host feed keep their own debt, and every reconciliation drains existing owed or retired work even when no new member changed, including a closed last chat whose feed is gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): stop inferring host-mirror companion IDs from visible tabs (C1) A host retraction can delete PTY or layout records for tabs neither inventory lists, so the mirror funnel marks its tab-keyed records full resync instead of advertising an incomplete addressed set. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): close indirect paths in the tab-map seam guard (C4) The guard now rejects ordinary callers of the bridge cold path, value imports the repaired consumers have not reviewed, and raw seam records built into a local binding without a seam helper annotating it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): drive real tab actions through the status bridge (F2) Close, session rebind with a late old-session tick, and a legacy owner change, through createUnifiedTab/setTabLabel/closeUnifiedTab, so the addressed reconciliation path is exercised. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore: exempt seam field-name constants from the layout-writer ratchet; drop dead setters (F4) The seam's SEAM_*_FIELDS lists name fields without writing them, so the ratchet skips them and the raised baseline row is gone (renderer total 569, main 571). setStructuredChatSleptAt and the two launch-directory setters lost their last callers to the batched companion write. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat(store): Map provenance and source-ordered change keys in the seam (PR A addenda) replaceMapEntries gives Map-typed fields (runtimeStatusByEnvironmentId) the same weak provenance and readRecordChanges protocol. Change keys compose forward through a chain, oldest write first, so added keys come out in source order (index keys first for records, as Object.keys orders them). A surviving key deleted and re-added, in one write or across a chain, and a record builder that moves a surviving key, read as a 'reordered' full resync. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): writers declare key order; seam reports ordered additions (N1c, N1a) The seam no longer scans both records to rediscover order on every annotation. replace* helpers know insertion order by construction; annotate* takes a declared order ('appended' by default, 'reordered' for a builder that moves keys, read as a full resync), verified only under test. Addressed changes now report keys, source-ordered added keys and deleted keys, so a reader holding its own key ranks places changes in O(changed). Worktree removal declares its editor-transfer records reordered. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): scope the chat-tab projection to chat-bearing workspaces (N2c) The projection keeps chat subsets only for workspaces that have chats, plus per-workspace source ranks that change only when a workspace is added or deleted. A focus, label or title write costs O(that workspace); the ordered list is materialized lazily, only for full-list readers, and keeps its identity while no chat changed. Workspace adds and deletes are addressed through the ranks instead of a cold rebuild. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): resolve aliases and require annotation before publication (C4) Any reference to a cold helper or Object enumerator outside its named callers counts, including aliases and callbacks; writer values are followed through local aliases and must be annotated before the write that publishes them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): scoped hydration keeps the warm chat list equal to a cold read (D1) Drives the real scoped hydrateTabsSession on early/later chats of one session: source order, list order and first-match precedence match a cold rebuild, including when the selection order differs from hydrated order. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(native-chat): cache the chat-workspace order across chat edits (D1 item 5) The lineage keeps chat-bearing workspaces in rank order and only inserts or removes one when it gains its first or loses its last chat; a chat object change re-flattens the list without re-sorting. Full resyncs rebuild it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): the seam guard recognizes only construction helpers and cold marks (D1) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor(store): addressed provenance only from constructing helpers (D1) Remove annotateRecordReplacement/annotateTabBucketReplacement and their caller-declared order: only replace*/recordDraft/tabBucketDraft, which perform the construction, derive changed keys, additions and deletions from their operations (delete-then-reinsert reads as reordered); opaque reconstructions use markFullResync. Every former annotate caller is migrated: ordinary local writes build their records once through helpers or drafts with today's operations and order; scoped tab and terminal hydration, the reconnect inventory, host-mirror application and layout flush are full resyncs. Change readers move to keyed-record-change-reads.ts. Renderer layout-writer total 567 (main 571). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * test(native-chat): type the hydration fixture without a cast Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(store): seam record writes define own entries, even __proto__ (N5c) replaceRecordEntries and drafts assigned through the inherited __proto__ setter, so a tab id '__proto__' lost its own PTY, layout and startup entries. Both now define an own data property, as the computed-key literals they replaced did; contract test included. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(terminal): build each createTab record once (N4c) createTab took ensureGroup's and insertSplitGroup's whole records and the orphan cleanup's seam records, then rebuilt them through the seam. It now takes the per-worktree group and split results and gives the orphan cleanup only the bucket it reads, so every seam record is constructed once with its ordered operations. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(ratchets): record createTab's orphan-cleanup input view (renderer total 570, main 571) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * refactor(terminal): split orphan cleanup so createTab cleans only companion caches (N6c) buildOrphanTerminalCompanionCleanupPatch holds the per-tab cache, tab-bar order and selection cleanup; buildOrphanTerminalCleanupPatch adds the seam record deletes on top, unchanged for reconciliation. createTab calls only the companion part with real state and deletes the seam entries through its single construction, so the stub input view and its layout-writer baseline rise are gone (terminal-tab-creation.ts back to 10). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * perf(terminal): filter the orphan cleanup's kept bucket once (N7c) The full cleanup filters the workspace's tabs once and hands the kept bucket to the companion part, which takes its replacement active tab from it; createTab's companion-only call still makes its single find pass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(tabs): keep removed worktrees' group entries deleted on removal The second emptied-group collapse in removeWorktreeLayout also visited removed worktrees and wrote their deleted groupsByWorktree entry back as an empty list, a delete-then-set the seam read as a reordered full resync. It now visits only surviving workspaces, so removal stays addressed. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(tabs): closeEmptyGroup collapses through the shared builder again collapseGroupLayout takes the record builder, and the renderer passes the seam's replaceRecordEntries, so the per-worktree collapse publishes with provenance without new counted layout writes (tabs-group-actions back to 12). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(tabs): reconciliation names its draft fields once (2 + 4 <= 9) The written-field sets come from SEAM_ field-name constants instead of string literals, so the reconciliation split no longer raises the combined layout-writer count (tabs-reconciliation 2, tabs-reconciliation-batch 4, against the original 9). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * chore(tabs): publish reconciliation drafts with explicit field writes (N9c) Revert the SEAM_ field-name constants: the drafts are held under their own names and finishReconciliationDrafts publishes each written draft as an explicit unifiedTabsByWorktree/groupsByWorktree/activeGroupIdByWorktree/ layoutByWorktree property, so the counter sees every real write and the split totals 2 + 4 against the original 9, with no exemption. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
d291670a01 |
refactor(speech): remove sherpa-onnx (#39473)
transcribe-cpp is now the only on-device engine on every platform, so the sherpa-onnx packages, their packaging (extraResources, the darwin libonnxruntime prune, the native-variant assert and the Linux libstdc++ exemption), the sherpa recognizer in the speech process and the per-model engine choice all go. Hotwords are written as plain terms. |
||
|
|
fd46321d85 |
feat(speech): move the speech models to transcribe-cpp and offer an update for old downloads (#39468)
* feat(speech): move the speech catalog to transcribe-cpp models Parakeet v2/v3, Whisper tiny and SenseVoice now download their GGUF builds, which run on transcribe-cpp everywhere, Intel Macs included (on the CPU). A model still holding its old sherpa-onnx download shows "Update to the faster version (<size>)"; updating replaces the old files, and dictating before then says the model needs that update. The five models with no GGUF build are retired and their users moved over: the Japanese Parakeet, the Chinese-English Zipformer and the Paraformer to SenseVoice, and the Korean and Chinese streaming Zipformers to the new Nemotron 3.5 (28 languages). Nemotron's locale codes (ko-KR) are matched from the ISO language setting. * feat(speech): offer the speech model update once after the engine change A card in the notification corner tells people whose selected on-device model needs the new download, or whose retired model was replaced, and starts the same download as Settings > Voice. After a replacement it offers to delete the retired model's files. * feat(speech): move retired Korean and Chinese models to SenseVoice and offer Whisper Large v3 Turbo On transcribe-cpp 0.4.1 with Metal, SenseVoice beat Nemotron 3.5 on Korean and Chinese FLEURS clips, so the retired Korean and Chinese streaming Zipformers now move to SenseVoice. Whisper Large v3 Turbo (Q8_0, 886 MB) joins the catalog as the most accurate choice for Japanese, Korean and Chinese. Nemotron 3.5 stays, described by the languages it does best. |
||
|
|
0b8e94aa5c |
feat(speech): run GGUF models on transcribe-cpp with a CPU fallback (#39326)
* feat(speech): run GGUF models on transcribe-cpp, falling back to the CPU The speech host child can now load a second engine. A model whose files are GGUF runs on transcribe-cpp (Metal on Apple silicon, Vulkan on Windows and Linux, CPU otherwise); everything else stays on sherpa-onnx, which remains the only engine on Intel Macs. A GPU that fails to load, errors, stalls for 25 s or crashes the process moves the dictation to a CPU-only process (TRANSCRIBE_BACKENDS=cpu) that replays the audio the GPU had not decoded yet, so no words are lost or repeated. A GPU that crashed or would not load is remembered per transcribe-cpp version and OS release, and voice.speechGpu = 'off' keeps it on the CPU. Packaging copies transcribe-cpp, koffi and the target's native package into resources/node_modules outside asar, fails when a target's package is missing, and ships the MSVC runtime beside transcribe.dll on Windows. No catalog model is GGUF yet, so nothing runs on transcribe-cpp until the catalog change that follows. * fix(speech): keep the speech queue running after a failed task, and drop audio frames after a discard * fix(speech): keep the engine's file reads off the main thread's hot paths The engine lookup and the GPU failure marker are read once per process instead of on every dictation start and mobile catalog request, the marker is written asynchronously, and the child reads the hotwords file with fs/promises. The baseline moves the existing engine presence checks from stt-worker-paths to the shared package table and adds the once-per-process marker reads. |
||
|
|
0a7ce6e78f |
test: remove low-value bridge speech and lineage checks (#40356)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
7d5e5dc2ac |
test: remove low-value custom smoke workflows and stale benchmark (#40060)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
c192f04dba |
chore(claude): update the Claude Agent SDK to 0.3.318 (#39940)
* chore(claude): update the Claude Agent SDK to 0.3.318 Includes the upstream fix for omitted permissionMode (claude-agent-sdk-typescript#519), so the 'use my Claude settings' permission choice honors settings defaultMode. * test(orcad): expect the SDK's joined --permission-prompt-tool=stdio argument Claude Agent SDK 0.3.295+ passes named option values in the same argument as their flag. * refactor(claude): drop the permission flag SDK 0.3.318 no longer reads The SDK leaves an omitted permissionMode to the CLI, so the 'own' choice needs no opt-in option. |
||
|
|
1d28b8882c |
chore(ratchets): fail PRs that add sync fs calls on Electron main or new setInterval polls (#39930)
* chore(ratchets): count sync fs calls on Electron main and setInterval calls
Sync fs on main and fixed-cadence intervals that never settle were two of the
most common perf fix classes since September, and no gate counted them. Both
ratchets grandfather today's uses per file and fail when a file's count grows.
* chore(ratchets): count every sync fs export, src/shared and node:timers intervals
Review: the allow-list missed descriptor/copy APIs, src/shared helpers run on
main too, and setInterval imported from node:timers escaped the timer count.
* chore(ratchets): keep hosted setInterval calls beside a named timer import
Review: a named node:timers import zeroed window/globalThis calls too, a
destructured require was counted twice, and collector edits didn't select
the timer ratchet in check:changed.
* chore(ratchets): charge calls through an alias, not the alias binding
Decider ruling B on review finding C6: binding a plain alias of a gated call
counted as a use, so an alias refactor failed every collector-based ratchet.
Conditional/fallback aliases and exported bindings stay charged.
* chore(ratchets): count bare setInterval only when nothing local shadows it
Review: the timer ratchet kept its own narrower binding resolver, so alias
and namespace-destructure forms of an imported setInterval counted twice.
Module bindings are the shared collector's; a bare call is the global only
when the file declares no setInterval binding.
* chore(ratchets): resolve bare setInterval calls per scope
Decider ruling A: the file-wide shadow rule let an unrelated parameter or type
declaration named setInterval hide every global poll in the file. Each bare
call now resolves through a single-file TypeScript checker (noLib, noResolve)
and counts when it binds to nothing declared in the file.
* chore(ratchets): write the timer baseline exactly as --prune does
* chore(ratchets): charge global timer aliases and bracket access
CodeRabbit: `const schedule = setInterval; schedule(poll)` and
`window['setInterval'](poll)` counted zero. Count value references to the
global timer (per scope) instead of only direct calls.
* chore(ratchets): charge shorthand timer escapes; skip writes, typeof and JSX tags
Review: `{ setInterval }` of the global counted 0, while assignments to it,
parenthesized typeof probes and a <setInterval/> tag counted 1.
* chore(ratchets): charge compound assignments to the global timer
Review: `||=` and `??=` read setInterval before writing it, so only a
plain `=` target is write-only.
* chore(ratchets): regenerate baselines for files main moved
main's SSH reorganisation moved counted files under src/main/ssh and
src/main/managed-server; counts are unchanged except one sync fs call main
removed.
|
||
|
|
dddc1260e5 |
chore(lint): oxlint 1.91, cheap perf/correctness rules, return-await fixes (#39730)
* chore(lint): bump oxlint to 1.91, add perf lint rules and perf audits * fix(lint): await promises returned inside try/catch/finally for return-await Prepare typescript/return-await with error-handling-correctness-only: await returns whose catch or finally was meant to cover them, and suppress the eight sites where the catch must not re-handle the returned promise. * chore(lint): enable return-await (error-handling-correctness-only); exempt secondary-scan directives in the changed gate * refactor(mobile): move file preview discard modal into its own module Keeps MobileFilePreviewScreen under the 400-line limit after merging main. --------- Co-authored-by: m4air <m4air@m4airs-MacBook-Air.local> |
||
|
|
ee6506714e |
test: remove 244 low-value tests (#39781)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
d058920e15 |
test: remove 357 low-value tests (#39743)
* test: remove 362 low-value tests * test: retain five boundary regression cases --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
7ae6448b44 |
perf(terminal): opt-in adaptive ACK pacing for alternate-screen streams on slow remote links (#39735)
* refactor(terminal): own multiplex ACK window accounting in one module * perf(terminal): pace alternate-screen multiplex output to the measured link BDP Slow SSH links queued up to 2MB of superseded TUI frames ahead of keystroke echo. orcad now estimates delivery rate and base RTT from existing output ACK timing, caps in-flight output for alternate-screen streams near 2x BDP on links under 4 MB/s, and replaces a backlog larger than that budget with the existing recovery snapshot. Normal-screen streams and fast links keep the legacy windows. ORCA_TERMINAL_ADAPTIVE_ACK_WINDOW=0 restores legacy behavior. * perf(terminal): back off unavailable superseding snapshots and bound legacy echo checks * perf(terminal): gate ACK pacing to measured remote links and keep supersedes history-neutral Pacing now needs a base RTT of at least 40ms, 16 fresh window-limited samples, and a sample within 15s, so LAN/local links and stale estimates keep the legacy windows. Superseding snapshots are screen-only, only replace frames that never switch screen mode (rechecked after serializing), and leave client history untouched. Paced streams keep today's total buffering before overflow, so overflow recovery fires no earlier than with legacy windows. * fix(terminal): close supersede gaps found in review Scan for screen switches and OSC side effects across frame and send boundaries (raw and JSON-escaped), back off after an aborted supersede so it cannot re-serialize in a loop, and keep paced pending headroom until the queue drains so leaving the alternate screen cannot force an overflow recovery. * fix(terminal): judge supersedable backlogs on decoded text across every seam Scan the joined text of the whole queue (plus the sent tail) so screen switches split across any frame, send, or covered/retained boundary are seen; never supersede span frames; reject bells (via the shared bell detector), OSC clipboard/notification writes and 8-bit OSC; back off for 1s after a rejected scan instead of rescanning on every ACK. * perf(terminal): make backlog superseding opt-in and forget the sent tail after snapshots Every recovery snapshot makes current clients replay their reattach reset (cursor shape/visibility, focus reporting), which is visible when it fires routinely, so superseding is opt-in via ORCA_TERMINAL_SUPERSEDE_ALT_BACKLOG=1 until clients can skip it. Pacing stays on by default: on a slow link the existing overflow recovery then reaches the client promptly instead of queuing behind a 2MB window. After any snapshot the sent tail is unknown (it can end inside an escape), so superseding waits for the next text frame. * test(terminal): cover default pacing and opt-in superseding separately * perf(terminal): read the supersede switch once per connection and skip its bookkeeping when off * perf(terminal): make adaptive ACK pacing opt-in and fix review findings - Default off: ORCA_TERMINAL_ADAPTIVE_ACK_WINDOW=1 enables it; when off every new path is a single flag check, so behavior matches legacy windows. - Base RTT is a windowed minimum kept honest by periodic probes that drain our own queue; a paced RTT beyond what our window can add means the path changed, so legacy windows hold while the base re-learns (no more self-tightening to 64KiB after an RTT increase). - Paced pending headroom is capped by the connection window legacy would have used and released on drain, pause and detach. - Superseding refuses snapshots that end inside an escape. - Replace the latency-threshold unit test with hardcoded estimator tests and move the link simulation to bench:terminal-multiplex-ack-pacing. * perf(terminal): drop backlog superseding and harden opt-in ACK pacing - Remove the opt-in backlog-superseding snapshot path (code, env switch, frame classifier and tests); it needs a client capability to skip the reattach reset before it can ship. - Paced-ness is decided once at admission (alt screen checked before the estimate) and reused by the send, so a probe starting in between cannot mislabel a sample. - Base RTT is fed only by sends with a near-empty connection queue; probes end only on such samples from paced streams, and a probe that cannot drain backs off. A path change forgets the base and holds legacy windows until a drained sample re-learns it. - Paced pending headroom is sized from the steady window (never a probe's zero) and released whenever the queue drains back within the legacy cap. - Flow-level tests: disabled pacing keeps legacy frames on a measured slow link; drained headroom returns so later output overflows at the legacy cap. * fix(terminal): release paced headroom whenever the queue drains, including after recovery |
||
|
|
60003df154 |
feat(i18n): make render-path translation reactive to the UI language (#39353)
Add useTranslate()/useIntlLocale() backed by a TranslationScopeProvider whose key changes only with the active language or its own resources, an AST codemod that rewrites render-path translate()/getIntlLocale() calls and threads the hook values into render-called helpers, a helper analysis report, and a ratchet that keeps render-path module translate() calls from growing. Apply the codemod to components/native-chat. Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
eb9312fc7c |
test: remove 660 low-value tests (#39547)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
75910ba631 |
build(renderer): gate React Compiler compatibility with a ratchet (#39324)
Adds oxc-transform-react as a devDependency and a ratchet that runs React Compiler in analysis mode over the shipped renderer sources. Files can't gain bailouts (new files must compile fully), and new code the compiler would run differently is banned: hooks it memoizes into a cached block, bare `void x;` reads, member postfix updates used as values, and "use no memo" opt-outs. Both baselines are generated by --update / --prune. Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
0314da7ed8 | refactor(main): group RPC and orchestration modules by owner (#38813) | ||
|
|
3a6bb347b5 |
Apply supported read-only controls to hidden text helpers (#38558)
* Keep background text generation read-only * Align runtime MIME dependency in frozen lockfile * Bundle MIME lookup data for background text tasks * Preserve text task cancellation and process ownership during policy probes * Update streamed generation fixture for permission probe * fix: preserve naming recipes with compatible restrictions * test: align naming contracts with single-attempt behavior * fix: preserve older OpenCode helper restrictions * test: complete OpenCode capability fixtures * Separate supported read-only controls from naming retries |
||
|
|
590f945a5e |
test: remove 513 low-value persistence and benchmark tests (#38922)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
6bb2e13c35 |
refactor(tooling): organize remaining scripts by domain owners (#38407)
* refactor(tooling): group remaining scripts by concrete domain owners * fix(tooling): preserve relocated launcher resource roots |
||
|
|
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 |
||
|
|
e98c6a439a |
test: remove 2816 low-value test declarations (#38030)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
2c03c4b989 | refactor: organize agent status and lifecycle owners (#37961) | ||
|
|
f3c65cd556 |
fix(deps): update Electron to 43.8.6 and resolve open security advisories (#37916)
- Electron 43.8.4 -> 43.8.6: upstream Chromium/V8/ANGLE/PDFium/Skia/WebRTC security backports. Drops the now-unneeded minimumReleaseAge exclusion. - @hono/node-server 2.1.0 -> 2.1.5 (GHSA-rmxm-3fg6-px4f), lockfile only. - mobile node-forge 1.4.0 -> 1.4.2: fixes 10 advisories (5 high) and the previously patched GHSA-86w9-cpqp-85rv, so the local patch and its audit exception are removed. The regression test still passes on 1.4.2. |
||
|
|
86a2fe9684 |
Load Linear drawer fields in one issue query (#37663)
* Read Linear drawer details in one issue query * Keep readable Linear details after optional field errors * Select only Linear fields needed by each issue reader * Explain the typed Linear partial response boundary * Typecheck Linear integration in the mixed-process project * Update Linear integration fixtures for raw issue reads |
||
|
|
8f2817a4c8 | test: remove ten non-gating benchmark cases and obsolete tooling (#37453) | ||
|
|
5cca72e605 |
test: remove 33 low-value tests and obsolete benchmark runner (#37441)
* test: remove 33 low-value tests and obsolete benchmark runner * test: remove import left unused by test deletion |
||
|
|
d061d235b6 |
test: remove 16 low-value test cases (#37333)
* test: remove 15 low-value test declarations * test: remove scheduling and routing budget checks; route editor shots --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
b69963356d |
chore(terminal): bump xterm to 6.1.0-beta.336 and regenerate patches (#37266)
Port the xterm, webgl, search, serialize and image source patches to upstream 08829c7. Where upstream fixed the same bug (#6204 mouse NaN guard, #6226 warm-up cancel on dispose, #6235/#6237 serialize width clamp) take upstream and keep only Orca's remaining delta (domContainer warm-up gate, clipped wide-cell blanking). Bump mobile's webgl subset patch alongside. Drop serialize fuzz seed normal:5, which now round-trips. |
||
|
|
b17d408416 |
Plugin dev loop: TS workers, hot reload with state, orca plugin dev watch, authoring skill (#36982)
* feat(plugins): build-less TypeScript workers A worker's main may be .ts/.mts. The plugin host installs module.registerHooks scoped to the plugin folder: .ts files are transpiled with the frames' sucrase options (lines kept, inline source map, source maps on), relative imports fall back to the frames' candidate files, and a value import of the type-only 'orca/worker' fails with a clear error. Needs engines.orca >=1.4.246. * feat(plugins): components panels hot reload with their state - In dev folders a save swaps only the hidden guest: keyed memory atoms are handed to the new guest (ui.retain → ui.hydrate memory), dropped when an atom's version changes. - A save that fails to load keeps the last good render and shows an inline file:line:col error banner; the next good save clears it. A subtle Reloaded mark follows a reload. - Transpile and import errors carry line and column; dev worker restarts keep storage. * feat(plugins): orca plugin dev watch One command for the inner loop: refreshes .orca/types, dev-loads the folder, follows its frame and worker logs (plugins.getLogs gains an optional cursor), prints reloads (optional devChangeCount on list entries) and status changes, and unloads on Ctrl-C. --json streams NDJSON events for agents. * feat(skills): orca-plugin-authoring bundled skill guide A guide for agents to build Orca plugins end to end (decision table, build-less rules, the dev watch loop, test/check, validate, release-entry, approvals, gotchas) with references generated from the component catalog, host API table, event schemas, manifest schema and CLI specs, checked for drift. Fixes the components template's Reset to set(count, 0). * feat(plugins): orca plugin dev watch --check; test kit details in the authoring skill - --check runs orca plugin check after the load and after each reload (one at a time; saves made meanwhile fold into one rerun) and prints each panel's render or errors inline, as a `check` event with --json. Local folders only, since it runs the plugin's code here. - The orca-plugin-authoring guide's Test and check section now documents orca plugin test and check from #36969 exactly (JSON results, exit codes, test placement, the orca/testing kit and its common mistakes), and the loop uses dev watch --check. * refactor(plugins): move the components renderer's timing and helper constants to their own module |
||
|
|
531658f1d1 |
Plugin test kit: orca/testing, orca plugin test and orca plugin check (#36969)
* feat(plugins): orca/testing kit, `orca plugin test` and `orca plugin check` - `orca/testing` mounts a components panel in plain Node (node:test, vitest, bun) with the real runtime and Orca's own tree validator: find by text/role/label/testId, press/type/submit/toggle/ select that resolve once the panel settles, tree() snapshots, errors (with stacks) and warnings, persisted state (with stored() for migrations), emit/setVisible/rerender, and unmount running setup cleanup. It re-exports node:test and strict assert so tests type-check without @types/node. - mockHost refuses what Orca refuses with the same codes (surface, capability from the manifest, params, a gesture method without a press), checks configured results against the host API, and records calls. - `orca plugin test [dir]` discovers *.test.ts(x) and runs them with node:test through Node module hooks that resolve `orca` like the guest's import map and transpile/resolve sources exactly as Orca's build-less loader, or with the plugin's own vitest via a generated config. - `orca plugin check [dir]` validates, then renders each components panel once and reports what it threw (file:line), layouts Orca would refuse, and props it would drop. - The kit, hooks and register entry ship minified beside orca-runtime.mjs and are unpacked from asar; typings land in .orca/types/orca-testing. The components template and hello-tsx get sample tests. - ui.error carries an optional stack; a new runtime starts every atom from its initial value; the hydration fallback timer is cleared once hydrated. * plugins: run plugin test/check on a system Node or Orca's own, and warn they are unsandboxed * test(plugins): run the shipped example plugin tests from the unit suite |
||
|
|
4ee788a725 |
Build-less TS/TSX plugins, typings and authoring tools (#36918)
* feat(plugins): build-less TS/TSX plugins, typings and authoring tools - Plugin frames transpile .ts/.tsx/.mts/.jsx on load (sucrase on a shared worker thread with a 2 s budget, cached in main), resolve relative imports to exact files, and refuse bare package imports by name. Components and html panel/editor entries may be .ts/.tsx. - orca plugin types writes typings for the components orca module, window.orca, worker activate(orca), host.call and events into .orca/types, from one host-typings generator. - orca plugin create --template components; templates omit publisher and target 1.4.246. - orca plugin release-entry, dev inspect and restart; validate:plugin checks named files. - Guest console errors reach orca plugin logs; dev workers restart on edits; the dev watcher ignores .git, .orca and node_modules; Git and folder installs cannot replace catalog installs. - examples/plugins/hello-tsx, docs, and the plugin-buildless-tsx e2e spec. * ci: run the Windows parity probes with one tsgo checker tsconfig.node peaks near 22 GB with tsgo's default four checkers (each holds its own types) and about 16 GB with one; the 16 GB Windows runner paged the native probe past its 900 s timeout once this branch's package.json change triggered the job. One checker gives the same diagnostics (verified locally with --parity-only); the timing benchmark is unchanged. |
||
|
|
7df246b9d1 | feat(plugins): components (TSX) plugin panels (#36814) | ||
|
|
fdc03848a5 |
fix(plugins): protect every security and destructive string from language packs (#36219)
* fix(plugins): protect every security and destructive string from language packs Language packs could rewrite trust copy outside a hand-kept list of app areas (catalog-link dialog, browser-extension Allow/Deny, Node mirror). Protected keys are now generated from structure: every key in a file that renders a security surface, a destructive confirmation, or a native message box, or that carries a // @protected-copy pragma, plus same-directory copy modules. verify:localization-catalogs fails when the list is stale. Pack strings are also capped at max(64, 4x English) characters and may not contain control or bidi characters. Validation stays strict; loading drops only the offending entries. * chore(plugins): resync protected copy keys with main * fix(plugins): cap pack strings in shared strict checks and pin new trust copy * fix(plugins): keep the packaged CLI off the English catalog * chore(plugins): resync protected copy keys with main * chore(plugins): resync protected copy keys with main |
||
|
|
f586149b3d |
chore(deps): update Electron to 43.8.4 (#36323)
Picks up File System Access blocklist and asar hardening fixes. 43.8.4 is excluded from minimumReleaseAge since it was published under 3 days ago. |
||
|
|
15023ab339 |
fix(editor): match Unicode heading anchors across rich and preview modes (#35077)
* fix(editor): match Unicode heading anchors across rich and preview modes * test(editor): drop slugger tests that only re-test github-slugger The preview-parity test in markdown-anchor-scroll.test.ts covers the behavior that matters. --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
19f6c10c3f |
perf(renderer): drop group-has-[:focus-visible] rules that restyle whole subtrees (#36098)
Fixes #34312. Takes over naufaldi/orca#1 by @naufaldi, with the main.css part dropped because #34932 already covers it. - SshTargetCard and the reasoning chevron now use the scoped `[[class~='group/x']:has(:focus-visible)_&]` shape. Tailwind's `group-has-*` compiles to a non-subject `:has()` whose subject is `*`, and that rule made Blink restyle whole subtrees on every mutation. This change is the entire measured win: 19.4 → 1.6 ms, 12.5 → 3.6 ms and 8.0 → 2.4 ms per mutation. - rich-markdown-editor.css drops a redundant `:has()` on the TOC header, as defence in depth. - Adds a guard, check-has-restyle-scope.mjs. It compiles the renderer's Tailwind CSS, adds plain stylesheets and the listed vendor stylesheets, and fails on any non-subject `:has()` whose subject has no class, id or attribute. Three pdf.js rules are baselined after being measured as harmless. It runs in lint, check:changed and PR CI in about 1.5 s. Co-authored-by: Naufaldi <naufaldi.rafif@gmail.com> |
||
|
|
5834a3dcfd |
fix(browser): agent clicks keep their target when a page changes, by upgrading agent-browser to 0.39.4 (#36007)
* chore(browser): upgrade bundled agent-browser to 0.39.4 0.39.4 keeps refs stable across snapshots and refuses stale or hidden click targets. Its replies now carry daemon lifecycle bookkeeping, which is dropped where the JSON is parsed, and its tarball binaries lose the executable bit pnpm's skipped postinstall used to restore, so the orcad dev resolver now restores it like the desktop one. * fix(browser): keep orcad's Chromium unbounded and read 0.39's stale-ref error * fix(browser): import the shared stale-ref rule in orcad and keep the parser typed * fix(browser): keep workers and frames running after the agent-browser helper leaves agent-browser 0.39 asks auto-attached targets to wait for it before starting. The proxy forwards that onto the guest's shared debugger, which outlives the helper, so after the helper's idle exit nothing resumed new workers or frames. |
||
|
|
ec58374a4c |
fix(browser): Orca's own buttons and links open per the open-links-in-Orca setting (#35992)
* fix(browser): every web link in Orca follows the open-links-in-Orca setting * test(browser): pin where links from Orca UI open * fix(browser): keep the link-routing escape modifier and owning workspace on UI links Credential and star links stay in the system browser; shared markdown keeps its owner-aware routing. * fix(browser): hover cards and review toasts open links in their own workspace API-key and console pages stay in the system browser; non-web hrefs are ignored like the system bridge does. * fix(browser): UI link wrappers pass the click so the escape modifier applies Share to X stays in the system browser with the other account-action pages. * fix(browser): folder workspace PR-check links open in the folder workspace * test(browser): name UI link tests after the path they exercise * chore(browser): keep the link-open ratchet's helpers private * fix(browser): narrow the Linear project toast link before routing it * fix(browser): UI links route with this desktop as their source owner Links from Orca's own UI no longer read the Active Server setting; the opener routes by the host workspace. * fix(browser): UI links open under the host workspace's own owner A remote workspace's browser gets the original URL, not this desktop's localhost label. * fix(native-chat): read browser route eligibility from its owner module Importing it through workspace-browser-tab-open pulled the store into every link button and formed an import cycle. |
||
|
|
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>
|
||
|
|
12a7d4c13a |
feat(mobile): localization infrastructure and language setting (#35399)
* feat(mobile): add UI localization infrastructure Mobile follows the phone's language (or an in-app choice under Settings > Appearance) across the same 11 languages as desktop, switching live like the theme does. - i18next with desktop's translate(key, fallback, options) call shape; catalogs in mobile/src/i18n/locales load lazily, English fallbacks stay inline - Hermes lacks Intl.PluralRules: load the FormatJS polyfill with the 11 languages' rules - OTA pages get the shell's language through an optional bridge init field - iOS permission prompts localized; iOS and Android 13+ per-app language pickers - verify:mobile-localization and a coverage ratchet run in lint, check:changed and CI * fix(mobile): mount pages after the newest language request; tighten localization gates - Wait for the latest page language activation, not a superseded one - Keep literal fallbacks when a key also has a dynamic one - Count headerTitle as visible copy; select the mobile check when the runtime catalog generator changes * feat(mobile): repaint themed components on language changes Components that read the theme already subscribe for repaint; a language switch repaints them too, so labels built by helpers during render follow it. RPC recordings load the real i18next and JSON catalogs. * fix(mobile): scope the translate() gate to render bodies and memos; prune stale keys on sync Handlers and effects may call translate() when they run. sync:mobile-localization now removes keys no code references from every catalog. * fix(mobile): use node: imports in the locale config plugin; pass uiLocale in bridge hook test * chore(mobile): refresh the localization coverage baseline * fix(mobile): follow render callbacks in the translate() gate; keep used plural siblings on prune Also let anonymous default-exported screens count as components, flag any plural family a locale started, and mark JSON modules as ES modules in the recording loader. * fix(mobile): treat async and named local callbacks as handlers in the translate() gate * chore(mobile): refresh the localization coverage baseline * chore(mobile): refresh the localization coverage baseline --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
18b5ee3a4f |
fix(i18n): re-render memoized translated UI on language changes (#35358)
* fix(i18n): re-render memoized translated UI on language and catalog changes Memoized components and useMemo/module caches that call translate() kept the previous language after a switch or a plugin language-pack reload, because react-i18next only re-renders components that subscribe themselves. Add useUiLanguageRevision() (language + catalog revision via useSyncExternalStore), call it in the 34 memoized translating components, key translated useMemo results and module caches on it, and add a ratchet so new memoized translating components must subscribe. Fixes the composer pickers reported in #34783. Co-authored-by: Vyacheslav Scherbinin <14369958+gentslava@users.noreply.github.com> * fix(i18n): drive the language revision from the resource version Tests that mock @/i18n/i18n have no i18n instance, so subscribe through translation-resource-version (now also bumped on languageChanged) and give useSyncExternalStore a server snapshot for renderToString tests. --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Co-authored-by: Vyacheslav Scherbinin <14369958+gentslava@users.noreply.github.com> |
||
|
|
f80a3ccefb |
fix(i18n): upgrade i18next to 26.5.11 and react-i18next to 17.0.19 (#35335)
Picks up the GHSA-5jr9-983r-c8x4 nesting-regex ReDoS fix (26.4.4), the placeholder-injection fix for interpolated values (26.5.4), and react-i18next's useTranslation resubscribe/stale resolvedLanguage fixes. Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
7c57ad6a55 |
Reuse equations while chat replies stream (#34819)
* perf(chat): typeset each unchanged formula once instead of on every streamed update A streaming paragraph or list re-parses on each revealed prefix, and every complete formula in it went through KaTeX again, as did every formula on a virtual-row remount. Keep a bounded cache of typeset results keyed by what the typesetter reads (tag, math classes, formula text), hand each tree its own copy, and remember failures so invalid formulas still show their source. * test(chat): import the typeset module type at the top of the math test * fix(chat): evict the oldest cached formula without a type assertion * fix(chat): type the readable math fallback without an assertion * Cache immutable math results with bounded retention |
||
|
|
7cdfebdc1b |
Revert iteration checks and custom Vitest selection (#34834)
* revert: remove iteration checks and custom Vitest selection * chore: use upstream affected-test selection --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |
||
|
|
0866cb1b08 |
fix: bound local iteration checks and show live progress (#34700)
* fix: bound local iteration checks and show live progress * fix: harden check lifecycles and cached test evidence * fix: preserve process instrumentation and fixture lifecycles * fix: give fixture unref spy a portable function type --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> |