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.
Files changed (3) hide show
  1. package/CHANGELOG.md +70 -156
  2. package/dist/nomad.mjs +30 -21
  3. 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
- about to overwrite into a dated folder under `~/.cache/claude-nomad/backup/`, and it creates that
11
- folder before it touches your files so a full disk or a permissions problem stops the sync before
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
- `sharedDirs`, its subfolders travel with it, including ones with everyday names like `sessions`,
44
- `plans`, `tasks`, and `cache`. Those names used to be refused wherever they appeared, so a push
45
- could fail, or `nomad adopt` could turn you away, over a folder holding nothing sensitive. Your
46
- Claude login, your credential files, your per-host settings, and your local history still never
47
- leave the machine, in either direction.
48
- - **`nomad adopt` checks the whole folder before it moves anything.** It used to copy everything,
49
- so a file that never syncs between machines could land in your repo and fail your next push, on
50
- content you never chose to add. Adopt now stops before touching anything and names every path it
51
- objected to and why: a name that collides with the never-sync list, which renaming clears, or a
52
- name that looks like a credential file, where renaming only helps if the new name looks different
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
- it.
119
-
120
- - **`nomad pull --force-remote` no longer discards edits you have not published.** The flag exists
121
- to rescue a sync repo that got stuck part-way through an update. On native Windows it also skipped
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
- shared config no longer match the repo, it lists them. Before, you got a count and had to run it
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
- password and key files (things like `.env`, `id_rsa`, or `server.pem`) out of the project folders
190
- you sync. It spots them by name, and a name with an extra dot or space on the end, such as
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
- cmd), deleting a file inside a synced folder, say `~/.claude/commands/old.md`, used to leave it
223
- sitting in the sync repo, and the next `nomad pull` put it straight back. The deletion is now
224
- carried into the sync repo instead, so it survives the pull and reaches your other machines.
225
- Nothing is removed unless this machine's own record shows it had the file, and every removed file
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
- recognizes has been updated and synced with the current Claude Code settings schema, so settings
273
- the app actually writes (quiet hours, the break reminder, the token-usage reminder, and others)
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
- file like `~/.claude/CLAUDE.md` and then running `nomad pull` overwrote it from the repo, and
314
- `nomad sync` went on to publish the reverted version, silently undoing the change you ran sync to
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 = isExtrasScoped(segments) ? segments.slice(4) : segments;
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 (${text}). ${state()} Check that it is readable and not being written to, then run \`nomad adopt ${name}\` again.`,
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(policy, target) {
8116
- return !policy.adoptNew && !existsSync42(target);
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(policy, target)) return;
8134
+ if (notShared(target)) return;
8126
8135
  if (opts.dryRun === true) {
8127
8136
  warn(
8128
- `${name} could not be read (${err.message}), 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`
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.message}), so it was left out of shared/ this run. Check its permissions, or whether another program has it open`
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(policy, target)) return;
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, { adoptNew: false, overlay: false }, opts);
8172
+ mirrorSharedNames(map, { overlay: false }, opts);
8164
8173
  }
8165
8174
  function stageLocalSharedEdits(map, ts, opts = {}) {
8166
- mirrorSharedNames(map, { adoptNew: false, overlay: true, backupTs: ts }, opts);
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.message}), so it was left in place: ${denied}, so remove it by hand`
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.message}`);
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.0",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-nomad",
3
- "version": "0.67.0",
3
+ "version": "0.67.1",
4
4
  "type": "module",
5
5
  "description": "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
6
6
  "keywords": [