npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@migrate-sdk/tui

v0.14.0

Published

Interactive terminal UI for Migrate SDK

Readme

Migrate TUI

Explore and operate migrations without memorizing CLI flags. For local use, the TUI's Node Migrate Server loads the same migrate.config.ts as the CLI. The TUI provides status, item counts, messages, dependency-aware execution plans, and contextual actions for every registered migration.

The migration list opens after connecting, without waiting for durable status. Status loads once in the background with a Loading status… indicator and a session activity entry. Navigation and operations remain available while it loads. Unloaded counts are shown as Not loaded, not zero.

For expensive stores, defer the first status read until you press R (Shift+R):

pnpm exec migrate-tui --status manual
pnpm exec migrate-tui --server https://migrate.example.com/api/rpc --status manual

The default is --status background. Both modes retain the last loaded idle status until R requests another read. When a status read finds an active run, or you start a run from the TUI, live dashboard updates continue until no runs remain active. Runs started elsewhere while the dashboard is idle appear after R. Status failures leave the list usable and can be retried with R.

If the renderer restarts after an error, it reuses the last dashboard state. An idle manual session stays idle; an active run resumes live updates. Source scans that find active runs also restore live updates and run controls.

Requires Node.js 22.19.0 or newer. Install it in the migration project alongside the SDK:

pnpm add migrate-sdk effect
pnpm add --save-dev @migrate-sdk/tui
pnpm exec migrate-tui

The published command is a small Node launcher. It runs the renderer with the pinned Bun runtime supplied by the package, so users do not need a global Bun installation. The renderer starts a local Node Migrate Server and communicates with it over Effect RPC. migrate.config.ts, migrate-sdk, migration dependencies, stores, sources, destinations, and execution adapters all remain in Node, matching the local CLI runtime contract. See ADR 0007.

Programmatic consumers use the same client/server boundary:

import { makeMigrationTuiRuntime } from "@migrate-sdk/tui";

const runtime = await makeMigrationTuiRuntime({ cwd: process.cwd() });

try {
  const dashboard = await runtime.refresh();
  console.log(dashboard.rows);
} finally {
  await runtime.dispose?.();
}

The package does not expose the in-process server runtime from its public entry point.

Set MIGRATE_SERVER_BUILD_ID to the immutable identifier of the application build that contains the migration configuration. A changed build ID selects a separate local Node server endpoint; the previous endpoint keeps running until its active Migration Runs finish. This is deployment-skew identity, not a value to update after editing migrate.config.ts, and it does not reload local source. ADR 0008 defines the separate Local Source Generation model. Without a build ID, local clients continue to reuse the server identified by the config path and Migrate SDK version.

Connect to a deployed Migrate Server without loading a local migration config:

pnpm exec migrate-tui --server https://migrate.example.com/api/rpc

When MIGRATE_SERVER_TOKEN is set, its value is sent as an HTTP Bearer token. Source, destination, Migration Store, and Execution Adapter credentials remain in the remote environment. The TUI requires the complete Migrate Server contract, so local and remote connections provide the same dashboard, messages, operations, source scanning, active-run discovery, source-identity history, and run controls. Availability that depends on a selected migration or run is reported in its data—for example, whether rollback or stopping is supported.

Remote clients and servers may use different Migrate SDK releases when they advertise the same Migrate Protocol version. The server's SDK version remains available in connection metadata for diagnostics; protocol compatibility is the remote connection gate. Schema administration requires Migrate Protocol v2, so update the TUI and server together.

If the configured SQL store needs an upgrade, the TUI connects and opens a Store schema upgrade required popup before loading the dashboard. Review the pending changes and choose Upgrade store (u). The server applies the reviewed plan, then the dashboard opens. Cancel keeps the connection open; r reopens the plan and q quits. Errors remain visible for retry.

Local connections reuse sqlStore in migrate.config.*. Remote hosts supply the same SQL client layer and table prefix as sqlStore on RegistryMigrateServer.layer or MigrateServer.layer. The database credentials stay on the server. Non-SQL stores do not need this setup.

Transport and server hosts can integrate directly with the Effect services exported as MigrateClient from migrate-sdk/client and MigrateServer from migrate-sdk/server. The local TUI supplies a child-process transport and a Node bootstrap that discovers migrate.config.*. Remote hosts instead supply an already-imported registry and execution-adapter Layer to the registry-backed server; no config file is required.

Remote hosts can expose the same server Layer as a Web-standard HTTP handler:

import { Effect, Layer } from "effect";
import {
  HttpMiddleware,
  HttpServerRequest,
  HttpServerResponse,
} from "effect/unstable/http";
import {
  MigrateServerHttp,
  RegistryMigrateServer,
} from "migrate-sdk/server/http";

const executableLayer = /* the selected execution-adapter Layer */;
const serverLayer = RegistryMigrateServer.layer({
  environment: {
    id: "production",
    label: "Production",
  },
  registry,
}).pipe(Layer.provide(executableLayer));
const httpLayer = MigrateServerHttp.layer.pipe(Layer.provide(serverLayer));
const authorize = HttpMiddleware.make((httpApp) =>
  HttpServerRequest.HttpServerRequest.pipe(
    Effect.flatMap((request) =>
      verifyMigrateRequest(request)
        ? httpApp
        : Effect.succeed(
            HttpServerResponse.text("Unauthorized", { status: 401 }),
          ),
    ),
  ),
);
const remoteServer = MigrateServerHttp.toWebHandler(httpLayer, authorize);

export const POST = (request: Request) => remoteServer.handler(request);

The host route owns the public URL; the Migrate Server handler is routerless and does not need to know where it is mounted.

On a serverless or otherwise short-lived HTTP host, executableLayer must use a durable Execution Adapter. An inline Execution Adapter is supported only when the Migrate Server process remains alive for the entire run; ending that process ends the inline execution.

Authorization is application-owned Effect HTTP middleware so deployments can use their existing identity provider without leaving the request fiber. Deployments where authenticated infrastructure already enforces access can omit the middleware when converting the fully composed Layer. The HTTP transport uses bounded observation leases: each response returns an opaque resume token and absolute progress snapshot, and the TUI reconnects from the last token. No function invocation or HTTP response owns the lifetime of a durable Migration Run.

migrate-sdk and effect remain peer dependencies: the TUI and config use the migration project's compatible versions. @migrate-sdk/tui and migrate-sdk are published with matching versions.

For workspace development:

pnpm --filter @migrate-sdk/tui demo

Use an explicit project config:

pnpm --filter @migrate-sdk/tui dev -- --config ./migrate.config.ts

The npm package is the supported local distribution. A compiled renderer binary remains available for packaging experiments and version smoke tests:

pnpm --filter @migrate-sdk/tui build:binary
(cd packages/tui && ./dist/binary/migrate-tui --version)

The renderer binary is not currently a standalone Migrate TUI distribution: a functional release also needs the Node Migrate Server entry and the migration project's compatible migrate-sdk and effect packages. Cross-compilation, the companion server layout, signing gates, and OpenCode references are documented in docs/research/tui-binary-distribution.md.

The footer keeps primary and contextual shortcuts visible for the current selection. Press Enter to open All actions, which includes the complete action set such as rescan, update, and Concurrency settings. Concurrency settings provides session-scoped concurrency overrides for the Process Pipeline, Rollback Pipeline, and source scans; blank values preserve the configured defaults and Process or Rollback concurrency can be set to unbounded. Press c to open Concurrency settings and g to switch between migration and group tabs, m for errors and messages, r to run the selected migration or group, e to open Run selected entries, f to retry failed items, b to rollback, s to scan sources for the current selection and its required dependencies, l to open Session activity, R to reload status, and q to quit. Source scan results stay visible when switching migrations or scanning other sources; R clears them when reloading status. When applicable, t retries skipped items, v focuses a running migration, x requests a safe stop for a run owned by the connected Migrate Server, and u opens the guarded break-lock confirmation. Use Page Up and Page Down to scroll the overview while the arrow keys continue to select migrations. Messages are loaded only when you press m or open the Messages tab. Latest message shows m to load until then. Loaded results, including empty results, are cached per migration or group for the session; navigation does not reload them. Observed changes to run history or durable item counts mark affected caches stale, including their groups. Press m again to reload a stale result or retry a failed read. An unchanged status refresh keeps the cache. Source scans and lock heartbeats do not invalidate it. Changes made by other clients while this TUI is idle are discovered on R, just like status changes.

The Messages tab displays a bounded list with the current message highlighted; use the arrow keys to move through it and Enter to open the complete message and structured details. For non-interactive inspection or export, use migrate messages <migration> or migrate messages --all --json from the same project.

Run selected entries opens Next items, where you can enter an item limit for this run. Each migration gets its own limit, including any dependencies you add. Unchanged items do not count; failed and skipped attempts do. Press Enter or choose Run to start. If dependencies need attention, choose whether to include them or run without them.

For a single migration, use Next items or Source IDs to choose how to select items. From the input, press Shift+Tab to focus the selection control, use Left/Right to switch, then Tab to return to the input. You can also click the tabs. Adding an ID keeps Source IDs active, and reopening the dialog remembers your selection method. The ordinary Run action stays unlimited.

In Source IDs, the IDs set the scope. By default, unchanged migrated items stay unchanged. Enable Update: reprocess unchanged items to process the selected IDs again. From the ID input, press Tab then Space to toggle Update, or click its label; choose Update to start. This preserves other items and saved scan progress. Update resets to off when you reopen the dialog or switch selection methods. The separate Update action still updates the whole migration.

Session activity keeps the statuses, notices, warnings, and errors observed by the current TUI session in chronological order, including active-run lifecycle changes discovered through dashboard observation. Use the arrow keys, j/k, Page Up and Page Down, or Home and End to navigate. Press Enter to read and scroll the complete selected event, or e to export the retained entries as JSON Lines without replacing an existing file. Session activity is limited to the current TUI process; durable Migration Messages remain available through the Messages tab and CLI after the TUI closes.

Runs start directly when their dependencies are ready. A group concurrency override controls item processing within each migration; migration definitions still execute in SDK plan order. If required dependencies lack completion, the TUI asks whether to include them or force the selected run.

Rollback offers two scope choices in one confirmation dialog. Include dependencies (i) is selected by default and recommended; the plan rolls back dependent migrations first. Selected only (s) leaves those migrations outside the plan. If they still have tracked items, the dialog explains that their records will remain and references may break; confirming this choice authorizes forced rollback. If they have no tracked items, force is unnecessary. Review the updated plan and choose Rollback selected (y) to execute it once. Selected-entry rollback keeps dependency inclusion disabled and preserves the selected identities. A failed plan or status update stays in the dialog for retry; confirmation waits for a successfully prepared plan.

While a run is active, committed cursor-window checkpoints carry cumulative run counts and trigger targeted durable-status refreshes for the migration that made progress. Inline runs and runs managed by an Execution Adapter therefore update in committed batches without scanning their sources; after an idle interval, a slower full-plan refresh covers adapters that cannot publish checkpoints. When an execution adapter supports native observation, the TUI also waits through its Execution Adapter identity. If that observation channel is unavailable, the TUI reports the fallback and continues following durable run state. Execution Adapter failure or cancellation is reconciled against durable terminal state before it is reported. q, Ctrl+C, SIGINT, SIGTERM, and SIGHUP end the current observation and close the TUI without stopping the run. The local Node Migrate Server owns each run independently and remains available while any run is active, so a later TUI session can reconnect by Migration Run id. Non-overlapping migrations can run concurrently; plans that include an already-running definition are rejected by its Migration Definition Lock. The server exits after the final client disconnects when no run remains active. A second Ctrl+C, or a five-second graceful-shutdown timeout, always restores the terminal and exits.

The server discovers active runs from non-terminal durable run state whose run id still owns a Migration Definition Lock. When that state includes an Execution Adapter identity, View run follows the Reconnectable Migration Run's existing checkpoints and terminal result by Migration Run id. Closing that observation leaves the Reconnectable Migration Run active. The current protocol can stop an inline run owned by the connected Migrate Server. Provider-owned runs report stopping as unsupported until their Execution Adapter implements cancellation. Break lock removes stale lock ownership but does not cancel provider work.

If React or the terminal renderer fails unexpectedly, the TUI destroys the failed renderer, reloads durable migration state, and creates one fresh UI session. An active execution remains owned by the runtime and the replacement screen reattaches to its status. A second renderer failure exits normally after restoring the terminal instead of entering a restart loop.

Terminal regression test

Pilotty is pinned as a development dependency. Exercise the real PTY interaction and responsive-layout path with:

pnpm --filter @migrate-sdk/tui test:pilotty

The harness verifies planned retry and rollback scopes, view transitions, cooperative cancellation and draining, the 72×34 compact dashboard, and the 120×36 confirmation views. It prints the directory that contains its text snapshots for further inspection.

The compiled-binary smoke check builds and relocates the host executable, loads its embedded version, and verifies it can start independently. The npm package smoke and local IPC test cover real migration execution:

pnpm --filter @migrate-sdk/tui test:binary
pnpm --filter @migrate-sdk/tui test:ipc