@@ -1312,20 +1312,40 @@ async def list_credentials(credential_id: str = "") -> str:
13121312 Returns credential IDs, aliases, status, and identity metadata.
13131313 Never returns secret values. Optionally filter by credential_id.
13141314 """
1315+ # Load shell config vars into os.environ — same first step as check-agent.
1316+ # Ensures keys set in ~/.zshrc/~/.bashrc are visible to is_available() checks.
1317+ try :
1318+ from framework .credentials .validation import ensure_credential_key_env
1319+
1320+ ensure_credential_key_env ()
1321+ except Exception :
1322+ pass
1323+
13151324 try :
13161325 # Primary: CredentialStoreAdapter sees both Aden OAuth and local accounts
13171326 from aden_tools .credentials import CredentialStoreAdapter
13181327
13191328 store = CredentialStoreAdapter .default ()
13201329 all_accounts = store .get_all_account_info ()
13211330
1322- # Filter by credential_id / provider if requested
1331+ # Filter by credential_id / provider if requested.
1332+ # A spec name like "gmail_oauth" maps to provider "google" via
1333+ # credential_id field — resolve that alias before filtering.
13231334 if credential_id :
1335+ try :
1336+ from aden_tools .credentials import CREDENTIAL_SPECS
1337+
1338+ spec = CREDENTIAL_SPECS .get (credential_id )
1339+ resolved_provider = (
1340+ (spec .credential_id or credential_id ) if spec else credential_id
1341+ )
1342+ except Exception :
1343+ resolved_provider = credential_id
13241344 all_accounts = [
13251345 a
13261346 for a in all_accounts
13271347 if a .get ("credential_id" , "" ).startswith (credential_id )
1328- or a .get ("provider" , "" ) == credential_id
1348+ or a .get ("provider" , "" ) in ( credential_id , resolved_provider )
13291349 ]
13301350
13311351 return json .dumps (
@@ -1342,13 +1362,43 @@ async def list_credentials(credential_id: str = "") -> str:
13421362
13431363 # Fallback: local encrypted store only
13441364 try :
1365+ from framework .credentials .local .models import LocalAccountInfo
13451366 from framework .credentials .local .registry import LocalCredentialRegistry
1367+ from framework .credentials .storage import EncryptedFileStorage
13461368
13471369 registry = LocalCredentialRegistry .default ()
13481370 accounts = registry .list_accounts (
13491371 credential_id = credential_id or None ,
13501372 )
13511373
1374+ # Also include flat-file credentials saved by the GUI (no "/" separator).
1375+ # LocalCredentialRegistry.list_accounts() skips these — read them directly.
1376+ seen_cred_ids = {info .credential_id for info in accounts }
1377+ storage = EncryptedFileStorage ()
1378+ for storage_id in storage .list_all ():
1379+ if "/" in storage_id :
1380+ continue # already handled by LocalCredentialRegistry above
1381+ if credential_id and storage_id != credential_id :
1382+ continue
1383+ if storage_id in seen_cred_ids :
1384+ continue
1385+ try :
1386+ cred_obj = storage .load (storage_id )
1387+ except Exception :
1388+ continue
1389+ if cred_obj is None :
1390+ continue
1391+ accounts .append (
1392+ LocalAccountInfo (
1393+ credential_id = storage_id ,
1394+ alias = "default" ,
1395+ status = "unknown" ,
1396+ identity = cred_obj .identity ,
1397+ last_validated = cred_obj .last_refreshed ,
1398+ created_at = cred_obj .created_at ,
1399+ )
1400+ )
1401+
13521402 credentials = []
13531403 for info in accounts :
13541404 entry : dict [str , Any ] = {
0 commit comments