# Changelog All notable changes to `move` are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added - Random pattern selection: `-r` / `--random`, and `random` as a value for `--pattern` and the `pattern` config key. Every time a sweep is triggered, a different movement pattern is chosen, so the motion varies across the day instead of repeating one shape. Two rules keep it predictable: the same pattern is never chosen twice in a row, and the pick happens once per trigger — in loop mode it holds for the whole loop run rather than changing mid-run. The pick is a real strategy, so `--verbose` logs the concrete pattern name and a pick with an infinite loop path (`line`, `diagonal`) still bounces edge-to-edge under `--loop`. `-r` is defined as sugar for `--pattern random`, so passing both is rejected (exit `2`) unless they agree: `move -r -p arc` is an error, while `move -r -p random` is a no-op. There is no `random` boolean config key — the file spells it `"pattern": "random"`. `random` is deliberately not a registry entry: it has no path of its own, and the keeper resolves it to a real strategy per sweep. `PATTERN_NAMES` therefore still lists only real generators, with the new `SELECTABLE_PATTERN_NAMES` covering what a user may select. ### Changed - `parseCliArgs` now takes its argument list as an optional parameter (defaulting to the real command line), so the flag surface is unit-testable without touching `process.argv`. Adds `tests/cli.test.ts`, which previously had no coverage. ## [1.4.0] - 2026-08-17 ### Added - Loop mode: `-l` / `--loop` (and the `loop` config key) keep the mouse moving after a sweep is triggered until real user activity is detected, instead of firing a single sweep. In loop mode the cursor is never restored between iterations, so `line` and `diagonal` bounce edge-to-edge across the screen (a roaming-DVD effect) rather than stopping at the first edge. Patterns with a finite path (`jitter`, `walk`, `arc`, `figureEight`) chain that path cycle after cycle. Interruption remains mouse-movement only. ### Changed - Simplified on-screen confinement to a single policy: the executor now reflects every pattern's out-of-range coordinates back inside the screen. The `abort` and `clamp` bounds policies (and the per-strategy `bounds` field) were removed. `abort` truncated a sweep at the first edge and `clamp` could park the cursor against an edge — both counter to keeping the cursor moving — while `reflect` bounces and keeps going. Behavior is unchanged for every pattern at normal cursor positions; the only differences are at a screen edge, where motion now bounces instead of stopping. No config keys, flags, or pattern names changed. ## [1.3.3] - 2026-08-17 ### Changed - `install.sh` now installs the newest published tag by default instead of tracking the `master` branch, so the plain `curl ... | sh` one-liner installs a real release and reports its version (e.g. `v1.3.2`). The tag is resolved from the Gitea tags API; if that lookup fails (offline, API unreachable, or no tags yet) it falls back to `master`, preserving the old behavior. Set `MOVE_VERSION` to pin an explicit branch or tag as before. ## [1.3.2] - 2026-08-17 ### Added - `install.sh` is now interactive. When it finds an existing install and a controlling terminal is available, it reports what's there and asks before replacing it, instead of leaving `MOVE_FORCE` as the only control. If a config file already exists it asks separately whether to reseed it from the shipped defaults. Both questions are asked before anything is downloaded or deleted, so declining changes nothing. - `MOVE_RESEED_CONFIG=1` overwrites the user config with the shipped defaults without prompting, for unattended use. The previous file is kept as `config.json.bak`; the same backup is written when reseeding is confirmed at the prompt. ### Changed - `MOVE_FORCE=1` now means "skip every prompt and reinstall unconditionally". It deliberately does not touch the user config, so automation that reinstalls the CLI can't take customizations down with it. - Existing-install detection looks for the install tree and the wrapper, not just the `.installed-version` marker, so a half-finished or hand-moved install is caught rather than silently overwritten. ### Fixed - Installing a *different* version over an existing one used to wipe and replace it with no warning; only an exact version match was ever reported. That case now prompts. With no terminal (CI, cron, container builds) the previous non-interactive behavior is preserved exactly: an identical version is a no-op, a different version is replaced. ## [1.3.1] - 2026-08-14 ### Added - `docs/execution-happy-path.md`: a sequence diagram (plus invariants) tracing a clean idle-triggered sweep end to end, linked from the README. ### Fixed - Stale comments corrected to match the current code: the `install.sh` / `uninstall.sh` header curl URLs pointed at a nonexistent repo-root path (they live under `scripts/`), so the documented command 404'd; `move.ts`'s module list omitted `editor.ts` and the `--edit` step; and `config.ts` still described a removed pixel unit. ## [1.3.0] - 2026-08-14 ### Added - Pluggable movement strategies. New `-p, --pattern ` flag and `pattern` config key select how the cursor moves: `line` (default, unchanged behavior), `diagonal`, `jitter`, `walk`, `arc`, `figureEight`. Each pattern owns its own size and step count as constants; there is no user knob for sweep magnitude. - Pattern names are matched leniently: case and separators are ignored, so `figureEight`, `figure-eight`, `figure_eight`, and `FIGUREEIGHT` are all accepted (on the CLI and in the config file) and resolve to the canonical name. - `src/device.ts`: injectable `Device` seam over nut.js, enabling unit tests for movement without the native binary or a real screen. - `src/strategies.ts`: pure, per-pattern path generators plus the registry and name validation. - `src/executor.ts`: single `executePath` driver owning bounds policy (`abort`/`clamp`/`reflect`), pacing, interrupt detection, and restore. - Test suites for strategies, the executor (all bounds policies, rounding, interrupt), and the keeper loop. ### Changed - `simulateActivity` no longer hardcodes a straight-line sweep; it selects a strategy from the registry and delegates execution to `executePath`. The default `line` pattern is byte-for-byte the previous behavior. - Interrupt detection now compares against the last *commanded* (rounded) point rather than an ideal target, so fractional/curved paths don't self-trip. - `mouse.config.autoDelayMs = 0` moved from `runKeeper` into `createNutDevice` — the single place nut.js is wired up. - `runKeeper(config, device?)` accepts an injected device for testing. - Interrupt detection tolerates a small (2px) gap between the commanded and read-back cursor position, and the `clamp`/`reflect` patterns stay a few pixels off the screen edge. Together these avoid false "user activity" aborts from sub-pixel cursor placement on scaled or multi-monitor setups, which the new edge-seeking patterns would otherwise hit. `line` (policy `abort`) is unaffected. ### Removed - `-n, --step-count` flag and the `stepCount` / `stepSize` config keys. Sweep size and step count are now intrinsic to each movement pattern, not user knobs. Config files that still contain these keys keep working: the loader ignores them with a one-line notice instead of rejecting them, so existing installs (all seeded with `stepCount`) don't break on upgrade. The removed CLI flag, however, is a hard error like any other unknown option. ## [1.2.0] - 2026-06-17 ### Added - `-e, --edit` flag opens the resolved config file in `$EDITOR`. ### Changed - `keeper.ts` (and `@nut-tree-fork/nut-js`) is lazy-imported, so `--help` and `--version` skip the nut.js load and start ~10x faster. ## [1.1.1] - 2026-06-17 ### Changed - Tests moved from `src/` to a top-level `tests/` directory. - `tsconfig.json` sets `"types": ["bun"]` so VS Code resolves `bun:test`. ### Fixed - `package.json` version now matches the published tag. ## [1.1.0] - 2026-06-17 ### Added - JSON config file support at `${XDG_CONFIG_HOME:-~/.config}/move/config.json`. Precedence: CLI flags > config file > defaults. Strict validation. - `-C, --config ` to override the default config path. - Installer seeds `config.json` with project defaults on fresh install only. - Bun test suite for `resolveConfig` and `loadConfigFile`. ### Changed - Installer scripts now live in `scripts/`. - `verbose` is now a first-class `Config` field; `resolveVerbose` removed. - `CliError` extracted into `src/errors.ts`. - `defaultConfigPath()` throws when both `$XDG_CONFIG_HOME` and `$HOME` are unset. - `mouse.config.autoDelayMs = 0` moved into `runKeeper` (no module-load side effect). - Runtime errors go through a `failRuntime` helper that mirrors `failUser`. - `keeper.ts` declares a named `Logger` interface. - `dev-setup.sh` is now POSIX `sh`. - `tsconfig.json`: enabled `noUncheckedIndexedAccess` and `resolveJsonModule`. ## [1.0.1] - 2026-06-17 ### Added - End-user `install.sh` runnable via `curl ... | sh`. XDG-respecting, idempotent. - `uninstall.sh` removes the wrapper and install tree; leaves Bun and user config alone. - `dev-setup.sh` for contributors. ### Removed - `DISTRIBUTION-PLAN.md` (design notes, superseded by the implementation). ## [1.0.0] - 2026-06-15 Initial release. ### Added - `move` CLI for keeping presence-tracking apps marked Available by nudging the cursor after a configurable idle period. - Flags: `-h/--help`, `-v/--version`, `-m/--move-interval`, `-c/--check-interval`, `-d/--step-delay`, `-n/--step-count`, `-V/--verbose`. - Quiet-by-default logging. - Source split into `src/{move,cli,config,keeper}.ts`. - `bin` entry + shebang so `bun link` registers `move` globally. [1.4.0]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.3.3...v1.4.0 [1.3.3]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.3.2...v1.3.3 [1.3.2]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.3.1...v1.3.2 [1.3.1]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.3.0...v1.3.1 [1.3.0]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.2.0...v1.3.0 [1.2.0]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.1.1...v1.2.0 [1.1.1]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.1.0...v1.1.1 [1.1.0]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.0.1...v1.1.0 [1.0.1]: https://gitea.cahlen.com/nokeo08/Move/compare/v1.0.0...v1.0.1 [1.0.0]: https://gitea.cahlen.com/nokeo08/Move/releases/tag/v1.0.0