@elevenlabs/convai-cli
Version:
CLI tool to manage ElevenLabs conversational AI agents
161 lines • 8.56 kB
JavaScript
import React, { useState, useEffect } from 'react';
import { Box, Text, useApp } from 'ink';
import App from '../App.js';
import StatusCard from '../components/StatusCard.js';
import theme from '../themes/elevenlabs.js';
import { readAgentConfig } from '../../utils.js';
import { loadLockFile } from '../../utils.js';
import path from 'path';
import fs from 'fs-extra';
export const StatusView = ({ agentName, environment, onComplete }) => {
const { exit } = useApp();
const [agents, setAgents] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const loadStatus = async () => {
try {
// Load agents configuration
const agentsConfigPath = path.resolve('agents.json');
if (!(await fs.pathExists(agentsConfigPath))) {
throw new Error('agents.json not found. Run "convai init" first.');
}
const agentsConfig = await readAgentConfig(agentsConfigPath);
const lockFilePath = path.resolve('convai.lock');
const lockData = await loadLockFile(lockFilePath);
const statusList = [];
// Process each agent
for (const agentDef of agentsConfig.agents) {
// Filter by agent name if specified
if (agentName && agentDef.name !== agentName) {
continue;
}
// Handle both old and new config formats
const environments = agentDef.environments || { prod: { config: agentDef.config } };
for (const [env, envConfig] of Object.entries(environments)) {
// Filter by environment if specified
if (environment && env !== environment) {
continue;
}
const configPath = envConfig.config;
const fullConfigPath = path.resolve(configPath);
const configExists = await fs.pathExists(fullConfigPath);
let status = 'missing';
let configHash;
let deployedHash;
let agentId;
if (configExists) {
// Calculate current config hash
const config = await readAgentConfig(fullConfigPath);
const { calculateConfigHash } = await import('../../utils.js');
configHash = calculateConfigHash(config);
// Get deployed info from lock file
const lockKey = `${agentDef.name}_${env}`;
const agentLock = lockData.agents?.[lockKey];
if (agentLock && typeof agentLock === 'object') {
if ('config_hash' in agentLock) {
deployedHash = agentLock.config_hash;
agentId = agentLock.id;
}
else if ('hash' in agentLock) {
deployedHash = agentLock.hash;
agentId = agentLock.id;
}
if (configHash === deployedHash) {
status = 'synced';
}
else {
status = 'modified';
}
}
else {
status = 'not-deployed';
}
}
statusList.push({
name: agentDef.name,
environment: env,
configPath,
configExists,
configHash,
deployedHash,
agentId,
status
});
}
}
setAgents(statusList);
setLoading(false);
}
catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load status');
setLoading(false);
}
};
loadStatus();
// Auto-exit after showing status
const timer = setTimeout(() => {
if (onComplete) {
onComplete();
}
else {
exit();
}
}, 10000); // Show for 10 seconds
return () => clearTimeout(timer);
}, [agentName, environment, exit, onComplete]);
const syncedCount = agents.filter(a => a.status === 'synced').length;
const modifiedCount = agents.filter(a => a.status === 'modified').length;
const notDeployedCount = agents.filter(a => a.status === 'not-deployed').length;
const missingCount = agents.filter(a => a.status === 'missing').length;
return (React.createElement(App, { title: "ElevenLabs Conversational AI", subtitle: "Agent Status", showOverlay: false },
React.createElement(Box, { flexDirection: "column", gap: 1 }, loading ? (React.createElement(StatusCard, { title: "Loading Status", status: "loading", message: "Checking agent configurations..." })) : error ? (React.createElement(StatusCard, { title: "Error", status: "error", message: error })) : agents.length === 0 ? (React.createElement(StatusCard, { title: "No Agents Found", status: "idle", message: "No agents match the specified criteria" })) : (React.createElement(React.Fragment, null,
React.createElement(Box, { marginBottom: 1 },
React.createElement(StatusCard, { title: "Status Summary", status: modifiedCount > 0 ? 'warning' : 'success', message: `${agents.length} agent(s) found`, details: [
`✓ ${syncedCount} synced`,
`⚠ ${modifiedCount} modified`,
`○ ${notDeployedCount} not deployed`,
`✗ ${missingCount} missing`
] })),
React.createElement(Box, { flexDirection: "column", gap: 1 },
React.createElement(Text, { color: theme.colors.text.primary, bold: true }, "Agents:"),
agents.map((agent, index) => {
let status;
let statusText;
let details = [];
switch (agent.status) {
case 'synced':
status = 'success';
statusText = '✓ Synced';
break;
case 'modified':
status = 'warning';
statusText = '⚠ Modified locally';
details.push('Run "convai sync" to update');
break;
case 'not-deployed':
status = 'idle';
statusText = '○ Not deployed';
details.push('Run "convai sync" to deploy');
break;
case 'missing':
status = 'error';
statusText = '✗ Config file missing';
break;
default:
status = 'idle';
statusText = 'Unknown';
}
if (agent.agentId) {
details.push(`ID: ${agent.agentId}`);
}
if (agent.configPath) {
details.push(`Config: ${agent.configPath}`);
}
return (React.createElement(StatusCard, { key: index, title: `${agent.name} (${agent.environment})`, status: status, message: statusText, details: details, borderStyle: "single" }));
})),
React.createElement(Box, { marginTop: 1 },
React.createElement(Text, { color: theme.colors.text.muted }, "Press Ctrl+C to exit (auto-exit in 10s)")))))));
};
export default StatusView;
//# sourceMappingURL=StatusView.js.map