docs: Add specs and tasks for previously scoped work in todo.md
This commit is contained in:
59
.config/dot/.claude/spec/dot-setup-folders.md
Normal file
59
.config/dot/.claude/spec/dot-setup-folders.md
Normal file
@@ -0,0 +1,59 @@
|
||||
## Problem Statement
|
||||
|
||||
The old `~/wrk/dotfiles` repo's `setup_folders` (part of its bash `bin/dot init`) renamed the standard XDG user folders to short names (`Documents→doc`, `Downloads→dwn`, etc.) for better fish shell-completion ergonomics — shorter shared prefixes are easier to disambiguate by typing fewer characters. That behavior has no equivalent in the new bare-repo `dot` CLI. Right now this machine's `user-dirs.dirs` is untracked and has drifted from even the old convention: it uses the full XDG default names, plus an ad hoc `XDG_PROJECTS_DIR=$HOME/Projects` line that never existed in the old repo at all. If this machine were rebuilt today, none of the short-name convention would be restored, and the current drifted state isn't recorded anywhere.
|
||||
|
||||
## Solution
|
||||
|
||||
Add a `folders` task to a new `dot setup` subcommand family (the general home for idempotent, re-runnable machine-setup tasks, as opposed to `dot init`'s one-shot bootstrap). `dot setup folders` brings the 8 standard XDG user directories under the project's short-name convention, tracks the resulting `user-dirs.dirs` directly as a plain dotfile, and safely migrates any content sitting in the old, full-named folders into their short-named replacements.
|
||||
|
||||
`~/wrk` (already in active use, e.g. `~/wrk/dotfiles`) replaces the old `Projects`-style folder as the general working-files location, but is treated as a plain convention-only directory, not a tracked XDG category.
|
||||
|
||||
## User Stories
|
||||
|
||||
1. As the machine owner, I want the standard XDG user folders renamed to short names (`doc`, `dwn`, `mus`, `pic`, `vid`, `.desktop`), so that fish-completion on my home directory has shorter, easier-to-disambiguate shared prefixes than the full XDG default names.
|
||||
2. As the machine owner, I want `Templates` and `Public` (both unused) collapsed into a single hidden `.ignoreme` folder, so that apps respecting `XDG_TEMPLATES_DIR`/`XDG_PUBLICSHARE_DIR` don't scatter files directly into `$HOME`, without needing two separate unused folders.
|
||||
3. As the machine owner, I want the nested `Pictures/Screenshots` folder lowercased to `pic/screenshots` in the same pass as the `Pictures→pic` rename, so that the screenshot folder matches the rest of the short-folder naming convention without a separate migration step.
|
||||
4. As the machine owner, I want `~/wrk` to have no XDG variable pointing at it, so that a non-standard, barely-recognized XDG extension (`XDG_PROJECTS_DIR`) doesn't get tracked for a directory that already works fine as a plain convention.
|
||||
5. As the machine owner, I want `user-dirs.dirs` tracked directly in the bare dotfiles repo like any other plain dotfile, so that the desired short names are recorded and restorable on a fresh machine without needing a code-generation step.
|
||||
6. As the machine owner, I want `dot setup folders` to migrate content out of any legacy full-named folder into its short-named replacement automatically when the legacy folder is empty, so that re-running setup on a fresh install requires no manual folder shuffling.
|
||||
7. As the machine owner, I want `dot setup folders` to stop and ask for explicit confirmation before moving anything out of a legacy folder that actually has content in it, so that I never silently lose files to an automated migration I forgot was going to run.
|
||||
8. As the machine owner, I want confirmation to be satisfiable via a `--yes` flag rather than an interactive prompt, so that the same command works identically whether I'm running it by hand or from an automated/tested context.
|
||||
9. As the machine owner, I want a filename collision between a legacy folder and an already-populated short-named target to never be silently overwritten, so that re-running the migration after a partial/interrupted prior run can't destroy a file just because both sides happen to have a same-named entry.
|
||||
10. As the machine owner, I want to be told which files were skipped due to a collision and have the legacy folder left in place when that happens, so that I have a clear, actionable signal that something needs manual attention instead of silent partial data loss.
|
||||
11. As the machine owner, I want `dot setup folders` to notify running apps of the directory changes via `xdg-user-dirs-update` after migrating, so that session-long apps pick up the new paths without requiring a full logout/login.
|
||||
12. As the machine owner, I want to run `dot setup` with no arguments to perform every machine-setup task (folders plus future ones like extra groups) in one command, so that setting up a fresh machine doesn't require remembering and running each task individually.
|
||||
13. As the machine owner, I want to also be able to run `dot setup folders` on its own, so that I can re-run just this one task in isolation (e.g. after a confirmation was declined) without re-running unrelated setup tasks.
|
||||
|
||||
## Implementation Decisions
|
||||
|
||||
- **Subcommand family**: `dot setup`, following the project's existing nested-subcommand dispatch convention (`help`-then-`argparse`, `_dot_<name>_usage`). Bare `dot setup` (no arguments) runs every machine-setup task unconditionally (folders, plus future tasks such as extra groups, mirroring the old bash `bin/dot init`'s dual-mode: no-args ran everything, an explicit keyword ran just one task). `dot setup folders` runs just the folders task.
|
||||
- **Folder mapping** (identical to the old repo's `setup_folders`, no changes): `Desktop→.desktop`, `Documents→doc`, `Downloads→dwn`, `Music→mus`, `Pictures→pic`, `Videos→vid`, `Templates→.ignoreme`, `Public→.ignoreme`. `Templates` and `Public` both point at the *same* `.ignoreme` folder, as before.
|
||||
- **Nested screenshots rename**: as part of the same `Pictures→pic` migration pass, the nested `Screenshots` folder (currently created empty by KDE/Spectacle defaults) is renamed to lowercase `screenshots`, so the result is `pic/screenshots`. This is folded into the folders task rather than deferred to the separate Spectacle-keybind work, since it's the same naming-convention concern and falls out for free once `Pictures/*` is moved into `pic/`.
|
||||
- **`wrk` is out of the XDG mapping**: no `XDG_PROJECTS_DIR` (or any other XDG variable) is written for it. It's a plain, convention-only directory. The currently-existing ad hoc `~/Projects` folder (created by this machine's diverged, untracked `user-dirs.dirs`) is left alone — out of scope for the folders task, since it was never one of the 8 standard XDG categories the task manages, and it's empty and harmless.
|
||||
- **`user-dirs.dirs` is tracked directly** as a plain dotfile in the bare repo (not generated/overwritten by `dot setup folders` from a hardcoded table each run) — unlike KDE's rc files (tracked via a separate declarative-manifest mechanism, see the `dot-kde` spec), `user-dirs.dirs` has no volatile/machine-specific fields, so it fits the same direct-tracking treatment as any other plain dotfile (`.bashrc`, etc.). The tracked file is the single source of truth for the desired short names.
|
||||
- **`dot setup folders` still needs a small hardcoded table** mapping each of the 8 standard XDG categories to its legacy default folder name (`Documents`, `Downloads`, etc.) — this is used purely to locate content left behind by a fresh XDG-defaults install and merge it into the already-tracked short-named target; it is not the source of truth for the target names themselves (that's the tracked `user-dirs.dirs`).
|
||||
- **Migration safety, per legacy folder**:
|
||||
- Empty (strict check: any file at all, including dotfiles/metadata like a stray KDE `.directory` file, counts as non-empty) → merge silently, no prompt.
|
||||
- Non-empty → print what would be moved and require an explicit `--yes` flag before proceeding. No interactive prompt.
|
||||
- Collisions (a same-named entry exists in both the legacy folder and its short-named target) → use no-clobber semantics (e.g. `mv -n`) so a colliding file is never silently overwritten; report which files were skipped; leave the legacy folder in place (don't remove it) if any collision occurred, rather than deleting a folder that still holds something that couldn't be merged.
|
||||
- **Post-migration step**: run `xdg-user-dirs-update` (no arguments) once folder moves are complete, to notify running apps/portals via its D-Bus signal. This is safe against the hand-tracked file — `user-dirs.dirs`'s own header documents that local edits are preserved across runs of the tool.
|
||||
|
||||
## Testing Decisions
|
||||
|
||||
- **Guiding principle**: test the folders task's own logic (mapping, empty-vs-non-empty gating, `--yes` behavior, collision handling, idempotency) through the real CLI entry point, not the internals of `mv`/`mkdir` themselves.
|
||||
- **Primary seam**: full CLI invocation of `dot setup folders` (and bare `dot setup`), run against a scratch `$HOME` per test case — the existing project convention (see `dot install`'s tests). No new seam is introduced.
|
||||
- **External command handling**: `xdg-user-dirs-update` is faked out via a `PATH`-prepended fake binary that logs its invocation (and exit code), exactly mirroring how `sudo`/`pacman` are faked for `dot install`'s tests. Real `mkdir`/`mv`/`rmdir` run for real against the scratch `$HOME` — no need to fake filesystem operations themselves.
|
||||
- **Cases to cover**: fresh migration of empty legacy folders (no `--yes` needed); a legacy folder with real content refuses without `--yes` and proceeds with it; the nested `Pictures/Screenshots→pic/screenshots` rename; a stray dotfile (e.g. a fake `.directory`) in an otherwise-"empty" legacy folder still triggers the confirmation gate; a filename collision between legacy and target is skipped (not overwritten), reported, and leaves the legacy folder in place; re-running `dot setup folders` after a clean migration is a no-op (idempotency); bare `dot setup` runs the folders task as part of running everything; `dot setup folders help` prints usage and touches nothing.
|
||||
- **Prior art**: `tests/dot.fish`'s existing scratch-`$HOME`-plus-`fishtape` pattern, and specifically the fake-`sudo`/fake-`pacman`-via-`PATH` technique used for `dot install`.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- The **extra groups** task (`dot setup groups` or similar, porting the old `.extra_groups`/`setup_users` behavior) — it will share the same `dot setup` dispatcher and dual-mode (bare-runs-everything vs. named-task) shape decided here, but its own design (group list format, idempotency, etc.) was not addressed in this spec.
|
||||
- Any KDE-side settings (caps-lock/Escape swap, screenshot keybinds, Lock Session rebind) — covered separately by the `dot-kde` spec/design.
|
||||
- Removing the currently-existing, now-orphaned `~/Projects` folder — explicitly left alone, not cleaned up by this feature.
|
||||
- Any `~/.github/README.md` command-table row or `~/.github/keybindings.md` update — not applicable here (no keybind changes), but the README row is still required by the project's standard "adding a subcommand" checklist at implementation time.
|
||||
|
||||
## Further Notes
|
||||
|
||||
- The old bash `setup_folders`'s naive `mv $from/* $to` has a latent bug this design deliberately avoids: an unquoted glob against an empty directory can misbehave, and it has no collision protection at all. The no-clobber-plus-report behavior specified here is a deliberate improvement over the old script's behavior, not a straight port.
|
||||
- This spec covers only the `folders` task; `dot setup` itself (the dispatcher, `_dot_setup_usage`, wiring into `commands/`, the completions/help-glob duplication point noted in the project's `CLAUDE.md`) needs to exist as scaffolding for this task to attach to, even though its only other planned task (extra groups) is out of scope here.
|
||||
Reference in New Issue
Block a user