cli: add openai-key and anthropic token flag
This commit is contained in:
+30
-10
@@ -1,6 +1,11 @@
|
|||||||
import type { Command } from 'commander';
|
import type { Command } from 'commander';
|
||||||
import readline from 'readline';
|
import readline from 'readline';
|
||||||
import { loadStoredAnthropicAuth, storeAnthropicAuth } from '../auth/index.js';
|
import {
|
||||||
|
loadStoredAnthropicAuth,
|
||||||
|
loadStoredAnthropicAuthToken,
|
||||||
|
storeAnthropicAuth,
|
||||||
|
storeAnthropicAuthToken,
|
||||||
|
} from '../auth/index.js';
|
||||||
|
|
||||||
async function promptHidden(question: string): Promise<string> {
|
async function promptHidden(question: string): Promise<string> {
|
||||||
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
||||||
@@ -29,13 +34,23 @@ async function promptHidden(question: string): Promise<string> {
|
|||||||
export function registerAnthropicAuthCommand(program: Command): void {
|
export function registerAnthropicAuthCommand(program: Command): void {
|
||||||
program
|
program
|
||||||
.command('anthropic-auth')
|
.command('anthropic-auth')
|
||||||
.description('Store an Anthropic API key (auth.json)')
|
.description('Store an Anthropic API key or auth token (auth.json)')
|
||||||
.action(async () => {
|
.option('--token', 'Store an Anthropic auth token instead of an API key')
|
||||||
const existing = loadStoredAnthropicAuth();
|
.action(async (opts: { token?: boolean }) => {
|
||||||
if (existing) {
|
|
||||||
console.log('Anthropic credential already exists.');
|
if (opts.token) {
|
||||||
console.log('Delete ~/.config/flynn/auth.json anthropic entry if you want to re-authenticate.');
|
if (loadStoredAnthropicAuthToken()) {
|
||||||
process.exit(0);
|
console.log('Anthropic auth token already exists.');
|
||||||
|
console.log('Delete ~/.config/flynn/auth.json anthropic.auth_token entry if you want to re-authenticate.');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const existing = loadStoredAnthropicAuth();
|
||||||
|
if (existing?.api_key) {
|
||||||
|
console.log('Anthropic API key already exists.');
|
||||||
|
console.log('Delete ~/.config/flynn/auth.json anthropic.api_key entry if you want to re-authenticate.');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Anthropic uses API keys for authentication.');
|
console.log('Anthropic uses API keys for authentication.');
|
||||||
@@ -43,8 +58,13 @@ export function registerAnthropicAuthCommand(program: Command): void {
|
|||||||
console.log('');
|
console.log('');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const apiKey = await promptHidden('Enter Anthropic API key: ');
|
if (opts.token) {
|
||||||
storeAnthropicAuth(apiKey);
|
const token = await promptHidden('Enter Anthropic auth token: ');
|
||||||
|
storeAnthropicAuthToken(token);
|
||||||
|
} else {
|
||||||
|
const apiKey = await promptHidden('Enter Anthropic API key: ');
|
||||||
|
storeAnthropicAuth(apiKey);
|
||||||
|
}
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Anthropic credential stored in ~/.config/flynn/auth.json');
|
console.log('Anthropic credential stored in ~/.config/flynn/auth.json');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ describe('CLI program', () => {
|
|||||||
expect(commandNames).toContain('doctor');
|
expect(commandNames).toContain('doctor');
|
||||||
expect(commandNames).toContain('config');
|
expect(commandNames).toContain('config');
|
||||||
expect(commandNames).toContain('skills');
|
expect(commandNames).toContain('skills');
|
||||||
|
|
||||||
|
expect(commandNames).toContain('openai-auth');
|
||||||
|
expect(commandNames).toContain('openai-key');
|
||||||
|
expect(commandNames).toContain('anthropic-auth');
|
||||||
|
expect(commandNames).toContain('zai-auth');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('has version info', () => {
|
it('has version info', () => {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { registerGdocsAuthCommand } from './gdocs-auth.js';
|
|||||||
import { registerGdriveAuthCommand } from './gdrive-auth.js';
|
import { registerGdriveAuthCommand } from './gdrive-auth.js';
|
||||||
import { registerGtasksAuthCommand } from './gtasks-auth.js';
|
import { registerGtasksAuthCommand } from './gtasks-auth.js';
|
||||||
import { registerOpenaiAuthCommand } from './openai-auth.js';
|
import { registerOpenaiAuthCommand } from './openai-auth.js';
|
||||||
|
import { registerOpenaiKeyCommand } from './openai-key.js';
|
||||||
import { registerZaiAuthCommand } from './zai-auth.js';
|
import { registerZaiAuthCommand } from './zai-auth.js';
|
||||||
import { registerAnthropicAuthCommand } from './anthropic-auth.js';
|
import { registerAnthropicAuthCommand } from './anthropic-auth.js';
|
||||||
import { registerSkillsCommand } from './skills.js';
|
import { registerSkillsCommand } from './skills.js';
|
||||||
@@ -45,6 +46,7 @@ export function createProgram(): Command {
|
|||||||
registerGdriveAuthCommand(program);
|
registerGdriveAuthCommand(program);
|
||||||
registerGtasksAuthCommand(program);
|
registerGtasksAuthCommand(program);
|
||||||
registerOpenaiAuthCommand(program);
|
registerOpenaiAuthCommand(program);
|
||||||
|
registerOpenaiKeyCommand(program);
|
||||||
registerZaiAuthCommand(program);
|
registerZaiAuthCommand(program);
|
||||||
registerAnthropicAuthCommand(program);
|
registerAnthropicAuthCommand(program);
|
||||||
registerSkillsCommand(program);
|
registerSkillsCommand(program);
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import type { Command } from 'commander';
|
||||||
|
import readline from 'readline';
|
||||||
|
import { loadStoredOpenAIApiKey, storeOpenAIApiKey } from '../auth/index.js';
|
||||||
|
|
||||||
|
async function promptHidden(question: string): Promise<string> {
|
||||||
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
||||||
|
const rlAny = rl as unknown as { stdoutMuted?: boolean; _writeToOutput?: (s: string) => void };
|
||||||
|
rlAny.stdoutMuted = true;
|
||||||
|
|
||||||
|
rlAny._writeToOutput = (s: string) => {
|
||||||
|
if (!rlAny.stdoutMuted) {
|
||||||
|
process.stdout.write(s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (s.includes('\n')) {
|
||||||
|
process.stdout.write('\n');
|
||||||
|
} else {
|
||||||
|
process.stdout.write('*');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const answer = await new Promise<string>((resolve) => rl.question(question, resolve));
|
||||||
|
rlAny.stdoutMuted = false;
|
||||||
|
rl.close();
|
||||||
|
process.stdout.write('\n');
|
||||||
|
return answer.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerOpenaiKeyCommand(program: Command): void {
|
||||||
|
program
|
||||||
|
.command('openai-key')
|
||||||
|
.description('Store an OpenAI API key (auth.json)')
|
||||||
|
.action(async () => {
|
||||||
|
const existing = loadStoredOpenAIApiKey();
|
||||||
|
if (existing) {
|
||||||
|
console.log('OpenAI API key already exists.');
|
||||||
|
console.log('Delete ~/.config/flynn/auth.json openai.api_key entry if you want to re-authenticate.');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('OpenAI uses API keys for standard API access.');
|
||||||
|
console.log('Create a key at: https://platform.openai.com/api-keys');
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const apiKey = await promptHidden('Enter OpenAI API key: ');
|
||||||
|
storeOpenAIApiKey(apiKey);
|
||||||
|
console.log('');
|
||||||
|
console.log('OpenAI API key stored in ~/.config/flynn/auth.json');
|
||||||
|
} catch (error) {
|
||||||
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
|
console.error(`OpenAI API key storage failed: ${message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user