#!/usr/bin/env bun /** * move.ts * ------- * Entry point for the `move` CLI. * * Thin shim that ties the four logic modules together: * - `cli.ts` parses and validates `process.argv`. * - `configFile.ts` loads and validates the JSON config file. * - `config.ts` holds defaults and the layered `resolveConfig` overlay. * - `keeper.ts` owns the synthetic-activity sweep and idle-watch loop. * * Order of operations: * 1. Parse CLI args. Bad input -> stderr + usage hint, exit 2. * 2. `--help` / `--version` short-circuit before any I/O or mouse work. * 3. Load + validate the config file (default XDG path, or `--config * ` if supplied). Validation failures share the exit-2 path. * 4. Resolve the full `Config` (CLI > file > DEFAULT_CONFIG) — verbose * lives inside `Config` and is layered with the same precedence as * the numeric fields. * 5. Run keeper. Any unhandled rejection exits 1. * * Runtime: Bun (uses `@nut-tree-fork/nut-js` via `keeper.ts`). The shebang * above lets this file run as a real CLI once linked via `bun link`. */ import { parseCliArgs, printHelp, VERSION } from "./cli.ts"; import type { ParsedCliArgs } from "./cli.ts"; import { resolveConfig } from "./config.ts"; import type { ConfigOverrides } from "./config.ts"; import { loadConfigFile } from "./configFile.ts"; import { runKeeper } from "./keeper.ts"; /** * Print a user-error message and exit 2. Used for anything that comes from * invalid input: unknown CLI flags, bad numbers, malformed or missing * config files, unresolvable default paths. The accompanying "Try 'move * --help'" pointer is appropriate for these cases. * * Returns `never` so callers can invoke it without TypeScript flagging * "variable might be undefined" downstream. */ function failUser(err: unknown): never { const msg: string = err instanceof Error ? err.message : String(err); process.stderr.write(`move: ${msg}\nTry 'move --help' for more information.\n`); process.exit(2); } /** * Print a runtime-failure message and exit 1. Used for anything the user * couldn't have prevented from the command line: nut.js errors, missing * Accessibility permission on macOS, unexpected exceptions from the * keeper loop. Prefers the stack trace when available since these failures * usually need a developer to interpret. */ function failRuntime(err: unknown): never { const detail: string = err instanceof Error ? (err.stack ?? err.message) : String(err); process.stderr.write(`move: runtime error: ${detail}\n`); process.exit(1); } let cliArgs: ParsedCliArgs; try { cliArgs = parseCliArgs(); } catch (err: unknown) { failUser(err); } if (cliArgs.help) { // printHelp() resolves defaultConfigPath(), which can throw CliError // when neither $XDG_CONFIG_HOME nor $HOME is set. try { printHelp(); } catch (err: unknown) { failUser(err); } process.exit(0); } if (cliArgs.version) { process.stdout.write(`move ${VERSION}\n`); process.exit(0); } let fileOverrides: ConfigOverrides | null; try { fileOverrides = loadConfigFile(cliArgs.config); } catch (err: unknown) { failUser(err); } const cliOverrides: ConfigOverrides = { moveInterval: cliArgs.moveInterval, checkInterval: cliArgs.checkInterval, stepDelay: cliArgs.stepDelay, stepCount: cliArgs.stepCount, verbose: cliArgs.verbose, }; const config = resolveConfig(fileOverrides, cliOverrides); runKeeper(config).catch(failRuntime);