diff --git a/README.md b/README.md index 62ce6fc..d1ffda6 100644 --- a/README.md +++ b/README.md @@ -84,54 +84,23 @@ The ElevenLabs CLI supports managing agents, tools, and tests across multiple is #### Login to Multiple Environments ```bash -# Login to production -elevenlabs auth login --env prod - -# Login to staging -elevenlabs auth login --env staging - -# Login to development -elevenlabs auth login --env dev +# Login with your API key +elevenlabs auth login ``` -Each environment stores its API key securely and independently. - -#### Check All Environments +#### Check Authentication Status ```bash elevenlabs auth whoami -# Shows all configured environments and their authentication status +# Shows your authentication status ``` -#### Logout from Specific Environment +#### Logout ```bash -elevenlabs auth logout --env dev -``` - -#### Environment Field in Configurations - -Agent, tool, and test definitions include an `env` field: - -```json -{ - "agents": [ - { - "config": "agent_configs/support_bot.json", - "id": "agent_123", - "env": "prod" - }, - { - "config": "agent_configs/support_bot_dev.json", - "id": "agent_456", - "env": "dev" - } - ] -} +elevenlabs auth logout ``` -When `env` is not specified, it defaults to `prod`. - ## Quick Start ```bash @@ -141,7 +110,7 @@ elevenlabs agents init # Or override existing configuration elevenlabs agents init --override -# 2. Login with API key (defaults to 'prod' environment) +# 2. Login with API key elevenlabs auth login # 3. Create agent with template @@ -204,37 +173,37 @@ elevenlabs auth logout elevenlabs auth whoami # Create agent -elevenlabs agents add "Agent Name" [--template customer-service] [--env prod] +elevenlabs agents add "Agent Name" [--template customer-service] # Create webhook tool -elevenlabs tools add-webhook "Tool Name" [--config-path path] [--env prod] +elevenlabs tools add-webhook "Tool Name" [--config-path path] # Create client tool -elevenlabs tools add-client "Tool Name" [--config-path path] [--env prod] +elevenlabs tools add-client "Tool Name" [--config-path path] -# Push changes (operates on all environments by default) -elevenlabs agents push [--agent "Agent Name"] [--env prod] [--dry-run] +# Push changes +elevenlabs agents push [--agent "Agent Name"] [--dry-run] -# Sync tools (operates on all environments by default) -elevenlabs tools push [--tool "Tool Name"] [--env prod] [--dry-run] +# Sync tools +elevenlabs tools push [--tool "Tool Name"] [--dry-run] -# Sync tests (operates on all environments by default) -elevenlabs tests push [--env prod] [--dry-run] +# Sync tests +elevenlabs tests push [--dry-run] # Check status elevenlabs agents status [--agent "Agent Name"] -# Pull agents from ElevenLabs (pulls from all environments by default) -elevenlabs agents pull [--search "term"] [--env prod] [--dry-run] +# Pull agents from ElevenLabs +elevenlabs agents pull [--search "term"] [--dry-run] -# Pull tools from ElevenLabs (pulls from all environments by default) -elevenlabs tools pull [--search "term"] [--tool "tool-name"] [--env prod] [--dry-run] [--output-dir tool_configs] +# Pull tools from ElevenLabs +elevenlabs tools pull [--search "term"] [--tool "tool-name"] [--dry-run] [--output-dir tool_configs] -# Import tests from ElevenLabs (pulls from all environments by default) -elevenlabs tests pull [--output-dir test_configs] [--env prod] [--dry-run] +# Import tests from ElevenLabs +elevenlabs tests pull [--output-dir test_configs] [--dry-run] # Create and run test -elevenlabs tests add "Test Name" [--template basic-llm] [--env prod] +elevenlabs tests add "Test Name" [--template basic-llm] # Run tests elevenlabs agents test "Agent Name" @@ -254,18 +223,12 @@ elevenlabs tools delete # Delete all tools elevenlabs tools delete --all -# Delete all tools in specific environment -elevenlabs tools delete --all --env prod - # Delete test locally and from ElevenLabs elevenlabs tests delete # Delete all tests elevenlabs tests delete --all -# Delete all tests in specific environment -elevenlabs tests delete --all --env dev - # Add componenents from [ui.elevenlabs.io](https://ui.elevenlabs.io) elevenlabs components add "Component Name" ``` @@ -371,62 +334,7 @@ elevenlabs agents list elevenlabs agents delete agent_123456789 ``` -> **Tip**: When `--env` is not specified, most commands operate across all configured environments. - -## Multi-Environment Workflows - -**Setup Multiple Environments:** - -```bash -# Initialise project -elevenlabs agents init - -# Login to all environments -elevenlabs auth login --env dev -elevenlabs auth login --env staging -elevenlabs auth login --env prod - -# Verify all environments -elevenlabs auth whoami -``` - -**Develop and Promote Agents:** - -```bash -# Create agent in dev environment -elevenlabs agents add "My Agent" --template assistant --env dev - -# Edit and test in dev -# Edit agent_configs/my_agent.json -elevenlabs agents push --env dev - -# Pull to promote to staging -elevenlabs agents pull --env dev -# Update env field in agents.json from "dev" to "staging" -elevenlabs agents push --env staging - -# Promote to production -# Update env field to "prod" -elevenlabs agents push --env prod -``` - -**Environment-Specific Operations:** - -```bash -# Push only dev agents -elevenlabs agents push --env dev - -# Pull only prod agents -elevenlabs agents pull --env prod - -# Delete all dev tools -elevenlabs tools delete --all --env dev - -# Pull tests from staging -elevenlabs tests pull --env staging -``` - -**Cross-Environment Management:** +## Workflow Examples ```bash # List all agents across all environments diff --git a/src/__tests__/cli.e2e.test.ts b/src/__tests__/cli.e2e.test.ts index 41a4001..042a810 100644 --- a/src/__tests__/cli.e2e.test.ts +++ b/src/__tests__/cli.e2e.test.ts @@ -288,12 +288,12 @@ describe("CLI End-to-End Tests", () => { }); it("should handle invalid arguments", async () => { - const result = await runCli(["agents", "add"]); // missing required argument + const result = await runCli(["agents", "add", "test-agent", "--invalid-flag"]); // invalid flag expect(result.exitCode).toBe(1); // Check both stdout and stderr for the error message const output = result.stdout + result.stderr; - expect(output).toContain("missing required argument"); + expect(output).toContain("unknown option"); }); }); @@ -348,10 +348,8 @@ describe("CLI End-to-End Tests", () => { expect(result.stderr).toContain("tools.json not found"); }); - it("should handle specific tool name option", async () => { - // Note: tools push doesn't support --tool option, only --env - // This test verifies the command works with --env filter - const result = await runCli(["tools", "push", "--env", "test"]); + it("should handle tools push command", async () => { + const result = await runCli(["tools", "push"]); // Should succeed (no tools to push is valid) expect(result.exitCode).toBe(0); @@ -2517,308 +2515,4 @@ describe("CLI End-to-End Tests", () => { }); }); - describeIfApiKey("[integration write] multi-environment workflow", () => { - let multiEnvTempDir: string; - const hasTestApiKey = !!process.env.ELEVENLABS_TEST_API_KEY; - - // Skip this test suite if TEST API key is not provided - const testFn = hasTestApiKey ? it : it.skip; - - beforeAll(async () => { - if (!hasTestApiKey) { - console.log("Skipping multi-environment tests: ELEVENLABS_TEST_API_KEY not found"); - console.log(" To run these tests, add ELEVENLABS_TEST_API_KEY to your .env file"); - return; - } - - // One-time cleanup for both environments - console.log("One-time cleanup: Removing all remote agents from both environments..."); - - const cleanupTempDir = await fs.mkdtemp(path.join(os.tmpdir(), "agents-e2e-multienv-cleanup-")); - - try { - // Initialize project - await runCli(["agents", "init", "--no-ui"], { - cwd: cleanupTempDir, - includeApiKey: true, - }); - - // Cleanup prod environment - const prodApiKey = process.env.ELEVENLABS_API_KEY!; - await runCli(["auth", "login", "--no-ui", "--env", "prod"], { - cwd: cleanupTempDir, - input: `${prodApiKey}\n`, - includeApiKey: true, - }); - - await runCli(["agents", "pull", "--all", "--no-ui", "--env", "prod"], { - cwd: cleanupTempDir, - includeApiKey: true, - input: "y\n", - }); - - try { - await runCli(["agents", "delete", "--all", "--no-ui", "--env", "prod"], { - cwd: cleanupTempDir, - includeApiKey: true, - input: "y\n", - }); - console.log("✓ Cleaned up prod environment"); - } catch (error) { - console.warn(`Failed to delete prod agents: ${error}`); - } - - // Cleanup test environment - const testApiKey = process.env.ELEVENLABS_TEST_API_KEY!; - await runCli(["auth", "login", "--no-ui", "--env", "test"], { - cwd: cleanupTempDir, - input: `${testApiKey}\n`, - includeApiKey: true, - }); - - await runCli(["agents", "pull", "--all", "--no-ui", "--env", "test"], { - cwd: cleanupTempDir, - includeApiKey: true, - input: "y\n", - }); - - try { - await runCli(["agents", "delete", "--all", "--no-ui", "--env", "test"], { - cwd: cleanupTempDir, - includeApiKey: true, - input: "y\n", - }); - console.log("✓ Cleaned up test environment"); - } catch (error) { - console.warn(`Failed to delete test agents: ${error}`); - } - } finally { - await fs.remove(cleanupTempDir); - } - }); - - beforeEach(async () => { - multiEnvTempDir = await fs.mkdtemp(path.join(os.tmpdir(), "agents-e2e-multienv-")); - }); - - afterEach(async () => { - await fs.remove(multiEnvTempDir); - }); - - testFn("should handle complete multi-environment workflow", async () => { - const prodApiKey = process.env.ELEVENLABS_API_KEY!; - const testApiKey = process.env.ELEVENLABS_TEST_API_KEY!; - - // Step 1: Initialize project - console.log("Step 1: Initializing project..."); - const initResult = await runCli(["agents", "init", "--no-ui"], { - cwd: multiEnvTempDir, - includeApiKey: true, - }); - expect(initResult.exitCode).toBe(0); - - // Step 2: Login to prod environment - console.log("Step 2: Login to prod environment..."); - const loginProdResult = await runCli(["login", "--no-ui", "--env", "prod"], { - cwd: multiEnvTempDir, - input: `${prodApiKey}\n`, - includeApiKey: true, - }); - expect(loginProdResult.exitCode).toBe(0); - - // Step 3: Login to test environment - console.log("Step 3: Login to test environment..."); - const loginTestResult = await runCli(["login", "--no-ui", "--env", "test"], { - cwd: multiEnvTempDir, - input: `${testApiKey}\n`, - includeApiKey: true, - }); - expect(loginTestResult.exitCode).toBe(0); - - // Verify both environments are logged in - // Don't include API key env var so whoami reads from stored keys - const whoamiResult = await runCli(["auth", "whoami", "--no-ui"], { - cwd: multiEnvTempDir, - includeApiKey: false, - }); - expect(whoamiResult.exitCode).toBe(0); - expect(whoamiResult.stdout).toContain("prod"); - expect(whoamiResult.stdout).toContain("test"); - - // Step 4: Add agent to prod (default) - console.log("Step 4: Adding agent to prod environment..."); - const addProdResult = await runCli(["agents", "add", "prod-agent", "--no-ui"], { - cwd: multiEnvTempDir, - includeApiKey: true, - }); - expect(addProdResult.exitCode).toBe(0); - - // Step 5: Add agent to test environment - console.log("Step 5: Adding agent to test environment..."); - const addTestResult = await runCli(["agents", "add", "test-agent", "--no-ui", "--env", "test"], { - cwd: multiEnvTempDir, - includeApiKey: true, - }); - expect(addTestResult.exitCode).toBe(0); - - // Verify both agents exist in agents.json with correct environments - let agentsJsonPath = path.join(multiEnvTempDir, "agents.json"); - let agentsConfig = JSON.parse(await fs.readFile(agentsJsonPath, "utf-8")); - expect(agentsConfig.agents).toHaveLength(2); - - const prodAgent = agentsConfig.agents.find((a: AgentConfigEntry) => (a.env || 'prod') === 'prod'); - const testAgent = agentsConfig.agents.find((a: AgentConfigEntry) => a.env === 'test'); - expect(prodAgent).toBeTruthy(); - expect(testAgent).toBeTruthy(); - - const prodAgentId = prodAgent.id; - const testAgentId = testAgent.id; - console.log(`✓ Created prod agent (${prodAgentId}) and test agent (${testAgentId})`); - - // Step 6: Delete local files - console.log("Step 6: Deleting local files..."); - await fs.remove(agentsJsonPath); - await fs.remove(path.join(multiEnvTempDir, "agent_configs")); - - // Step 7: Pull from test environment only - console.log("Step 7: Pulling from test environment..."); - const pullTestResult = await runCli(["agents", "pull", "--all", "--no-ui", "--env", "test"], { - cwd: multiEnvTempDir, - includeApiKey: true, - input: "y\n", - }); - if (pullTestResult.exitCode !== 0) { - console.log("Pull stderr:", pullTestResult.stderr); - console.log("Pull stdout:", pullTestResult.stdout); - } - expect(pullTestResult.exitCode).toBe(0); - - // Step 8: Check that only one agent was pulled (test agent) - console.log("Step 8: Verifying only test agent was pulled..."); - agentsConfig = JSON.parse(await fs.readFile(agentsJsonPath, "utf-8")); - expect(agentsConfig.agents).toHaveLength(1); - expect(agentsConfig.agents[0].env).toBe("test"); - expect(agentsConfig.agents[0].id).toBe(testAgentId); - console.log("✓ Only test agent was pulled"); - - // Step 9: Pull from prod environment - console.log("Step 9: Pulling from prod environment..."); - const pullProdResult = await runCli(["agents", "pull", "--all", "--no-ui", "--env", "prod"], { - cwd: multiEnvTempDir, - includeApiKey: true, - input: "y\n", - }); - expect(pullProdResult.exitCode).toBe(0); - - // Step 10: Check both agents exist - console.log("Step 10: Verifying both agents exist..."); - agentsConfig = JSON.parse(await fs.readFile(agentsJsonPath, "utf-8")); - expect(agentsConfig.agents).toHaveLength(2); - - const pulledProdAgent = agentsConfig.agents.find((a: AgentConfigEntry) => a.id === prodAgentId); - const pulledTestAgent = agentsConfig.agents.find((a: AgentConfigEntry) => a.id === testAgentId); - expect(pulledProdAgent).toBeTruthy(); - expect(pulledTestAgent).toBeTruthy(); - expect(pulledProdAgent.env || 'prod').toBe('prod'); - expect(pulledTestAgent.env).toBe('test'); - console.log("✓ Both agents exist with correct environments"); - - // Step 11: Modify both agents - console.log("Step 11: Modifying both agents..."); - const prodConfigPath = path.join(multiEnvTempDir, pulledProdAgent.config); - const testConfigPath = path.join(multiEnvTempDir, pulledTestAgent.config); - - const prodConfig = JSON.parse(await fs.readFile(prodConfigPath, "utf-8")); - const testConfig = JSON.parse(await fs.readFile(testConfigPath, "utf-8")); - - prodConfig.name = "modified-prod-agent"; - testConfig.name = "modified-test-agent"; - - await fs.writeFile(prodConfigPath, JSON.stringify(prodConfig, null, 2)); - await fs.writeFile(testConfigPath, JSON.stringify(testConfig, null, 2)); - console.log("✓ Modified both agents"); - - // Step 12: Push changes - console.log("Step 12: Pushing changes..."); - const pushResult = await runCli(["agents", "push", "--no-ui"], { - cwd: multiEnvTempDir, - includeApiKey: true, - }); - expect(pushResult.exitCode).toBe(0); - console.log("✓ Pushed changes"); - - // Step 13: Remove local files again - console.log("Step 13: Removing local files..."); - await fs.remove(agentsJsonPath); - await fs.remove(path.join(multiEnvTempDir, "agent_configs")); - - // Step 14: Pull from test environment - console.log("Step 14: Pulling from test environment..."); - await runCli(["agents", "pull", "--all", "--no-ui", "--env", "test"], { - cwd: multiEnvTempDir, - includeApiKey: true, - input: "y\n", - }); - - // Step 15: Confirm test agent was modified - console.log("Step 15: Verifying test agent was modified..."); - agentsConfig = JSON.parse(await fs.readFile(agentsJsonPath, "utf-8")); - expect(agentsConfig.agents).toHaveLength(1); - const modifiedTestConfig = JSON.parse( - await fs.readFile(path.join(multiEnvTempDir, agentsConfig.agents[0].config), "utf-8") - ); - expect(modifiedTestConfig.name).toBe("modified-test-agent"); - console.log("✓ Test agent was modified"); - - // Step 16: Pull from prod environment - console.log("Step 16: Pulling from prod environment..."); - await runCli(["agents", "pull", "--all", "--no-ui", "--env", "prod"], { - cwd: multiEnvTempDir, - includeApiKey: true, - input: "y\n", - }); - - // Step 17: Confirm prod agent was modified - console.log("Step 17: Verifying prod agent was modified..."); - agentsConfig = JSON.parse(await fs.readFile(agentsJsonPath, "utf-8")); - expect(agentsConfig.agents).toHaveLength(2); - const modifiedProdAgent = agentsConfig.agents.find((a: AgentConfigEntry) => a.id === prodAgentId); - const modifiedProdConfig = JSON.parse( - await fs.readFile(path.join(multiEnvTempDir, modifiedProdAgent.config), "utf-8") - ); - expect(modifiedProdConfig.name).toBe("modified-prod-agent"); - console.log("✓ Prod agent was modified"); - - // Step 18: Delete all agents - console.log("Step 18: Deleting all agents..."); - const deleteAllResult = await runCli(["agents", "delete", "--all", "--no-ui"], { - cwd: multiEnvTempDir, - includeApiKey: true, - input: "y\n", - }); - expect(deleteAllResult.exitCode).toBe(0); - - // Verify agents.json is empty - agentsConfig = JSON.parse(await fs.readFile(agentsJsonPath, "utf-8")); - expect(agentsConfig.agents).toHaveLength(0); - console.log("✓ All agents deleted"); - - // Step 19: Pull from both environments - console.log("Step 19: Pulling from both environments..."); - const finalPullResult = await runCli(["agents", "pull", "--all", "--no-ui"], { - cwd: multiEnvTempDir, - includeApiKey: true, - input: "y\n", - }); - expect(finalPullResult.exitCode).toBe(0); - - // Step 20: Confirm nothing was pulled - console.log("Step 20: Verifying nothing was pulled..."); - agentsConfig = JSON.parse(await fs.readFile(agentsJsonPath, "utf-8")); - expect(agentsConfig.agents).toHaveLength(0); - console.log("✓ No agents pulled (both environments empty)"); - - console.log("✓ Multi-environment workflow test completed successfully"); - }); - }); }); diff --git a/src/__tests__/residency.test.ts b/src/__tests__/residency.test.ts index 63ad01f..e97ba15 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 --env prod' to authenticate or set ELEVENLABS_API_KEY environment variable." + "No API key found for environment 'prod'. 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 bb39e95..8486c7e 100644 --- a/src/agents/commands/add.ts +++ b/src/agents/commands/add.ts @@ -14,20 +14,17 @@ interface AgentsConfig { agents: Array<{ config: string; id?: string; - env?: string; }>; } interface AgentDefinition { config: string; id?: string; - env?: string; } interface AddOptions { configPath?: string; template?: string; - env: string; } export function createAddCommand(): Command { @@ -36,7 +33,6 @@ export function createAddCommand(): Command { .argument('[name]', 'Name of the agent to create') .option('--config-path ', 'Custom config path (optional)') .option('--template