Turn the hardcoded straight-line sweep into a strategy system behind three
seams so new patterns are easy to add and, for the first time, testable
without nut.js or a real screen:
- src/device.ts: injectable Device seam over nut.js (autoDelayMs lives
here now); the only module that touches the native lib.
- src/strategies.ts: pure per-pattern path generators + registry + lenient
name resolution. Ships line, diagonal, jitter, walk,
arc, figureEight.
- src/executor.ts: single executePath driver owning bounds policy
(abort/clamp/reflect), pacing, interrupt detection, and
restore-on-clean.
keeper.ts's simulateActivity now selects a strategy and delegates to the
executor; the default `line` pattern is byte-for-byte the previous behavior.
New config surface, layered CLI > file > default with strict validation:
- -p/--pattern <name> movement strategy (names matched case/-/_-insensitive)
- -s/--step-size <px> pixels per step; stepCount is now a step *count*
Robustness for the new edge-seeking patterns: interrupt detection compares
against the last commanded (rounded) point with a 2px tolerance, and
clamp/reflect stay a couple pixels off the screen edge, so sub-pixel cursor
placement on scaled/multi-monitor displays isn't misread as user activity.
jitter's radius scales with sweep length so it moves at the default stepSize.
Tests: new suites for strategies, the executor (all bounds policies,
rounding, interrupt, tolerance, pacing), and the keeper loop; config and
configFile suites extended for pattern/stepSize. editor.test.ts moved to
tests/ for consistency. 64 pass.
Notable changes since v1.1.1:
- New -e/--edit flag opens the active config file in $EDITOR.
- Lazy import of keeper.ts so --help and --version skip the nut.js
native load on cold start.
- Various audit cleanups: failRuntime() mirror, named Logger interface,
errors.ts module, autoDelayMs moved out of module-load side effects,
defaultConfigPath guards against unset HOME, noUncheckedIndexedAccess
enabled in tsconfig.
- Added Bun test suite (34 tests across resolveConfig, loadConfigFile,
editConfig).
- scripts/dev-setup.sh made POSIX-portable.
The CLI reads its version string from package.json at runtime, so
'move --version' was printing 1.0.0 even after the v1.1.0 tag landed.
Bumping the manifest here so v1.1.1 (carrying the tests/ move and the
TS LSP fix) ships with matching output:
$ move --version
move 1.1.1
Discipline going forward: bump package.json BEFORE creating a tag.
Two new test files exercise the layered config resolver and the JSON
config-file loader:
src/config.test.ts 25 cases:
- resolveConfig precedence (CLI > file > default) per field
- seconds-to-ms conversion at the resolver boundary
- verbose precedence across all four cells
- defaultConfigPath: XDG honored, HOME fallback, empty-as-unset,
throws CliError when both are missing
src/configFile.test.ts 11 cases:
- valid file -> overrides, with undefined for unspecified keys
- missing explicit path throws
- malformed JSON / non-object root throws with file path
- unknown key / wrong type / non-positive number all throw with
the offending key named
- default path missing -> null (silent default)
Runs via 'bun test' (or 'bun run test', now wired in package.json).
All 25 tests pass on the current codebase.
- src/move.ts entry point with CLI parsing, --help, --version
- src/cli.ts: parseCliArgs, printHelp, ParsedCliArgs, CliError, VERSION
- src/config.ts: Config type, DEFAULT_CONFIG, resolveConfig
- src/keeper.ts: synthetic-activity sweep + idle-watch loop
- package.json bin entry + shebang for 'bun link' global install
- install.sh: contributor bootstrap (will be repurposed; see
DISTRIBUTION-PLAN.md for the end-user installer design)
- DISTRIBUTION-PLAN.md captures the tabled end-user distribution work