Repository navigation
Let claude-current fall back from a native Claude Code that does not run to the next one that does, and let claude-restart-check recognise a running native in a custom CLAUDE_CURRENT_NATIVE_DIR, symlinked included - #211
Merged
Conversation
…155 written (not yet run); left: the fixes in claude-current and claude-restart-check, the docs lines, the test run, the PR Tests only, no fix yet, so they are expected to fail on main where the fixes matter. tests/test_claude_current.py: a broken newest native falls back to the next that runs (exits, silent, garbled, hung), the fall back goes down every native, only the newest working native is probed, update runs through the native that runs, and every-native-broken still refuses (exit 1 or 2) as today. tests/test_claude_restart_check.py: a session from a CLAUDE_CURRENT_NATIVE_DIR directory is recognised (current, behind, replaced), canonical comparison for a trailing slash, a dot-dot spelling and a symlinked directory, and the narrow negatives (a non-version name, a nested path, another directory, a missing directory, no process table). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… recognise a running native from CLAUDE_CURRENT_NATIVE_DIR in claude-restart-check claude-current chose the newest native file by name before reading its --version, so a newest file that did not run was dropped with every older native that did (#154). add_native now reads from the highest name down and keeps the first that answers, which also makes it the native that `claude update` runs through. A working newest file still costs one read. claude-restart-check read installed versions from CLAUDE_CURRENT_NATIVE_DIR but recognised a running native only under .../claude/versions/, so a session launched from a configured directory was missed (#155). is_native_binary also accepts <x.y.z> directly in the canonical (cd -P) path of that directory, which is the path /proc/<pid>/exe reports, and serves both places that tested for a native. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days. You can request another review in 22 hours and 59 minutes by commenting |
Reviewer's GuideThe pull request hardens native Claude discovery by probing descending native versions until one actually answers, ensuring updates use that runnable installation, and extends restart detection to canonicalized custom native directories while preserving existing default and npm behavior. Sequence diagram for runnable Claude native selectionsequenceDiagram
participant User
participant Current as claude-current
participant Native285 as Native 2.1.285
participant Native284 as Native 2.1.284
participant NPM as npm install
User->>Current: collect
Current->>Native285: --version
Native285-->>Current: failure or timeout
Current->>Native284: --version
Native284-->>Current: version answers
Current-->>User: select Native 2.1.284
User->>Current: claude update
Current->>Native284: update
alt native update does not reach target
Current->>NPM: install target version
end
Flow diagram for canonical custom native restart detectionflowchart TD
A[claude-restart-check starts] --> B{ /proc available? }
B -- No --> C[Exit without notice]
B -- Yes --> D[Canonicalize CLAUDE_CURRENT_NATIVE_DIR]
D --> E[Read process exe path]
E --> F{Native binary?}
F -- Default versions path --> G[Use existing native recognition]
F -- Canonical custom directory and x.y.z filename --> H[Recognize running native]
F -- No --> I[Check npm binary recognition]
G --> J[Compare running and installed versions]
H --> J
I --> J
J --> K{Newer installed version?}
K -- Yes --> L[Print restart notice]
K -- No --> M[No notice]
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
…ce per launch, and a recognised current session Tests only, ahead of the fixes they prove: a session in a symlinked default directory with CLAUDE_CURRENT_NATIVE_DIR unset, a native whose --version failed being probed once and not again on each of a launch's later reads, and the newest-custom-version test asking the same process twice so its silence is a recognised session and not a missed one. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…robe each failed native once per launch claude-restart-check canonicalised only a configured CLAUDE_CURRENT_NATIVE_DIR, so with ~/.local/share/claude a symlink the kernel's real path held no /claude/versions/ and the session was missed until the variable was set to the default. The effective directory, spelled as claude-current spells it, is now canonicalised whether it is configured or not, and the installed-version read uses the same one. claude-current read the native directory again, in full, for each of the up to four collect passes of a launch, and a native whose --version had failed cost its whole bound each time. Names are now ordered once with sort and each failure is remembered for the run. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…nd after a wait for the lock Tests only, ahead of the fix. A native that failed is remembered for the run, which is wrong in two places the checker found at a1b9f91: claude update can rewrite the very file that failed, and another launch can finish a file this one read half written while this one waited for the lock. Both must be read again. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…it for the update lock The failure memory added in a1b9f91 lasted the whole launch, so a native that claude update repaired in place, or one another launch finished while this one waited for the lock, was skipped by the read that follows and the launch went to npm and could refuse (exit 2) where 149f298 verified. take_lock now records that it slept, and the memory is dropped after that wait and after update_native. A hung native still costs its bound once per read that can differ, not once per read. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This was referenced Oct 18, 2026
This was referenced Oct 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Closes #154
Closes #155
What was wrong
#154,
claude-current.native_newestchose the native file with the highest x.y.z name before anything read its--version. When that file did not run (a download cut short, a binary for another libc, a first start that hangs),add_candidatedropped it and no older native was tried, so a machine with a working older native read as having none.claude updatewas also run through that broken file.#155,
claude-restart-check. The installed versions were read from$CLAUDE_CURRENT_NATIVE_DIR, but a running process was recognised as native only when itsexepath contained/claude/versions/. A session launched from a configured directory such as/custom/native/2.1.283was never found, so no notice was printed even when a newer sibling existed.What changed
claude-currentnative_names(lines 427-439) lists the native version names once, highest first, with onesort -t. -k1,1nr -k2,2nr -k3,3nr(POSIX; no per-comparisonvercmpprocess).add_native(lines 441-469) replacesnative_newest. It reads native versions from the highest down through the existingadd_candidateand keeps the first whose--versionanswers. A working newest file still costs one read.native_broken(line 414) remembers each file that failed, so the up to fourcollectpasses of a launch do not pay a hung file's bound again each time, and it is forgotten wherever something else may have written the file: after a wait for the update lock (take_locksetslock_slept, lines 570 and 652; the reset is at line 780, before the post-lockcollect), because the launch that held the lock may have finished a native this one read half written; and afterupdate_native(line 796, before thecollectthat follows), becauseclaude updaterewrites files, the failed one among them. Without those two resets a repaired native was skipped and the launch could go to npm and refuse (exit 2) where it had verified.native_path(line 413) now names the native that runs, soclaude updateruns through that one; with no native that runs, the update goes straight to the npm install it would have fallen to anyway.collect(line 471) calls it. Header step 2 (lines 28-32) says so. Bash 3.2 safe: a newline-delimited string, no associative array.claude-restart-checknative_dirandnative_real(lines 204-214): the native versions directory spelled exactly asclaude-currentspells it ($CLAUDE_CURRENT_NATIVE_DIR, else$HOME/.local/share/claude/versions, nothing when both are unset), and its canonical path bycd -Pandpwd -P, which is the path/proc/<pid>/exereports. That covers a symlinked configured directory and also a symlinked default (~/.local/share/claudelinked to/x/persist/cl-native, which the kernel reports as/x/persist/cl-native/versions/<x.y.z>). Noreadlink -f, so it stays bash 3.2 and BSD safe. It runs after the existing no-/procexit.is_native_binary(lines 216-223) accepts*/claude/versions/*as before, or<x.y.z>directly in the canonical directory. It serves bothis_claude_binary(line 225) and the installed-version branch (line 331), which formerly each spelled the*/claude/versions/*test; that branch's directory read (line 344) uses the samenative_dir. The(deleted)replacement check is untouched.docs/README-claude-current.md: candidate 1, the update paragraph and theclaude-restart-checkwalk paragraph say the above. No line ofREADME.mdwas added.Tests
tests/test_claude_current.py(10 new functions, 13 cases): a broken newest native falls back, for each of four failures (exits non-zero, silent, garbled, hung and bounded byCLAUDE_CURRENT_VERSION_TIMEOUT); the fall back goes down every native; a working newest native is the only one probed; a native that failed is probed once per launch, not once per read; a native thatclaude updaterepaired in place is read again (the npm install fails, so reading it again is the only way to a launch); a native another launch finished while this one waited for the lock is read again and the answer is "updated by another launch";claude updateruns through the native that runs; every native broken still gives exit 1 with nothing else installed, and the user prefix install still recovers it; a broken newest native behind a stale user copy is still the exit 2 refusal.tests/test_claude_restart_check.py(11 new functions, 14 cases), on fake process tables: a custom directory session behind, current (asked twice, so its silence is a recognised session and not a missed one) and replaced; a trailing slash, a..spelling and a symlinked directory (the exe path is the canonical one, as the kernel reports it); a symlinked default directory with no variable set; the default directory still found when another is set; and the narrow negatives (a non-version name, a nested path, another directory, a missing directory, no/proc).Verification.
flock -w 7200 ${TMPDIR:-/tmp}/openrepotools-pytest.lock python3 -m pytest tests/test_claude_current.py tests/test_claude_restart_check.py -q -p no:cacheprovider055f19f: run 39072812551, all green. The Linuxtestsjob ran the merge of055f19fintoaa14de3(main when the run started):1471 passed, 9 skipped in 2981.90s (0:49:41).tests-no-submoduleandguard-launch-modealso passed.claude updaterepaired the file in place, or after another launch finished it during the lock wait, so the launch could go to npm and refuse): proved red then green under the shared lock.a1b9f91'sclaude-current, the two new tests fail (2 failed, 100 deselected):test_a_native_the_update_repaired_in_place_is_read_againexits 2 withREFUSED: npm publishes claude 2.1.284 and the newest installed is 2.1.283 ..., andtest_a_native_another_launch_finished_while_this_one_waited_is_read_againanswers the user prefix install instead of the finished native.tests/test_claude_current.pyin full:102 passed in 78.30s.npm install:a1b9f91exits 2; this head exits 0,status=verified, at the repaired native 2.1.284.a1b9f91, both scoped files:137 passed in 64.88s. The new tests of the earlier rounds againstf87fd5a's two scripts: 13 fail and 11 pass (the 11 are the "still as today" guards: a working newest native probed alone, every native broken still refusing, the narrow negatives, the default directory, no/proc).test_claude_current.pyapplies, called directly on both scripts ata1b9f91: 0 failures;/bin/bash -non both at this head: clean.Out of scope: #149.
🤖 Generated with Claude Code
Summary by Sourcery
Improve native Claude discovery and restart detection so broken installations no longer hide runnable versions and native sessions in custom directories are correctly identified.
Bug Fixes:
Enhancements:
Documentation:
Tests: