@@ -57,6 +57,7 @@ export interface MistralAuthOptions {
5757}
5858
5959export function resolveMistralConfigDir ( options ?: MistralAuthOptions ) : string {
60+ // Keep for backward compatibility; prefer resolveVibeHome below
6061 if ( options ?. mistralConfigDir ) {
6162 return expandHomeDir ( options . mistralConfigDir ) ;
6263 }
@@ -65,17 +66,27 @@ export function resolveMistralConfigDir(options?: MistralAuthOptions): string {
6566 return expandHomeDir ( process . env . MISTRAL_CONFIG_DIR ) ;
6667 }
6768
68- // Authentication is shared globally
6969 return path . join ( homedir ( ) , '.codemachine' , 'mistral' ) ;
7070}
7171
72+ function resolveVibeHome ( options ?: MistralAuthOptions ) : string {
73+ if ( options ?. mistralConfigDir ) {
74+ return expandHomeDir ( options . mistralConfigDir ) ;
75+ }
76+ if ( process . env . VIBE_HOME ) {
77+ return expandHomeDir ( process . env . VIBE_HOME ) ;
78+ }
79+ // default under codemachine
80+ return path . join ( homedir ( ) , '.codemachine' , 'vibe' ) ;
81+ }
82+
7283/**
7384 * Gets the path to the credentials file
7485 * Mistral Vibe stores it at ~/.vibe/.env
7586 */
7687export function getCredentialsPath ( configDir : string ) : string {
77- // Mistral Vibe uses ~/.vibe/.env for API key
78- const vibeDir = path . join ( homedir ( ) , '.vibe' ) ;
88+ // Use VIBE_HOME override or fallback to ~/.codemachine/ vibe/.env
89+ const vibeDir = resolveVibeHome ( { mistralConfigDir : configDir } ) ;
7990 return path . join ( vibeDir , '.env' ) ;
8091}
8192
@@ -113,7 +124,7 @@ export async function isAuthenticated(options?: MistralAuthOptions): Promise<boo
113124 return true ;
114125 }
115126
116- const credPath = getCredentialsPath ( resolveMistralConfigDir ( options ) ) ;
127+ const credPath = getCredentialsPath ( resolveVibeHome ( options ) ) ;
117128
118129 try {
119130 await stat ( credPath ) ;
@@ -133,7 +144,8 @@ export async function ensureAuth(options?: MistralAuthOptions): Promise<boolean>
133144 }
134145
135146 const configDir = resolveMistralConfigDir ( options ) ;
136- const credPath = getCredentialsPath ( configDir ) ;
147+ const vibeHome = resolveVibeHome ( options ) ;
148+ const credPath = getCredentialsPath ( vibeHome ) ;
137149
138150 // If already authenticated, nothing to do
139151 try {
@@ -145,8 +157,7 @@ export async function ensureAuth(options?: MistralAuthOptions): Promise<boolean>
145157
146158 if ( process . env . CODEMACHINE_SKIP_AUTH === '1' ) {
147159 // Create a placeholder for testing/dry-run mode
148- const vibeDir = path . dirname ( credPath ) ;
149- await mkdir ( vibeDir , { recursive : true } ) ;
160+ await mkdir ( vibeHome , { recursive : true } ) ;
150161 await writeFile ( credPath , 'MISTRAL_API_KEY=placeholder' , { encoding : 'utf8' } ) ;
151162 return true ;
152163 }
@@ -164,18 +175,39 @@ export async function ensureAuth(options?: MistralAuthOptions): Promise<boolean>
164175 throw new Error ( `${ metadata . name } CLI is not installed.` ) ;
165176 }
166177
167- // CLI is present but no API key - prompt user and persist to ~/.vibe /.env
178+ // CLI is present but no API key - run setup or prompt and persist to VIBE_HOME /.env
168179 console . log ( `\n────────────────────────────────────────────────────────────` ) ;
169180 console . log ( ` 🔐 ${ metadata . name } Authentication` ) ;
170181 console . log ( `────────────────────────────────────────────────────────────` ) ;
171182 console . log ( `\n${ metadata . name } CLI requires the MISTRAL_API_KEY.` ) ;
172- console . log ( `You can paste it here and we'll save it to ~/.vibe/.env for you.\n` ) ;
183+ console . log ( `VIBE_HOME will be used to store credentials: ${ vibeHome } ` ) ;
184+ console . log ( `(override with VIBE_HOME env)\n` ) ;
185+
186+ // Try interactive setup via vibe-acp --setup with VIBE_HOME set
187+ try {
188+ const resolvedSetup = Bun . which ( 'vibe-acp' ) ?? 'vibe-acp' ;
189+ const proc = Bun . spawn ( [ resolvedSetup , '--setup' ] , {
190+ env : { ...process . env , VIBE_HOME : vibeHome } ,
191+ stdio : [ 'inherit' , 'inherit' , 'inherit' ] ,
192+ } ) ;
193+ await proc . exited ;
194+ // After setup, check again
195+ try {
196+ await stat ( credPath ) ;
197+ return true ;
198+ } catch {
199+ // fall through to manual prompt
200+ }
201+ } catch {
202+ // ignore and fall back to manual prompt
203+ }
204+
205+ console . log ( `You can paste the API key here and we'll save it to ${ path . join ( vibeHome , '.env' ) } for you.\n` ) ;
173206
174207 const apiKey = await promptForApiKey ( ) ;
175208 if ( apiKey ) {
176- const vibeDir = path . join ( homedir ( ) , '.vibe' ) ;
177- await mkdir ( vibeDir , { recursive : true } ) ;
178- const envPath = path . join ( vibeDir , '.env' ) ;
209+ await mkdir ( vibeHome , { recursive : true } ) ;
210+ const envPath = path . join ( vibeHome , '.env' ) ;
179211 await writeFile ( envPath , `MISTRAL_API_KEY=${ apiKey } \n` , { encoding : 'utf8' } ) ;
180212 process . env . MISTRAL_API_KEY = apiKey ; // make available for this process
181213 console . log ( `\nSaved API key to ${ envPath } \n` ) ;
@@ -198,10 +230,10 @@ export async function ensureAuth(options?: MistralAuthOptions): Promise<boolean>
198230 */
199231export async function clearAuth ( options ?: MistralAuthOptions ) : Promise < void > {
200232 const configDir = resolveMistralConfigDir ( options ) ;
233+ const vibeHome = resolveVibeHome ( options ) ;
201234 const authPaths = getMistralAuthPaths ( configDir ) ;
202235
203- // Remove only CodeMachine-specific auth files (if any)
204- // We do NOT delete ~/.vibe/.env as that belongs to Mistral Vibe CLI
236+ // Remove CodeMachine-specific auth files (if any)
205237 await Promise . all (
206238 authPaths . map ( async ( authPath ) => {
207239 try {
@@ -211,6 +243,14 @@ export async function clearAuth(options?: MistralAuthOptions): Promise<void> {
211243 }
212244 } ) ,
213245 ) ;
246+
247+ // Also remove the Vibe credentials file to fully sign out
248+ const vibeEnv = path . join ( vibeHome , '.env' ) ;
249+ try {
250+ await rm ( vibeEnv , { force : true } ) ;
251+ } catch ( _error ) {
252+ // Ignore removal errors
253+ }
214254}
215255
216256/**
0 commit comments