1 Commits
Author SHA1 Message Date
Juan DenisandClaude Opus 5 047e69501a feat(plugins): let extensions run commands on the fleet
Everything an extension could do stopped at the machine the panel runs on,
which is at odds with a product built around a fleet of servers. A plugin can
now run an agent command and get its result back.

This is also where agent.command:<action> starts meaning something. The
manifest permission has existed as a declaration — collected in the manifest,
surfaced at install time for consent — with nothing enforcing it, because
plugins called the agent registry directly. Dispatching through the SDK checks
it first, matched verbatim, so a plugin can only run the actions it asked the
operator for by name. The one bundled extension that uses agent commands still
calls the registry directly; retrofitting it onto this is a follow-up.

Nothing underneath is re-implemented: the per-server ACL still decides whether
that server permits the action, and the ServerCommand audit row is still
written — pass user_id so it names a person rather than "the panel".

Three things the wrapper adds over a bare send_command:

- it unwraps the double envelope. A transport-successful reply can carry a
  handler failure inside, which reads as success to anyone checking only the
  outer flag.
- it fails before dispatch on an offline agent or a missing capability, so the
  caller gets a reason instead of an unknown-action error from the far side.
- the default timeout is 45s rather than the registry's 30s. An agent on the
  HTTP long-poll fallback can sit ~25s before it even sees the command, which
  leaves a 30s budget almost no room to actually run anything.

Failures raise with a .code, so a plugin can tell an offline agent from a
refused one from a timeout, and map them to its own HTTP responses.

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