feat(cli): add gmail-auth command for OAuth2 token setup
Implements `flynn gmail-auth` to complete the OAuth2 flow that GmailWatcher references but was never built. Supports local callback server (default) and --manual paste mode. Adds Gmail health check to `flynn doctor`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import type { Command } from 'commander';
|
||||
import type { Config } from '../config/index.js';
|
||||
import { getConfigPath, getDataDir, formatStatus, resolveOverlayPath } from './shared.js';
|
||||
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
||||
import { homedir } from 'os';
|
||||
import { resolve, join } from 'path';
|
||||
import { parse } from 'yaml';
|
||||
import { configSchema } from '../config/schema.js';
|
||||
@@ -216,6 +217,35 @@ const checkTailscale: Check = async (ctx) => {
|
||||
}
|
||||
};
|
||||
|
||||
function expandPath(p: string): string {
|
||||
if (p.startsWith('~/') || p === '~') {
|
||||
return resolve(homedir(), p.slice(2));
|
||||
}
|
||||
return resolve(p);
|
||||
}
|
||||
|
||||
const checkGmail: Check = async (ctx) => {
|
||||
if (!ctx.config) {
|
||||
return { status: 'skip', label: 'Gmail configured', detail: '(config invalid)' };
|
||||
}
|
||||
const gmail = ctx.config.automation.gmail;
|
||||
if (!gmail?.enabled) {
|
||||
return { status: 'skip', label: 'Gmail configured', detail: '(not enabled)' };
|
||||
}
|
||||
|
||||
const credentialsPath = expandPath(gmail.credentials_file ?? '~/.config/flynn/gmail-credentials.json');
|
||||
if (!existsSync(credentialsPath)) {
|
||||
return { status: 'fail', label: 'Gmail configured', detail: `credentials file not found: ${credentialsPath}` };
|
||||
}
|
||||
|
||||
const tokenPath = expandPath(gmail.token_file ?? '~/.config/flynn/gmail-token.json');
|
||||
if (!existsSync(tokenPath)) {
|
||||
return { status: 'warn', label: 'Gmail configured', detail: 'run `flynn gmail-auth` to authenticate' };
|
||||
}
|
||||
|
||||
return { status: 'pass', label: 'Gmail configured', detail: `(output: ${gmail.output.channel}/${gmail.output.peer})` };
|
||||
};
|
||||
|
||||
const allChecks: Check[] = [
|
||||
checkConfigExists,
|
||||
checkOverlayExists,
|
||||
@@ -226,6 +256,7 @@ const allChecks: Check[] = [
|
||||
checkSessionDb,
|
||||
checkModelConnectivity,
|
||||
checkTelegram,
|
||||
checkGmail,
|
||||
checkMcpServers,
|
||||
checkSkills,
|
||||
checkTailscale,
|
||||
|
||||
Reference in New Issue
Block a user