4 Commits
Author SHA1 Message Date
nokeo08 68e64eeaef Release 1.3.1 2026-08-14 15:09:59 -05:00
nokeo08 d0528b4a92 docs: fix mermaid parse error in happy-path diagram
Mermaid treats ';' as a statement separator, so the label
'lastPos (== start; re-sync)' terminated mid-line and the parser then
expected an arrow (the 'Parse error on line 59' the preview showed).
Removed the semicolon and, defensively, replaced 'Iterable<Point>' with
plain text so the angle brackets aren't interpreted as an HTML tag in the
rendered label.
2026-08-14 13:50:21 -05:00
nokeo08 c002a6d902 Fix stale comments to match current code
Audited comments project-wide against the current implementation:

- scripts/install.sh, scripts/uninstall.sh: header curl URLs pointed at a
  root-level install.sh/uninstall.sh, but the files live under scripts/ —
  the documented command 404'd. Corrected to the scripts/ path (matching
  the README and the actual file location).
- src/move.ts: header said it ties "four logic modules" and omitted
  editor.ts; the --edit terminal action was also missing from the order of
  operations. Both corrected.
- src/config.ts: numeric Config fields are all milliseconds now; dropped the
  stale "pixels" unit left over from stepCount/stepSize.

Comments-only (plus two script header lines); tsc clean, 64 tests pass.
2026-08-14 13:39:15 -05:00
nokeo08 41903ebaf1 docs: add execution happy-path sequence diagram 2026-08-14 13:28:43 -05:00
8 changed files with 119 additions and 9 deletions
+14
View File
@@ -5,6 +5,19 @@ 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).
## [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
@@ -113,6 +126,7 @@ Initial release.
- Source split into `src/{move,cli,config,keeper}.ts`.
- `bin` entry + shebang so `bun link` registers `move` globally.
[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
+4
View File
@@ -206,6 +206,9 @@ file with `--config`.
## How it works
For a step-by-step trace of a clean sweep, see the
[execution happy-path sequence diagram](docs/execution-happy-path.md).
The source lives under `src/`, split into an entry point plus logic
modules:
@@ -358,6 +361,7 @@ move --help
| `src/device.ts` | `Device` I/O seam over nut.js (`Point`, `createNutDevice`); the only nut.js importer. |
| `src/strategies.ts` | Pure movement-pattern generators, the strategy registry, and name validation. |
| `src/executor.ts` | `executePath` driver: bounds policy, pacing, interrupt detection, restore. |
| `docs/execution-happy-path.md` | Sequence diagram + invariants for a clean sweep. |
| `package.json` | Bun project manifest. Single runtime dep: `@nut-tree-fork/nut-js`. |
| `tsconfig.json` | Strict TypeScript config tuned for Bun (ESNext, bundler resolution). |
| `bun.lock` | Bun's lockfile. Commit this. |
+88
View File
@@ -0,0 +1,88 @@
# Execution: the happy path
This traces one full idle-triggered sweep that completes cleanly — the
"happy path" where the machine is idle long enough to fire, the configured
pattern runs to exhaustion, and no real user activity interrupts it.
For the module breakdown and the three seams (`device` / `strategies` /
`executor`), see the "How it works" section of the [README](../README.md).
```mermaid
sequenceDiagram
autonumber
participant Entry as move.ts
participant Keeper as runKeeper
participant Sim as simulateActivity
participant Strat as Strategy<br/>(e.g. line)
participant Exec as executePath
participant Dev as Device<br/>(nut.js)
Note over Entry: startup (args → config)
Entry->>Entry: parseCliArgs()
Entry->>Entry: loadConfigFile()
Entry->>Entry: resolveConfig(file, cli)
Entry->>Keeper: runKeeper(config)
Keeper->>Dev: createNutDevice()
Note right of Dev: sets mouse.config.autoDelayMs = 0
Keeper->>Keeper: log.info(banner)
Keeper->>Dev: getPosition()
Dev-->>Keeper: lastPos
Note over Keeper: lastActivity = now
loop every checkInterval (until idle long enough)
Keeper->>Dev: sleep(checkInterval)
Keeper->>Dev: getPosition()
Dev-->>Keeper: pos
Note over Keeper: pos == lastPos (no user movement)<br/>now - lastActivity ≥ moveInterval → fire
end
Keeper->>Sim: simulateActivity(config, log, dev)
Sim->>Dev: getPosition()
Dev-->>Sim: start
Sim->>Dev: width()
Dev-->>Sim: width
Sim->>Dev: height()
Dev-->>Sim: height
Note over Sim: strategy = STRATEGIES[config.pattern]<br/>ctx = { start, width, height, rng }
Sim->>Exec: executePath(strategy, ctx, dev, log, config)
Exec->>Strat: path(ctx)
Strat-->>Exec: iterable of Points
loop for each target point (clean run)
Exec->>Exec: resolveTarget(bounds, target) → point
Exec->>Dev: setPosition(point)
Exec->>Dev: sleep(stepDelay)
Exec->>Dev: getPosition()
Dev-->>Exec: current
Note over Exec: |current - point| ≤ 2px → not the user, continue
end
Note over Exec: path exhausted, no interruption
Exec->>Dev: setPosition(round(start))
Note right of Exec: restore cursor to origin
Exec-->>Sim: "completed"
Sim-->>Keeper: (done)
Keeper->>Dev: getPosition()
Dev-->>Keeper: lastPos (equals start, re-synced)
Note over Keeper: lastActivity = now<br/>loop continues
```
## Invariants this path relies on
- **`createNutDevice()` is the only nut.js touchpoint.** It disables nut.js's
100ms auto-delay so `executePath` owns cadence via `stepDelay`.
- **The strategy is pure.** `path(ctx)` yields ideal points from geometry
alone (`start` / `width` / `height` / `rng`); it never touches the device,
which is what makes every pattern unit-testable without a screen.
- **Every step re-reads the cursor** and compares it against the *commanded*
point (not the strategy's ideal, possibly fractional target) within a 2px
tolerance. On the happy path each check passes, so the loop runs to
exhaustion. A mismatch beyond tolerance is real user activity and returns
`"interrupted"` without restoring — the branch this diagram omits.
- **Clean completion restores the cursor to `round(start)`.** That is why the
follow-up `getPosition()` in `runKeeper` re-syncs `lastPos` to the origin as
a no-op, and the next idle check sees no net movement (so the synthetic
sweep is never mistaken for the user returning).
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "move",
"version": "1.3.0",
"version": "1.3.1",
"private": true,
"license": "GPL-3.0-only",
"type": "module",
+1 -1
View File
@@ -4,7 +4,7 @@
#
# Curl-pipe ready:
#
# curl -fsSL https://gitea.cahlen.com/nokeo08/Move/raw/branch/master/install.sh | sh
# curl -fsSL https://gitea.cahlen.com/nokeo08/Move/raw/branch/master/scripts/install.sh | sh
#
# What it does:
# 1. Detect platform; bail on anything @nut-tree-fork/nut-js doesn't ship.
+1 -1
View File
@@ -4,7 +4,7 @@
#
# Curl-pipe ready:
#
# curl -fsSL https://gitea.cahlen.com/nokeo08/Move/raw/branch/master/uninstall.sh | sh
# curl -fsSL https://gitea.cahlen.com/nokeo08/Move/raw/branch/master/scripts/uninstall.sh | sh
#
# Removes the `move` wrapper from $XDG_BIN_HOME and the install tree from
# $XDG_DATA_HOME/move. Does NOT remove Bun — that's your runtime, not ours.
+1 -1
View File
@@ -10,7 +10,7 @@
* `resolveConfig` rather than mutating the defaults, so the defaults stay
* genuinely constant and the resolved config stays structurally typed.
*
* All numeric `Config` fields are in their internal units (ms, pixels).
* All numeric `Config` fields are in their internal units (milliseconds).
* The CLI and config file expose the time-valued fields in seconds for
* ergonomics; `resolveConfig` performs the seconds->ms conversion at the
* boundary so downstream code never has to think about it.
+9 -5
View File
@@ -4,23 +4,27 @@
* -------
* Entry point for the `move` CLI.
*
* Thin shim that ties the four logic modules together:
* Thin shim that ties the 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.
* - `editor.ts` backs `--edit` (open the config file in `$EDITOR`).
* - `keeper.ts` owns the idle-watch loop and drives the movement
* machinery (device / strategy / executor).
*
* Order of operations:
* 1. Parse CLI args. Bad input -> stderr + usage hint, exit 2.
* 2. `--help` / `--version` short-circuit before any I/O, config load, or
* mouse work. `keeper.ts` is also lazy-imported (see below) so these
* flags don't pay the cost of loading the nut.js native binary.
* 3. Load + validate the config file (default XDG path, or `--config
* 3. `--edit` opens the resolved config file in `$EDITOR` and is a
* terminal action (propagates the editor's exit code).
* 4. Load + validate the config file (default XDG path, or `--config
* <path>` if supplied). Validation failures share the exit-2 path.
* 4. Resolve the full `Config` (CLI > file > DEFAULT_CONFIG) — verbose
* 5. Resolve the full `Config` (CLI > file > DEFAULT_CONFIG) — verbose
* lives inside `Config` and is layered with the same precedence as
* the numeric fields.
* 5. Lazy-import `keeper.ts` (dynamic import keeps nut.js out of the
* 6. Lazy-import `keeper.ts` (dynamic import keeps nut.js out of the
* `--help` / `--version` startup path) and run it. Any unhandled
* rejection — from the import itself or from the loop — exits 1.
*