@putdotio/rokit
v2.3.0
Published
A tiny CLI companion for Roku device harness work.
Downloads
2,047
Readme
Install
Requires Node >=24.14.0; install it in a consumer repo with:
pnpm add -D @putdotio/rokitQuick Start
Set the target Roku in the app repo that consumes rokit:
export ROKIT_TARGET=<roku-ip>
export ROKIT_PASSWORD=<developer-mode-password>Then run the generic device checks and actions you need:
pnpm exec rokit check
pnpm exec rokit package --out artifacts/live/channel.zip
pnpm exec rokit install artifacts/live/channel.zip
pnpm exec rokit launch dev
pnpm exec rokit press Down Select
pnpm exec rokit console artifacts/live/console.log --duration-ms 30000
pnpm exec rokit proof artifacts/live/proof --screenshotROKIT_PASSWORD is required for developer-installer operations such as
install and screenshot. ROKU_DEV_TARGET and ROKU_DEV_PASSWORD are
accepted as optional aliases when the ROKIT_* names are unset.
Automation
Prefer JSON when rokit feeds another tool:
pnpm exec rokit describe
pnpm exec rokit --json active-app
pnpm exec rokit --dry-run launch dev
pnpm exec rokit --fields status,data.state media-player
pnpm exec rokit --input-json '{"command":"press","keys":["Down","Select"]}'describe prints the machine-readable command surface, including command
names, parameters, JSON payload fields, global options, and automation feature
flags. When stdout is not a TTY, command output defaults to JSON unless
--output text is explicit.
Command Surface
Common commands:
| Command | Purpose |
| -------------------------------------------------- | -------------------------------------------------- |
| describe | Print the machine-readable command surface |
| check | Confirm ECP and developer-installer reachability |
| discover | Find Roku ECP devices with SSDP |
| device-info | Read Roku device metadata |
| active-app | Read the foreground app |
| console <output-path> | Capture BrightScript console output from 8085 |
| debug-command <command> [args...] | Run an allowlisted Roku debug command |
| media-player | Read parsed /query/media-player state |
| snapshot | Read a compact state snapshot |
| proof <output-dir> | Write reviewable local proof artifacts |
| package --out <zip-path> | Create a sideload ZIP from the current app root |
| install <zip-path> | Publish an existing ZIP to the Roku developer slot |
| launch <app-id> | Launch an app by id with optional params |
| press <key...> | Send Roku remote keys |
| query <ecp-path> | Print a raw ECP response |
| sgnodes | Print the raw SceneGraph tree |
| assert-node / wait-node | Check generic SceneGraph node state |
| wait-active / wait-media-player / wait-ready | Poll generic runtime readiness |
| screenshot <output-path> | Save a timestamped developer screenshot |
Mutating commands support --dry-run where the platform can validate without
changing device or filesystem state. ECP paths reject query strings, fragments,
traversal, backslashes, control characters, and percent-encoded path segments.
Generated output paths must stay within the current working directory.
Screenshots append a timestamp to the requested filename and report the actual
path written, so repeated captures do not reuse cache-prone filenames.
Library Use
App-specific scenario scripts can import the generic helpers:
import {
assertMediaPlayerContainer,
assertSceneGraphNode,
captureScreenshot,
pressKey,
querySceneGraph,
waitForSceneGraphAssertion,
type RokuContext,
} from "@putdotio/rokit";
const target = process.env.ROKIT_TARGET;
if (!target) {
throw new Error("ROKIT_TARGET is not set");
}
const context: RokuContext = {
target,
timeoutMs: 10_000,
username: "rokudev",
};
await pressKey(context, "Info");
await querySceneGraph(context, { attempts: 3, requireAppNode: true, requireComplete: true });
await assertSceneGraphNode(context, "videoPlayerScreen", { state: "visible" });
await assertMediaPlayerContainer(context, "mp4");
await captureScreenshot(
{ ...context, password: process.env.ROKIT_PASSWORD ?? "" },
"artifacts/player.jpg",
{ attempts: 3 },
);
await waitForSceneGraphAssertion(context, "player ready", (xml) => {
if (!xml.includes("videoPlayerScreen")) {
throw new Error("expected player screen");
}
});Boundaries
rokit owns generic Roku mechanics:
- package, install, launch, deeplink params, and remote keypresses
- raw ECP queries and parsed media-player state
- BrightScript console capture and allowlisted debug-server commands
- SceneGraph state queries and named-node assertions
- timestamped screenshots, snapshots, and proof artifacts
Consumer app repos own product behavior: opening specific routes, asserting playback for real content, checking app-specific UI nodes, and generating review artifacts.
