claude-nomad 0.67.0 → 0.67.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -156
- package/dist/nomad.mjs +30 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,27 +1,49 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.67.1](https://github.com/funkadelic/claude-nomad/compare/v0.67.0...v0.67.1) (2026-08-20)
|
|
4
|
+
|
|
5
|
+
### What's new
|
|
6
|
+
|
|
7
|
+
**On all supported platforms, i.e. \*nix, Mac, WSL2, and native Windows.**
|
|
8
|
+
|
|
9
|
+
- **A project in a folder named `sessions`, `tasks`, `plans`, or `cache` now syncs its own history.** Those names, along with `debug`, `jobs`, `security`, and a few more, belong to nomad's own working folders, so a project of yours that happened to share one was refused as though it held something private. Nothing in it was, and the name alone decided it. Those projects now sync like any other, and nomad still checks what is actually inside a folder exactly as before.
|
|
10
|
+
- **A per-host settings file sitting at the very top of a folder you share now stays out of your sync repo.** Inside a folder you opted into sharing, nomad already blocked `settings.local.json` and anything else shaped like a credential file at every level except the very top, where one could slip past and reach your other machines. The top level is now covered too.
|
|
11
|
+
|
|
12
|
+
**On native Windows (PowerShell or cmd).** Note: WSL2 behaves like Linux and none of these apply to it.
|
|
13
|
+
|
|
14
|
+
- **A pull no longer removes that project's transcripts from your sync repo.** The same name check ran during a pull, where it deleted rather than refused, so every pull stripped that project's saved history out of the sync repo. Each one left a backup under `~/.cache/claude-nomad/backup/`, but never put anything back. Pulls now leave those projects alone.
|
|
15
|
+
- **When a sync cannot remove or back up a file, it now tells you why.** These warnings sometimes printed the word `undefined` where the reason belongs, so you got a filename and nothing else. They now carry the real reason. A failure arriving in an unexpected form could also stop the cleanup partway through, leaving the files after the first problem unhandled and unmentioned. The pass now runs to the end and reports everything it did.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
* **config:** stop a project's own folder name from blocking its history ([#536](https://github.com/funkadelic/claude-nomad/issues/536)) ([1994c55](https://github.com/funkadelic/claude-nomad/commit/1994c55a32c62220e8d7291554f95099b2c12eba))
|
|
21
|
+
* **mirror:** name the reason in sync warnings instead of undefined ([#537](https://github.com/funkadelic/claude-nomad/issues/537)) ([e973ff3](https://github.com/funkadelic/claude-nomad/commit/e973ff392e369694e517c5aabfb26c996836378f))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
* **codeql:** exclude test files from security scanning ([#534](https://github.com/funkadelic/claude-nomad/issues/534)) ([c86a6d3](https://github.com/funkadelic/claude-nomad/commit/c86a6d3c80a640e0a251181c8c0461edef2375da))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Dependencies
|
|
30
|
+
|
|
31
|
+
* bump fast-uri from 3.1.4 to 3.1.5 ([#527](https://github.com/funkadelic/claude-nomad/issues/527)) ([6a8f6ba](https://github.com/funkadelic/claude-nomad/commit/6a8f6baa534dae9d9e6786acf96627c85bb8d400))
|
|
32
|
+
* bump js-yaml from 4.3.0 to 4.3.1 in /docs-site ([#529](https://github.com/funkadelic/claude-nomad/issues/529)) ([a4e541f](https://github.com/funkadelic/claude-nomad/commit/a4e541fd74100527306ebaa713a2a730ffe98af7))
|
|
33
|
+
* bump nanoid from 3.3.15 to 3.3.18 in /docs-site ([#531](https://github.com/funkadelic/claude-nomad/issues/531)) ([0a0f53e](https://github.com/funkadelic/claude-nomad/commit/0a0f53ee46e3b69babd82b84e39c6982791f8896))
|
|
34
|
+
* bump postcss from 8.5.15 to 8.5.26 in /docs-site ([#530](https://github.com/funkadelic/claude-nomad/issues/530)) ([413f75d](https://github.com/funkadelic/claude-nomad/commit/413f75db6c292785f6b7d67fbd629680d5b39e04))
|
|
35
|
+
* bump postcss from 8.5.16 to 8.5.26 ([#532](https://github.com/funkadelic/claude-nomad/issues/532)) ([b03bd62](https://github.com/funkadelic/claude-nomad/commit/b03bd62ab77249bdcc31c78ac2440da434b2de39))
|
|
36
|
+
* bump svgo from 4.0.1 to 4.0.2 in /docs-site ([#528](https://github.com/funkadelic/claude-nomad/issues/528)) ([a424693](https://github.com/funkadelic/claude-nomad/commit/a4246932d01a79082383d6a09e08e7542eb7a873))
|
|
37
|
+
|
|
3
38
|
## [0.67.0](https://github.com/funkadelic/claude-nomad/compare/v0.66.0...v0.67.0) (2026-08-18)
|
|
4
39
|
|
|
5
40
|
### What's new
|
|
6
41
|
|
|
7
42
|
**On all supported platforms, i.e. \*nix, Mac, WSL2, and native Windows.**
|
|
8
43
|
|
|
9
|
-
- **Your backup cache no longer collects empty folders.** Every sync saves a copy of anything it is
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
it has changed anything. A sync that turns out to have nothing to save now clears its own folder
|
|
13
|
-
instead of leaving an empty one behind, and so does one that stops early.
|
|
14
|
-
- **`nomad clean --backups` removes empty backup folders whatever their age.** They hold nothing to
|
|
15
|
-
recover, so neither the 14-day default nor `--keep <N>` keeps one alive, and they no longer use up
|
|
16
|
-
the slots `--keep <N>` reserves: ask for the five newest and you get the five newest that actually
|
|
17
|
-
hold something. Backups holding anything at all, a file or even a link, are left exactly as
|
|
18
|
-
before. `nomad clean --backups --dry-run` always prints its preview, since it changes nothing and
|
|
19
|
-
never waits on another command.
|
|
20
|
-
- **`nomad adopt` no longer runs at the same time as a pull, push, or sync.** It waits its turn the
|
|
21
|
-
way those commands already wait for each other, so a cleanup or a sync running in another terminal
|
|
22
|
-
cannot remove or overwrite a backup that adopt is still writing. If another one is already
|
|
23
|
-
running, adopt says so and does nothing rather than starting a move it cannot finish safely.
|
|
24
|
-
Previewing with `nomad adopt <name> --dry-run` never waits, since it only reads and prints.
|
|
44
|
+
- **Your backup cache no longer collects empty folders.** Every sync saves a copy of anything it is about to overwrite into a dated folder under `~/.cache/claude-nomad/backup/`, and it creates that folder before it touches your files so a full disk or a permissions problem stops the sync before it has changed anything. A sync that turns out to have nothing to save now clears its own folder instead of leaving an empty one behind, and so does one that stops early.
|
|
45
|
+
- **`nomad clean --backups` removes empty backup folders whatever their age.** They hold nothing to recover, so neither the 14-day default nor `--keep <N>` keeps one alive, and they no longer use up the slots `--keep <N>` reserves: ask for the five newest and you get the five newest that actually hold something. Backups holding anything at all, a file or even a link, are left exactly as before. `nomad clean --backups --dry-run` always prints its preview, since it changes nothing and never waits on another command.
|
|
46
|
+
- **`nomad adopt` no longer runs at the same time as a pull, push, or sync.** It waits its turn the way those commands already wait for each other, so a cleanup or a sync running in another terminal cannot remove or overwrite a backup that adopt is still writing. If another one is already running, adopt says so and does nothing rather than starting a move it cannot finish safely. Previewing with `nomad adopt <name> --dry-run` never waits, since it only reads and prints.
|
|
25
47
|
|
|
26
48
|
|
|
27
49
|
### Added
|
|
@@ -39,53 +61,17 @@
|
|
|
39
61
|
|
|
40
62
|
**On all supported platforms, i.e. \*nix, Mac, WSL2, and native Windows.**
|
|
41
63
|
|
|
42
|
-
- **A folder you share now carries everything inside it.** If you share a folder through
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
too. `--dry-run` gives exactly the same answer as the real run, so you can check a folder before
|
|
54
|
-
committing to it.
|
|
55
|
-
- **An interrupted `nomad adopt` now explains itself instead of writing a crash report.** If
|
|
56
|
-
another program has the directory open, or its permissions block the move partway through, the
|
|
57
|
-
command says what happened, where your content ended up, and what to run next. Your content is
|
|
58
|
-
safe in every one of these cases: either it was never touched on this machine, or it is already
|
|
59
|
-
in the repo.
|
|
60
|
-
|
|
61
|
-
**On native Windows (PowerShell or cmd).** Note: WSL2 behaves like Linux and none of these apply to
|
|
62
|
-
it.
|
|
63
|
-
|
|
64
|
-
- **A push no longer publishes a folder you never asked to share.** Windows keeps your shared
|
|
65
|
-
config as real file copies rather than symlinks, and a push used to pick up any folder sitting in
|
|
66
|
-
your Claude directory and publish it to your other machines. Sharing is now the same deliberate
|
|
67
|
-
step it has always been on macOS and Linux: run `nomad adopt <name>` once, then push. Your
|
|
68
|
-
existing shared folders keep syncing exactly as before.
|
|
69
|
-
- **`nomad doctor --verbose` names a folder your repo does not carry yet.** It lists the local
|
|
70
|
-
copies that are still private to this machine, and the command that shares one.
|
|
71
|
-
- **One unreadable file no longer ends your pull.** A single config file that another program has
|
|
72
|
-
open, or that your account cannot read, used to stop the whole pull with a crash report. Nomad
|
|
73
|
-
now names the file and the reason, then carries on: your settings, your skills, and your session
|
|
74
|
-
history all still sync, and the command finishes normally. The warning also says whether the file
|
|
75
|
-
is still there or has been removed, and points at the backup copy when there is one.
|
|
76
|
-
- **`nomad adopt` recovers cleanly when it cannot restore your local copy.** Adopt finishes by
|
|
77
|
-
copying the folder back out of the sync repo so this machine keeps a usable copy. If that copy
|
|
78
|
-
was blocked, the command used to end in a crash report, with the folder gone from your Claude
|
|
79
|
-
directory and nothing staged for publishing. It now stops with a plain message naming the folder
|
|
80
|
-
and the reason, stages the adopted content either way, and tells you to run `nomad pull` before
|
|
81
|
-
your next push and why that order matters. A half written folder left behind by the interrupted
|
|
82
|
-
copy is removed, so a later push cannot replace your adopted folder with the partial one.
|
|
83
|
-
- **A refused `nomad pull --force-remote` now tells you what actually clears it.** The old advice
|
|
84
|
-
did not work, and would land you back on the same refusal. The message now gives the steps that
|
|
85
|
-
finish the job and names the one that clears the check, and it says that the stuck rebase has
|
|
86
|
-
already been undone by that point, so retrying is now just an ordinary pull. It no longer calls
|
|
87
|
-
every listed file at risk, since the list can include files where the shared repo is simply ahead
|
|
88
|
-
of yours. The quickstart says the same thing and links to the matching recovery steps in the FAQ.
|
|
64
|
+
- **A folder you share now carries everything inside it.** If you share a folder through `sharedDirs`, its subfolders travel with it, including ones with everyday names like `sessions`, `plans`, `tasks`, and `cache`. Those names used to be refused wherever they appeared, so a push could fail, or `nomad adopt` could turn you away, over a folder holding nothing sensitive. Your Claude login, your credential files, your per-host settings, and your local history still never leave the machine, in either direction.
|
|
65
|
+
- **`nomad adopt` checks the whole folder before it moves anything.** It used to copy everything, so a file that never syncs between machines could land in your repo and fail your next push, on content you never chose to add. Adopt now stops before touching anything and names every path it objected to and why: a name that collides with the never-sync list, which renaming clears, or a name that looks like a credential file, where renaming only helps if the new name looks different too. `--dry-run` gives exactly the same answer as the real run, so you can check a folder before committing to it.
|
|
66
|
+
- **An interrupted `nomad adopt` now explains itself instead of writing a crash report.** If another program has the directory open, or its permissions block the move partway through, the command says what happened, where your content ended up, and what to run next. Your content is safe in every one of these cases: either it was never touched on this machine, or it is already in the repo.
|
|
67
|
+
|
|
68
|
+
**On native Windows (PowerShell or cmd).** Note: WSL2 behaves like Linux and none of these apply to it.
|
|
69
|
+
|
|
70
|
+
- **A push no longer publishes a folder you never asked to share.** Windows keeps your shared config as real file copies rather than symlinks, and a push used to pick up any folder sitting in your Claude directory and publish it to your other machines. Sharing is now the same deliberate step it has always been on macOS and Linux: run `nomad adopt <name>` once, then push. Your existing shared folders keep syncing exactly as before.
|
|
71
|
+
- **`nomad doctor --verbose` names a folder your repo does not carry yet.** It lists the local copies that are still private to this machine, and the command that shares one.
|
|
72
|
+
- **One unreadable file no longer ends your pull.** A single config file that another program has open, or that your account cannot read, used to stop the whole pull with a crash report. Nomad now names the file and the reason, then carries on: your settings, your skills, and your session history all still sync, and the command finishes normally. The warning also says whether the file is still there or has been removed, and points at the backup copy when there is one.
|
|
73
|
+
- **`nomad adopt` recovers cleanly when it cannot restore your local copy.** Adopt finishes by copying the folder back out of the sync repo so this machine keeps a usable copy. If that copy was blocked, the command used to end in a crash report, with the folder gone from your Claude directory and nothing staged for publishing. It now stops with a plain message naming the folder and the reason, stages the adopted content either way, and tells you to run `nomad pull` before your next push and why that order matters. A half written folder left behind by the interrupted copy is removed, so a later push cannot replace your adopted folder with the partial one.
|
|
74
|
+
- **A refused `nomad pull --force-remote` now tells you what actually clears it.** The old advice did not work, and would land you back on the same refusal. The message now gives the steps that finish the job and names the one that clears the check, and it says that the stuck rebase has already been undone by that point, so retrying is now just an ordinary pull. It no longer calls every listed file at risk, since the list can include files where the shared repo is simply ahead of yours. The quickstart says the same thing and links to the matching recovery steps in the FAQ.
|
|
89
75
|
|
|
90
76
|
|
|
91
77
|
### Added
|
|
@@ -114,39 +100,16 @@ it.
|
|
|
114
100
|
|
|
115
101
|
### What's new
|
|
116
102
|
|
|
117
|
-
**On native Windows (PowerShell or cmd).** Note: WSL2 behaves like Linux and none of these apply to
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
|
|
122
|
-
the step that saves your local shared-config edits into the repo, every time it ran, even on a
|
|
123
|
-
healthy machine with nothing to rescue. That was the flag's only visible effect on a healthy repo,
|
|
124
|
-
and nothing told you it had happened. It now rescues a stuck repo and nothing else, and when a
|
|
125
|
-
rescue genuinely does replace your copies, the pull says how many and where your previous ones
|
|
126
|
-
were saved.
|
|
127
|
-
- **A pull now says what it did to your shared config.** On Windows your shared config is kept as
|
|
128
|
-
real file copies rather than symlinks, so every pull starts by copying your local edits into the
|
|
129
|
-
sync repo. That step used to be silent. It now prints a `Symlinks` section naming each file it
|
|
130
|
-
picked up, and each file it removed from the repo because you deleted it here. If a file cannot be
|
|
131
|
-
read at all, because another program is holding it open or its permissions changed, the pull names
|
|
132
|
-
it and says why rather than leaving a silent gap. `nomad diff` and `nomad pull --dry-run` read
|
|
133
|
-
from the same place, so a preview now matches what a real pull does.
|
|
134
|
-
- **Windows keeps the same things out of your sync repo that your other machines do.** The Windows
|
|
135
|
-
copy step used to hold back only files whose names looked like passwords or keys. It now skips
|
|
136
|
-
everything on the never-sync list, so the folders Claude Code uses for its own state, named things
|
|
137
|
-
like `sessions`, `tasks`, `plans`, and `cache`, stay on the machine even when they sit inside a
|
|
138
|
-
folder you share. If one of them is already sitting in your sync repo, the pull tells you, and
|
|
139
|
-
takes a backup copy before removing it.
|
|
103
|
+
**On native Windows (PowerShell or cmd).** Note: WSL2 behaves like Linux and none of these apply to it.
|
|
104
|
+
|
|
105
|
+
- **`nomad pull --force-remote` no longer discards edits you have not published.** The flag exists to rescue a sync repo that got stuck part-way through an update. On native Windows it also skipped the step that saves your local shared-config edits into the repo, every time it ran, even on a healthy machine with nothing to rescue. That was the flag's only visible effect on a healthy repo, and nothing told you it had happened. It now rescues a stuck repo and nothing else, and when a rescue genuinely does replace your copies, the pull says how many and where your previous ones were saved.
|
|
106
|
+
- **A pull now says what it did to your shared config.** On Windows your shared config is kept as real file copies rather than symlinks, so every pull starts by copying your local edits into the sync repo. That step used to be silent. It now prints a `Symlinks` section naming each file it picked up, and each file it removed from the repo because you deleted it here. If a file cannot be read at all, because another program is holding it open or its permissions changed, the pull names it and says why rather than leaving a silent gap. `nomad diff` and `nomad pull --dry-run` read from the same place, so a preview now matches what a real pull does.
|
|
107
|
+
- **Windows keeps the same things out of your sync repo that your other machines do.** The Windows copy step used to hold back only files whose names looked like passwords or keys. It now skips everything on the never-sync list, so the folders Claude Code uses for its own state, named things like `sessions`, `tasks`, `plans`, and `cache`, stay on the machine even when they sit inside a folder you share. If one of them is already sitting in your sync repo, the pull tells you, and takes a backup copy before removing it.
|
|
140
108
|
|
|
141
109
|
**On all supported platforms, i.e. \*nix, Mac, WSL2, and native Windows.**
|
|
142
110
|
|
|
143
|
-
- **`nomad doctor` names the files that have drifted.** When it reports that your skills or your
|
|
144
|
-
|
|
145
|
-
again with `--verbose` to find out which files it meant.
|
|
146
|
-
- **`nomad pull --force-remote` tells you when there was nothing to rescue.** On a repo that is not
|
|
147
|
-
stuck it now says so and pulls normally, instead of appearing to do nothing. If it cannot tell
|
|
148
|
-
whether the repo is stuck, it says that too rather than reporting a clean repo. The help text,
|
|
149
|
-
README, and docs site now agree on what the flag does.
|
|
111
|
+
- **`nomad doctor` names the files that have drifted.** When it reports that your skills or your shared config no longer match the repo, it lists them. Before, you got a count and had to run it again with `--verbose` to find out which files it meant.
|
|
112
|
+
- **`nomad pull --force-remote` tells you when there was nothing to rescue.** On a repo that is not stuck it now says so and pulls normally, instead of appearing to do nothing. If it cannot tell whether the repo is stuck, it says that too rather than reporting a clean repo. The help text, README, and docs site now agree on what the flag does.
|
|
150
113
|
|
|
151
114
|
|
|
152
115
|
### Added
|
|
@@ -185,21 +148,9 @@ it.
|
|
|
185
148
|
|
|
186
149
|
### What's new
|
|
187
150
|
|
|
188
|
-
- **A stray dot or space at the end of a file name no longer hides a secret.** nomad never copies
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
`.env.`, did not match, so a file like that could end up in your sync repo. It matches now, and so
|
|
192
|
-
do the other files nomad always keeps out, such as `settings.local.json`. Nothing changes in how
|
|
193
|
-
you use nomad. It simply catches more ways of writing the same names it already blocked.
|
|
194
|
-
- **A `.claude` folder is recognized however it is capitalized.** If a project had a folder named
|
|
195
|
-
`.Claude` instead of `.claude`, nomad checked what was inside it less carefully than it should
|
|
196
|
-
have. Both are treated the same now.
|
|
197
|
-
- **A folder name nomad will never sync is turned down as soon as you add it.** You can ask nomad to
|
|
198
|
-
sync extra folders by listing their names in `path-map.json`. If a name you list is one nomad
|
|
199
|
-
refuses to sync, because it looks like a password file, or because it is a name that causes
|
|
200
|
-
trouble on one of the machines you sync to, you are told straight away and told why. Before,
|
|
201
|
-
nothing was said until a later `nomad push` stopped without explaining itself. `nomad doctor` also
|
|
202
|
-
lists any names in this situation and what to do about them.
|
|
151
|
+
- **A stray dot or space at the end of a file name no longer hides a secret.** nomad never copies password and key files (things like `.env`, `id_rsa`, or `server.pem`) out of the project folders you sync. It spots them by name, and a name with an extra dot or space on the end, such as `.env.`, did not match, so a file like that could end up in your sync repo. It matches now, and so do the other files nomad always keeps out, such as `settings.local.json`. Nothing changes in how you use nomad. It simply catches more ways of writing the same names it already blocked.
|
|
152
|
+
- **A `.claude` folder is recognized however it is capitalized.** If a project had a folder named `.Claude` instead of `.claude`, nomad checked what was inside it less carefully than it should have. Both are treated the same now.
|
|
153
|
+
- **A folder name nomad will never sync is turned down as soon as you add it.** You can ask nomad to sync extra folders by listing their names in `path-map.json`. If a name you list is one nomad refuses to sync, because it looks like a password file, or because it is a name that causes trouble on one of the machines you sync to, you are told straight away and told why. Before, nothing was said until a later `nomad push` stopped without explaining itself. `nomad doctor` also lists any names in this situation and what to do about them.
|
|
203
154
|
|
|
204
155
|
All of this applies on macOS, Linux, WSL2, and native Windows.
|
|
205
156
|
|
|
@@ -218,31 +169,11 @@ All of this applies on macOS, Linux, WSL2, and native Windows.
|
|
|
218
169
|
|
|
219
170
|
### What's new
|
|
220
171
|
|
|
221
|
-
- **Native Windows: deleting a shared config file now sticks.** On native Windows (PowerShell or
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
is copied to the backup directory first. The first pull after upgrading has no record yet, so
|
|
227
|
-
deletions start propagating from the pull after that. macOS, Linux, and WSL2 were never affected:
|
|
228
|
-
they symlink shared config, so deleting the file was always a deletion in the repo.
|
|
229
|
-
- **Native Windows: a name clash during a pull now explains itself.** If a file you created inside a
|
|
230
|
-
synced folder has the same name as one an incoming update adds, the pull stops before changing
|
|
231
|
-
anything. You used to be left with git's own error, which pointed at a copy inside the sync repo
|
|
232
|
-
and told you to move it, and following that advice looped, because the next pull copied your file
|
|
233
|
-
back over it. You now get the file under `~/.claude/` to act on and the two ways to finish, keep
|
|
234
|
-
the incoming version or keep both and merge them, and nomad clears its own copy out of the way for
|
|
235
|
-
you. Your file is untouched either way.
|
|
236
|
-
- **Native Windows shared-config changes show up in a preview first.** `nomad pull --dry-run` and
|
|
237
|
-
`nomad diff` now list both the edits being carried into the repo and the files being removed from
|
|
238
|
-
it, worked out before the pull so the preview and the real run agree.
|
|
239
|
-
- **`nomad doctor` notices a native Windows shared file that has drifted.** When a synced copy under
|
|
240
|
-
`~/.claude/` no longer matches the one in the repo, doctor warns about it instead of reporting the
|
|
241
|
-
machine as healthy. On the symlink platforms there is only ever one file, so there is nothing to
|
|
242
|
-
drift.
|
|
243
|
-
- **`nomad doctor` no longer recognizes `leftArrowOpensAgents`.** Claude Code dropped it from its
|
|
244
|
-
settings schema, so doctor will flag it as an unknown key if you still have it set. This one
|
|
245
|
-
applies everywhere, not just on Windows.
|
|
172
|
+
- **Native Windows: deleting a shared config file now sticks.** On native Windows (PowerShell or cmd), deleting a file inside a synced folder, say `~/.claude/commands/old.md`, used to leave it sitting in the sync repo, and the next `nomad pull` put it straight back. The deletion is now carried into the sync repo instead, so it survives the pull and reaches your other machines. Nothing is removed unless this machine's own record shows it had the file, and every removed file is copied to the backup directory first. The first pull after upgrading has no record yet, so deletions start propagating from the pull after that. macOS, Linux, and WSL2 were never affected: they symlink shared config, so deleting the file was always a deletion in the repo.
|
|
173
|
+
- **Native Windows: a name clash during a pull now explains itself.** If a file you created inside a synced folder has the same name as one an incoming update adds, the pull stops before changing anything. You used to be left with git's own error, which pointed at a copy inside the sync repo and told you to move it, and following that advice looped, because the next pull copied your file back over it. You now get the file under `~/.claude/` to act on and the two ways to finish, keep the incoming version or keep both and merge them, and nomad clears its own copy out of the way for you. Your file is untouched either way.
|
|
174
|
+
- **Native Windows shared-config changes show up in a preview first.** `nomad pull --dry-run` and `nomad diff` now list both the edits being carried into the repo and the files being removed from it, worked out before the pull so the preview and the real run agree.
|
|
175
|
+
- **`nomad doctor` notices a native Windows shared file that has drifted.** When a synced copy under `~/.claude/` no longer matches the one in the repo, doctor warns about it instead of reporting the machine as healthy. On the symlink platforms there is only ever one file, so there is nothing to drift.
|
|
176
|
+
- **`nomad doctor` no longer recognizes `leftArrowOpensAgents`.** Claude Code dropped it from its settings schema, so doctor will flag it as an unknown key if you still have it set. This one applies everywhere, not just on Windows.
|
|
246
177
|
|
|
247
178
|
|
|
248
179
|
### Added
|
|
@@ -268,17 +199,9 @@ All of this applies on macOS, Linux, WSL2, and native Windows.
|
|
|
268
199
|
|
|
269
200
|
### What's new
|
|
270
201
|
|
|
271
|
-
- **`nomad doctor` stops warning about settings you legitimately set.** The list of settings it
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
are no longer reported as unknown keys on an otherwise healthy machine. Entries that were never
|
|
275
|
-
settings at all have been dropped at the same time.
|
|
276
|
-
- **A new Claude Code setting is recognized within a day.** The job that tracks the official
|
|
277
|
-
settings list ran once a week, so a setting added on a Tuesday could be reported as unknown until
|
|
278
|
-
the following Monday. It now runs daily.
|
|
279
|
-
- **The list keeps its own bookkeeping straight from here.** When a setting Claude Code writes
|
|
280
|
-
ahead of its published documentation is later documented, it now moves across on its own instead
|
|
281
|
-
of being recorded in two places at once.
|
|
202
|
+
- **`nomad doctor` stops warning about settings you legitimately set.** The list of settings it recognizes has been updated and synced with the current Claude Code settings schema, so settings the app actually writes (quiet hours, the break reminder, the token-usage reminder, and others) are no longer reported as unknown keys on an otherwise healthy machine. Entries that were never settings at all have been dropped at the same time.
|
|
203
|
+
- **A new Claude Code setting is recognized within a day.** The job that tracks the official settings list ran once a week, so a setting added on a Tuesday could be reported as unknown until the following Monday. It now runs daily.
|
|
204
|
+
- **The list keeps its own bookkeeping straight from here.** When a setting Claude Code writes ahead of its published documentation is later documented, it now moves across on its own instead of being recorded in two places at once.
|
|
282
205
|
|
|
283
206
|
|
|
284
207
|
### Fixed
|
|
@@ -309,18 +232,9 @@ All of this applies on macOS, Linux, WSL2, and native Windows.
|
|
|
309
232
|
|
|
310
233
|
### What's new
|
|
311
234
|
|
|
312
|
-
- **Windows: your own edits to shared config are no longer reverted.** On Windows, editing a synced
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
publish. Your edit is now carried into the sync repo first, so it survives the pull and gets
|
|
316
|
-
published instead.
|
|
317
|
-
- **The secret prompt on push is readable and asks once per secret.** When a push finds a possible
|
|
318
|
-
secret it used to ask the same question several times over for one secret, and the snippet it
|
|
319
|
-
showed was mostly noise. It now asks once per secret and describes what was actually found, so you
|
|
320
|
-
can tell a real credential from a false positive at a glance.
|
|
321
|
-
- **Three ways that prompt could show you a secret it meant to hide are closed**, along with a case
|
|
322
|
-
where allowing one false positive could quietly let a real secret through beside it on the same
|
|
323
|
-
line.
|
|
235
|
+
- **Windows: your own edits to shared config are no longer reverted.** On Windows, editing a synced file like `~/.claude/CLAUDE.md` and then running `nomad pull` overwrote it from the repo, and `nomad sync` went on to publish the reverted version, silently undoing the change you ran sync to publish. Your edit is now carried into the sync repo first, so it survives the pull and gets published instead.
|
|
236
|
+
- **The secret prompt on push is readable and asks once per secret.** When a push finds a possible secret it used to ask the same question several times over for one secret, and the snippet it showed was mostly noise. It now asks once per secret and describes what was actually found, so you can tell a real credential from a false positive at a glance.
|
|
237
|
+
- **Three ways that prompt could show you a secret it meant to hide are closed**, along with a case where allowing one false positive could quietly let a real secret through beside it on the same line.
|
|
324
238
|
|
|
325
239
|
|
|
326
240
|
### Added
|
package/dist/nomad.mjs
CHANGED
|
@@ -70,6 +70,9 @@ function regionKey(segment) {
|
|
|
70
70
|
function isExtrasScoped(segments) {
|
|
71
71
|
return segments[0] === "shared" && segments.length > 1 && regionKey(segments[1]) === "extras";
|
|
72
72
|
}
|
|
73
|
+
function isLogicalNameScoped(segments) {
|
|
74
|
+
return segments[0] === "shared" && segments.length > 1 && UNFILTERED_SHARED_REGIONS.has(regionKey(segments[1]));
|
|
75
|
+
}
|
|
73
76
|
function isSharedNameScoped(segments) {
|
|
74
77
|
return segments[0] === "shared" && segments.length > 1 && !UNFILTERED_SHARED_REGIONS.has(regionKey(segments[1]));
|
|
75
78
|
}
|
|
@@ -83,7 +86,7 @@ function blockSetFor(segments) {
|
|
|
83
86
|
function deniedSegmentFor(path) {
|
|
84
87
|
const segments = path.split("/");
|
|
85
88
|
const blockSet = blockSetFor(segments);
|
|
86
|
-
const scan =
|
|
89
|
+
const scan = isLogicalNameScoped(segments) && segments.length > 3 ? segments.slice(3) : segments;
|
|
87
90
|
for (const segment of scan) {
|
|
88
91
|
if (isDeniedName(blockSet, segment)) return segment;
|
|
89
92
|
}
|
|
@@ -1564,10 +1567,22 @@ import { dirname as dirname2, join as join7, resolve as resolve2 } from "node:pa
|
|
|
1564
1567
|
|
|
1565
1568
|
// src/commands.adopt.scan.ts
|
|
1566
1569
|
init_config();
|
|
1567
|
-
init_exit_codes();
|
|
1568
|
-
init_utils();
|
|
1569
1570
|
import { lstatSync, readdirSync } from "node:fs";
|
|
1570
1571
|
import { join as join2, relative } from "node:path";
|
|
1572
|
+
|
|
1573
|
+
// src/error-text.ts
|
|
1574
|
+
function errorText(err) {
|
|
1575
|
+
try {
|
|
1576
|
+
const message = err?.message;
|
|
1577
|
+
return typeof message === "string" ? message : String(err);
|
|
1578
|
+
} catch {
|
|
1579
|
+
return "unprintable error value";
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
// src/commands.adopt.scan.ts
|
|
1584
|
+
init_exit_codes();
|
|
1585
|
+
init_utils();
|
|
1571
1586
|
function toForwardSlash(p) {
|
|
1572
1587
|
return p.replaceAll("\\", "/");
|
|
1573
1588
|
}
|
|
@@ -1596,10 +1611,8 @@ function scanOrFatal(name, root, state) {
|
|
|
1596
1611
|
try {
|
|
1597
1612
|
return scanDeniedEntries(root);
|
|
1598
1613
|
} catch (err) {
|
|
1599
|
-
const message = err?.message;
|
|
1600
|
-
const text = typeof message === "string" ? message : String(err);
|
|
1601
1614
|
throw new NomadFatal(
|
|
1602
|
-
`cannot adopt ${name}: could not scan ${root} for never-sync content (${
|
|
1615
|
+
`cannot adopt ${name}: could not scan ${root} for never-sync content (${errorText(err)}). ${state()} Check that it is readable and not being written to, then run \`nomad adopt ${name}\` again.`,
|
|
1603
1616
|
{ code: EXIT.GENERIC_FAILURE }
|
|
1604
1617
|
);
|
|
1605
1618
|
}
|
|
@@ -2339,10 +2352,6 @@ function regenerateSettings(ts, opts = {}) {
|
|
|
2339
2352
|
|
|
2340
2353
|
// src/commands.adopt.recover.ts
|
|
2341
2354
|
init_utils();
|
|
2342
|
-
function errorText(err) {
|
|
2343
|
-
const message = err?.message;
|
|
2344
|
-
return typeof message === "string" ? message : String(err);
|
|
2345
|
-
}
|
|
2346
2355
|
function lexists(p) {
|
|
2347
2356
|
try {
|
|
2348
2357
|
lstatSync6(p);
|
|
@@ -8112,8 +8121,8 @@ function emitMirror(onPreview, name, localPath, repoPath) {
|
|
|
8112
8121
|
function emitMirrorWet(onPreview, name, localPath, repoPath) {
|
|
8113
8122
|
if (onPreview) onPreview({ kind: "mirror", name, localPath, repoPath });
|
|
8114
8123
|
}
|
|
8115
|
-
function notShared(
|
|
8116
|
-
return !
|
|
8124
|
+
function notShared(target) {
|
|
8125
|
+
return !existsSync42(target);
|
|
8117
8126
|
}
|
|
8118
8127
|
function mirrorOneSharedName(name, claude, repo, policy, opts) {
|
|
8119
8128
|
const localPath = join56(claude, name);
|
|
@@ -8122,21 +8131,21 @@ function mirrorOneSharedName(name, claude, repo, policy, opts) {
|
|
|
8122
8131
|
try {
|
|
8123
8132
|
stat = lstatSync20(localPath, { throwIfNoEntry: false });
|
|
8124
8133
|
} catch (err) {
|
|
8125
|
-
if (notShared(
|
|
8134
|
+
if (notShared(target)) return;
|
|
8126
8135
|
if (opts.dryRun === true) {
|
|
8127
8136
|
warn(
|
|
8128
|
-
`${name} could not be read (${err
|
|
8137
|
+
`${name} could not be read (${errorText(err)}), so nothing was captured for it and nothing was written. A pull that captures shared edits would skip it too. Check its permissions, or whether another program has it open`
|
|
8129
8138
|
);
|
|
8130
8139
|
return;
|
|
8131
8140
|
}
|
|
8132
8141
|
warn(
|
|
8133
|
-
`${name} could not be read (${err
|
|
8142
|
+
`${name} could not be read (${errorText(err)}), so it was left out of shared/ this run. Check its permissions, or whether another program has it open`
|
|
8134
8143
|
);
|
|
8135
8144
|
return;
|
|
8136
8145
|
}
|
|
8137
8146
|
if (stat === void 0) return;
|
|
8138
8147
|
if (stat.isSymbolicLink()) return;
|
|
8139
|
-
if (notShared(
|
|
8148
|
+
if (notShared(target)) return;
|
|
8140
8149
|
if (opts.dryRun === true) {
|
|
8141
8150
|
emitMirror(opts.onPreview, name, localPath, target);
|
|
8142
8151
|
return;
|
|
@@ -8160,10 +8169,10 @@ function mirrorSharedNames(map, policy, opts = {}) {
|
|
|
8160
8169
|
}
|
|
8161
8170
|
}
|
|
8162
8171
|
function syncSharedLinksPush(map, opts = {}) {
|
|
8163
|
-
mirrorSharedNames(map, {
|
|
8172
|
+
mirrorSharedNames(map, { overlay: false }, opts);
|
|
8164
8173
|
}
|
|
8165
8174
|
function stageLocalSharedEdits(map, ts, opts = {}) {
|
|
8166
|
-
mirrorSharedNames(map, {
|
|
8175
|
+
mirrorSharedNames(map, { overlay: true, backupTs: ts }, opts);
|
|
8167
8176
|
}
|
|
8168
8177
|
function presentAt(abs) {
|
|
8169
8178
|
try {
|
|
@@ -8186,7 +8195,7 @@ function removeUntrackedDenied(repo, path, segment, ts) {
|
|
|
8186
8195
|
backupRepoWrite(abs, ts, repo);
|
|
8187
8196
|
} catch (err) {
|
|
8188
8197
|
warn(
|
|
8189
|
-
`could not snapshot ${abs} before removing it (${err
|
|
8198
|
+
`could not snapshot ${abs} before removing it (${errorText(err)}), so it was left in place: ${denied}, so remove it by hand`
|
|
8190
8199
|
);
|
|
8191
8200
|
return;
|
|
8192
8201
|
}
|
|
@@ -8199,7 +8208,7 @@ function removeUntrackedDenied(repo, path, segment, ts) {
|
|
|
8199
8208
|
const where = snapshotted ? `. A copy was snapshotted under backup/${ts}/repo/ first` : "";
|
|
8200
8209
|
warn(`removed ${path} from the sync repo working tree: ${denied}${where}`);
|
|
8201
8210
|
} catch (err) {
|
|
8202
|
-
warn(`could not remove ${abs}: ${err
|
|
8211
|
+
warn(`could not remove ${abs}: ${errorText(err)}`);
|
|
8203
8212
|
}
|
|
8204
8213
|
}
|
|
8205
8214
|
function reportTrackedDenied(repo, path, segment) {
|
|
@@ -10704,7 +10713,7 @@ function parseSyncArgs(argv) {
|
|
|
10704
10713
|
// package.json
|
|
10705
10714
|
var package_default = {
|
|
10706
10715
|
name: "claude-nomad",
|
|
10707
|
-
version: "0.67.
|
|
10716
|
+
version: "0.67.1",
|
|
10708
10717
|
type: "module",
|
|
10709
10718
|
description: "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
|
|
10710
10719
|
keywords: [
|
package/package.json
CHANGED