2 Commits
Author SHA1 Message Date
Juan Denis ee152eb1bd feat(search): add resource picker contract 2026-08-21 09:20:54 -04:00
Juan DenisandClaude Opus 5 2a0b4ca029 feat(plugins): let extensions put their objects in global search
The omnisearch fan-out was a hardcoded sequence of core entity blocks, so an
extension's objects were absent from the command palette — the one place the
UI tells you to look. A plugin now registers a provider and its rows appear
alongside services, servers and domains, with no frontend change: the palette
already renders unknown types, bucketing them under "Results".

Scoping stays the provider's job, because search invents no ACL — every core
block scopes its own query and the provider is handed the user and workspace
to do the same. The shape, though, is not trusted:

- rows are always tagged with the registered type, so a plugin cannot mint a
  row that claims to be a 'service' or a 'vault' (which are trusted to have
  been scoped by core);
- the per-type cap is re-applied host-side rather than trusted from the
  provider, so one contributed type can't drown the core ones;
- a path must be an in-app router path. The palette hands it straight to
  navigate(), so a protocol-relative '//host' would walk the user off the
  panel entirely.

A malformed row is dropped on its own, a broken provider degrades to "no rows
of that type" — the same isolation each core block already has.

The lazy accessor in plugins_sdk now carries a table of surfaces rather than a
single special case for deploys, since the other SDK surfaces land the same way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 13:40:00 -04:00