99_IGNORED_VERSION_ENTRIES = {'.DS_Store' }
1010
1111
12- def route_claude_binary_cache (home_root : Path , shared_cache_root : Path ) -> dict [str , object ]:
12+ def route_claude_binary_cache (
13+ home_root : Path ,
14+ shared_cache_root : Path ,
15+ * ,
16+ source_home : Path | None = None ,
17+ ) -> dict [str , object ]:
1318 home = Path (home_root ).expanduser ().resolve (strict = False )
1419 shared_versions_dir = Path (shared_cache_root ).expanduser ().resolve (strict = False ) / 'versions'
1520 versions_dir = home / '.local' / 'share' / 'claude' / 'versions'
21+ source_active_version = _source_active_version (source_home , managed_home = home )
22+ source_active_version_name = source_active_version .name if source_active_version is not None else ''
1623
1724 try :
1825 shared_versions_dir .mkdir (parents = True , exist_ok = True )
@@ -27,7 +34,18 @@ def route_claude_binary_cache(home_root: Path, shared_cache_root: Path) -> dict[
2734
2835 if versions_dir .is_symlink ():
2936 if _same_path (versions_dir , shared_versions_dir ):
30- active_version_name = _ensure_latest_claude_link (home , shared_versions_dir )
37+ failure = _copy_source_active_version_to_shared (
38+ source_active_version ,
39+ shared_versions_dir = shared_versions_dir ,
40+ versions_dir = versions_dir ,
41+ )
42+ if failure is not None :
43+ return failure
44+ active_version_name = _ensure_claude_link (
45+ home ,
46+ shared_versions_dir ,
47+ preferred_version_name = source_active_version_name ,
48+ )
3149 write_projected_marker (
3250 versions_dir ,
3351 label = _PROJECTION_LABEL ,
@@ -75,16 +93,27 @@ def route_claude_binary_cache(home_root: Path, shared_cache_root: Path) -> dict[
7593 versions_dir = versions_dir ,
7694 version_names = scan ['version_names' ],
7795 )
96+ if failure is not None :
97+ return failure
98+ failure = _copy_source_active_version_to_shared (
99+ source_active_version ,
100+ shared_versions_dir = shared_versions_dir ,
101+ versions_dir = versions_dir ,
102+ )
78103 if failure is not None :
79104 return failure
80105 linked = _link_versions_dir (
81106 versions_dir ,
82107 shared_versions_dir ,
83108 reason = 'migrated_symlink' if scan ['version_paths' ] else 'linked_empty' ,
84- version_names = scan [ 'version_names' ] ,
109+ version_names = _version_names ( shared_versions_dir ) ,
85110 )
86111 if linked .get ('status' ) == 'ok' :
87- linked ['active_version_name' ] = _ensure_latest_claude_link (home , shared_versions_dir ) or ''
112+ linked ['active_version_name' ] = _ensure_claude_link (
113+ home ,
114+ shared_versions_dir ,
115+ preferred_version_name = source_active_version_name ,
116+ ) or ''
88117 if scan ['ignored_entries' ] and linked .get ('status' ) == 'ok' :
89118 linked ['warnings' ] = tuple (scan ['ignored_entries' ])
90119 return linked
@@ -98,11 +127,26 @@ def route_claude_binary_cache(home_root: Path, shared_cache_root: Path) -> dict[
98127 )
99128
100129 if not versions_dir .exists ():
101- return _link_versions_dir (
130+ failure = _copy_source_active_version_to_shared (
131+ source_active_version ,
132+ shared_versions_dir = shared_versions_dir ,
133+ versions_dir = versions_dir ,
134+ )
135+ if failure is not None :
136+ return failure
137+ linked = _link_versions_dir (
102138 versions_dir ,
103139 shared_versions_dir ,
104140 reason = 'linked_empty' ,
141+ version_names = _version_names (shared_versions_dir ),
105142 )
143+ if linked .get ('status' ) == 'ok' :
144+ linked ['active_version_name' ] = _ensure_claude_link (
145+ home ,
146+ shared_versions_dir ,
147+ preferred_version_name = source_active_version_name ,
148+ ) or ''
149+ return linked
106150
107151 scan = _scan_versions_dir (versions_dir )
108152 if scan ['unknown_entries' ]:
@@ -121,17 +165,28 @@ def route_claude_binary_cache(home_root: Path, shared_cache_root: Path) -> dict[
121165 versions_dir = versions_dir ,
122166 version_names = scan ['version_names' ],
123167 )
168+ if failure is not None :
169+ return failure
170+ failure = _copy_source_active_version_to_shared (
171+ source_active_version ,
172+ shared_versions_dir = shared_versions_dir ,
173+ versions_dir = versions_dir ,
174+ )
124175 if failure is not None :
125176 return failure
126177
127178 linked = _link_versions_dir (
128179 versions_dir ,
129180 shared_versions_dir ,
130181 reason = 'migrated' if scan ['version_paths' ] else 'linked_empty' ,
131- version_names = scan [ 'version_names' ] ,
182+ version_names = _version_names ( shared_versions_dir ) ,
132183 )
133184 if linked .get ('status' ) == 'ok' :
134- linked ['active_version_name' ] = _ensure_latest_claude_link (home , shared_versions_dir ) or ''
185+ linked ['active_version_name' ] = _ensure_claude_link (
186+ home ,
187+ shared_versions_dir ,
188+ preferred_version_name = source_active_version_name ,
189+ ) or ''
135190 if scan ['ignored_entries' ] and linked .get ('status' ) == 'ok' :
136191 linked ['warnings' ] = tuple (scan ['ignored_entries' ])
137192 return linked
@@ -171,6 +226,22 @@ def _copy_versions_to_shared(
171226 return None
172227
173228
229+ def _copy_source_active_version_to_shared (
230+ source_active_version : Path | None ,
231+ * ,
232+ shared_versions_dir : Path ,
233+ versions_dir : Path ,
234+ ) -> dict [str , object ] | None :
235+ if source_active_version is None :
236+ return None
237+ return _copy_versions_to_shared (
238+ version_paths = (source_active_version ,),
239+ shared_versions_dir = shared_versions_dir ,
240+ versions_dir = versions_dir ,
241+ version_names = (source_active_version .name ,),
242+ )
243+
244+
174245def _scan_versions_dir (versions_dir : Path ) -> dict [str , object ]:
175246 version_paths : list [Path ] = []
176247 unknown_entries : list [str ] = []
@@ -237,25 +308,34 @@ def _link_versions_dir(
237308 )
238309
239310
240- def _ensure_latest_claude_link (home : Path , shared_versions_dir : Path ) -> str :
241- latest = _newest_version_path (shared_versions_dir )
242- if latest is None :
311+ def _ensure_claude_link (home : Path , shared_versions_dir : Path , * , preferred_version_name : str = '' ) -> str :
312+ target_version = _preferred_or_newest_version_path (shared_versions_dir , preferred_version_name = preferred_version_name )
313+ if target_version is None :
243314 return ''
244- executable = _version_executable_path (latest )
315+ executable = _version_executable_path (target_version )
245316 if executable is None :
246317 return ''
247318 link = home / '.local' / 'bin' / 'claude'
248319 try :
249320 if link .is_symlink () and _same_path (link , executable ):
250- return latest .name
321+ return target_version .name
251322 if link .exists () and not link .is_symlink ():
252323 return ''
253324 link .parent .mkdir (parents = True , exist_ok = True )
254325 link .unlink (missing_ok = True )
255326 link .symlink_to (executable )
256327 except Exception :
257328 return ''
258- return latest .name
329+ return target_version .name
330+
331+
332+ def _preferred_or_newest_version_path (versions_dir : Path , * , preferred_version_name : str ) -> Path | None :
333+ preferred = str (preferred_version_name or '' ).strip ()
334+ if preferred :
335+ candidate = versions_dir / preferred
336+ if _looks_like_claude_version_name (candidate .name ) and _version_executable_path (candidate ) is not None :
337+ return candidate
338+ return _newest_version_path (versions_dir )
259339
260340
261341def _newest_version_path (versions_dir : Path ) -> Path | None :
@@ -300,6 +380,33 @@ def _version_names(versions_dir: Path) -> tuple[str, ...]:
300380 return ()
301381
302382
383+ def _source_active_version (source_home : Path | None , * , managed_home : Path ) -> Path | None :
384+ if source_home is None :
385+ return None
386+ try :
387+ home = Path (source_home ).expanduser ().resolve (strict = False )
388+ except Exception :
389+ return None
390+ if _same_path (home , managed_home ):
391+ return None
392+ link = home / '.local' / 'bin' / 'claude'
393+ if not link .is_symlink ():
394+ return None
395+ try :
396+ target = link .resolve (strict = True )
397+ versions_dir = (home / '.local' / 'share' / 'claude' / 'versions' ).resolve (strict = True )
398+ relative = target .relative_to (versions_dir )
399+ except Exception :
400+ return None
401+ if not relative .parts :
402+ return None
403+ version_name = relative .parts [0 ]
404+ if not _looks_like_claude_version_name (version_name ):
405+ return None
406+ candidate = versions_dir / version_name
407+ return candidate if _version_executable_path (candidate ) is not None else None
408+
409+
303410def _same_path (left : Path , right : Path ) -> bool :
304411 try :
305412 return left .resolve () == right .resolve ()
0 commit comments