11import fs from "node:fs/promises" ;
22import path from "node:path" ;
33import { ensureAuthProfileStore } from "./auth-profiles.js" ;
4- import type { AuthProfileCredential } from "./auth-profiles/types.js" ;
5- import { normalizeProviderId } from "./model-selection.js" ;
4+ import {
5+ piCredentialsEqual ,
6+ resolvePiCredentialMapFromStore ,
7+ type PiCredential ,
8+ } from "./pi-auth-credentials.js" ;
69
710/**
811 * @deprecated Legacy bridge for older flows that still expect `agentDir/auth.json`.
912 * Runtime auth resolution uses auth-profiles directly and should not depend on this module.
1013 */
11- type AuthJsonCredential =
12- | {
13- type : "api_key" ;
14- key : string ;
15- }
16- | {
17- type : "oauth" ;
18- access : string ;
19- refresh : string ;
20- expires : number ;
21- [ key : string ] : unknown ;
22- } ;
14+ type AuthJsonCredential = PiCredential ;
2315
2416type AuthJsonShape = Record < string , AuthJsonCredential > ;
2517
@@ -36,75 +28,6 @@ async function readAuthJson(filePath: string): Promise<AuthJsonShape> {
3628 }
3729}
3830
39- /**
40- * Convert an OpenClaw auth-profiles credential to pi-coding-agent auth.json format.
41- * Returns null if the credential cannot be converted.
42- */
43- function convertCredential ( cred : AuthProfileCredential ) : AuthJsonCredential | null {
44- if ( cred . type === "api_key" ) {
45- const key = typeof cred . key === "string" ? cred . key . trim ( ) : "" ;
46- if ( ! key ) {
47- return null ;
48- }
49- return { type : "api_key" , key } ;
50- }
51-
52- if ( cred . type === "token" ) {
53- // pi-coding-agent treats static tokens as api_key type
54- const token = typeof cred . token === "string" ? cred . token . trim ( ) : "" ;
55- if ( ! token ) {
56- return null ;
57- }
58- const expires =
59- typeof ( cred as { expires ?: unknown } ) . expires === "number"
60- ? ( cred as { expires : number } ) . expires
61- : Number . NaN ;
62- if ( Number . isFinite ( expires ) && expires > 0 && Date . now ( ) >= expires ) {
63- return null ;
64- }
65- return { type : "api_key" , key : token } ;
66- }
67-
68- if ( cred . type === "oauth" ) {
69- const accessRaw = ( cred as { access ?: unknown } ) . access ;
70- const refreshRaw = ( cred as { refresh ?: unknown } ) . refresh ;
71- const expiresRaw = ( cred as { expires ?: unknown } ) . expires ;
72-
73- const access = typeof accessRaw === "string" ? accessRaw . trim ( ) : "" ;
74- const refresh = typeof refreshRaw === "string" ? refreshRaw . trim ( ) : "" ;
75- const expires = typeof expiresRaw === "number" ? expiresRaw : Number . NaN ;
76-
77- if ( ! access || ! refresh || ! Number . isFinite ( expires ) || expires <= 0 ) {
78- return null ;
79- }
80- return { type : "oauth" , access, refresh, expires } ;
81- }
82-
83- return null ;
84- }
85-
86- /**
87- * Check if two auth.json credentials are equivalent.
88- */
89- function credentialsEqual ( a : AuthJsonCredential | undefined , b : AuthJsonCredential ) : boolean {
90- if ( ! a || typeof a !== "object" ) {
91- return false ;
92- }
93- if ( a . type !== b . type ) {
94- return false ;
95- }
96-
97- if ( a . type === "api_key" && b . type === "api_key" ) {
98- return a . key === b . key ;
99- }
100-
101- if ( a . type === "oauth" && b . type === "oauth" ) {
102- return a . access === b . access && a . refresh === b . refresh && a . expires === b . expires ;
103- }
104-
105- return false ;
106- }
107-
10831/**
10932 * pi-coding-agent's ModelRegistry/AuthStorage expects credentials in auth.json.
11033 *
@@ -123,31 +46,16 @@ export async function ensurePiAuthJsonFromAuthProfiles(agentDir: string): Promis
12346} > {
12447 const store = ensureAuthProfileStore ( agentDir , { allowKeychainPrompt : false } ) ;
12548 const authPath = path . join ( agentDir , "auth.json" ) ;
126-
127- // Group profiles by provider, taking the first valid profile for each
128- const providerCredentials = new Map < string , AuthJsonCredential > ( ) ;
129-
130- for ( const [ , cred ] of Object . entries ( store . profiles ) ) {
131- const provider = normalizeProviderId ( String ( cred . provider ?? "" ) ) . trim ( ) ;
132- if ( ! provider || providerCredentials . has ( provider ) ) {
133- continue ;
134- }
135-
136- const converted = convertCredential ( cred ) ;
137- if ( converted ) {
138- providerCredentials . set ( provider , converted ) ;
139- }
140- }
141-
142- if ( providerCredentials . size === 0 ) {
49+ const providerCredentials = resolvePiCredentialMapFromStore ( store ) ;
50+ if ( Object . keys ( providerCredentials ) . length === 0 ) {
14351 return { wrote : false , authPath } ;
14452 }
14553
14654 const existing = await readAuthJson ( authPath ) ;
14755 let changed = false ;
14856
149- for ( const [ provider , cred ] of providerCredentials ) {
150- if ( ! credentialsEqual ( existing [ provider ] , cred ) ) {
57+ for ( const [ provider , cred ] of Object . entries ( providerCredentials ) ) {
58+ if ( ! piCredentialsEqual ( existing [ provider ] , cred ) ) {
15159 existing [ provider ] = cred ;
15260 changed = true ;
15361 }
0 commit comments