Skip to content

fix(update): PATH-priority installer detection, asdf shims, --all#179

Merged
rafa-thayto merged 6 commits into
mainfrom
rafa-thayto/auto-updatee
Apr 20, 2026
Merged

fix(update): PATH-priority installer detection, asdf shims, --all#179
rafa-thayto merged 6 commits into
mainfrom
rafa-thayto/auto-updatee

Conversation

@rafa-thayto
Copy link
Copy Markdown
Contributor

@rafa-thayto rafa-thayto commented Apr 17, 2026

Fixes clerk update silently writing to the wrong installer on machines with multiple clerk binaries on PATH. Replaces runtime-based installer detection with PATH-priority-aware resolution, adds asdf shim support, and introduces an opt-in --all batch mode.

Before / after

Reporter's setup (bun + asdf-managed npm + Homebrew):

$ which -a clerk
/Users/rafa/.bun/bin/clerk
/Users/rafa/.asdf/shims/clerk
/opt/homebrew/bin/clerk

Before: clerk update --channel canary reported success, but clerk -v still showed the old version. The update had landed in ~/.asdf/shims/clerk (via an npm fallback), not in ~/.bun/bin/clerk (the one the shell actually resolves).

After: the update writes to ~/.bun/install/global/node_modules/ via bun add -g, and clerk -v reflects the new version. A post-run report lists the asdf and Homebrew installs with their owners; --all updates the asdf install too (via asdf which → underlying npm, plus asdf reshim nodejs after).

What the new UX looks like

Default (first-on-PATH only, other installs reported):

┌  clerk update
◇  Checking for updates
│    Current: 0.8.4
│    Latest:  0.8.5 (canary)
│    Target:  /Users/rafa/.bun/bin/clerk (bun)
│
◇  Updated bun: /Users/rafa/.bun/bin/clerk
│
│  Also found 2 other clerk installs:
│    /Users/rafa/.asdf/shims/clerk (npm)
│    /opt/homebrew/bin/clerk (homebrew) — Homebrew has no canary tap
│  Run `clerk update --all` to update them too.
│
│  If `clerk` still points to the old binary, run `hash -r` or open a new shell.
└  Successfully updated to 0.8.5

--all (batch + per-install summary):

◇  Updated bun: /Users/rafa/.bun/bin/clerk
◇  Updated npm: /Users/rafa/.asdf/shims/clerk
│
│  Summary:
│    ✓ /Users/rafa/.bun/bin/clerk (bun)
│    ✓ /Users/rafa/.asdf/shims/clerk (npm)
│    ⚠ /opt/homebrew/bin/clerk (homebrew) — skipped: no canary tap

install.sh standalone (refuse, don't guess):

│    Target:  /usr/local/bin/clerk (unknown)
│
│  ⚠ Cannot auto-update: unknown installer — not a package-manager-owned binary
│    Reinstall via your preferred method, e.g.:
│      bun add -g clerk@0.8.5
│      npm install -g clerk@0.8.5
│      curl -fsSL …/install.sh | bash
└  Update required manual action

Fixed

  • PATH-priority installer detection. Resolves the first clerk on PATH (what the shell actually executes) and runs the installer that owns it. If no known installer owns the primary target, refuses with reinstall guidance instead of silently writing to a different prefix.
  • bun detection. detectInstaller() Stage 2b compared process.execPath against bun pm bin -g (the shim dir), which never matched the Bun-compiled platform binary under ~/.bun/install/global/node_modules. Replaced with path-based ownerOfBinary() that matches the install dir.
  • asdf shims. asdf shims are bash scripts (not symlinks), so realpath returns the shim itself and nothing matches. Now resolved via asdf which <name>; the underlying binary is owner-matched normally, and asdf reshim <plugin> runs after install as a safety net for asdf versions that don't auto-reshim.

Added

  • --all flag. Updates every clerk install on PATH in one run. Skips Homebrew on non-stable channels and null-owned binaries with per-install warnings; summary printed at the end.
  • Other-installs report. After every run, lists other clerk installs with their owners so shadowing is visible.
  • Shell-hash hint. Prints hash -r (bash/zsh/sh/dash/ksh), rehash (tcsh/csh), or nothing (fish auto-rehashes, PowerShell has no cache) based on $SHELL.

Version managers

  • nvm — works out of the box. Real symlinks; realpath chases into <nvm-version>/lib/node_modules, which matches active npm prefix -g.
  • asdf — handled via resolveAsdfShim + post-install asdf reshim. Honors $ASDF_DATA_DIR. Falls back to "unknown" (refuse) when asdf isn't installed.

New exports in packages/cli-core/src/lib/installer.ts

Export Contract
findClerkOnPath(name?) Walks process.env.PATH, realpaths + dedupes, filters to executable regular files (POSIX X bit / Windows PATHEXT). Shell-agnostic.
getInstallerPackageDirs() Returns the packages dir for each PM present (npm, pnpm, yarn, bun).
ownerOfBinary(path, installDirs) Pure, synchronous. Homebrew pattern → longest-match PM prefix → null.
isAsdfShimPath(path) Path-based, doesn't require asdf installed.
resolveAsdfShim(path) asdf which-based resolution. Returns input unchanged when asdf is absent or can't resolve.
asdfPluginFromPath(path) Extracts plugin name from <asdf>/installs/<plugin>/<ver>/....
asdfReshim(plugin) Best-effort; swallows errors.

The existing detectInstaller() is preserved for backward compatibility but no longer used by the update command.

Test plan

  • bun run typecheck passes
  • bun run lint passes (oxlint, 0 warnings / 0 errors)
  • bun run test passes (71/71 files); installer.test.ts has 53 cases including 16 new ones covering ownerOfBinary, findClerkOnPath, isAsdfShimPath, asdfPluginFromPath, and resolveAsdfShim
  • Manual verification on reporter's setup (bun + asdf-npm + Homebrew): clerk update --channel canary writes to ~/.bun/install/global/node_modules and clerk -v reflects the new version
  • --all updates both bun and asdf-npm (via asdf which) and runs asdf reshim nodejs after
  • --all skips Homebrew with a channel-mismatch warning when --channel canary is used
  • install.sh-installed clerk (standalone binary) is refused with reinstall guidance
  • hash -r hint renders on zsh/bash; rehash on tcsh; no hint on fish/pwsh

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 17, 2026

🦋 Changeset detected

Latest commit: 78171e3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
clerk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 17, 2026

Warning

Rate limit exceeded

@rafa-thayto has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 58 minutes and 7 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 58 minutes and 7 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bd68a84b-1e45-40a5-8e5a-e6ed51aeba50

📥 Commits

Reviewing files that changed from the base of the PR and between eae52ae and 78171e3.

📒 Files selected for processing (7)
  • .changeset/clerk-update-path-aware.md
  • README.md
  • packages/cli-core/src/cli-program.ts
  • packages/cli-core/src/commands/update/README.md
  • packages/cli-core/src/commands/update/index.ts
  • packages/cli-core/src/lib/installer.test.ts
  • packages/cli-core/src/lib/installer.ts
📝 Walkthrough

Walkthrough

This PR makes clerk update PATH-aware by discovering all clerk binaries on PATH (resolving asdf shims and symlinks), mapping each resolved binary to an owning installer via ownerOfBinary(), and invoking the corresponding installer. It adds a --all flag to update multiple installs, refuses automatic updates for binaries with unknown owners (prints reinstall guidance), corrects bun detection to the bun install dir, constrains Homebrew behavior, performs asdf reshim when applicable, and emits a shell-specific hash/rehash hint. Tests and docs updated accordingly.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(update): PATH-priority installer detection, asdf shims, --all' is concise, specific, and accurately summarizes the main changes: PATH-aware installer detection fix, asdf shim support, and the new --all flag.
Description check ✅ Passed The description comprehensively explains the problem being fixed, the solution approach, and the new features added, with clear before/after examples and detailed UX walkthrough.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rafa-thayto rafa-thayto requested a review from wyattjoh April 17, 2026 16:50
@rafa-thayto rafa-thayto force-pushed the rafa-thayto/auto-updatee branch from 3446aa3 to b364003 Compare April 17, 2026 16:54
@rafa-thayto rafa-thayto changed the title fix(update): resolve installer by PATH priority, add --all fix(update): PATH-priority installer detection, asdf shims, --all Apr 17, 2026
Copy link
Copy Markdown
Contributor

@wyattjoh wyattjoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — PR #179

Reviewed with Opus + Codex second-opinion validation.

Major

M1. brew upgrade clerk now auto-runs on stable; docs disagree (codex confirmed)
packages/cli-core/src/commands/update/index.ts:94-96,117-124,247 runs brew upgrade clerk via runGlobalInstall, but packages/cli-core/src/commands/update/README.md:23-31 still says Homebrew "prints brew upgrade clerk and exits (no auto-install)". Pick a semantic. If auto-upgrade is intended, update the docs and consider a separate confirmation step; running brew upgrade under a silenced spinner hides brew side-effects (dependency upgrades, autoremoves).

M2. npx clerk update / bunx clerk update silently regress (codex partial)
The old code had detectFromUserAgent returning "npm" when npm_config_user_agent=npm/.... New findClerkOnPath() cannot see the npx cache at ~/.npm/_npx/<hash>/... (not on PATH), and the fallback to process.execPath makes ownerOfBinary return null, so the command refuses with "outside any known package manager". Users who used to run npx clerk update now get a misleading install-sh error. Either preserve user-agent detection for this case, or emit an actionable "install globally first" message.

M3. Changeset is patch but PR adds --all and changes behavior
.changeset/clerk-update-path-aware.md bumps patch. A new flag plus the Homebrew behavior change lean minor.

Missed on first pass (codex caught)

  • Cache poisoning on partial --all failure. writeUpdateCache() runs after the loop in update/index.ts:240-256,270 even when some targets errored, so a failed run marks the latest version as cached and suppresses future update prompts until staleness.
  • Non-interactive auto-confirm without --yes. README.md:77 says agent mode requires --yes, but update/index.ts:222-223 auto-confirms whenever !isHuman(), regardless of --yes.

Minor

  • process.env.ASDF_DATA_DIR ?? join(...) (installer.ts:167-169,191-196): ?? treats "" as set. Use || or an explicit empty-check.
  • queryBunPackageDir always returns a path via safeRealpath (installer.ts:156-159), contradicting the getInstallerPackageDirs docstring that says absent PMs are omitted.
  • ownerOfBinary.startsWith on Windows (installer.ts:218-230): realpath case differences on drive letters can cause spurious "outside any known package manager" refusals.
  • resolveTargets fallback to process.execPath (update/index.ts:64-66) pairs with M2 to surface misleading errors for package-runner invocations.
  • hashHint (update/index.ts:146-155) falls through to POSIX hash -r on Windows when $SHELL is unset.
  • --all summary doesn't distinguish primary-install status; a user whose shell-resolved clerk failed can miss that fact.

Positives

Excellent unit-test coverage for findClerkOnPath, ownerOfBinary, and the asdf helpers. The refuse-rather-than-guess ownership model is a real improvement over the prior silent npm fallback. The bun shim-vs-install-dir diagnosis is correct, and the realpath(mkdtemp(...)) trick to paper over /var -> /private/var is exactly the kind of detail that usually gets missed.

@rafa-thayto rafa-thayto force-pushed the rafa-thayto/auto-updatee branch from 7fb8b88 to f2ebbf4 Compare April 18, 2026 02:26
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cli-core/src/lib/installer.ts`:
- Around line 135-140: Replace the hardcoded POSIX path in queryNpmPackageDir()
with the output of `npm root -g` (call Bun.$`npm root -g`.quiet().nothrow(),
check exitCode, safeRealpath the stdout trimmed) so it works on Windows, and
update ownerOfBinary() to perform case-insensitive comparisons on Windows by
normalizing both paths (e.g., path.normalize()/path.resolve() and
.toLowerCase()) before matching when process.platform === 'win32'; ensure
existing null/exitCode handling remains intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0982a67d-4144-4122-91bb-ed5ad4b738c3

📥 Commits

Reviewing files that changed from the base of the PR and between 3446aa3 and f2ebbf4.

📒 Files selected for processing (7)
  • .changeset/clerk-update-path-aware.md
  • README.md
  • packages/cli-core/src/cli-program.ts
  • packages/cli-core/src/commands/update/README.md
  • packages/cli-core/src/commands/update/index.ts
  • packages/cli-core/src/lib/installer.test.ts
  • packages/cli-core/src/lib/installer.ts
✅ Files skipped from review due to trivial changes (2)
  • README.md
  • .changeset/clerk-update-path-aware.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/cli-core/src/commands/update/README.md
  • packages/cli-core/src/commands/update/index.ts

Comment thread packages/cli-core/src/lib/installer.ts
rafa-thayto added a commit that referenced this pull request Apr 18, 2026
- Homebrew auto-upgrades on stable channel, docs said otherwise. Update
  README to reflect the actual behavior.
- `npx clerk update` / `bunx clerk update` used to fall back to npm;
  after PATH-aware detection they hit the "unknown installer" refuse
  branch. Detect the runner via env vars and print a global-install
  hint instead of the install.sh message.
- Agent mode was auto-confirming whenever stdout was not a TTY, which
  contradicted the documented `--yes`-required behavior. Refuse in
  agent mode without `--yes` and print the exact command to run.
- Partial `--all` failures still refreshed the update cache; only
  write the cache when every attempted install succeeded.
- Bump changeset from patch to minor (adds `--all`, changes Homebrew
  behavior).
- Minor: `??` -> `||` for `ASDF_DATA_DIR` (empty string now treated as
  unset), require the bun install dir to exist before claiming ownership
  of paths under it, normalize case on Windows in `ownerOfBinary`, skip
  the POSIX `hash -r` hint on Windows, mark the primary target in the
  `--all` summary.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli-core/src/commands/update/index.ts (1)

206-269: ⚠️ Potential issue | 🟠 Major

Don’t let primary-target state short-circuit --all.

With --all, an unknown/Homebrew-canary primary should be skipped, not abort the whole run; likewise, an already-latest running CLI should not prevent updating older secondary installs. As written, both early returns happen before others can be updated.

Possible control-flow fix
-  if (compareSemver(latest, currentVersion) <= 0) {
+  const currentIsLatest = compareSemver(latest, currentVersion) <= 0;
+  if (currentIsLatest && !options.all) {
     log.info(`${green("✓")} Already on latest (${currentVersion})`);
     reportOtherInstalls(others, channel);
     if (isHuman()) outro("Up to date");
     return;
   }
@@
-  if (primarySkip) {
+  if (primarySkip && !options.all) {
     const runner = detectPackageRunner();
@@
     if (isHuman()) outro("Update required manual action");
     return;
   }
+  if (primarySkip) {
+    log.warn(`Skipping primary target: ${primarySkip}`);
+  }
@@
-  const toUpdate: Target[] = [primary];
+  const toUpdate: Target[] = primarySkip ? [] : [primary];
   if (options.all) {
     for (const t of others) {
       if (whyCantUpdate(t, channel) === null) toUpdate.push(t);
     }
   }
+
+  if (toUpdate.length === 0) {
+    log.warn("No updatable clerk installs found.");
+    if (isHuman()) outro("Update required manual action");
+    return;
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli-core/src/commands/update/index.ts` around lines 206 - 269, The
current logic returns early when the running primary is already latest or when
whyCantUpdate(primary, channel) is truthy, which aborts an --all update; change
control flow so --all continues to update eligible items in others: for the
compareSemver(latest, currentVersion) <= 0 branch, if options.all do not return
— instead log "Already on latest" for primary but continue to build toUpdate
from others (skip adding primary); similarly for the primarySkip branch, if
options.all do not return — emit the same warnings/info for the primary but do
not return, and ensure toUpdate is populated by pushing only targets from others
where whyCantUpdate(t, channel) === null; keep existing behavior (warnings +
early return) when --all is not set. Use the existing symbols primary, others,
options.all, whyCantUpdate, compareSemver, toUpdate and preserve
agent/yes/confirm logic unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/cli-core/src/commands/update/index.ts`:
- Around line 206-269: The current logic returns early when the running primary
is already latest or when whyCantUpdate(primary, channel) is truthy, which
aborts an --all update; change control flow so --all continues to update
eligible items in others: for the compareSemver(latest, currentVersion) <= 0
branch, if options.all do not return — instead log "Already on latest" for
primary but continue to build toUpdate from others (skip adding primary);
similarly for the primarySkip branch, if options.all do not return — emit the
same warnings/info for the primary but do not return, and ensure toUpdate is
populated by pushing only targets from others where whyCantUpdate(t, channel)
=== null; keep existing behavior (warnings + early return) when --all is not
set. Use the existing symbols primary, others, options.all, whyCantUpdate,
compareSemver, toUpdate and preserve agent/yes/confirm logic unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f82cdf74-16ce-49ce-a9b0-c5635d5b3b16

📥 Commits

Reviewing files that changed from the base of the PR and between f2ebbf4 and eae52ae.

📒 Files selected for processing (4)
  • .changeset/clerk-update-path-aware.md
  • packages/cli-core/src/commands/update/README.md
  • packages/cli-core/src/commands/update/index.ts
  • packages/cli-core/src/lib/installer.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/clerk-update-path-aware.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli-core/src/lib/installer.ts

@rafa-thayto rafa-thayto requested a review from wyattjoh April 20, 2026 16:11
rafa-thayto added a commit that referenced this pull request Apr 20, 2026
- Homebrew auto-upgrades on stable channel, docs said otherwise. Update
  README to reflect the actual behavior.
- `npx clerk update` / `bunx clerk update` used to fall back to npm;
  after PATH-aware detection they hit the "unknown installer" refuse
  branch. Detect the runner via env vars and print a global-install
  hint instead of the install.sh message.
- Agent mode was auto-confirming whenever stdout was not a TTY, which
  contradicted the documented `--yes`-required behavior. Refuse in
  agent mode without `--yes` and print the exact command to run.
- Partial `--all` failures still refreshed the update cache; only
  write the cache when every attempted install succeeded.
- Bump changeset from patch to minor (adds `--all`, changes Homebrew
  behavior).
- Minor: `??` -> `||` for `ASDF_DATA_DIR` (empty string now treated as
  unset), require the bun install dir to exist before claiming ownership
  of paths under it, normalize case on Windows in `ownerOfBinary`, skip
  the POSIX `hash -r` hint on Windows, mark the primary target in the
  `--all` summary.
@rafa-thayto rafa-thayto force-pushed the rafa-thayto/auto-updatee branch from eae52ae to baf31a2 Compare April 20, 2026 16:11
Copy link
Copy Markdown
Contributor

@wyattjoh wyattjoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review

Ambitious rewrite of clerk update's installer resolution. The PATH-walking and ownership-by-install-dir design is solid and the test coverage for ownerOfBinary, findClerkOnPath, and the asdf helpers is thorough. A few issues stood out: the homebrew branch silently misreports success when the tap lags, --all can no-op when the primary is a refuse-case, and the update-cache gate holds primary success hostage to ancillary failures.

Comment thread packages/cli-core/src/commands/update/index.ts
Comment thread packages/cli-core/src/commands/update/index.ts
Comment thread packages/cli-core/src/commands/update/index.ts Outdated
Comment thread packages/cli-core/src/lib/installer.ts
Comment thread packages/cli-core/src/commands/update/index.ts Outdated
Before this change, `clerk update` called `detectInstaller()` on the
running binary's `process.execPath`. Two bugs compounded:

1. Bun detection compared against `bun pm bin -g` (the shim dir
   `~/.bun/bin`), but the Bun-compiled platform binary lives in
   `~/.bun/install/global/node_modules/@clerk/cli-<arch>`. The match
   never succeeded, so detection fell through to npm.
2. The fallback `npm install -g clerk@<new>` returned exit 0 and the
   spinner reported success — but on machines with asdf-managed node,
   the update landed in `~/.asdf/shims/` while the user's shell still
   resolved `clerk` to the (unchanged) `~/.bun/bin/clerk`.

The fix splits resolution from execution:

- New `findClerkOnPath()` walks `process.env.PATH` (shell-agnostic) and
  returns realpath'd, deduped, executable `clerk` binaries in PATH order.
- New `getInstallerPackageDirs()` returns the dir where each PM stores
  *packages* (not shims); the bun entry uses `$BUN_INSTALL/install/
  global/node_modules` — fixing bug 1.
- New `ownerOfBinary()` maps a binary path to its owning installer,
  returning `null` on no match. The update command treats `null` as
  refuse-rather-than-guess, preventing bug 2.
- The update command targets the *first* `clerk` on PATH (what the
  user's shell will actually execute), not whatever `process.execPath`
  reports.

Also:

- `--all` flag updates every `clerk` install on PATH in one run,
  skipping Homebrew on non-stable channels and `null`-owned binaries
  with a per-install warning and summary.
- Other installs are reported after every run so shadowing is visible.
- Post-update `hash -r` / `rehash` hint based on `$SHELL` (skipped for
  fish and PowerShell, which don't cache).
asdf shims are bash scripts (not symlinks), so realpath returns the
shim path itself and ownerOfBinary can't match it against any PM
prefix. The PATH survey marked asdf-installed clerks as "unknown
installer" and --all would skip them with a warning.

resolveAsdfShim() calls `asdf which <name>` to find the underlying
binary, realpaths the result, and feeds it into ownerOfBinary. Non-
shim paths pass through unchanged. When asdf is absent or can't
resolve, the shim path is returned and ownerOfBinary correctly
reports null — preserving the refuse-on-unknown behavior.

After a successful install, runs `asdf reshim <plugin>` for every
asdf plugin whose binary was updated. Safety net for asdf versions
that don't auto-reshim on npm install.

Target splits into displayPath (what's on PATH — the shim) and
resolvedPath (what ownerOfBinary consults) so users see the familiar
shim path in output while install logic operates on the resolved
binary.
- Remove dead detectInstaller, detectFromUserAgent, matchPmFromExecPath,
  and queryPmPrefix. They were the legacy runtime-based detection path,
  superseded by ownerOfBinary + findClerkOnPath. Only installer.test.ts
  still imported them.
- Drop the stale "TODO for a contributor" comment in the Strategy B
  section header; ownerOfBinary has been implemented.
- Rewrite getInstallerPackageDirs with Promise.all so the parallelism
  is obvious at the call site.
- Replace em-dashes with regular punctuation throughout installer.ts,
  update/index.ts, and update/README.md.
- Fix formatTarget double-dim: dim("unknown") was being wrapped inside
  another dim(...) in the null-owner case; the inner ANSI reset broke
  the outer styling. Pass the raw string instead.
- Homebrew auto-upgrades on stable channel, docs said otherwise. Update
  README to reflect the actual behavior.
- `npx clerk update` / `bunx clerk update` used to fall back to npm;
  after PATH-aware detection they hit the "unknown installer" refuse
  branch. Detect the runner via env vars and print a global-install
  hint instead of the install.sh message.
- Agent mode was auto-confirming whenever stdout was not a TTY, which
  contradicted the documented `--yes`-required behavior. Refuse in
  agent mode without `--yes` and print the exact command to run.
- Partial `--all` failures still refreshed the update cache; only
  write the cache when every attempted install succeeded.
- Bump changeset from patch to minor (adds `--all`, changes Homebrew
  behavior).
- Minor: `??` -> `||` for `ASDF_DATA_DIR` (empty string now treated as
  unset), require the bun install dir to exist before claiming ownership
  of paths under it, normalize case on Windows in `ownerOfBinary`, skip
  the POSIX `hash -r` hint on Windows, mark the primary target in the
  `--all` summary.
`npm prefix -g` + hardcoded `lib/node_modules` gives the wrong path on
Windows, where npm stores global packages directly under the prefix
(`%AppData%\npm\node_modules`, no `lib` segment). `npm root -g` reports
the correct directory on both POSIX and Windows.
- brew upgrade: verify installed version post-install and fail when the
  tap lags the target; `brew upgrade` ignores the packageSpec pin and
  exits 0 even when it's a no-op, so the caller was silently left on the
  old version.
- --all: when the primary target is blocked (e.g. Homebrew on canary,
  unknown owner), promote updatable others to effective primaries instead
  of refusing the whole run. Only refuse when every target is blocked.
  Surface the skipped primary in the summary so users can see why
  `clerk -v` didn't change.
- detectPackageRunner: drop the `npm_config_user_agent` UA disjunct and
  key off npm_execpath only. The UA is set for every npm/bun invocation
  (e.g. `npm run build` that shells out to clerk), so matching `npm/`
  misfired on ordinary script use.
- ownerOfBinary: strip Win32 extended-length (`\\?\`) and UNC (`\\?\UNC\`)
  prefixes before comparison so realpath-returned extended paths match
  plain install-dir prefixes.
- hashHint: collapse the dead `powershell.exe` branch that was shadowed
  by the `process.platform === "win32"` early-return, keeping
  `$SHELL=/usr/bin/pwsh` (PowerShell on Linux) correctly opted out.
@rafa-thayto rafa-thayto force-pushed the rafa-thayto/auto-updatee branch from baf31a2 to 78171e3 Compare April 20, 2026 18:30
@rafa-thayto rafa-thayto requested a review from wyattjoh April 20, 2026 18:33
@rafa-thayto rafa-thayto merged commit 83f6f47 into main Apr 20, 2026
10 checks passed
@rafa-thayto rafa-thayto deleted the rafa-thayto/auto-updatee branch April 20, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants