Skip to content

Commit 935f637

Browse files
committed
Fixed the VIBE_HOME and AUTH
1 parent ff07068 commit 935f637

File tree

3 files changed

+63
-20
lines changed

3 files changed

+63
-20
lines changed

src/infra/engines/providers/mistral/auth.ts

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export interface MistralAuthOptions {
5757
}
5858

5959
export 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
*/
7687
export 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
*/
199231
export 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
/**

src/infra/engines/providers/mistral/execution/runner.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,18 @@ export async function runMistral(options: RunMistralOptions): Promise<RunMistral
149149
throw new Error('runMistral requires a working directory.');
150150
}
151151

152-
// Set up MISTRAL_CONFIG_DIR for authentication
153-
const mistralConfigDir = process.env.MISTRAL_CONFIG_DIR
154-
? expandHomeDir(process.env.MISTRAL_CONFIG_DIR)
155-
: path.join(homedir(), '.codemachine', 'mistral');
152+
// Set up VIBE_HOME / MISTRAL_CONFIG_DIR for authentication (prefer VIBE_HOME)
153+
const vibeHome = process.env.VIBE_HOME
154+
? expandHomeDir(process.env.VIBE_HOME)
155+
: process.env.MISTRAL_CONFIG_DIR
156+
? expandHomeDir(process.env.MISTRAL_CONFIG_DIR)
157+
: path.join(homedir(), '.codemachine', 'vibe');
156158

157159
const mergedEnv = {
158160
...process.env,
159161
...(env ?? {}),
160-
MISTRAL_CONFIG_DIR: mistralConfigDir,
162+
VIBE_HOME: vibeHome,
163+
MISTRAL_CONFIG_DIR: vibeHome,
161164
};
162165

163166
const plainLogs = (process.env.CODEMACHINE_PLAIN_LOGS || '').toString() === '1';

src/infra/engines/providers/mistral/metadata.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const metadata: EngineMetadata = {
88
cliBinary: 'vibe',
99
installCommand: 'uv tool install mistral-vibe',
1010
defaultModel: 'devstral-2',
11-
order: 0,
11+
order: 4,
1212
experimental: true,
1313
};
1414

0 commit comments

Comments
 (0)