Skip to content

Widget CLI

The package is @glasshome/widget-cli and its binary is glasshome-widget. Scaffolded projects pin @glasshome/widget-cli in devDependencies and add a widget script alias in package.json (e.g. "widget": "glasshome-widget"), which is why every command below is shown as bun widget <command>; the alias runs the project-local version, kept current with bun update. Outside a scaffolded project use bunx @glasshome/widget-cli@latest <command> instead. The @latest tag matters: a bare bunx @glasshome/widget-cli can reuse a stale cached version.

Version requirements

Hub enforces a minimum CLI version. The current floor is 0.4.11, served from /api/widgets/cli-version. CLIs at or above 0.4.14 fetch this endpoint on login and publish, and hard-stop below the floor with an actionable message instead of a cryptic OAuth or HTTP error. CLIs older than 0.4.14 lack the check, so the floor only protects clients that can read it.

If you see a “widget CLI is no longer supported” error, update:

# one-off, no install:
bunx @glasshome/widget-cli@latest publish

# or update the project dev dependency:
bun add -D @glasshome/widget-cli@latest

create

bunx @glasshome/widget-cli@latest create
# or, equivalent, runs `create` by default when not inside a project:
bunx @glasshome/widget-cli@latest

Scaffolds a new widget project with package.json, vite.config.ts, tsconfig, and a starter widget (create already prompts for the first widget’s details, no extra add call needed). Run this outside of an existing project.

add

bun widget add

Adds a new widget to your project. Prompts for a name and description, then creates src/{name}/index.tsx and src/{name}/manifest.json.

build

bun widget build

Builds all widgets into per-widget, self-contained JS bundles in dist/. Also generates dist/registry.json with metadata for all widgets.

validate

bun widget validate [name]

Checks manifests, bundle sizes, and registry consistency. Pass a widget name to validate just one, or omit for all.

info

bun widget info [name]

Prints the project header, the local registry summary, and per-widget metadata + bundle size. Useful for sanity-checking before publishing.

connect

bun widget connect <url> [--re-auth]

Connects to a running Dash instance for live testing. Builds all widgets, uploads each bundle to the dashboard API under the local scope, registers them with the dashboard, and watches for changes. Widgets hot-reload as you edit. No local server is started (see Local Testing Workflow).

Auth: connect uses the OAuth device-code flow against the local Dash instance. A browser window opens to the Dash approval page; approve it, and the CLI stores a host-scoped bearer token. This is distinct from login, which authenticates against GlassHome Hub.

Flags:

  • --re-auth: discard stored credentials and force a fresh device-authorization flow.

publish

bun widget publish [hub-url] [--name <widget>] [--bump keep|patch|minor|major] [--scope <scope>]

Validates first, prompts for scope/widget/version (or takes them from flags), then builds and uploads via a presigned R2 URL. Auto-runs login if no token is found, so the explicit login step is optional.

Flags:

  • --name <widget>: publish only the named widget instead of prompting.
  • --bump keep|patch|minor|major: pre-pick the version bump (updates the version field in src/<name>/manifest.json).
  • --scope <scope>: pre-pick the publishing scope (e.g. @my-team).

login

bun widget login [hub-url]

Authenticates with GlassHome Hub via OAuth PKCE (not the local Dash instance). Opens a browser, listens on http://127.0.0.1:9274/callback for the callback (localhost is also accepted; 120 s timeout), stores the resulting token locally. publish runs this automatically if no token is present.

upgrade

bun widget upgrade

Syncs the sdkVersion field in every manifest.json to the SDK version actually installed in your project. The SDK (@glasshome/widget-sdk) is published to npm. How the upgrade works depends on your project type:

Standalone project: Update the @glasshome/widget-sdk range in peerDependencies (or devDependencies) in your package.json, run bun install to fetch the new version from npm, then run bun widget upgrade to sync the manifests and validate compatibility.

Monorepo workspace: The CLI reads the SDK version from the workspace package and runs bun install from the monorepo root to sync, then updates all manifest files.

In both cases bun widget upgrade re-runs bun widget validate afterwards to catch any breaking API changes.

Local Testing Workflow

The connect command is how you test widgets against a running Dash instance. Here’s what it does:

  • Builds all widgets in your project.
  • Runs an OAuth device-code flow against the Dash URL (browser opens to the Dash approval page).
  • Uploads each bundle to the Dash API under the local scope.
  • Registers the widgets via the Dash internal tRPC endpoint and enables dev mode.
  • Watches src/ for changes; on save, rebuilds and re-uploads the affected widget.
  • On Ctrl+C, unregisters the widgets and exits.

No local HTTP server is started; Dash talks to its own API for the bundle bytes.

Global flag

Use --dir <path> with any project-scoped command (add, build, validate, info, connect, publish, upgrade) to point at a different widget project directory. create ignores it; it scaffolds into a new directory under the current working directory.