@@ -292,9 +292,13 @@ def update(self, pack_id: str, updates: dict):
292292 existing = self .data ["presets" ][pack_id ]
293293 # Merge: existing fields preserved, new fields override
294294 merged = {** existing , ** updates }
295- # Always preserve original installed_at
295+ # Always preserve original installed_at based on key existence, not truthiness,
296+ # to handle cases where the field exists but may be falsy (legacy/corruption)
296297 if "installed_at" in existing :
297298 merged ["installed_at" ] = existing ["installed_at" ]
299+ else :
300+ # If not present in existing, explicitly remove from merged if caller provided it
301+ merged .pop ("installed_at" , None )
298302 self .data ["presets" ][pack_id ] = merged
299303 self ._save ()
300304
@@ -1488,17 +1492,35 @@ def resolve(
14881492 # Priority 3: Extension-provided templates (sorted by priority — lower number wins)
14891493 if self .extensions_dir .exists ():
14901494 registry = ExtensionRegistry (self .extensions_dir )
1491- for ext_id , _metadata in registry .list_by_priority ():
1492- ext_dir = self .extensions_dir / ext_id
1493- if not ext_dir .is_dir ():
1494- continue
1495- for subdir in subdirs :
1496- if subdir :
1497- candidate = ext_dir / subdir / f"{ template_name } { ext } "
1498- else :
1499- candidate = ext_dir / f"{ template_name } { ext } "
1500- if candidate .exists ():
1501- return candidate
1495+ registered_extensions = registry .list_by_priority ()
1496+
1497+ # If registry is empty but extension directories exist, fall back to
1498+ # directory scanning for robustness (handles corrupted/missing registry)
1499+ if not registered_extensions :
1500+ # Scan directories alphabetically with implicit priority=10
1501+ for ext_dir in sorted (self .extensions_dir .iterdir ()):
1502+ if not ext_dir .is_dir () or ext_dir .name .startswith ("." ):
1503+ continue
1504+ for subdir in subdirs :
1505+ if subdir :
1506+ candidate = ext_dir / subdir / f"{ template_name } { ext } "
1507+ else :
1508+ candidate = ext_dir / f"{ template_name } { ext } "
1509+ if candidate .exists ():
1510+ return candidate
1511+ else :
1512+ # Use registry-based resolution with priority ordering
1513+ for ext_id , _metadata in registered_extensions :
1514+ ext_dir = self .extensions_dir / ext_id
1515+ if not ext_dir .is_dir ():
1516+ continue
1517+ for subdir in subdirs :
1518+ if subdir :
1519+ candidate = ext_dir / subdir / f"{ template_name } { ext } "
1520+ else :
1521+ candidate = ext_dir / f"{ template_name } { ext } "
1522+ if candidate .exists ():
1523+ return candidate
15021524
15031525 # Priority 4: Core templates
15041526 if template_type == "template" :
@@ -1558,18 +1580,35 @@ def resolve_with_source(
15581580
15591581 if self .extensions_dir .exists ():
15601582 ext_registry = ExtensionRegistry (self .extensions_dir )
1561- for ext_id , ext_meta in ext_registry .list_by_priority ():
1562- ext_dir = self .extensions_dir / ext_id
1563- if not ext_dir .is_dir ():
1564- continue
1565- try :
1566- resolved .relative_to (ext_dir )
1567- version = ext_meta .get ("version" , "?" ) if ext_meta else "?"
1568- return {
1569- "path" : resolved_str ,
1570- "source" : f"extension:{ ext_id } v{ version } " ,
1571- }
1572- except ValueError :
1573- continue
1583+ registered_extensions = ext_registry .list_by_priority ()
1584+
1585+ if registered_extensions :
1586+ # Use registry-based attribution
1587+ for ext_id , ext_meta in registered_extensions :
1588+ ext_dir = self .extensions_dir / ext_id
1589+ if not ext_dir .is_dir ():
1590+ continue
1591+ try :
1592+ resolved .relative_to (ext_dir )
1593+ version = ext_meta .get ("version" , "?" ) if ext_meta else "?"
1594+ return {
1595+ "path" : resolved_str ,
1596+ "source" : f"extension:{ ext_id } v{ version } " ,
1597+ }
1598+ except ValueError :
1599+ continue
1600+ else :
1601+ # Fallback: scan directories when registry is empty/corrupted
1602+ for ext_dir in sorted (self .extensions_dir .iterdir ()):
1603+ if not ext_dir .is_dir () or ext_dir .name .startswith ("." ):
1604+ continue
1605+ try :
1606+ resolved .relative_to (ext_dir )
1607+ return {
1608+ "path" : resolved_str ,
1609+ "source" : f"extension:{ ext_dir .name } (unregistered)" ,
1610+ }
1611+ except ValueError :
1612+ continue
15741613
15751614 return {"path" : resolved_str , "source" : "core" }
0 commit comments