Commit Graph
6 Commits
Author SHA1 Message Date
Neil 36f17a04a7 plugins: Box layout container for components panels (catalog 4) (#37420)
- Box (ui.catalog 4, since 1.4.248): direction, gap/padding/paddingX/
  paddingY/margin on the gap scale, align, justify, wrap, grow, shrink,
  width/height/min/max (px up to 4096 or whole percents), columns,
  scroll, border (true or a tone), radius, background (theme surfaces or
  tone tints). Strict props: hex colours, CSS lengths and unknown props
  are dropped with a warning like other components.
- Renderer maps props to theme tokens through data attributes; sizes
  reach inline style only as validated px or percents.
- Typings, docs, skill references, gallery Layout tab; orca/testing
  finds Boxes and summarizes danger or warning Boxes.
2026-11-02 01:05:57 -08:00
Neil fa7c3f95fe feat(plugins): check custom editors and test them with mockEditorHost (#37293)
* feat(plugins): check custom editors statically and add mockEditorHost

orca plugin check now follows each custom editor entry (local script src,
inline module scripts, relative imports), transpiled and resolved as the
frame loader does, and fails at file:line:column on syntax errors, missing
files, refused imports, string eval/Function and files over their size
cap, with no running Orca. The check ships in the test hooks bundle.

orca/testing gains mockEditorHost: it runs the frame shell's real
window.orca (document API and session) over an in-memory text or bytes
file, with edits, replace, conflictNext, flush, setTheme and dispose.
Typings, docs and the skill guide cover both.

* feat(plugins): warn on editor eval and check editors in dev watch

editor_eval comes from a lexical scan that can misread rare code, so it is
now a warning that does not fail orca plugin check. dev watch --check runs
the editor check beside the panel check and reports it under editors.

* fix(plugins): check editors by the frame protocol's rules; mock blocks lost saves

The static editor check now reads files through the loader's contained
reader (symlinks out of the plugin are refused), runs only JavaScript
script types, honors the page's import map for native modules, classifies
files by the protocol's content types (JSON imports, extensionless HTML
entries), decodes escaped script URLs, and uses the protocol's caps: 10 MiB
entry, 1 MiB transpiled module, 16 MiB checked dependency.

mockEditorHost refuses an oversized edit before reading it and then rejects
flush() until a later edit lands, as Orca blocks the save.

* test(plugins): type mockEditorHost's frame API instead of reflecting on it

* fix(plugins): keep main's case-spelling check and hook typings through the rebase

The rebase onto main resolved plugin-artifact-validation.ts and
orca-testing.d.ts to B4's side; this puts back main's exact-path-spelling
check and hooks typings beside B4's contained reader and mockEditorHost
types, and regenerates the testing bundle.
2026-11-01 21:28:13 -08:00
NeilandClaude ac8c1125f0 feat(plugins): hooks that can change or block terminal sends and workspace creation (#37287)
* plugins: contributes.hooks runtime with terminal.send and workspace.create hooks

Workers register orca.hooks.on(hook, (event, next) => ...). Orca runs listed
plugins in order before it acts: next(event) continues with allowed fields
changed, { deny } stops, nothing passes. A plugin past its 2 s deadline, or
one that throws, crashes or is disabled, counts as passing and is logged with
plugin, hook and duration. First hooks: terminal.send (runtime sendTerminal),
workspace.create.before (IPC and runtime creates, folders included) and
observe-only workspace.create.after. orca/testing mountWorker gains
hooks.fire. Needs main + trusted-worker and engines.orca >=1.4.248.

Co-Authored-By: Claude <noreply@anthropic.com>

* plugins: keep hook plugins' workers started; bound start-up separately from the hook deadline

Workers of enabled plugins that list hooks start as soon as they are approved
and are never idle-reaped; crash restarts follow the manager's policy. A hook
waits up to the worker ready timeout for start-up, then gives the handler its
full 2 s, so a cold worker no longer lets the first hooked action through.

Co-Authored-By: Claude <noreply@anthropic.com>

* plugins: give hook workers their own soft cap instead of the active-worker cap

Always-running hook workers no longer hold slots of the shared 5-worker cap, so
many hook plugins cannot starve the rest. They have a soft cap of 16; past it a
hook worker waits for another to stop, logged once.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(plugins): type the hook warmer's ensureWorker mock

* plugins: address hook review: ordering, human input, overflow, revalidation, folder creates

- Hook workers past the soft cap start as overflow (logged once) instead of
  waiting, so reconciliation, disable and uninstall never hang.
- Writes to one terminal stay in order while terminal.send decides, so a later
  Enter cannot submit the previous line.
- terminal.send runs only for programmatic sends (main, plugins, the CLI);
  desktop, mobile and legacy client input is a person's typing.
- Text a hook rewrote passes the AI Vault resume check again.
- Project-group folder workspace creates (RPC, agent launch, window) run the
  workspace.create hooks through one boundary.
- A decision from a plugin disabled or changed while it ran is discarded.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(plugins): drive hook start-up timing with fake-timer deferreds, no real sleeps

Co-Authored-By: Claude <noreply@anthropic.com>

* plugins: only the hook decision holds a terminal's write order

A delivery that waits (a permission prompt, the launch composer) no longer
blocks later writes, and a person's input, interrupts and query replies never
wait behind a pending decision.

Co-Authored-By: Claude <noreply@anthropic.com>

* plugins: hook DX: onError deny, denied_by_plugin, a Hooks reference, --template hook

- contributes.hooks[].onError: "deny" makes a throw, timeout, crash or bad
  answer refuse the action, naming the plugin; the default still passes.
  orca/testing mountWorker honours it, and mockHost answers fire-and-forget
  methods (result { ok: true }) with success by default.
- A plugin denial reaches RPC clients as denied_by_plugin with the plugin and
  reason, and the CLI no longer suggests a retry for it.
- The skill's host-api reference gains a generated Hooks section (event, what
  next may change, stop result); the recipe passes sends through unchanged and
  warns against awaiting other calls before deciding.
- orca plugin create --template hook: a worker-only terminal.send guard that
  fails closed, with a test.

Co-Authored-By: Claude <noreply@anthropic.com>

* plugins: regenerate hook docs on main; bind the plugin runtime and its hook runner in one call

Keeps main-process-plugins.ts under 300 lines now that status bar items landed.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-01 21:12:57 -08:00
Neil ce8ea081c0 Plugin check shows what drew; responsive Table columns; quieter Table and Stack (#37062)
* plugins: check shows what drew; responsive Table columns; quieter Table and Stack

- orca plugin check: each scenario result carries a summary (headings,
  callouts, empty states, table and tree sizes, the selected tab, loading
  placeholders, danger/warning text), printed under its line, and --json
  adds the drawn tree. dev watch's check event keeps only the summary.
  orca/testing gains panel.summary().
- Table columns take minWidth (floor for an auto column) and hideBelow
  ('sm' 360px, 'md' 480px), measured on the table itself; at least one
  column stays. Cut-off cells and headers show their text on hover. The
  kit's columnsOf(table, { width }) answers which columns fit.
- The active-row ring shows only while the grid has keyboard focus.
- A Stack with no align keeps buttons at their own width while fields,
  tables and cards still fill it; align='stretch' stretches everything.
- Typings, docs, the skill's workflow reference, regenerated references;
  the gallery's Kind column drops out in a narrow sidebar.

* plugins: check can render one scenario and return its drawn tree

For orca plugin shot --scenario (tree replay): checkPluginPanels takes
{ panel, scenario, drawnTree }, and with drawnTree returns each render's
validated tree exactly as Orca draws it (handlers as { $callback }),
re-validated on the CLI side. An unknown scenario is reported as an issue.
readPluginCheckScenarioNames(dir, entry) lists a panel's scenarios by
loading its .check file without mounting anything.
2026-11-01 09:07:14 -08:00
Neil 8503ecda71 plugins: check runs the worker and scenarios; RelativeTime (#37047)
- orca plugin check mounts the plugin's worker (main) on the same mock host
  as each panel, so plugin.request reaches its orca.panels.handle handlers
  as in Orca; a worker that fails to activate or deactivate is an issue
  named after its file. In orca/testing, a worker mounted on a host answers
  that host's panel requests unless `requests` stubs the name.
- Check scenarios: <entry>.check.ts (e.g. src/panel.check.ts) exports
  defineCheck({ name: { ...mockHost options, persisted, theme, events } });
  check renders the panel once per scenario and labels each result.
- RelativeTime (catalog 3, since 1.4.247) and { type: 'relative', at } Table
  cells: Orca ticks them (each second under a minute, then less often), so
  plugins never poll. Inline inside Text; test kit reads them as drawn.
- Typings, docs, skill guide, generated references; gallery shows it.
2026-11-01 06:56:19 -08:00
Neil e5b87cb8e6 Components catalog 2 and worker tests: forms, tabs, table, tree, markdown, code, images (#36997)
* plugins: components catalog 2 (forms, tabs, table, tree, markdown, code, images)

Adds 18 components to TSX components panels, drawn with Orca's own
primitives and gated by ui.catalog 2 / ui.has() (Orca 1.4.247):
Textarea, Checkbox, RadioGroup, Slider, Field, Tabs/Tab, Collapsible,
Toolbar, Grid, a virtualized Table with sort, selection and pull-based
paging, a keyboard Tree with lazy children, Markdown (sanitized, links
through the checked open path), CodeView (Orca's highlighter), Image
(header-checked plugin files read by main), KeyValue, Callout and
Skeleton, plus a tooltip prop on Button and IconButton.

Value controls share the edit protocol; handlers get plain JSON event
args, including small objects ({ keys }, { key, expanded }). The test kit
gains matching actions and hides unselected tabs and closed collapsibles;
a components-gallery example and e2e cover the catalog end to end.

* plugins: worker test harness, host refusals in tests and check

- orca/testing gains mountWorker(main, { host, events, commands }): it calls
  the default-exported activate(orca) with the orca object Orca itself builds
  (createPluginWorkerOrcaApi, moved to shared so the kit reuses it), backed by
  mockHost. emit() checks payloads against Orca's event schemas and only
  delivers subscribed events; command(), request() (the worker's
  orca.panels.handle, as a panel's plugin.request), posts, logs, refusals and
  deactivate(). Storage and settings share the mock host's in-memory store.
- orca plugin test loads a worker main's module graph as Orca's worker host
  does (.ts/.mts transform, Node resolution, no runtime orca import).
- mockHost records refusals (capability_denied, not_permitted, ...) even
  when plugin code catches them; panel.refusals exposes them and
  orca plugin check reports them as warnings. Check dedupes repeated issues.
- Typings, docs and a generated references/testing.md skill reference; the
  reference generator reads the split orca typings.
2026-11-01 05:43:15 -08:00