Roku device harness primitives for package, launch, input, state, and proof loops.
Generic by design: app journeys, credentials, content IDs, and product assertions stay in consumer repos.
Needs the Node version in engines.node of package.json. In the consumer repo:
pnpm add -D @putdotio/rokitOnly the latest published version receives routine fixes.
Set the target Roku in the consumer app repo, in your shell or a gitignored
.rokit/.env:
export ROKIT_TARGET=<roku-ip>
export ROKIT_PASSWORD=<developer-mode-password>install and screenshot need ROKIT_PASSWORD. ROKU_DEV_TARGET and
ROKU_DEV_PASSWORD work as fallbacks when the ROKIT_* names are unset.
pnpm exec rokit check
pnpm exec rokit package 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 describe prints every command, parameter, and JSON payload field;
rokit describe <command> prints one.
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"]}'
pnpm exec rokit --input-json @artifacts/rokit-payload.json
printf '{"command":"press","keys":["Back"]}' | pnpm exec rokit --input-json -- Output is JSON when stdout is not a TTY, unless you pass
--output text. --input-jsonalso carries literal values that look like flags.- Waits poll inside one timeout budget. On expiry they report the last completed observation and reject late success.
- Bounded navigation:
press Down --until-node videoPlayerScreen --until-state visible --max 8. --dry-runvalidates a mutating command without touching the device or files.- Output paths must stay inside the current directory.
- Screenshots append a timestamp to the filename; read the written path from
the result. Captures that fail decoding or exceed the limits in
src/screenshot-image.tsretry, then fail.
App scenario scripts import the generic helpers that
src/index.ts exports:
import { assertSceneGraphNode, pressKey, 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 assertSceneGraphNode(context, "videoPlayerScreen", { state: "visible" });