Skip to content

sync: plugin UI, desktop bridge, and chat launchers - #117

Merged
Luhaozhu merged 2 commits into
mainfrom
sync/ce-2026-08-23
Aug 23, 2026
Merged

sync: plugin UI, desktop bridge, and chat launchers#117
Luhaozhu merged 2 commits into
mainfrom
sync/ce-2026-08-23

Conversation

@Luhaozhu

@Luhaozhu Luhaozhu commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Community edition sync from the development tree.

Plugin-declared UI contributions

A plugin can now describe its entire front end in plugin.json, under the
extensions["org.hugagent"].ui namespace, and the host renders straight from
that declaration. The host render path no longer branches on any plugin or
tool name, so disabling or uninstalling a plugin removes its interface on the
next refresh with no host change.

  • View librarysrc/frontend/src/plugin-ui/ ships 19 views in three
    groups (document, analytic, container/interactive), one file per view behind
    a single registry.ts extension point, with a README on adding more.
  • Declarations are data, not code — field mapping goes through a
    whitelisted pointer evaluator that rejects subscripts, expressions and
    statement injection, and reads own properties only.
  • Fail-soft parsing — a malformed contribution is dropped on its own and
    reported in the import result instead of blocking the install; a ui.version
    newer than the host supports is ignored as a whole.
  • Data proxy — credentials are interpolated on the server and the browser
    only ever holds a source id. Hosts configured by an administrator are
    allowed, while all other upstreams must use public HTTPS.
  • Plugin-supplied front-end modules — served from the plugin package with
    connect-src 'none' and path traversal rejected, rendered in an iframe
    sandboxed as allow-scripts without allow-same-origin.

Desktop capability bridge

Bridge injection moved into the catalog resolver, the single source of truth
for resolving enabled capabilities, so scheduled jobs, batch sub-agents, job
wake-ups and plan mode all use the same assembly path. Cloud gateway
configuration became an explicit bridge_servers argument with a documented
override order. Per-user effective configuration is cached for 30 seconds, and
the gateway route no longer holds a database connection while forwarding a
stream.

Chat launchers

  • Typing @ now opens a structured launcher for available files, agents, plan,
    batch, workflow, and loop actions, with direct agent filtering in the second
    level.
  • Typing / groups modes, plugins, and skills and shows descriptions to make
    command discovery easier.
  • Keyboard handling now ignores Enter and Tab when no candidate is available,
    and entering the agent picker clears the launcher query without removing the
    mention marker.
  • The English and Chinese chat guides document both launchers and their
    keyboard controls.

Fixes and hardening

  • UI contributions are back-filled at startup for already-installed built-in
    plugins, so an upgrade does not leave the declared views missing.
  • Contribution resolution is batched, authorization is checked per slug, the
    data proxy uses a shared HTTP connection pool, and registry lookups are
    memoized.
  • Shared plugin UI strings are registered in the common dictionary.

Checks

scripts/build_ce.py ran on the final clean commit with import, release, and
front-end self-checks enabled. All gates passed: brand gate (0 text hits and a
full path scan), required-runtime-file gate, forbidden-artifact gate, binary
asset allowlist, LICENSE gate, backend import/OpenAPI/ORM checks, CE release
regression tests, and the front-end i18n, dark-mode, TypeScript, and Vite build
checks.

Plugin UI contributions
- Plugins now declare their whole front end in plugin.json under
  `extensions["org.hugagent"].ui`. The host renders from the declaration,
  so no host code branches on a plugin or tool name any more: disabling or
  uninstalling a plugin makes its UI disappear on the next refresh.
- New shared view library under `src/frontend/src/plugin-ui/`: 19 views in
  three groups (document, analytic, container/interactive), one file per
  view behind a single `registry.ts` extension point. Charts are hand-drawn
  SVG primitives on purpose — pulling in a chart library would let the
  contract decay into chart-library DSL passthrough.
- Field mapping uses a whitelisted pointer evaluator, never expressions:
  declarations are data, not code. Own-property reads only, so prototype
  members such as `constructor` are unreachable.
- Contribution parsing is fail-soft per entry: one malformed contribution is
  dropped and reported instead of blocking the install, and a `ui.version`
  above what the host supports is ignored as a whole.
- Two generic endpoints back it: a server-side data proxy (credentials are
  interpolated on the server, the browser only ever sees a source id, and
  SSRF policy allows hosts an administrator already configured while
  requiring public HTTPS otherwise) and a static asset route for
  plugin-supplied front-end modules (CSP `connect-src 'none'`, path
  traversal rejected).
- Plugin-supplied modules run in an iframe sandboxed with `allow-scripts`
  and without `allow-same-origin`; the postMessage bridge authenticates on
  `event.source` rather than `event.origin`, which is always "null" there.

Desktop capability bridge
- Bridge injection moved down into the catalog resolver, the single source
  of truth for resolving enabled capabilities, so scheduled jobs, batch
  sub-agents, job wake-ups and plan mode all take the same assembly path.
- Cloud gateway configuration is now an explicit `bridge_servers` argument
  with a written-down override order (global < bridge < owned).
- Per-user effective configuration is cached for 30s so the gateway no
  longer re-queries owned servers on every tool call, and the gateway route
  no longer holds a database connection while streaming.

Fixes and hardening
- Back-fill UI contributions for already-installed built-in plugins at
  startup, so upgrades do not leave the column NULL and the declared views
  missing.
- Hot-path work: batched contribution resolution (1+N queries down to 2),
  per-slug authorization instead of enumerating every installed plugin,
  a shared HTTP connection pool in the data proxy, and memoized front-end
  registry lookups so streaming no longer re-renders the whole view subtree.
- Register the three plugin-ui strings in the shared dictionary: the views
  that use them are shared code, so an edition-only dictionary left them
  untranslated here.
- Cross-language test pinning that the view kinds accepted by the backend
  and registered in the front end cannot drift apart.
@Luhaozhu Luhaozhu changed the title sync: plugin-declared UI contributions, desktop capability bridge sync: plugin UI, desktop bridge, and chat launchers Aug 23, 2026
@Luhaozhu
Luhaozhu merged commit fb7a726 into main Aug 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant