claude-nomad 0.18.0 → 0.19.0

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.19.0](https://github.com/funkadelic/claude-nomad/compare/v0.18.0...v0.19.0) (2026-05-22)
4
+
5
+
6
+ ### Added
7
+
8
+ * **update:** auto-resolve sole package-lock.json merge conflict ([#96](https://github.com/funkadelic/claude-nomad/issues/96)) ([8d76be9](https://github.com/funkadelic/claude-nomad/commit/8d76be9791b427484d709d97a5d077539c0f9f1a))
9
+
3
10
  ## [0.18.0](https://github.com/funkadelic/claude-nomad/compare/v0.17.2...v0.18.0) (2026-05-22)
4
11
 
5
12
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-nomad",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
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": [
@@ -169,6 +169,46 @@ function runVanilla(opts: CmdUpdateOpts): void {
169
169
  gitOrFatal(['pull', '--ff-only', 'origin', 'main'], 'git pull', REPO_HOME);
170
170
  }
171
171
 
172
+ /**
173
+ * Auto-resolve a merge conflict when `package-lock.json` is the only unmerged
174
+ * path. Release-please bumps the lockfile on every release, so any host that
175
+ * has run `npm install` against its mirror will hit this conflict on the next
176
+ * `nomad update`. The semantically-correct resolution is "take upstream's
177
+ * lockfile, then regenerate locally", so do that automatically when no other
178
+ * files are unmerged. Multi-file conflicts still fail loud for human review.
179
+ *
180
+ * @returns `true` when the conflict was auto-resolved and the merge committed; `false` when other files are also unmerged (caller should re-throw the original failure).
181
+ */
182
+ function tryAutoResolveLockfileConflict(): boolean {
183
+ let unmerged: string[];
184
+ try {
185
+ unmerged = execFileSync('git', ['diff', '--name-only', '--diff-filter=U'], {
186
+ cwd: REPO_HOME,
187
+ stdio: ['ignore', 'pipe', 'pipe'],
188
+ })
189
+ .toString()
190
+ .split('\n')
191
+ .filter((line) => line !== '');
192
+ } catch {
193
+ // Probe failure must not mask the original merge NomadFatal. Returning
194
+ // false lets the caller re-throw the merge error unchanged.
195
+ return false;
196
+ }
197
+ if (unmerged.length !== 1 || unmerged[0] !== 'package-lock.json') return false;
198
+
199
+ gitOrFatal(
200
+ ['checkout', '--theirs', '--', 'package-lock.json'],
201
+ 'git checkout --theirs package-lock.json',
202
+ REPO_HOME,
203
+ );
204
+ gitOrFatal(['add', 'package-lock.json'], 'git add package-lock.json', REPO_HOME);
205
+ execFileSync('npm', ['install'], { cwd: REPO_HOME, stdio: 'inherit' });
206
+ gitOrFatal(['add', 'package-lock.json'], 'git add package-lock.json', REPO_HOME);
207
+ gitOrFatal(['commit', '--no-edit'], 'git commit --no-edit', REPO_HOME);
208
+ log('auto-resolved package-lock.json conflict (took upstream, reinstalled, committed merge)');
209
+ return true;
210
+ }
211
+
172
212
  /**
173
213
  * Perform a fork-style update by fetching from `upstream`, merging `upstream/main` into `main`, and optionally pushing the merge to `origin`.
174
214
  *
@@ -199,7 +239,11 @@ function runFork(opts: CmdUpdateOpts): void {
199
239
  return;
200
240
  }
201
241
  gitOrFatal(['fetch', 'upstream'], 'git fetch upstream', REPO_HOME);
202
- gitOrFatal(['merge', 'upstream/main'], 'git merge upstream/main', REPO_HOME);
242
+ try {
243
+ gitOrFatal(['merge', 'upstream/main'], 'git merge upstream/main', REPO_HOME);
244
+ } catch (err) {
245
+ if (!tryAutoResolveLockfileConflict()) throw err;
246
+ }
203
247
  if (opts.pushOrigin === true) {
204
248
  gitOrFatal(['push', 'origin', 'main'], 'git push origin main', REPO_HOME);
205
249
  return;