feat(config): opt-in preserve_tilde_on_save for dotfiles-friendly path serialization#155
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces an opt-in PreserveTildeOnSave configuration setting that folds absolute home directory paths back to the ~ form during YAML serialization, ensuring machine-agnostic configuration files. The implementation includes a new FoldHomePath utility and logic to clone and process configuration fields before saving. Feedback suggests including the missing AgentsSource field in the folding logic and optimizing performance by caching the result of os.UserHomeDir() instead of calling it repeatedly during serialization.
| out.Source = utils.FoldHomePath(out.Source) | ||
| out.ExtrasSource = utils.FoldHomePath(out.ExtrasSource) |
There was a problem hiding this comment.
The AgentsSource field is missing from the path folding logic in cloneForSave. For consistency with Source and ExtrasSource, it should also be folded back to the ~ form when PreserveTildeOnSave is enabled.
| out.Source = utils.FoldHomePath(out.Source) | |
| out.ExtrasSource = utils.FoldHomePath(out.ExtrasSource) | |
| out.Source = utils.FoldHomePath(out.Source) | |
| out.AgentsSource = utils.FoldHomePath(out.AgentsSource) | |
| out.ExtrasSource = utils.FoldHomePath(out.ExtrasSource) |
| if path == "" || HasTildePrefix(path) { | ||
| return path | ||
| } | ||
| home, err := os.UserHomeDir() |
There was a problem hiding this comment.
Calling os.UserHomeDir() repeatedly inside a loop (as done in cloneForSave) can be inefficient, especially on Windows where it involves syscalls. Consider retrieving the home directory once in the caller and passing it to FoldHomePath, or caching the result within the utils package to improve performance during serialization.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 772054f67c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // config to YAML. Useful when the config is shared via dotfiles across | ||
| // machines or users. The in-memory config is unaffected; Load() still | ||
| // expands ~ as usual. | ||
| PreserveTildeOnSave bool `yaml:"preserve_tilde_on_save,omitempty"` |
There was a problem hiding this comment.
Add new config key to published JSON schema
Introducing preserve_tilde_on_save in Config without updating schemas/config.schema.json makes saved configs invalid against the advertised schema (additionalProperties: false at the root), so editors and any schema-based validation will reject this new key even though the app now writes/reads it. Since Save() always emits the schema directive comment, users enabling this option will immediately see schema errors.
Useful? React with 👍 / 👎.
Add PreserveTildeOnSave config flag (default false). When enabled, the
Save path folds $HOME prefixes back to ~ when serializing the in-memory
Config to YAML so the on-disk config stays portable across machines
(e.g. when shared via dotfiles).
The in-memory Config is left untouched; cloneForSave() produces a
shallow copy with path fields rewritten. Mirrors the existing
expandPath() calls performed in Load():
- cfg.Source, cfg.ExtrasSource
- cfg.Targets[*].Path / Skills.Path / Agents.Path
- cfg.Extras[*].Source and Extras[*].Targets[*].Path
Adds:
- utils.FoldHomePath() helper with unit tests (exact-home, child,
sibling-non-home, unrelated-abs, relative, Windows case-insensitive)
- 3 Save-path tests covering default-off, fold-on, and Load→Save
idempotency.
Default off keeps the change backward compatible: existing users see no
behavior difference. Users who share their config via dotfiles can opt
in with:
preserve_tilde_on_save: true
772054f to
29a48f4
Compare
|
Addressed all three review comments in the latest force-push (
All |
|
Thanks! I'll handle docs update on our side after merge. |
Problem
When a user shares their
skillshareconfig via dotfiles (or any other cross-machine sync), everycfg.Save()call rewrites~/...paths into absolute/home/<user>/...form. The user-name (and OS-specific home prefix) gets burned into the config, breaking portability and creating noisy diffs on every operation that touches a target.Repro:
Load()expands~(correctly —os.Statetc. don't understand~), butSave()writes the expanded value verbatim, losing the original form.Proposal
Add an opt-in config flag, default
false(no behavior change for existing users):When enabled,
Save()folds$HOMEprefixes back to~before serialization. The in-memoryConfigis left untouched; we marshal a shallow copy with rewritten path fields. Downstream consumers (sync, validators, etc.) are unaffected.Folded fields mirror the existing
expandPath()calls inLoad():cfg.Source,cfg.ExtrasSourcecfg.Targets[*].Path,Skills.Path,Agents.Pathcfg.Extras[*].Source,Extras[*].Targets[*].PathFoldHomePath()only folds when:$HOME(home + separatorprefix, or exacthome)~os.UserHomeDir()succeedsNon-home absolute paths (
/opt/foo,/tmp/bar) and relative paths are passed through unchanged. Windows paths fold viaPathHasPrefix(case-insensitive on Windows).Tests
internal/utils/path_test.go: 7 cases (exact home, child, sibling-non-home, unrelated-abs, relative, empty, already-tilde) + Windows case-fold test.internal/config/config_tilde_fold_test.go:Configis not mutated.Save→Load→Saveis byte-for-byte idempotent.All
internal/...tests pass on the branch.Backward compatibility
Zero. Default
false. Existing configs and CI behave identically.Notes