diff options
| author | Adam Malczewski <[email protected]> | 2026-05-21 17:30:08 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-05-21 17:30:08 +0900 |
| commit | d6b208342edf97bafa5b1dcc986b782f9879d141 (patch) | |
| tree | c6d8f9bffa86f78e3b1369b811bef9642df788d0 /packages/api/src/agent-manager.ts | |
| parent | 1f309ccca20aabbd0ee3fb8fbb3c8192124edd95 (diff) | |
| download | dispatch-d6b208342edf97bafa5b1dcc986b782f9879d141.tar.gz dispatch-d6b208342edf97bafa5b1dcc986b782f9879d141.zip | |
feat: SQLite database for all credentials, keys, wake schedule, and usage cache
- Add SQLite database at ~/.local/share/dispatch/dispatch.db with tables: credentials, api_keys, wake_schedule, usage_cache
- Store Claude OAuth credentials in DB with import button in Model Status UI
- Store OpenCode/Copilot API keys in DB with paste-to-import modal
- Store OpenCode cookie and workspace IDs in DB
- Migrate wake schedule from .wake-schedule.json to DB
- Migrate usage cache from in-memory Map + localStorage to DB
- Remove all env var and file fallbacks — DB is the single source of truth
- Add seed scripts: bin/import-credentials.ts, bin/seed-opencode-keys.ts
- Docker: container runs as host UID/GID with matching home directory
- Clean up dispatch.toml: remove env fields, update comments
- Progress bar time markers for usage cycle tracking
Diffstat (limited to 'packages/api/src/agent-manager.ts')
| -rw-r--r-- | packages/api/src/agent-manager.ts | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/packages/api/src/agent-manager.ts b/packages/api/src/agent-manager.ts index 4f45781..92396b6 100644 --- a/packages/api/src/agent-manager.ts +++ b/packages/api/src/agent-manager.ts @@ -20,9 +20,10 @@ import { TaskList, createTaskListTool, type ClaudeAccount, - discoverClaudeAccounts, + getClaudeAccountsFromDB, refreshAccountCredentials, refreshAccountCredentialsAsync, + resolveApiKey, } from "@dispatch/core"; import type { PermissionManager } from "./permission-manager.js"; import { setConfigGetter } from "./routes/config.js"; @@ -124,7 +125,7 @@ export class AgentManager { private _refreshClaudeAccounts(): void { try { - this.claudeAccounts = discoverClaudeAccounts(); + this.claudeAccounts = getClaudeAccountsFromDB(); if (this.claudeAccounts.length > 0) { console.log(`dispatch: discovered ${this.claudeAccounts.length} Claude account(s)`); } @@ -187,8 +188,8 @@ export class AgentManager { const ruleset = configToRuleset(this.config); // Try to resolve model from registry, fall back to env vars - let apiKey = process.env.OPENCODE_API_KEY ?? ""; - let model = process.env.DISPATCH_MODEL ?? "deepseek-v4-flash"; + let apiKey = ""; + let model = "deepseek-v4-flash"; let baseURL = "https://opencode.ai/zen/go/v1"; let provider: string | undefined; let claudeCredentials: { accessToken: string } | undefined; @@ -203,9 +204,8 @@ export class AgentManager { if (key.provider === "anthropic") { // Anthropic provider: resolve credentials from Claude accounts const credFile = key.credentials_file; - const account = credFile - ? this.claudeAccounts.find((a) => a.source === credFile) - : this.claudeAccounts[0]; + const account = this.claudeAccounts.find((a) => a.id === effectiveKeyId) + ?? (credFile ? this.claudeAccounts.find((a) => a.source === credFile) : this.claudeAccounts[0]); if (account) { const creds = refreshAccountCredentials(account); if (creds && creds.expiresAt > Date.now() + 60_000) { @@ -247,7 +247,7 @@ export class AgentManager { } } else { // Standard key: resolve from env var - const envKey = key.env ? process.env[key.env] : undefined; + const envKey = resolveApiKey(key.id); if (envKey) { apiKey = envKey; baseURL = key.base_url; @@ -284,9 +284,8 @@ export class AgentManager { // Check if resolved key is anthropic if (resolved.key.provider === "anthropic") { const credFile = resolved.key.credentials_file; - const account = credFile - ? this.claudeAccounts.find((a) => a.source === credFile) - : this.claudeAccounts[0]; + const account = this.claudeAccounts.find((a) => a.id === resolved.key.id) + ?? (credFile ? this.claudeAccounts.find((a) => a.source === credFile) : this.claudeAccounts[0]); if (account) { let creds = refreshAccountCredentials(account); if (!creds || creds.expiresAt <= Date.now() + 60_000) { @@ -304,14 +303,14 @@ export class AgentManager { console.warn(`dispatch: no Claude credentials found for key "${resolved.key.id}"`); } } else { - const envKey = process.env[resolved.key.env!]; + const envKey = resolveApiKey(resolved.key.id); if (envKey) { apiKey = envKey; } else { - console.warn(`dispatch: env var "${resolved.key.env}" not set for key "${resolved.key.id}", falling back to env vars`); - model = process.env.DISPATCH_MODEL ?? "deepseek-v4-flash"; + console.warn(`dispatch: env var not set for key "${resolved.key.id}", falling back to defaults`); + model = "deepseek-v4-flash"; baseURL = "https://opencode.ai/zen/go/v1"; - apiKey = process.env.OPENCODE_API_KEY ?? ""; + apiKey = ""; } } } else { |
