Skip to content

feat(console): runtime-injectable worker UI with per-worker toggles - #570

Merged
sergiofilhowz merged 3 commits into
mainfrom
feat/injectable-ui
Jul 23, 2026
Merged

sergiofilhowz merged 3 commits into
mainfrom
feat/injectable-ui

Conversation

@sergiofilhowz

Copy link
Copy Markdown
Contributor

Workers now ship UI into the running console at runtime — React pages, function-trigger renderers, config-form overrides, and scoped stylesheets — over three new trigger types (console:script, console:style, console:assets). No console rebuild, hot reload on re-registration, teardown on disconnect.

Best part: the console dogfoods its own protocol. The Workers tab's Console entry renders a toggle board — itself injected UI — to enable or disable each worker's injected UI. Saving applies live: every open tab drops or restores the affected assets, no restarts anywhere.

The entire worker side is one builder call:

ConsoleUi::new("state")
    .script("state/page.js", include_str!("../ui/dist/page.js"))
    .style("state/styles.css", include_str!("../ui/dist/styles.css"))
    .register(&iii);

New libraries:

  • iii-console-ui (crates/console-ui) — Rust crate owning the worker-side contract: content function, Message-path triggers, hot-reload watcher. Path-linked, never published.
  • @iii-dev/console-ui (packages/console-ui) — typed setup(host) surface plus the console's shared component library; adds zero bytes to worker bundles (resolved at runtime through the console's import map).

Authoring guide: docs/sops/injectable-console-ui.md

@vercel

vercel Bot commented Jul 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment Jul 23, 2026 1:51pm
workers-tech-spec Ready Ready Preview, Comment Jul 23, 2026 1:51pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 157 files, which is 57 over the limit of 100.

To get a review, narrow the scope:
• coderabbit review --committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1f05aa62-378b-4c3b-bee2-8262281179fa

📥 Commits

Reviewing files that changed from the base of the PR and between fd99b20 and ac14045.

⛔ Files ignored due to path filters (4)
  • console/Cargo.lock is excluded by !**/*.lock
  • crates/console-ui/Cargo.lock is excluded by !**/*.lock
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • state/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (158)
  • .github/scripts/discover_changed_workers.py
  • .github/scripts/tests/test_discover_changed_workers.py
  • .github/workflows/_rust-binary.yml
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • console/Cargo.toml
  • console/README.md
  • console/build.rs
  • console/src/assets.rs
  • console/src/config.rs
  • console/src/configuration.rs
  • console/src/functions/mod.rs
  • console/src/lib.rs
  • console/src/main.rs
  • console/src/proxy.rs
  • console/src/server.rs
  • console/src/ui.rs
  • console/src/ui_assets.rs
  • console/tests/integration.rs
  • console/ui/build.mjs
  • console/ui/config-form.tsx
  • console/ui/package.json
  • console/ui/src/injectable-ui-form/index.tsx
  • console/ui/styles.css
  • console/ui/tsconfig.json
  • console/web/biome.json
  • console/web/index.html
  • console/web/package.json
  • console/web/pnpm-workspace.yaml
  • console/web/public/vendor/console-ui.js
  • console/web/public/vendor/jsx-runtime.js
  • console/web/public/vendor/react-dom-client.js
  • console/web/public/vendor/react-dom.js
  • console/web/public/vendor/react.js
  • console/web/scripts/generate-vendor-shims.mjs
  • console/web/src/App.tsx
  • console/web/src/components/chat/ChatView.tsx
  • console/web/src/components/chat/FunctionTriggerGroup.stories.tsx
  • console/web/src/components/chat/FunctionTriggerGroup.tsx
  • console/web/src/components/chat/FunctionTriggerMessage.stories.tsx
  • console/web/src/components/chat/Message.tsx
  • console/web/src/components/chat/MessageList.tsx
  • console/web/src/components/chat/browser/index.tsx
  • console/web/src/components/chat/coder/index.tsx
  • console/web/src/components/chat/directory/index.tsx
  • console/web/src/components/chat/engine/index.tsx
  • console/web/src/components/chat/fp/index.tsx
  • console/web/src/components/chat/harness/index.tsx
  • console/web/src/components/chat/router/index.tsx
  • console/web/src/components/chat/sandbox/index.tsx
  • console/web/src/components/chat/scrapling/index.tsx
  • console/web/src/components/chat/shell/index.tsx
  • console/web/src/components/chat/state/__tests__/view.test.tsx
  • console/web/src/components/chat/state/index.tsx
  • console/web/src/components/chat/web/index.tsx
  • console/web/src/components/chat/worker/index.tsx
  • console/web/src/components/chat/workflow/index.tsx
  • console/web/src/components/function-trigger/FunctionTriggerCard.test.ts
  • console/web/src/components/function-trigger/FunctionTriggerCard.tsx
  • console/web/src/components/function-trigger/renderer-registry.tsx
  • console/web/src/components/permissions/PermissionModePicker.tsx
  • console/web/src/components/ui/EmptyState.tsx
  • console/web/src/hooks/use-browser-status.ts
  • console/web/src/hooks/use-conversations.test.ts
  • console/web/src/hooks/use-conversations.ts
  • console/web/src/hooks/use-hash-route.ts
  • console/web/src/index.css
  • console/web/src/lib/backend/approval-events-live.ts
  • console/web/src/lib/backend/approval-settings.ts
  • console/web/src/lib/backend/real.ts
  • console/web/src/lib/backend/translate.test.ts
  • console/web/src/lib/backend/translate.ts
  • console/web/src/lib/backend/types.ts
  • console/web/src/lib/browser.ts
  • console/web/src/lib/chat-activity.test.ts
  • console/web/src/lib/chat-activity.ts
  • console/web/src/lib/console-api.ts
  • console/web/src/lib/console-ui-conformance.test.ts
  • console/web/src/lib/export-session.test.ts
  • console/web/src/lib/export-session.ts
  • console/web/src/lib/function-trigger-copy.test.ts
  • console/web/src/lib/function-trigger-copy.ts
  • console/web/src/lib/markdown.tsx
  • console/web/src/lib/sessions/entry-mapper.test.ts
  • console/web/src/lib/sessions/entry-mapper.ts
  • console/web/src/lib/token-estimate.test.ts
  • console/web/src/lib/token-estimate.ts
  • console/web/src/lib/ui-loader.tsx
  • console/web/src/lib/ui-slots.ts
  • console/web/src/main.tsx
  • console/web/src/pages/Configuration/tabs/WorkersTab/WorkerEditor.tsx
  • console/web/src/pages/Ext/index.tsx
  • console/web/src/pages/TracesV2/components/SpanInfoTab.tsx
  • console/web/src/pages/TracesV2/fixtures/traces-fixtures.ts
  • console/web/src/pages/TracesV2/lib/functionTriggerFromSpan.test.ts
  • console/web/src/pages/TracesV2/lib/functionTriggerFromSpan.ts
  • console/web/src/pages/TracesV2/lib/spanLabel.ts
  • console/web/src/pages/TracesV2/lib/timelineSpans.ts
  • console/web/src/pages/TracesV2/lib/traceTimelineFilters.ts
  • console/web/src/pages/TracesV2/stories/SpanTabs.stories.tsx
  • console/web/src/stories/fixtures/coder-fixtures.ts
  • console/web/src/stories/fixtures/directory-fixtures.ts
  • console/web/src/stories/fixtures/engine-fixtures.ts
  • console/web/src/stories/fixtures/fp-fixtures.ts
  • console/web/src/stories/fixtures/harness-fixtures.ts
  • console/web/src/stories/fixtures/router-fixtures.ts
  • console/web/src/stories/fixtures/sandbox-fixtures.ts
  • console/web/src/stories/fixtures/scrapling-fixtures.ts
  • console/web/src/stories/fixtures/shell-fixtures.ts
  • console/web/src/stories/fixtures/state-fixtures.ts
  • console/web/src/stories/fixtures/web-fixtures.ts
  • console/web/src/stories/fixtures/worker-fixtures.ts
  • console/web/src/stories/fixtures/workflow-fixtures.ts
  • console/web/src/stories/fixtures/worktree-fixtures.ts
  • console/web/src/stories/playground/scenarios/error-on-fcall.ts
  • console/web/src/stories/playground/scenarios/multi-function-agent.ts
  • console/web/src/stories/playground/scenarios/pending-approval.ts
  • console/web/src/types/chat.ts
  • console/web/src/types/iii-agent-event.ts
  • console/web/src/types/injectable-ui.ts
  • console/web/vite.config.ts
  • crates/console-ui/Cargo.toml
  • crates/console-ui/README.md
  • crates/console-ui/src/lib.rs
  • docs/sops/README.md
  • docs/sops/injectable-console-ui.md
  • harness/engine.config.yaml
  • package.json
  • packages/console-ui/README.md
  • packages/console-ui/component-names.d.mts
  • packages/console-ui/component-names.mjs
  • packages/console-ui/index.d.ts
  • packages/console-ui/index.js
  • packages/console-ui/package.json
  • pnpm-workspace.yaml
  • state/Cargo.toml
  • state/README.md
  • state/build.rs
  • state/src/adapters.rs
  • state/src/boot.rs
  • state/src/functions.rs
  • state/src/lib.rs
  • state/src/store.rs
  • state/src/structs.rs
  • state/src/ui.rs
  • state/ui/build.mjs
  • state/ui/package.json
  • state/ui/page.tsx
  • state/ui/src/configuration/index.tsx
  • state/ui/src/function-trigger-message/index.tsx
  • state/ui/src/lib/events.ts
  • state/ui/src/lib/widgets.tsx
  • state/ui/src/page/ItemView.tsx
  • state/ui/src/page/ItemsView.tsx
  • state/ui/src/page/ScopesView.tsx
  • state/ui/src/page/index.tsx
  • state/ui/styles.css
  • state/ui/tsconfig.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/injectable-ui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 47 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

The nested console/web/pnpm-workspace.yaml (added on main for standalone
esbuild allowBuilds) made pnpm treat web/ as its own workspace root, so
--frozen-lockfile installs stopped finding the repo-root lockfile. The root
workspace already declares allowBuilds for esbuild. Also fix the rust job's
pre-build loop paths, which were double-prefixed with the worker dir and
silently skipped the build.
@sergiofilhowz
sergiofilhowz merged commit 1853bc1 into main Jul 23, 2026
21 of 22 checks passed
rohitg00 added a commit that referenced this pull request Jul 24, 2026
Ships the database worker's #/ext/database page over the injectable-UI
protocol (#570): a schema tree with lazy per-driver column/PK/FK/index
introspection, a sortable paginated row grid with a row inspector, and a
read-only SQL panel (shared Monaco CodeEditor, EXPLAIN, per-db history,
client-side write-verb gate). Reads the live database via database::query
and database::listDatabases. Registered through host.pages.register in the
existing database/ui setup, alongside the function-trigger renderer.

The SQL editor feeds the live table names plus SQL keywords to the
CodeEditor completions prop for as-you-type suggestions.
rohitg00 added a commit that referenced this pull request Jul 27, 2026
…598)

* feat(database): injectable console page (schema browser + SQL panel)

Ships the database worker's #/ext/database page over the injectable-UI
protocol (#570): a schema tree with lazy per-driver column/PK/FK/index
introspection, a sortable paginated row grid with a row inspector, and a
read-only SQL panel (shared Monaco CodeEditor, EXPLAIN, per-db history,
client-side write-verb gate). Reads the live database via database::query
and database::listDatabases. Registered through host.pages.register in the
existing database/ui setup, alongside the function-trigger renderer.

The SQL editor feeds the live table names plus SQL keywords to the
CodeEditor completions prop for as-you-type suggestions.

* fix(database): address review on the injectable page

- read-only SQL gate hardened: single-statement only (semicolons in
  strings/comments ignored), reject any write/DDL keyword anywhere so
  mutating CTEs and EXPLAIN ANALYZE cannot slip past the leading keyword,
  and reject writable PRAGMA forms (journal_mode=WAL) while keeping read
  PRAGMAs
- listDbs throws on a shape mismatch like runQuery, so a malformed
  response is distinguishable from an empty database list
- fetchTablePage fetches a pageSize+1 sentinel row so pagination stays
  bounded when the row count is unknown; normalize page/size to
  non-negative integers before interpolating
- copyText swallows the async clipboard rejection via ?.catch, not just
  the sync call
- icons preserve caller aria-hidden/aria-label (labeled icons stay
  accessible) instead of forcing aria-hidden
- result grid sets aria-sort on sortable headers

Worker-side read-only transaction enforcement is out of scope here (it is
a database worker change); this tightens the client gate as defense in
depth. SqlPanel already remounts per database via its key, so no separate
db-change reset is needed.
rohitg00 added a commit that referenced this pull request Jul 27, 2026
#597)

* feat(console): CodeEditor completions prop for as-you-type suggestions

Adds an opt-in `completions?: readonly string[]` to the shared CodeEditor
(#579). Non-empty turns on the suggest popup (the default stays prose-quiet,
so markdown/json/yaml behavior is byte-for-byte unchanged) and registers a
Monaco completion provider for the editor's language offering those words,
disposed on unmount. The database SQL panel is the first consumer, feeding
it the live table names plus SQL keywords.

* feat(database): injectable console page (schema browser + SQL panel) (#598)

* feat(database): injectable console page (schema browser + SQL panel)

Ships the database worker's #/ext/database page over the injectable-UI
protocol (#570): a schema tree with lazy per-driver column/PK/FK/index
introspection, a sortable paginated row grid with a row inspector, and a
read-only SQL panel (shared Monaco CodeEditor, EXPLAIN, per-db history,
client-side write-verb gate). Reads the live database via database::query
and database::listDatabases. Registered through host.pages.register in the
existing database/ui setup, alongside the function-trigger renderer.

The SQL editor feeds the live table names plus SQL keywords to the
CodeEditor completions prop for as-you-type suggestions.

* fix(database): address review on the injectable page

- read-only SQL gate hardened: single-statement only (semicolons in
  strings/comments ignored), reject any write/DDL keyword anywhere so
  mutating CTEs and EXPLAIN ANALYZE cannot slip past the leading keyword,
  and reject writable PRAGMA forms (journal_mode=WAL) while keeping read
  PRAGMAs
- listDbs throws on a shape mismatch like runQuery, so a malformed
  response is distinguishable from an empty database list
- fetchTablePage fetches a pageSize+1 sentinel row so pagination stays
  bounded when the row count is unknown; normalize page/size to
  non-negative integers before interpolating
- copyText swallows the async clipboard rejection via ?.catch, not just
  the sync call
- icons preserve caller aria-hidden/aria-label (labeled icons stay
  accessible) instead of forcing aria-hidden
- result grid sets aria-sort on sortable headers

Worker-side read-only transaction enforcement is out of scope here (it is
a database worker change); this tightens the client gate as defense in
depth. SqlPanel already remounts per database via its key, so no separate
db-change reset is needed.

* fix(database): page edge cases from review

- Subtitle: a database configured without a `url` no longer reads "no
  database configured"; it falls back to the database name, and the
  worker-unavailable / nothing-configured copy stays for the absent cases.
- SQL panel is keyed by database only, so a refresh reloads metadata
  instead of remounting the editor and discarding an in-progress
  statement and its results.
- "open in sql" seeds through quoteTableRef, so a schema-qualified
  postgres table quotes component-wise instead of becoming one
  identifier.
- Selectable grid rows are tabbable and activate on Enter/Space, matching
  the click path; non-clickable rows are unchanged.
- SQL history state is bounded by HISTORY_LIMIT, matching what is
  persisted.
- Re-expanding a table whose schema read failed retries instead of
  staying on the error row forever.
- Copy feedback moves into a shared useCopyFeedback hook that cancels its
  pending timer on unmount, replacing the duplicate implementations in
  the grid and the row inspector.
rohitg00 added a commit that referenced this pull request Jul 27, 2026
Keeps both nav sources in `viewOptions`: this branch's presence-gated
`promptsAvailable` entry and the injected extension pages that #570 added
on main. Resolving to either side alone drops one of the two.
rohitg00 added a commit that referenced this pull request Jul 31, 2026
PR #570 moved the pnpm version to the repo-root packageManager field and removed the version: 10 pin from ci.yml and _rust-binary.yml, but _bundle.yml kept its pin. pnpm/action-setup refuses to run when both are set, so every deploy: bundle worker release fails at setup. Drop the pin so the bundle workflow reads packageManager like the other two.
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