88
99import click
1010
11+
12+ def _find_component_path (base_dir : Path , dep_type : str , dep_name : str ) -> Optional [Path ]:
13+ """Find a component path, checking both directory and file variants.
14+
15+ Components can be directories (e.g., shared/skills/logging/) or
16+ files (e.g., shared/skills/new-skill.md). This function checks
17+ the exact path first, then looks for file matches with extensions.
18+ """
19+ exact = base_dir / dep_type / dep_name
20+ if exact .exists ():
21+ return exact
22+ # Look for file with extension (e.g., new-skill.md)
23+ parent = base_dir / dep_type
24+ if parent .exists ():
25+ for item in parent .iterdir ():
26+ if item .stem == dep_name and item .is_file ():
27+ return item
28+ return None
29+
1130from ..core .config import load_cldpm_config
1231from ..core .resolver import resolve_project
1332from ..utils .fs import ensure_dir , find_repo_root
@@ -207,10 +226,12 @@ def _download_local_project(
207226 for dep_type in ["skills" , "agents" , "hooks" , "rules" ]:
208227 for component in resolved ["shared" ].get (dep_type , []):
209228 comp_name = component ["name" ]
210- source_comp = shared_dir / dep_type / comp_name
211- target_comp = target_path / ".claude" / dep_type / comp_name
229+ source_comp = _find_component_path (shared_dir , dep_type , comp_name )
230+ if source_comp is None :
231+ continue
232+ target_comp = target_path / ".claude" / dep_type / source_comp .name
212233
213- if source_comp . exists () and not target_comp .exists ():
234+ if not target_comp .exists ():
214235 if source_comp .is_dir ():
215236 shutil .copytree (source_comp , target_comp )
216237 else :
@@ -334,11 +355,15 @@ def _handle_remote_get_sparse(
334355 cleanup_temp_dir (temp_project )
335356
336357 # Build path list for final sparse clone
358+ # Include both directory and file patterns for each dependency
359+ # since components can be directories (e.g., shared/skills/logging/)
360+ # or files (e.g., shared/skills/new-skill.md)
337361 all_paths = [project_path ]
338362 dependencies = project_config .get ("dependencies" , {})
339363 for dep_type in ["skills" , "agents" , "hooks" , "rules" ]:
340364 for dep_name in dependencies .get (dep_type , []):
341365 all_paths .append (f"{ shared_dir } /{ dep_type } /{ dep_name } " )
366+ all_paths .append (f"{ shared_dir } /{ dep_type } /{ dep_name } .*" )
342367
343368 # Phase 3: Download everything needed
344369 console .print (f"[dim]Downloading project and dependencies...[/dim]" )
@@ -478,8 +503,10 @@ def _build_sparse_result(
478503 for dep_type in ["skills" , "agents" , "hooks" , "rules" ]:
479504 result ["shared" ][dep_type ] = []
480505 for dep_name in dependencies .get (dep_type , []):
481- source_comp = temp_dir / shared_dir / dep_type / dep_name
482- if source_comp .exists ():
506+ source_comp = _find_component_path (
507+ temp_dir / shared_dir , dep_type , dep_name
508+ )
509+ if source_comp :
483510 # Get list of files in the component
484511 if source_comp .is_dir ():
485512 files = [f .name for f in source_comp .iterdir () if f .is_file ()]
@@ -488,7 +515,7 @@ def _build_sparse_result(
488515 result ["shared" ][dep_type ].append ({
489516 "name" : dep_name ,
490517 "type" : "shared" ,
491- "sourcePath" : f"{ shared_dir } /{ dep_type } /{ dep_name } " ,
518+ "sourcePath" : f"{ shared_dir } /{ dep_type } /{ source_comp . name } " ,
492519 "files" : files ,
493520 })
494521
@@ -576,10 +603,14 @@ def _download_sparse_project(
576603 # Place shared components directly in .claude/<type>/<name>/
577604 for dep_type in ["skills" , "agents" , "hooks" , "rules" ]:
578605 for dep_name in dependencies .get (dep_type , []):
579- source_comp = temp_dir / shared_dir / dep_type / dep_name
580- target_comp = target / ".claude" / dep_type / dep_name
606+ source_comp = _find_component_path (
607+ temp_dir / Path (shared_dir ), dep_type , dep_name
608+ )
609+ if source_comp is None :
610+ continue
611+ target_comp = target / ".claude" / dep_type / source_comp .name
581612
582- if source_comp . exists () and not target_comp .exists ():
613+ if not target_comp .exists ():
583614 ensure_dir (target_comp .parent )
584615 if source_comp .is_dir ():
585616 shutil .copytree (source_comp , target_comp )
@@ -678,10 +709,12 @@ def _download_remote_project(
678709 for dep_type in ["skills" , "agents" , "hooks" , "rules" ]:
679710 for component in resolved ["shared" ].get (dep_type , []):
680711 comp_name = component ["name" ]
681- source_comp = shared_dir / dep_type / comp_name
682- target_comp = target / ".claude" / dep_type / comp_name
712+ source_comp = _find_component_path (shared_dir , dep_type , comp_name )
713+ if source_comp is None :
714+ continue
715+ target_comp = target / ".claude" / dep_type / source_comp .name
683716
684- if source_comp . exists () and not target_comp .exists ():
717+ if not target_comp .exists ():
685718 if source_comp .is_dir ():
686719 shutil .copytree (source_comp , target_comp )
687720 else :
0 commit comments