mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-20 00:02:11 +00:00
feat(coding-agent): add OAuth authentication for Claude Pro/Max
- Add /login and /logout commands for OAuth flow - OAuth tokens stored in ~/.pi/agent/oauth.json with 0600 permissions - Auto-refresh tokens when expired (5min buffer) - Priority: OAuth > ANTHROPIC_OAUTH_TOKEN env > ANTHROPIC_API_KEY env - Fix model selector async loading and re-render - Add bracketed paste support to Input component for long codes - Update README.md with OAuth documentation - Add implementation docs and testing checklist
This commit is contained in:
parent
387cc97bac
commit
587d7c39a4
17 changed files with 1632 additions and 76 deletions
95
packages/coding-agent/src/oauth/storage.ts
Normal file
95
packages/coding-agent/src/oauth/storage.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
||||
import { homedir } from "os";
|
||||
import { join } from "path";
|
||||
|
||||
export interface OAuthCredentials {
|
||||
type: "oauth";
|
||||
refresh: string;
|
||||
access: string;
|
||||
expires: number;
|
||||
}
|
||||
|
||||
interface OAuthStorageFormat {
|
||||
[provider: string]: OAuthCredentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to oauth.json
|
||||
*/
|
||||
function getOAuthFilePath(): string {
|
||||
const configDir = join(homedir(), ".pi", "agent");
|
||||
return join(configDir, "oauth.json");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the config directory exists
|
||||
*/
|
||||
function ensureConfigDir(): void {
|
||||
const configDir = join(homedir(), ".pi", "agent");
|
||||
if (!existsSync(configDir)) {
|
||||
mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all OAuth credentials from oauth.json
|
||||
*/
|
||||
function loadStorage(): OAuthStorageFormat {
|
||||
const filePath = getOAuthFilePath();
|
||||
if (!existsSync(filePath)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
try {
|
||||
const content = readFileSync(filePath, "utf-8");
|
||||
return JSON.parse(content);
|
||||
} catch (error) {
|
||||
console.error(`Warning: Failed to load OAuth credentials: ${error}`);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all OAuth credentials to oauth.json
|
||||
*/
|
||||
function saveStorage(storage: OAuthStorageFormat): void {
|
||||
ensureConfigDir();
|
||||
const filePath = getOAuthFilePath();
|
||||
writeFileSync(filePath, JSON.stringify(storage, null, 2), "utf-8");
|
||||
// Set permissions to owner read/write only
|
||||
chmodSync(filePath, 0o600);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load OAuth credentials for a specific provider
|
||||
*/
|
||||
export function loadOAuthCredentials(provider: string): OAuthCredentials | null {
|
||||
const storage = loadStorage();
|
||||
return storage[provider] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save OAuth credentials for a specific provider
|
||||
*/
|
||||
export function saveOAuthCredentials(provider: string, creds: OAuthCredentials): void {
|
||||
const storage = loadStorage();
|
||||
storage[provider] = creds;
|
||||
saveStorage(storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove OAuth credentials for a specific provider
|
||||
*/
|
||||
export function removeOAuthCredentials(provider: string): void {
|
||||
const storage = loadStorage();
|
||||
delete storage[provider];
|
||||
saveStorage(storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* List all providers with OAuth credentials
|
||||
*/
|
||||
export function listOAuthProviders(): string[] {
|
||||
const storage = loadStorage();
|
||||
return Object.keys(storage);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue