CliError used to live in cli.ts and was imported by configFile.ts purely
to grab a one-line class — the dependency arrow said 'config-file loader
depends on the CLI parser' when really it just needed a shared error
type.
Moving CliError to its own errors.ts module flattens the graph:
errors.ts (no internal deps)
|
+-- cli.ts
+-- configFile.ts
+-- config.ts (will use it in the next commit)
cli.ts re-exports CliError for any consumer that prefers to keep
importing it from there; the canonical home is now errors.ts.
The defaults now live in a single file, scripts/config.default.json:
- src/config.ts imports it via 'with { type: "json" }' and derives
DEFAULT_CONFIG (with seconds->ms conversion at the boundary), so the
CLI help text always matches what the seeded user config contains.
- scripts/install.sh copies the same file to
$XDG_CONFIG_HOME/move/config.json only if no file is already there.
Existing configs (yours or from a previous install) are never
overwritten.
- scripts/uninstall.sh does not touch the user config file at all,
following the strict Unix convention. It does print a one-line
notice pointing at the path so the user can rm -rf the dir
themselves if they want a fully-clean removal.
- tsconfig.json gains resolveJsonModule:true so tsc accepts the JSON
import.
- A small runtime assertion in src/config.ts (assertSeedShape) fails
loudly if the seed file is missing keys or has wrong types.
- README Configuration section documents the seed behavior; Uninstall
section documents the leave-config-behind policy with the rm-it-
yourself command; Files table gains scripts/config.default.json.
Verbose was awkwardly a separate runKeeper argument with a separate
resolveVerbose helper, even though it's just another tunable on the
same precedence ladder as the numeric fields. This commit collapses it.
Changes:
- Config gains 'readonly verbose: boolean'. DEFAULT_CONFIG sets it to
false.
- resolveConfig now returns the full Config including verbose. Verbose
layers with the same 'first defined value wins' precedence as the
numeric fields.
- resolveVerbose is gone.
- ParsedCliArgs.verbose becomes boolean | undefined: undefined when -V
was not passed, true when it was. parseCliArgs maps accordingly.
This lets the layered resolver treat verbose uniformly.
- runKeeper takes a single Config arg. The internal logger reads from
config.verbose at the top of runKeeper.
- move.ts no longer plumbs verbose separately; the single resolved
Config drives everything.
- README How-it-works and Files-table entries updated to match.
Behavior verified for all five verbose-precedence cases (no file/no
flag, no file/-V, file:true/no flag, file:false/-V, file:false/no
flag) and config-error scenarios remain intact.
End users can now set defaults in a config file at:
${XDG_CONFIG_HOME:-$HOME/.config}/move/config.json
CLI flags continue to win when both are set:
CLI flags > config file > built-in defaults
Schema mirrors the CLI flag names and units. Loader is strict: unknown
keys, wrong types, and non-positive numerics are rejected with a clear
message naming the file and key, and the process exits 2.
Changes:
- New src/configFile.ts: existence-aware loader + strict schema
validation. Throws CliError; the entry point converts those to exit 2.
- src/config.ts: ConfigOverrides gains 'verbose'; resolveConfig takes
both file and CLI override layers; new defaultConfigPath() honors
XDG_CONFIG_HOME; new resolveVerbose() layers verbose with the
presence-only-CLI semantics documented.
- src/cli.ts: -C/--config <path> flag. printHelp prints the default
config path and the precedence rule.
- src/move.ts: loads the config file (default XDG path or --config),
passes both override layers into resolveConfig, resolves verbose
separately, exits 2 on any validation failure.
- README: new Configuration section with path, precedence, example,
validation rules, and the verbose CLI-can't-turn-off limitation.
Files table gains src/configFile.ts.
- 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