From 353ee780338dc24eb674bf217a42b38f4b7f078b Mon Sep 17 00:00:00 2001 From: Boris Starkov Date: Mon, 10 Nov 2025 14:58:13 +0000 Subject: [PATCH 1/6] remove more envs refs --- README.md | 26 ----- src/__tests__/residency.test.ts | 2 +- src/agents/commands/add.ts | 5 +- src/agents/commands/delete-impl.ts | 6 +- src/agents/commands/pull-impl.ts | 9 +- src/agents/commands/pull.ts | 4 +- src/agents/commands/push-impl.ts | 3 +- src/agents/commands/test-impl.ts | 7 +- src/agents/ui/PullView.tsx | 61 ++++++------ src/auth/commands/login.ts | 8 +- src/auth/commands/logout.ts | 10 +- src/auth/commands/whoami.ts | 33 ++----- src/auth/ui/WhoamiView.tsx | 69 +++---------- src/shared/auth.ts | 150 +++++------------------------ src/shared/config.ts | 21 ++-- src/shared/elevenlabs-api.ts | 9 +- src/tests/commands/impl.ts | 44 ++++----- src/tools/commands/impl.ts | 25 +++-- src/tools/commands/pull.ts | 4 +- src/tools/ui/PullToolsView.tsx | 62 +++++------- 20 files changed, 165 insertions(+), 393 deletions(-) diff --git a/README.md b/README.md index d1ffda6..db489c5 100644 --- a/README.md +++ b/README.md @@ -77,30 +77,6 @@ elevenlabs auth residency global # or 'us' elevenlabs auth logout ``` -### Multi-Environment Management - -The ElevenLabs CLI supports managing agents, tools, and tests across multiple isolated environments (e.g., dev, staging, prod). - -#### Login to Multiple Environments - -```bash -# Login with your API key -elevenlabs auth login -``` - -#### Check Authentication Status - -```bash -elevenlabs auth whoami -# Shows your authentication status -``` - -#### Logout - -```bash -elevenlabs auth logout -``` - ## Quick Start ```bash @@ -122,8 +98,6 @@ elevenlabs agents add "Support Bot" --template customer-service elevenlabs agents push ``` -> **Note**: This example uses the default 'prod' environment. For multi-environment workflows, see [Multi-Environment Management](#multi-environment-management) and [Multi-Environment Workflows](#multi-environment-workflows). - ## Directory Structure ``` diff --git a/src/__tests__/residency.test.ts b/src/__tests__/residency.test.ts index e97ba15..6e64429 100644 --- a/src/__tests__/residency.test.ts +++ b/src/__tests__/residency.test.ts @@ -147,7 +147,7 @@ describe("Residency-specific API Client", () => { mockedOs.homedir.mockReturnValue(tempDir); await expect(getElevenLabsClient()).rejects.toThrow( - "No API key found for environment 'prod'. Use 'elevenlabs auth login' to authenticate or set ELEVENLABS_API_KEY environment variable." + "No API key found. Use 'elevenlabs auth login' to authenticate or set ELEVENLABS_API_KEY environment variable." ); }); }); diff --git a/src/agents/commands/add.ts b/src/agents/commands/add.ts index 8486c7e..e2dd2b9 100644 --- a/src/agents/commands/add.ts +++ b/src/agents/commands/add.ts @@ -74,10 +74,9 @@ export function createAddCommand(): Command { } // Create agent in ElevenLabs first to get ID - const environment = 'prod'; - console.log(`Creating agent '${name}' in ElevenLabs (environment: ${environment})...`); + console.log(`Creating agent '${name}' in ElevenLabs...`); - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); // Extract config components const conversationConfig = agentConfig.conversation_config || {}; diff --git a/src/agents/commands/delete-impl.ts b/src/agents/commands/delete-impl.ts index b8d9bb7..0f40fae 100644 --- a/src/agents/commands/delete-impl.ts +++ b/src/agents/commands/delete-impl.ts @@ -34,13 +34,12 @@ export async function deleteAgent(agentId: string): Promise { const agentDef = agentsConfig.agents[agentIndex]; const agentName = await getAgentName(agentDef.config); const configPath = agentDef.config; - const environment = 'prod'; console.log(`Deleting agent '${agentName}' (ID: ${agentId})...`); // Delete from ElevenLabs (globally) console.log('Deleting from ElevenLabs...'); - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); try { await deleteAgentApi(client, agentId); @@ -109,13 +108,12 @@ export async function deleteAllAgents(ui: boolean = true): Promise { for (const agentDef of agentsToDelete) { try { const agentName = await getAgentName(agentDef.config); - const environment = 'prod'; console.log(`Deleting '${agentName}' (${agentDef.id})...`); // Delete from ElevenLabs if (agentDef.id) { try { - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); await deleteAgentApi(client, agentDef.id); console.log(` ✓ Deleted from ElevenLabs`); } catch (error) { diff --git a/src/agents/commands/pull-impl.ts b/src/agents/commands/pull-impl.ts index ef0b07b..3cdf30f 100644 --- a/src/agents/commands/pull-impl.ts +++ b/src/agents/commands/pull-impl.ts @@ -27,15 +27,14 @@ interface PullOptions { export async function pullAgents(options: PullOptions): Promise { const agentsConfigPath = path.resolve(AGENTS_CONFIG_FILE); - const environment = 'prod'; - console.log(`Pulling from environment: ${environment}`); + console.log(`Pulling agents from ElevenLabs...`); - await pullAgentsFromEnvironment(options, environment, agentsConfigPath); + await pullAgentsFromEnvironment(options, agentsConfigPath); } -async function pullAgentsFromEnvironment(options: PullOptions, environment: string, agentsConfigPath: string): Promise { - const client = await getElevenLabsClient(environment); +async function pullAgentsFromEnvironment(options: PullOptions, agentsConfigPath: string): Promise { + const client = await getElevenLabsClient(); // Load existing config let agentsConfig: AgentsConfig; diff --git a/src/agents/commands/pull.ts b/src/agents/commands/pull.ts index a92e2dc..e289495 100644 --- a/src/agents/commands/pull.ts +++ b/src/agents/commands/pull.ts @@ -25,15 +25,13 @@ export function createPullCommand(): Command { try { if (options.ui !== false) { // Use Ink UI for pull - const environments = ['prod']; const { waitUntilExit } = render( React.createElement(PullView, { agent: options.agent, outputDir: options.outputDir, dryRun: options.dryRun, update: options.update, - all: options.all, - environments + all: options.all }) ); await waitUntilExit(); diff --git a/src/agents/commands/push-impl.ts b/src/agents/commands/push-impl.ts index 0f3f26d..49596ab 100644 --- a/src/agents/commands/push-impl.ts +++ b/src/agents/commands/push-impl.ts @@ -25,9 +25,8 @@ export async function pushAgents(dryRun: boolean = false): Promise { const agentsConfig = await readConfig(agentsConfigPath); const agentsToProcess = agentsConfig.agents; - const environment = 'prod'; - console.log(`Pushing ${agentsToProcess.length} agent(s) to environment: ${environment}`); + console.log(`Pushing ${agentsToProcess.length} agent(s) to ElevenLabs...`); let changesMade = false; diff --git a/src/agents/commands/test-impl.ts b/src/agents/commands/test-impl.ts index 481814a..37d1a3a 100644 --- a/src/agents/commands/test-impl.ts +++ b/src/agents/commands/test-impl.ts @@ -48,14 +48,11 @@ export async function runAgentTests(agentId: string): Promise { const testIds = attachedTests.map(test => test.test_id); - // Get agent environment - const environment = 'prod'; - - console.log(`Running ${testIds.length} test(s) for agent '${agentName}' [${environment}]...`); + console.log(`Running ${testIds.length} test(s) for agent '${agentName}'...`); console.log(''); // Run tests without UI - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); try { // Import the API functions we need diff --git a/src/agents/ui/PullView.tsx b/src/agents/ui/PullView.tsx index f4ce25e..3e8a2c3 100644 --- a/src/agents/ui/PullView.tsx +++ b/src/agents/ui/PullView.tsx @@ -22,18 +22,16 @@ interface PullViewProps { dryRun: boolean; update?: boolean; all?: boolean; - environments: string[]; // Array of environments to pull from onComplete?: () => void; } -export const PullView: React.FC = ({ +export const PullView: React.FC = ({ agent, outputDir, dryRun, update, all, - environments, - onComplete + onComplete }) => { const { exit } = useApp(); const [agents, setAgents] = useState([]); @@ -54,16 +52,14 @@ export const PullView: React.FC = ({ const agentsConfig = await readConfig(agentsConfigPath); const existingAgentNames = new Set(agentsConfig.agents.map((a: any) => a.name as string)); - // Collect all agents from all environments + // Collect all agents const allAgentsToPull: PullAgent[] = []; - // Loop through each environment - for (const environment of environments) { - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); - // Fetch agents list - either specific agent by ID or all agents - let agentsList: unknown[]; - if (agent) { + // Fetch agents list - either specific agent by ID or all agents + let agentsList: unknown[]; + if (agent) { // Pull specific agent by ID const agentDetails = await getAgentApi(client, agent); const agentDetailsTyped = agentDetails as { agentId?: string; agent_id?: string; name: string }; @@ -77,16 +73,20 @@ export const PullView: React.FC = ({ agentsList = await listAgentsApi(client, 30); } - if (agentsList.length === 0) continue; + if (agentsList.length === 0) { + setError('No agents found in your ElevenLabs workspace.'); + setComplete(true); + return; + } - // Build ID-based map for existing agents - const existingAgentIds = new Map( - agentsConfig.agents - .map((agent: any) => [agent.id as string, agent]) - ); + // Build ID-based map for existing agents + const existingAgentIds = new Map( + agentsConfig.agents + .map((agent: any) => [agent.id as string, agent]) + ); - // Prepare agents for display with action determination - for (const agentMeta of agentsList) { + // Prepare agents for display with action determination + for (const agentMeta of agentsList) { const agentMetaTyped = agentMeta as { agentId?: string; agent_id?: string; name: string }; const agentId = agentMetaTyped.agentId || agentMetaTyped.agent_id; @@ -121,18 +121,17 @@ export const PullView: React.FC = ({ } } - allAgentsToPull.push({ - name: agentName, - agentId, - action, - status, - message: status === 'skipped' ? 'Skipped' : undefined - }); - } + allAgentsToPull.push({ + name: agentName, + agentId, + action, + status, + message: status === 'skipped' ? 'Skipped' : undefined + }); } if (allAgentsToPull.length === 0) { - setError('No agents found in any environment.'); + setError('No agents found.'); setComplete(true); return; } @@ -304,12 +303,6 @@ export const PullView: React.FC = ({ <> {/* Agent Status List - Compact Table */} - - - Pulling from {environments.length} environment{environments.length > 1 ? 's' : ''}: - - {environments.join(', ')} - Agents: diff --git a/src/auth/commands/login.ts b/src/auth/commands/login.ts index 299a5e8..6cf5c4b 100644 --- a/src/auth/commands/login.ts +++ b/src/auth/commands/login.ts @@ -13,8 +13,6 @@ export function createLoginCommand(): Command { .option('--no-ui', 'Disable interactive UI') .action(async (options: { ui: boolean }) => { try { - const environment = 'prod'; - if (options.ui !== false) { // Use Ink UI for login const { waitUntilExit } = render( @@ -25,7 +23,7 @@ export function createLoginCommand(): Command { // Fallback to text-based login const { read } = await import('read'); - console.log(`Logging in to environment: ${environment}`); + console.log('Logging in to ElevenLabs...'); const apiKey = await read({ prompt: 'Enter your ElevenLabs API key: ', silent: true, @@ -64,8 +62,8 @@ export function createLoginCommand(): Command { process.exit(1); } - await setApiKey(apiKey.trim(), environment); - console.log(`Login successful! API key saved securely for environment '${environment}'.`); + await setApiKey(apiKey.trim()); + console.log('Login successful! API key saved securely.'); } } catch (error) { console.error(`Error during login: ${error}`); diff --git a/src/auth/commands/logout.ts b/src/auth/commands/logout.ts index eae85f8..13b3615 100644 --- a/src/auth/commands/logout.ts +++ b/src/auth/commands/logout.ts @@ -10,8 +10,6 @@ export function createLogoutCommand(): Command { .option('--no-ui', 'Disable interactive UI') .action(async (options: { ui: boolean }) => { try { - const environment = 'prod'; - if (options.ui !== false) { // Use Ink UI for logout const { waitUntilExit } = render( @@ -20,14 +18,14 @@ export function createLogoutCommand(): Command { await waitUntilExit(); } else { // Fallback to text-based logout - const loggedIn = await isLoggedIn(environment); + const loggedIn = await isLoggedIn(); if (!loggedIn) { - console.log(`You are not logged in to environment '${environment}'`); + console.log('You are not logged in'); return; } - await removeApiKey(environment); - console.log(`Logged out successfully from environment '${environment}'. API key removed.`); + await removeApiKey(); + console.log('Logged out successfully. API key removed.'); } } catch (error) { console.error(`Error during logout: ${error}`); diff --git a/src/auth/commands/whoami.ts b/src/auth/commands/whoami.ts index 7f95bc8..2ab1634 100644 --- a/src/auth/commands/whoami.ts +++ b/src/auth/commands/whoami.ts @@ -2,7 +2,7 @@ import { Command } from 'commander'; import { render } from 'ink'; import React from 'react'; import WhoamiView from '../ui/WhoamiView.js'; -import { getApiKey, getResidency, listEnvironments } from '../../shared/config.js'; +import { getApiKey, getResidency } from '../../shared/config.js'; export function createWhoamiCommand(): Command { return new Command('whoami') @@ -19,33 +19,16 @@ export function createWhoamiCommand(): Command { } else { // Fallback to text-based output const residency = await getResidency(); + const apiKey = await getApiKey(); - // Check if using environment variable - if (process.env.ELEVENLABS_API_KEY) { - const maskedKey = process.env.ELEVENLABS_API_KEY.slice(0, 8) + '...' + process.env.ELEVENLABS_API_KEY.slice(-4); - console.log('Logged in with API key from environment variable:'); - console.log(` prod: ${maskedKey}`); + if (apiKey) { + const maskedKey = apiKey.slice(0, 8) + '...' + apiKey.slice(-4); + const source = process.env.ELEVENLABS_API_KEY ? ' (from environment variable)' : ''; + console.log(`Logged in: ${maskedKey}${source}`); console.log(`Residency: ${residency}`); } else { - // Load all configured environments - const environments = await listEnvironments(); - - if (environments.length > 0) { - console.log(`Logged in to ${environments.length} environment${environments.length > 1 ? 's' : ''}:`); - - for (const env of environments) { - const apiKey = await getApiKey(env); - if (apiKey) { - const maskedKey = apiKey.slice(0, 8) + '...' + apiKey.slice(-4); - console.log(` ${env}: ${maskedKey}`); - } - } - - console.log(`Residency: ${residency}`); - } else { - console.log('Not logged in'); - console.log('Use "elevenlabs auth login" to authenticate'); - } + console.log('Not logged in'); + console.log('Use "elevenlabs auth login" to authenticate'); } } } catch (error) { diff --git a/src/auth/ui/WhoamiView.tsx b/src/auth/ui/WhoamiView.tsx index 1a45021..bbc1e9f 100644 --- a/src/auth/ui/WhoamiView.tsx +++ b/src/auth/ui/WhoamiView.tsx @@ -3,55 +3,29 @@ import { Box, Text, useApp } from 'ink'; import App from '../../ui/App.js'; import StatusCard from '../../ui/components/StatusCard.js'; import theme from '../../ui/themes/elevenlabs.js'; -import { getApiKey, getResidency, listEnvironments } from '../../shared/config.js'; +import { getApiKey, getResidency } from '../../shared/config.js'; interface WhoamiViewProps { onComplete?: () => void; } -interface EnvironmentInfo { - name: string; - maskedKey: string; -} - export const WhoamiView: React.FC = ({ onComplete }) => { const { exit } = useApp(); const [loading, setLoading] = useState(true); - const [environments, setEnvironments] = useState([]); + const [apiKey, setApiKey] = useState(null); const [residency, setResidency] = useState(null); const [usingEnvVar, setUsingEnvVar] = useState(false); useEffect(() => { const loadStatus = async () => { try { - // Check if using environment variable - const hasEnvVar = !!process.env.ELEVENLABS_API_KEY; - setUsingEnvVar(hasEnvVar); - - if (hasEnvVar) { - // If using env var, show it for prod environment only - const apiKey = process.env.ELEVENLABS_API_KEY!; - const maskedKey = apiKey.slice(0, 8) + '...' + apiKey.slice(-4); - setEnvironments([{ name: 'prod (from env)', maskedKey }]); - } else { - // Load all configured environments - const envs = await listEnvironments(); - const envInfo: EnvironmentInfo[] = []; - - for (const env of envs) { - const apiKey = await getApiKey(env); - if (apiKey) { - const maskedKey = apiKey.slice(0, 8) + '...' + apiKey.slice(-4); - envInfo.push({ name: env, maskedKey }); - } - } - - setEnvironments(envInfo); - } - + const key = await getApiKey(); + setApiKey(key || null); + setUsingEnvVar(!!process.env.ELEVENLABS_API_KEY); + const res = await getResidency(); setResidency(res); - + setLoading(false); } catch (error) { setLoading(false); @@ -83,37 +57,22 @@ export const WhoamiView: React.FC = ({ onComplete }) => { status="loading" message="Checking authentication status..." /> - ) : environments.length > 0 ? ( + ) : apiKey ? ( <> 1 ? 's' : ''}`} + message="Logged in to ElevenLabs" details={[ - `Total environments: ${environments.length}`, - `Residency: ${residency || 'Global'}` + `Residency: ${residency || 'Global'}`, + usingEnvVar ? 'Source: Environment Variable' : 'Source: Stored API Key' ]} /> - - - - - Configured Environments: - - - - - {environments.map((env, index) => ( - - • {env.name} - {': '} - {env.maskedKey} - - ))} - - + + • API Key: {apiKey.slice(0, 8)}...{apiKey.slice(-4)} + • Region: {residency || 'Global'} diff --git a/src/shared/auth.ts b/src/shared/auth.ts index df653f9..c4efd83 100644 --- a/src/shared/auth.ts +++ b/src/shared/auth.ts @@ -1,20 +1,12 @@ /** * Simple credential management for CLI * Secure file storage with proper permissions - * Supports multiple environments */ import fs from 'fs-extra'; import path from 'path'; import os from 'os'; -/** - * Environment API keys mapping - */ -interface ApiKeysStorage { - [environment: string]: string; -} - /** * Get config directory path */ @@ -23,16 +15,9 @@ function getConfigDir(): string { } /** - * Get API keys file path (JSON format) - */ -function getApiKeysFile(): string { - return path.join(getConfigDir(), 'api_keys.json'); -} - -/** - * Get legacy API key file path (for migration) + * Get API key file path */ -function getLegacyApiKeyFile(): string { +function getApiKeyFile(): string { return path.join(getConfigDir(), 'api_key'); } @@ -50,98 +35,35 @@ async function ensureConfigDir(): Promise { } /** - * Migrate legacy API key file to new JSON format + * Store API key securely */ -async function migrateLegacyApiKey(): Promise { - const legacyFile = getLegacyApiKeyFile(); - const newFile = getApiKeysFile(); - - // If new file exists or legacy doesn't exist, no migration needed - if (await fs.pathExists(newFile) || !(await fs.pathExists(legacyFile))) { - return; - } - - try { - // Read legacy API key - const legacyKey = await fs.readFile(legacyFile, 'utf-8'); - - // Store under "prod" environment - const storage: ApiKeysStorage = { - prod: legacyKey.trim() - }; - - // Write to new JSON file - await fs.writeFile(newFile, JSON.stringify(storage, null, 2), { - mode: 0o600, - encoding: 'utf-8' - }); - - // Remove legacy file - await fs.remove(legacyFile); - } catch { - // If migration fails, silently continue - } -} - -/** - * Load all API keys from storage - */ -async function loadApiKeys(): Promise { +export async function storeApiKey(apiKey: string): Promise { await ensureConfigDir(); - await migrateLegacyApiKey(); - - const keysFile = getApiKeysFile(); - - try { - if (await fs.pathExists(keysFile)) { - const content = await fs.readFile(keysFile, 'utf-8'); - return JSON.parse(content) as ApiKeysStorage; - } - } catch { - // If file is corrupted, start fresh - } - - return {}; -} + const keyFile = getApiKeyFile(); -/** - * Save API keys to storage - */ -async function saveApiKeys(storage: ApiKeysStorage): Promise { - await ensureConfigDir(); - const keysFile = getApiKeysFile(); - - await fs.writeFile(keysFile, JSON.stringify(storage, null, 2), { + await fs.writeFile(keyFile, apiKey.trim(), { mode: 0o600, encoding: 'utf-8' }); } /** - * Store API key securely for a specific environment - */ -export async function storeApiKey(apiKey: string, environment: string = 'prod'): Promise { - const storage = await loadApiKeys(); - storage[environment] = apiKey.trim(); - await saveApiKeys(storage); -} - -/** - * Retrieve API key from secure storage for a specific environment + * Retrieve API key from secure storage */ -export async function retrieveApiKey(environment: string = 'prod'): Promise { - // Environment variable only applies to 'prod' environment - if (environment === 'prod') { - const envKey = process.env.ELEVENLABS_API_KEY; - if (envKey) { - return envKey; - } +export async function retrieveApiKey(): Promise { + const envKey = process.env.ELEVENLABS_API_KEY; + if (envKey) { + return envKey; } - // Try file storage + await ensureConfigDir(); + const keyFile = getApiKeyFile(); + try { - const storage = await loadApiKeys(); - return storage[environment]; + if (await fs.pathExists(keyFile)) { + const content = await fs.readFile(keyFile, 'utf-8'); + return content.trim(); + } } catch { // File not readable } @@ -150,21 +72,13 @@ export async function retrieveApiKey(environment: string = 'prod'): Promise { +export async function removeApiKey(): Promise { try { - const storage = await loadApiKeys(); - delete storage[environment]; - - // If no keys left, remove the file entirely - if (Object.keys(storage).length === 0) { - const keysFile = getApiKeysFile(); - if (await fs.pathExists(keysFile)) { - await fs.remove(keysFile); - } - } else { - await saveApiKeys(storage); + const keyFile = getApiKeyFile(); + if (await fs.pathExists(keyFile)) { + await fs.remove(keyFile); } } catch { // Ignore errors @@ -172,21 +86,9 @@ export async function removeApiKey(environment: string = 'prod'): Promise } /** - * Check if user has API key stored for a specific environment + * Check if user has API key stored */ -export async function hasApiKey(environment: string = 'prod'): Promise { - const apiKey = await retrieveApiKey(environment); +export async function hasApiKey(): Promise { + const apiKey = await retrieveApiKey(); return !!apiKey; -} - -/** - * List all configured environments - */ -export async function listEnvironments(): Promise { - try { - const storage = await loadApiKeys(); - return Object.keys(storage); - } catch { - return []; - } } \ No newline at end of file diff --git a/src/shared/config.ts b/src/shared/config.ts index 9369362..f37c1d9 100644 --- a/src/shared/config.ts +++ b/src/shared/config.ts @@ -10,11 +10,8 @@ import { storeApiKey, retrieveApiKey, removeApiKey as removeStoredApiKey, - hasApiKey, - listEnvironments + hasApiKey } from './auth.js'; - -export { listEnvironments }; export const LOCATIONS = ["us", "global", "eu-residency", "in-residency"] as const; export type Location = (typeof LOCATIONS)[number]; @@ -75,29 +72,29 @@ export async function saveConfig(config: CliConfig): Promise { /** * Get API key from storage or environment variable */ -export async function getApiKey(environment: string = 'prod'): Promise { - return await retrieveApiKey(environment); +export async function getApiKey(): Promise { + return await retrieveApiKey(); } /** * Set API key in secure storage */ -export async function setApiKey(apiKey: string, environment: string = 'prod'): Promise { - await storeApiKey(apiKey, environment); +export async function setApiKey(apiKey: string): Promise { + await storeApiKey(apiKey); } /** * Remove API key from storage */ -export async function removeApiKey(environment: string = 'prod'): Promise { - await removeStoredApiKey(environment); +export async function removeApiKey(): Promise { + await removeStoredApiKey(); } /** * Check if user is logged in (has API key) */ -export async function isLoggedIn(environment: string = 'prod'): Promise { - return await hasApiKey(environment); +export async function isLoggedIn(): Promise { + return await hasApiKey(); } /** diff --git a/src/shared/elevenlabs-api.ts b/src/shared/elevenlabs-api.ts index c59984f..86b5058 100644 --- a/src/shared/elevenlabs-api.ts +++ b/src/shared/elevenlabs-api.ts @@ -35,15 +35,14 @@ export function getApiBaseUrl(residency?: Location): string { /** * Retrieves the ElevenLabs API key from config or environment variables and returns an API client. - * - * @param environment - The environment to get the API key for (defaults to 'prod') + * * @throws {Error} If no API key is found * @returns An instance of the ElevenLabs client */ -export async function getElevenLabsClient(environment: string = 'prod'): Promise { - const apiKey = await getApiKey(environment); +export async function getElevenLabsClient(): Promise { + const apiKey = await getApiKey(); if (!apiKey) { - throw new Error(`No API key found for environment '${environment}'. Use 'elevenlabs auth login' to authenticate or set ELEVENLABS_API_KEY environment variable.`); + throw new Error(`No API key found. Use 'elevenlabs auth login' to authenticate or set ELEVENLABS_API_KEY environment variable.`); } const config = await loadConfig(); diff --git a/src/tests/commands/impl.ts b/src/tests/commands/impl.ts index 9dec13d..a96a54a 100644 --- a/src/tests/commands/impl.ts +++ b/src/tests/commands/impl.ts @@ -118,14 +118,12 @@ async function pushTests(testId?: string, dryRun = false): Promise { } } - const environment = 'prod'; - console.log(`Pushing ${testsToProcess.length} test(s) to environment: ${environment}`); + console.log(`Pushing ${testsToProcess.length} test(s) to ElevenLabs...`); let changesMade = false; for (const testDef of testsToProcess) { const configPath = testDef.config; - const environment = 'prod'; // Check if config file exists if (!(await fs.pathExists(configPath))) { @@ -148,20 +146,20 @@ async function pushTests(testId?: string, dryRun = false): Promise { const testId = testDef.id; // Always push (force override) - console.log(`${testDefName} [${environment}]: Will push (force override)`); + console.log(`${testDefName}: Will push (force override)`); if (dryRun) { - console.log(`[DRY RUN] Would update test: ${testDefName} [${environment}]`); + console.log(`[DRY RUN] Would update test: ${testDefName}`); continue; } - // Initialize ElevenLabs client for this test's environment + // Initialize ElevenLabs client let client; try { - client = await getElevenLabsClient(environment); + client = await getElevenLabsClient(); } catch (error) { console.log(`Error: ${error}`); - console.log(`Skipping test ${testDefName} - environment '${environment}' not configured`); + console.log(`Skipping test ${testDefName} - not configured`); continue; } @@ -199,14 +197,13 @@ async function pushTests(testId?: string, dryRun = false): Promise { async function pullTests(options: { test?: string; outputDir: string; dryRun: boolean; update?: boolean; all?: boolean }): Promise { // Check if tests.json exists const testsConfigPath = path.resolve(TESTS_CONFIG_FILE); - const environment = 'prod'; - console.log(`Pulling from environment: ${environment}`); + console.log(`Pulling tests from ElevenLabs...`); - await pullTestsFromEnvironment(options, environment, testsConfigPath); + await pullTestsFromEnvironment(options, testsConfigPath); } -async function pullTestsFromEnvironment(options: { test?: string; outputDir: string; dryRun: boolean; update?: boolean; all?: boolean }, environment: string, testsConfigPath: string): Promise { +async function pullTestsFromEnvironment(options: { test?: string; outputDir: string; dryRun: boolean; update?: boolean; all?: boolean }, testsConfigPath: string): Promise { let testsConfig: TestsConfig; try { @@ -217,7 +214,7 @@ async function pullTestsFromEnvironment(options: { test?: string; outputDir: str console.log(`Created ${TESTS_CONFIG_FILE}`); } - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); let testsList: unknown[]; @@ -407,8 +404,7 @@ async function deleteTest(testId: string): Promise { const testDef = testsConfig.tests[testIndex]; const configPath = testDef.config; - const environment = 'prod'; - + // Read test name from config if available let testName = testId; if (configPath && await fs.pathExists(configPath)) { @@ -419,12 +415,12 @@ async function deleteTest(testId: string): Promise { // If reading fails, just use ID } } - - console.log(`Deleting test '${testName}' (ID: ${testId}) [${environment}]...`); - + + console.log(`Deleting test '${testName}' (ID: ${testId})...`); + // Delete from ElevenLabs console.log('Deleting from ElevenLabs...'); - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); try { await deleteTestApi(client, testId); @@ -499,8 +495,6 @@ async function deleteAllTests(ui: boolean = true): Promise { // Delete each test for (const testDef of testsToDelete) { try { - const environment = 'prod'; - // Read test name from config if available let testName = testDef.id || 'Unknown'; if (testDef.config && await fs.pathExists(testDef.config)) { @@ -511,13 +505,13 @@ async function deleteAllTests(ui: boolean = true): Promise { // If reading fails, just use ID } } - - console.log(`Deleting '${testName}' (${testDef.id}) [${environment}]...`); - + + console.log(`Deleting '${testName}' (${testDef.id})...`); + // Delete from ElevenLabs if (testDef.id) { try { - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); await deleteTestApi(client, testDef.id); console.log(` ✓ Deleted from ElevenLabs`); } catch (error) { diff --git a/src/tools/commands/impl.ts b/src/tools/commands/impl.ts index 4012bed..cb7d6d8 100644 --- a/src/tools/commands/impl.ts +++ b/src/tools/commands/impl.ts @@ -157,14 +157,12 @@ async function pushTools(toolId?: string, dryRun = false): Promise { } } - const environment = 'prod'; - console.log(`Pushing ${toolsToProcess.length} tool(s) to environment: ${environment}`); + console.log(`Pushing ${toolsToProcess.length} tool(s) to ElevenLabs...`); let changesMade = false; for (const toolDef of toolsToProcess) { const configPath = toolDef.config; - const environment = 'prod'; if (!configPath) { console.log(`Warning: No config path specified`); @@ -199,13 +197,13 @@ async function pushTools(toolId?: string, dryRun = false): Promise { continue; } - // Initialize ElevenLabs client for this tool's environment + // Initialize ElevenLabs client let client; try { - client = await getElevenLabsClient(environment); + client = await getElevenLabsClient(); } catch (error) { console.log(`Error: ${error}`); - console.log(`Skipping tool ${toolDefName} - environment '${environment}' not configured`); + console.log(`Skipping tool ${toolDefName} - not configured`); continue; } @@ -241,14 +239,13 @@ async function pushTools(toolId?: string, dryRun = false): Promise { async function pullTools(options: PullToolsOptions): Promise { // Check if tools.json exists, create if not const toolsConfigPath = path.resolve(TOOLS_CONFIG_FILE); - const environment = 'prod'; - console.log(`Pulling from environment: ${environment}`); + console.log(`Pulling tools from ElevenLabs...`); - await pullToolsFromEnvironment(options, environment, toolsConfigPath); + await pullToolsFromEnvironment(options, toolsConfigPath); } -async function pullToolsFromEnvironment(options: PullToolsOptions, environment: string, toolsConfigPath: string): Promise { +async function pullToolsFromEnvironment(options: PullToolsOptions, toolsConfigPath: string): Promise { let toolsConfig: ToolsConfig; if (!(await fs.pathExists(toolsConfigPath))) { @@ -259,7 +256,7 @@ async function pullToolsFromEnvironment(options: PullToolsOptions, environment: toolsConfig = await readToolsConfig(toolsConfigPath); } - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); let filteredTools: unknown[]; @@ -488,10 +485,10 @@ async function deleteTool(toolId: string): Promise { } console.log(`Deleting tool '${toolName}' (ID: ${toolId}) [${environment}]...`); - + // Delete from ElevenLabs console.log('Deleting from ElevenLabs...'); - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); try { await deleteToolApi(client, toolId); @@ -591,7 +588,7 @@ async function deleteAllTools(ui: boolean = true): Promise { // Delete from ElevenLabs if (toolDef.id) { try { - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); await deleteToolApi(client, toolDef.id); console.log(` ✓ Deleted from ElevenLabs`); } catch (error) { diff --git a/src/tools/commands/pull.ts b/src/tools/commands/pull.ts index ed69a07..18788e3 100644 --- a/src/tools/commands/pull.ts +++ b/src/tools/commands/pull.ts @@ -25,15 +25,13 @@ export function createPullCommand(): Command { try { if (options.ui !== false) { // Use Ink UI for pull - const environments = ['prod']; const { waitUntilExit } = render( React.createElement(PullToolsView, { tool: options.tool, outputDir: options.outputDir, dryRun: options.dryRun, update: options.update, - all: options.all, - environments + all: options.all }) ); await waitUntilExit(); diff --git a/src/tools/ui/PullToolsView.tsx b/src/tools/ui/PullToolsView.tsx index 98f5bd1..95780f5 100644 --- a/src/tools/ui/PullToolsView.tsx +++ b/src/tools/ui/PullToolsView.tsx @@ -33,7 +33,6 @@ interface PullToolsViewProps { dryRun?: boolean; update?: boolean; all?: boolean; - environments: string[]; onComplete?: () => void; } @@ -45,7 +44,6 @@ export const PullToolsView: React.FC = ({ dryRun = false, update, all, - environments, onComplete }) => { const { exit } = useApp(); @@ -73,22 +71,20 @@ export const PullToolsView: React.FC = ({ toolsConfig = await readToolsConfig(toolsConfigPath); } - // Collect all tools from all environments + // Collect all tools const allToolsToPull: PullTool[] = []; - // Loop through each environment - for (const environment of environments) { - const client = await getElevenLabsClient(environment); + const client = await getElevenLabsClient(); - // Build ID-based map for existing tools - const existingToolIds = new Map( - toolsConfig.tools - .map((tool: ToolDefinition) => [tool.id, tool]) - ); + // Build ID-based map for existing tools + const existingToolIds = new Map( + toolsConfig.tools + .map((tool: ToolDefinition) => [tool.id, tool]) + ); - // Fetch tools - either specific tool by ID or all tools - let filteredTools: unknown[]; - if (tool) { + // Fetch tools - either specific tool by ID or all tools + let filteredTools: unknown[]; + if (tool) { // Pull specific tool by ID const toolDetails = await getToolApi(client, tool); const toolDetailsTyped = toolDetails as { tool_id?: string; toolId?: string; id?: string; tool_config?: { name?: string } }; @@ -105,12 +101,16 @@ export const PullToolsView: React.FC = ({ }]; } else { const toolsList = await listToolsApi(client); - if (toolsList.length === 0) continue; filteredTools = toolsList; } - // Prepare tools list with action determination - for (const toolItem of filteredTools) { + if (filteredTools.length === 0) { + setState(prev => ({ ...prev, error: 'No tools found in your ElevenLabs workspace.', loading: false })); + return; + } + + // Prepare tools list with action determination + for (const toolItem of filteredTools) { const toolId = (toolItem as any).tool_id || (toolItem as any).toolId || (toolItem as any).id; let toolName = (toolItem as any).tool_config?.name; @@ -140,19 +140,18 @@ export const PullToolsView: React.FC = ({ } } - allToolsToPull.push({ - name: toolName, - id: toolId, - type: (toolItem as any).tool_config?.type || (toolItem as any).type, - action, - status, - message: status === 'skipped' ? 'Skipped' : undefined - }); - } + allToolsToPull.push({ + name: toolName, + id: toolId, + type: (toolItem as any).tool_config?.type || (toolItem as any).type, + action, + status, + message: status === 'skipped' ? 'Skipped' : undefined + }); } if (allToolsToPull.length === 0) { - setState(prev => ({ ...prev, error: 'No tools found in any environment.', loading: false })); + setState(prev => ({ ...prev, error: 'No tools found.', loading: false })); return; } @@ -332,15 +331,6 @@ export const PullToolsView: React.FC = ({ title="ElevenLabs CLI" > - {!state.loading && !state.error && ( - - - Pulling from {environments.length} environment{environments.length > 1 ? 's' : ''}: - - {environments.join(', ')} - - )} - {state.loading ? ( Date: Mon, 10 Nov 2025 14:58:27 +0000 Subject: [PATCH 2/6] also env example --- .env.example | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.env.example b/.env.example index a5224dd..0fa7767 100644 --- a/.env.example +++ b/.env.example @@ -16,11 +16,6 @@ # Primary test API key (required for all e2e tests) ELEVENLABS_API_KEY=your_test_account_api_key_here -# Secondary test API key (optional - only needed for multi-environment e2e tests) -# Multi-environment tests verify the CLI can handle multiple environments (prod, staging, dev, etc.) -# If not provided, multi-environment tests will be skipped -ELEVENLABS_TEST_API_KEY=your_second_test_account_api_key_here - # For local development and testing: # 1. Copy this file to .env (DO NOT COMMIT .env) # cp .env.example .env From 5a6f197a3e4a30750330b9da96f2cc833fb81cf8 Mon Sep 17 00:00:00 2001 From: Boris Starkov Date: Mon, 10 Nov 2025 15:06:09 +0000 Subject: [PATCH 3/6] more fixes --- src/agents/commands/pull-impl.ts | 3 +-- src/agents/commands/push-impl.ts | 14 +++++++------- src/agents/ui/AddAgentView.tsx | 2 +- src/agents/ui/PullView.tsx | 2 +- src/agents/ui/PushView.tsx | 4 ++-- src/auth/ui/LoginView.tsx | 2 +- src/auth/ui/LogoutView.tsx | 4 ++-- src/tests/commands/impl.ts | 14 ++++++-------- src/tests/ui/AddTestView.tsx | 2 +- src/tools/commands/impl.ts | 20 +++++++++----------- src/tools/ui/PullToolsView.tsx | 11 +++++++---- src/tools/ui/PushToolsView.tsx | 4 ++-- 12 files changed, 40 insertions(+), 42 deletions(-) diff --git a/src/agents/commands/pull-impl.ts b/src/agents/commands/pull-impl.ts index 3cdf30f..1b15198 100644 --- a/src/agents/commands/pull-impl.ts +++ b/src/agents/commands/pull-impl.ts @@ -3,7 +3,6 @@ import fs from 'fs-extra'; import { readConfig, writeConfig, generateUniqueFilename } from '../../shared/utils.js'; import { getElevenLabsClient, listAgentsApi, getAgentApi } from '../../shared/elevenlabs-api.js'; import { AgentConfig } from '../templates.js'; -import { listEnvironments } from '../../shared/config.js'; import { promptForConfirmation } from './utils.js'; const AGENTS_CONFIG_FILE = "agents.json"; @@ -210,7 +209,7 @@ async function pullAgentsFromEnvironment(options: PullOptions, agentsConfigPath: }; agentsConfig.agents.push(newAgent); - console.log(` ✓ Added '${agent.name}' (config: ${configPath}) [${environment}]`); + console.log(` ✓ Added '${agent.name}' (config: ${configPath})`); } itemsProcessed++; diff --git a/src/agents/commands/push-impl.ts b/src/agents/commands/push-impl.ts index 49596ab..2b1c46c 100644 --- a/src/agents/commands/push-impl.ts +++ b/src/agents/commands/push-impl.ts @@ -59,20 +59,20 @@ export async function pushAgents(dryRun: boolean = false): Promise { const agentId = agentDef.id; // Always push (force override) - console.log(`${agentDefName} [${environment}]: Will push (force override)`); + console.log(`${agentDefName}: Will push (force override)`); if (dryRun) { - console.log(`[DRY RUN] Would update agent: ${agentDefName} [${environment}]`); + console.log(`[DRY RUN] Would update agent: ${agentDefName}`); continue; } - // Initialize ElevenLabs client for this agent's environment + // Initialize ElevenLabs client let client; try { - client = await getElevenLabsClient(environment); + client = await getElevenLabsClient(); } catch (error) { console.log(`Error: ${error}`); - console.log(`Skipping agent ${agentDefName} - environment '${environment}' not configured`); + console.log(`Skipping agent ${agentDefName} - not configured`); continue; } @@ -94,7 +94,7 @@ export async function pushAgents(dryRun: boolean = false): Promise { platformSettings, tags ); - console.log(`Created agent ${agentDefName} (ID: ${newAgentId}) [${environment}]`); + console.log(`Created agent ${agentDefName} (ID: ${newAgentId})`); // Store agent ID in index file agentDef.id = newAgentId; @@ -109,7 +109,7 @@ export async function pushAgents(dryRun: boolean = false): Promise { platformSettings, tags ); - console.log(`Updated agent ${agentDefName} (ID: ${agentId}) [${environment}]`); + console.log(`Updated agent ${agentDefName} (ID: ${agentId})`); } changesMade = true; diff --git a/src/agents/ui/AddAgentView.tsx b/src/agents/ui/AddAgentView.tsx index 07fb045..785df9f 100644 --- a/src/agents/ui/AddAgentView.tsx +++ b/src/agents/ui/AddAgentView.tsx @@ -68,7 +68,7 @@ export const AddAgentView: React.FC = ({ // Step 2: Upload to ElevenLabs first to get ID setStatusMessage('Creating agent in ElevenLabs...'); - const client = await getElevenLabsClient('prod'); + const client = await getElevenLabsClient(); const conversationConfig = agentConfig.conversation_config || {}; const platformSettings = agentConfig.platform_settings; const tags = agentConfig.tags || []; diff --git a/src/agents/ui/PullView.tsx b/src/agents/ui/PullView.tsx index 3e8a2c3..a0ddea6 100644 --- a/src/agents/ui/PullView.tsx +++ b/src/agents/ui/PullView.tsx @@ -192,7 +192,7 @@ export const PullView: React.FC = ({ await new Promise(resolve => setTimeout(resolve, 300)); try { - const client = await getElevenLabsClient('prod'); + const client = await getElevenLabsClient(); const agentName = agent.name; // Find existing entry for this agent ID diff --git a/src/agents/ui/PushView.tsx b/src/agents/ui/PushView.tsx index c7c9a78..682e221 100644 --- a/src/agents/ui/PushView.tsx +++ b/src/agents/ui/PushView.tsx @@ -93,8 +93,8 @@ export const PushView: React.FC = ({ ) ); - // Get ElevenLabs client for this agent's environment - const client = await getElevenLabsClient('prod'); + // Get ElevenLabs client + const client = await getElevenLabsClient(); // Extract config components const conversationConfig = agentConfig.conversation_config || {}; diff --git a/src/auth/ui/LoginView.tsx b/src/auth/ui/LoginView.tsx index dd249a7..cc9333a 100644 --- a/src/auth/ui/LoginView.tsx +++ b/src/auth/ui/LoginView.tsx @@ -58,7 +58,7 @@ export const LoginView: React.FC = ({ onComplete }) => { setError(null); try { - await setApiKey(apiKey, 'prod'); + await setApiKey(apiKey); setSuccess(true); setTimeout(() => { diff --git a/src/auth/ui/LogoutView.tsx b/src/auth/ui/LogoutView.tsx index 2c3fbf7..4a21630 100644 --- a/src/auth/ui/LogoutView.tsx +++ b/src/auth/ui/LogoutView.tsx @@ -29,7 +29,7 @@ export const LogoutView: React.FC = ({ onComplete }) => { useEffect(() => { const checkLoginStatus = async () => { - const loggedIn = await isLoggedIn('prod'); + const loggedIn = await isLoggedIn(); if (!loggedIn) { setNotLoggedIn(true); setConfirming(false); @@ -51,7 +51,7 @@ export const LogoutView: React.FC = ({ onComplete }) => { setProcessing(true); try { - await removeApiKey('prod'); + await removeApiKey(); setProcessing(false); setSuccess(true); diff --git a/src/tests/commands/impl.ts b/src/tests/commands/impl.ts index a96a54a..ab50dcd 100644 --- a/src/tests/commands/impl.ts +++ b/src/tests/commands/impl.ts @@ -9,7 +9,6 @@ import { getTestApi, deleteTestApi } from '../../shared/elevenlabs-api.js'; -import { listEnvironments } from '../../shared/config.js'; import { ElevenLabs } from '@elevenlabs/elevenlabs-js'; const TESTS_CONFIG_FILE = "tests.json"; @@ -60,10 +59,9 @@ async function addTest(name: string, templateType: string = "basic-llm"): Promis const testConfig = getTestTemplateByName(name, templateType); // Create test in ElevenLabs first to get ID - const env = 'prod'; - console.log(`Creating test '${name}' in ElevenLabs (environment: ${env})...`); + console.log(`Creating test '${name}' in ElevenLabs...`); - const client = await getElevenLabsClient(env); + const client = await getElevenLabsClient(); try { const testApiConfig = toCamelCaseKeys(testConfig) as unknown as ElevenLabs.conversationalAi.CreateUnitTestRequest; @@ -171,15 +169,15 @@ async function pushTests(testId?: string, dryRun = false): Promise { // Create new test const response = await createTestApi(client, testApiConfig); const newTestId = response.id; - console.log(`Created test ${testDefName} (ID: ${newTestId}) [${environment}]`); - + console.log(`Created test ${testDefName} (ID: ${newTestId})`); + // Store test ID in index file testDef.id = newTestId; changesMade = true; } else { // Update existing test await updateTestApi(client, testId, testApiConfig as ElevenLabs.conversationalAi.UpdateUnitTestRequest); - console.log(`Updated test ${testDefName} (ID: ${testId}) [${environment}]`); + console.log(`Updated test ${testDefName} (ID: ${testId})`); } changesMade = true; @@ -359,7 +357,7 @@ async function pullTestsFromEnvironment(options: { test?: string; outputDir: str }; testsConfig.tests.push(newTest); - console.log(` ✓ Added '${test.name}' (config: ${configPath}) [${environment}]`); + console.log(` ✓ Added '${test.name}' (config: ${configPath})`); } itemsProcessed++; diff --git a/src/tests/ui/AddTestView.tsx b/src/tests/ui/AddTestView.tsx index 6c7979b..bfc5d65 100644 --- a/src/tests/ui/AddTestView.tsx +++ b/src/tests/ui/AddTestView.tsx @@ -150,7 +150,7 @@ export const AddTestView: React.FC = ({ // Create test in ElevenLabs first to get ID const { getElevenLabsClient, createTestApi } = await import('../../shared/elevenlabs-api.js'); - const client = await getElevenLabsClient('prod'); + const client = await getElevenLabsClient(); const { toCamelCaseKeys, generateUniqueFilename } = await import('../../shared/utils.js'); const testApiConfig = toCamelCaseKeys(testConfig) as unknown as any; diff --git a/src/tools/commands/impl.ts b/src/tools/commands/impl.ts index cb7d6d8..64c5912 100644 --- a/src/tools/commands/impl.ts +++ b/src/tools/commands/impl.ts @@ -17,7 +17,6 @@ import { ToolDefinition, type Tool } from '../../shared/tools.js'; -import { listEnvironments } from '../../shared/config.js'; const TOOLS_CONFIG_FILE = "tools.json"; @@ -98,10 +97,9 @@ async function addTool(name: string, type: 'webhook' | 'client', configPath?: st } // Create tool in ElevenLabs first to get ID - const env = 'prod'; - console.log(`Creating ${type} tool '${name}' in ElevenLabs (environment: ${env})...`); - - const client = await getElevenLabsClient(env); + console.log(`Creating ${type} tool '${name}' in ElevenLabs...`); + + const client = await getElevenLabsClient(); try { const response = await createToolApi(client, toolConfig); @@ -190,10 +188,10 @@ async function pushTools(toolId?: string, dryRun = false): Promise { const toolId = toolDef.id; // Always push (force override) - console.log(`${toolDefName} [${environment}]: Will push (force override)`); + console.log(`${toolDefName}: Will push (force override)`); if (dryRun) { - console.log(`[DRY RUN] Would update tool: ${toolDefName} [${environment}]`); + console.log(`[DRY RUN] Would update tool: ${toolDefName}`); continue; } @@ -213,15 +211,15 @@ async function pushTools(toolId?: string, dryRun = false): Promise { // Create new tool const response = await createToolApi(client, toolConfig); const newToolId = (response as { toolId?: string }).toolId || `tool_${Date.now()}`; - console.log(`Created tool ${toolDefName} (ID: ${newToolId}) [${environment}]`); - + console.log(`Created tool ${toolDefName} (ID: ${newToolId})`); + // Store tool ID in index file toolDef.id = newToolId; changesMade = true; } else { // Update existing tool await updateToolApi(client, toolId, toolConfig); - console.log(`Updated tool ${toolDefName} (ID: ${toolId}) [${environment}]`); + console.log(`Updated tool ${toolDefName} (ID: ${toolId})`); } changesMade = true; @@ -426,7 +424,7 @@ async function pullToolsFromEnvironment(options: PullToolsOptions, toolsConfigPa }; toolsConfig.tools.push(newTool); - console.log(` ✓ Added '${tool.name}' (config: ${configPath}, type: ${toolType}) [${environment}]`); + console.log(` ✓ Added '${tool.name}' (config: ${configPath}, type: ${toolType})`); } itemsProcessed++; diff --git a/src/tools/ui/PullToolsView.tsx b/src/tools/ui/PullToolsView.tsx index 95780f5..a0a8497 100644 --- a/src/tools/ui/PullToolsView.tsx +++ b/src/tools/ui/PullToolsView.tsx @@ -90,9 +90,12 @@ export const PullToolsView: React.FC = ({ const toolDetailsTyped = toolDetails as { tool_id?: string; toolId?: string; id?: string; tool_config?: { name?: string } }; const toolId = toolDetailsTyped.tool_id || toolDetailsTyped.toolId || toolDetailsTyped.id || tool; const toolName = toolDetailsTyped.tool_config?.name; - - if (!toolName) continue; - + + if (!toolName) { + setState(prev => ({ ...prev, error: `Tool with ID ${tool} found but has no name`, loading: false })); + return; + } + filteredTools = [{ tool_id: toolId, toolId: toolId, @@ -217,7 +220,7 @@ export const PullToolsView: React.FC = ({ } try { - const client = await getElevenLabsClient('prod'); + const client = await getElevenLabsClient(); const toolDetails = await getToolApi(client, toolToPull.id); // Extract the tool_config from the response diff --git a/src/tools/ui/PushToolsView.tsx b/src/tools/ui/PushToolsView.tsx index 948f4d8..8e667fb 100644 --- a/src/tools/ui/PushToolsView.tsx +++ b/src/tools/ui/PushToolsView.tsx @@ -94,8 +94,8 @@ export const PushToolsView: React.FC = ({ ) ); - // Get ElevenLabs client for this tool's environment - const client = await getElevenLabsClient('prod'); + // Get ElevenLabs client + const client = await getElevenLabsClient(); if (!toolId) { // Create new tool From 94b026b7987e2d6b275830487ab13776a52c52f0 Mon Sep 17 00:00:00 2001 From: Boris Starkov Date: Mon, 10 Nov 2025 15:16:01 +0000 Subject: [PATCH 4/6] delete from docs too --- README.md | 12 ++++++------ src/tests/commands/impl.ts | 2 +- src/tools/commands/impl.ts | 13 +++++-------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index db489c5..89f183f 100644 --- a/README.md +++ b/README.md @@ -102,9 +102,9 @@ elevenlabs agents push ``` your_project/ -├── agents.json # Central configuration with env field per agent -├── tools.json # Tool configurations with env field per tool -├── tests.json # Test configurations with env field per test +├── agents.json # Central configuration +├── tools.json # Tool configurations +├── tests.json # Test configurations ├── agent_configs/ # Agent configuration files ├── tool_configs/ # Tool configurations └── test_configs/ # Test configurations @@ -311,13 +311,13 @@ elevenlabs agents delete agent_123456789 ## Workflow Examples ```bash -# List all agents across all environments +# List all agents elevenlabs agents list -# Push all agents to their respective environments +# Push all agents elevenlabs agents push -# Pull agents from all configured environments +# Pull agents elevenlabs agents pull ``` diff --git a/src/tests/commands/impl.ts b/src/tests/commands/impl.ts index ab50dcd..c04250e 100644 --- a/src/tests/commands/impl.ts +++ b/src/tests/commands/impl.ts @@ -244,7 +244,7 @@ async function pullTestsFromEnvironment(options: { test?: string; outputDir: str console.log(`Found ${testsList.length} test(s)`); } - // Build map of existing tests by ID for this environment + // Build map of existing tests by ID const existingTestIds = new Map( testsConfig.tests .map(test => [test.id, test]) diff --git a/src/tools/commands/impl.ts b/src/tools/commands/impl.ts index 64c5912..9baf8a2 100644 --- a/src/tools/commands/impl.ts +++ b/src/tools/commands/impl.ts @@ -469,8 +469,7 @@ async function deleteTool(toolId: string): Promise { const toolDef = toolsConfig.tools[toolIndex]; const configPath = toolDef.config; - const environment = 'prod'; - + // Read tool name from config if available let toolName = toolId; if (configPath && await fs.pathExists(configPath)) { @@ -481,8 +480,8 @@ async function deleteTool(toolId: string): Promise { // If reading fails, just use ID } } - - console.log(`Deleting tool '${toolName}' (ID: ${toolId}) [${environment}]...`); + + console.log(`Deleting tool '${toolName}' (ID: ${toolId})...`); // Delete from ElevenLabs console.log('Deleting from ElevenLabs...'); @@ -568,8 +567,6 @@ async function deleteAllTools(ui: boolean = true): Promise { // Delete each tool for (const toolDef of toolsToDelete) { try { - const environment = 'prod'; - // Read tool name from config if available let toolName = toolDef.id || 'Unknown'; if (toolDef.config && await fs.pathExists(toolDef.config)) { @@ -580,8 +577,8 @@ async function deleteAllTools(ui: boolean = true): Promise { // If reading fails, just use ID } } - - console.log(`Deleting '${toolName}' (${toolDef.id}) [${environment}]...`); + + console.log(`Deleting '${toolName}' (${toolDef.id})...`); // Delete from ElevenLabs if (toolDef.id) { From 5d841fb732126283ea82fea1c8dd059ceb18180e Mon Sep 17 00:00:00 2001 From: Boris Starkov Date: Mon, 10 Nov 2025 15:29:53 +0000 Subject: [PATCH 5/6] dont read .env --- src/cli.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index d41f522..5286071 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -6,7 +6,6 @@ import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import { render } from 'ink'; import React from 'react'; -import dotenv from 'dotenv'; import HelpView from './ui/views/HelpView.js'; // Import command groups @@ -16,9 +15,6 @@ import { createToolsCommand } from './tools/commands/index.js'; import { createTestsCommand } from './tests/commands/index.js'; import { createComponentsCommand } from './components/commands/index.js'; -// Load environment variables -dotenv.config(); - const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8')); From 682bf239560286358dd648a9dc8782fbc282016f Mon Sep 17 00:00:00 2001 From: Boris Starkov Date: Mon, 10 Nov 2025 16:05:20 +0000 Subject: [PATCH 6/6] fix e2e tests too --- src/__tests__/cli.e2e.test.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/__tests__/cli.e2e.test.ts b/src/__tests__/cli.e2e.test.ts index 042a810..7f88357 100644 --- a/src/__tests__/cli.e2e.test.ts +++ b/src/__tests__/cli.e2e.test.ts @@ -481,7 +481,7 @@ describe("CLI End-to-End Tests", () => { // Login const apiKey = process.env.ELEVENLABS_API_KEY!; - await runCli(["login", "--no-ui"], { + await runCli(["auth", "login", "--no-ui"], { cwd: pushPullTempDir, input: `${apiKey}\n`, includeApiKey: true, @@ -510,7 +510,7 @@ describe("CLI End-to-End Tests", () => { // Delete all agents at once try { - await runCli(["delete", "--all", "--no-ui"], { + await runCli(["agents", "delete", "--all", "--no-ui"], { cwd: pushPullTempDir, includeApiKey: true, input: "y\n", // Answer the "Are you sure?" prompt @@ -591,7 +591,7 @@ describe("CLI End-to-End Tests", () => { console.log(`✓ Verified agent '${agentName}' is the only agent after pull`); // Clean up: delete the agent - await runCli(["delete", createdAgent.id, "--no-ui"], { + await runCli(["agents", "delete", createdAgent.id, "--no-ui"], { cwd: pushPullTempDir, includeApiKey: true, }); @@ -717,6 +717,7 @@ describe("CLI End-to-End Tests", () => { for (const agentName of agentNames) { const addResult = await runCli([ + "agents", "add", agentName, "--template", @@ -1322,7 +1323,7 @@ describe("CLI End-to-End Tests", () => { // Login const apiKey = process.env.ELEVENLABS_API_KEY!; - await runCli(["login", "--no-ui"], { + await runCli(["auth", "login", "--no-ui"], { cwd: pushPullTempDir, input: `${apiKey}\n`, includeApiKey: true, @@ -1351,7 +1352,7 @@ describe("CLI End-to-End Tests", () => { // Delete all tests at once try { - await runCli(["delete-test", "--all", "--no-ui"], { + await runCli(["tests", "delete", "--all", "--no-ui"], { cwd: pushPullTempDir, includeApiKey: true, input: "y\n", // Answer the "Are you sure?" prompt @@ -1420,7 +1421,7 @@ describe("CLI End-to-End Tests", () => { console.log(`✓ Verified test '${testName}' is the only test after pull`); // Clean up: delete the test - await runCli(["delete-test", createdTest.id, "--no-ui"], { + await runCli(["tests", "delete", createdTest.id, "--no-ui"], { cwd: pushPullTempDir, includeApiKey: true, }); @@ -1547,7 +1548,8 @@ describe("CLI End-to-End Tests", () => { for (const testName of testNames) { const addResult = await runCli([ - "add-test", + "tests", + "add", testName, "--template", "basic-llm", @@ -1943,7 +1945,7 @@ describe("CLI End-to-End Tests", () => { // Login const apiKey = process.env.ELEVENLABS_API_KEY!; - await runCli(["login", "--no-ui"], { + await runCli(["auth", "login", "--no-ui"], { cwd: pushPullTempDir, input: `${apiKey}\n`, includeApiKey: true, @@ -1972,7 +1974,7 @@ describe("CLI End-to-End Tests", () => { // Delete all tools at once try { - await runCli(["delete-tool", "--all", "--no-ui"], { + await runCli(["tools", "delete", "--all", "--no-ui"], { cwd: pushPullTempDir, includeApiKey: true, input: "y\n", // Answer the "Are you sure?" prompt