@jsm-mit/cli-game-helpers
v0.1.3
Published
Interactive CLI helpers for menu-driven playground/sandbox tools: arrow-key menus, prompts, confirmations, and canister-error reporting.
Readme
@jsm-mit/cli-game-helpers
Interactive CLI helpers for menu-driven playground/sandbox tools ("CLI
games"): arrow-key menus, prompts, confirmations, and canister-error
reporting. Extracted from sultana-command-line-playground and the
rabbit-motoko-package sandbox, which carried near-identical copies.
Zero runtime dependencies — everything builds on Node's readline.
API
Menu
rl— the sharedreadline/promisesinterface on stdin/stdout, created on first use (a proxy overgetRl(), same object every time). Importing the package never opens stdin or switches the terminal to raw mode, so a script that only needshandleErrorexits on its own. Close it (rl.close()) when an interactive tool exits.getRl()— the underlying interface itself, for code that needs the real object rather than the proxy.selectOption<T>(prompt, options, labelFn, header?)— interactive arrow-key menu. UP/DOWN cycles, ENTER selects, ESC cancels (returnsnull), Ctrl+C exits the process. The menu clears and redraws the screen on every keypress — content that should stay visible above it must be passed asheader, not printed beforehand. An emptyoptionsarray returnsnullimmediately.MenuOption— the{ label, value }convenience interface.
Prompts
ask(prompt, defaultValue?)— asks a question, returns the trimmed answer; an empty answer returnsdefaultValuewhen given.confirm(prompt)— yes/no question;" (y/n): "is appended automatically. Onlyy/yes(any case) count as yes.pause(message?)— blocks until Enter; default message"\nPress Enter to continue...".
Reporting
handleError(error)— prints a canister-shaped error: the message, thenerrorKey/errorMessage/ alogstable fromerror.cause.nsToIso(ns)— bigint nanosecond timestamp (canister time) → ISO string;undefinedrenders as"-".
Usage
import { rl, selectOption, ask, confirm, pause } from "@jsm-mit/cli-game-helpers";
const action = await selectOption("=== MENU ===", actions, (a) => a.label);
if (action) {
const name = await ask("Name: ", "default");
if (await confirm(`Create '${name}'?`)) {
// ... do the thing
}
await pause("\nPress Enter to return to menu...");
}
rl.close();Development
npm test— vitest.npm run sandbox— interactive demo (sandbox/main.ts).npm run build— compilesrc/todist/.
