UNPKG

aura-ai

Version:

AI-powered marketing strategist CLI tool for developers

647 lines (635 loc) 28.1 kB
#!/usr/bin/env -S node --no-warnings import { jsxs, jsx, Fragment } from "react/jsx-runtime"; import { useState, useEffect, useRef } from "react"; import { useInput, Box, Text, Spacer, Newline, useApp, Static, render } from "ink"; import { Spinner, Alert } from "@inkjs/ui"; import fs from "fs/promises"; import TextInput from "ink-text-input"; import { I as InitPage, E as EmojiSpinner } from "./page-CHKhZAAX.js"; import SelectInput from "ink-select-input"; import { g as gitService, s as syncAIService, c as chatService } from "./chatService-7b3Ru5ZZ.js"; import path from "path"; import os from "os"; const CommandInput = ({ value, onChange, onSubmit, placeholder = "Type a command or message...", commands = [], exitPrompt = false, onClearInput = null, onExit = null }) => { const [suggestions, setSuggestions] = useState([]); const [showSuggestions, setShowSuggestions] = useState(false); const [selectedIndex, setSelectedIndex] = useState(0); useInput((input, key) => { if (key.ctrl && input === "c") { if (value.length > 0 && onClearInput) { onClearInput(); return; } if (onExit) { onExit(); return; } } if (showSuggestions && suggestions.length > 0) { if (key.upArrow) { setSelectedIndex((prev) => Math.max(0, prev - 1)); return; } if (key.downArrow) { setSelectedIndex((prev) => Math.min(suggestions.length - 1, prev + 1)); return; } if (key.tab) { const selectedCmd = suggestions[selectedIndex]; if (selectedCmd) { onChange(`/${selectedCmd.name}`); setShowSuggestions(false); } return; } } }); useEffect(() => { if (value.startsWith("/")) { const query = value.substring(1).toLowerCase(); const filteredCommands = commands.filter( (cmd) => cmd.name.toLowerCase().includes(query) || cmd.description.toLowerCase().includes(query) ); setSuggestions(filteredCommands); setShowSuggestions(filteredCommands.length > 0); setSelectedIndex(0); } else { setSuggestions([]); setShowSuggestions(false); setSelectedIndex(0); } }, [value, commands]); const handleSubmit = (inputValue) => { if (showSuggestions && suggestions.length > 0) { const selectedCmd = suggestions[selectedIndex]; if (selectedCmd) { setShowSuggestions(false); onSubmit(`/${selectedCmd.name}`); return; } } setShowSuggestions(false); onSubmit(inputValue); }; return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "100%", children: [ /* @__PURE__ */ jsxs(Box, { paddingX: 1, paddingY: 0, borderColor: "whiteBright", borderStyle: "round", width: "100%", children: [ /* @__PURE__ */ jsx(Text, { color: "blue", children: "> " }), /* @__PURE__ */ jsx( TextInput, { value, onChange, onSubmit: handleSubmit, placeholder, focus: true } ) ] }), showSuggestions && suggestions.length > 0 && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, marginBottom: 1, paddingLeft: 2, children: suggestions.map((cmd, index) => /* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexWrap: "wrap", children: [ /* @__PURE__ */ jsx(Box, { width: 16, children: /* @__PURE__ */ jsx(Text, { color: index === selectedIndex ? "blueBright" : "gray", children: /* @__PURE__ */ jsxs(Text, { color: index === selectedIndex ? "blueBright" : "gray", children: [ "/", cmd.name ] }) }) }), /* @__PURE__ */ jsx(Box, { paddingLeft: 3, children: /* @__PURE__ */ jsx(Text, { color: index === selectedIndex ? "blueBright" : "gray", children: cmd.description }) }) ] }, index)) }), /* @__PURE__ */ jsxs(Box, { width: "100%", children: [ /* @__PURE__ */ jsx(Text, { dimColor: true, children: exitPrompt ? /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Press Ctrl+C again to exit" }) : value.startsWith("/") ? /* @__PURE__ */ jsx(Fragment, { children: "Press Enter to continue" }) : /* @__PURE__ */ jsx(Fragment, { children: "Type / for commands" }) }), /* @__PURE__ */ jsx(Spacer, {}), /* @__PURE__ */ jsx(Text, { dimColor: true, children: !exitPrompt && /* @__PURE__ */ jsxs(Fragment, { children: [ " Ctrl+C to ", value ? "clear input" : "exit" ] }) }) ] }) ] }); }; const SettingsPage = ({ onBack }) => { const [mode, setMode] = useState("menu"); const [inputValue, setInputValue] = useState(""); const [currentSetting, setCurrentSetting] = useState(""); const [settings, setSettings] = useState({ avatars: { aura: "🌀", user: ">" } }); useEffect(() => { loadSettings(); }, []); const loadSettings = async () => { try { const data = await fs.readFile("./.aura.json", "utf-8"); setSettings(JSON.parse(data)); } catch { } }; const saveSettings = async (newSettings) => { try { await fs.writeFile("./.aura.json", JSON.stringify(newSettings, null, 2)); } catch (error) { console.error("Failed to save settings:", error); } }; const menuItems = [ { label: `${settings.avatars.aura} Set Aura avatar`, value: "setAura" }, { label: `${settings.avatars.user} Set User avatar`, value: "setUser" }, { label: "Reset to defaults", value: "reset" }, { label: "Exit", value: "exit" } ]; const handleSelect = async (item) => { if (item.value === "exit") { onBack(); } else if (item.value === "reset") { const defaultSettings = { avatars: { aura: "🌀", user: ">" } }; await saveSettings(defaultSettings); setSettings(defaultSettings); onBack(); } else { setCurrentSetting(item.value); setMode("input"); setInputValue(""); } }; const handleAvatarSubmit = async (value) => { if (value && value.length > 0) { const char = value.trim(); const newSettings = { ...settings }; if (currentSetting === "setAura") { newSettings.avatars.aura = char; } else if (currentSetting === "setUser") { newSettings.avatars.user = char; } await saveSettings(newSettings); setSettings(newSettings); setMode("menu"); setInputValue(""); } }; if (mode === "input") { return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [ /* @__PURE__ */ jsx(Box, { paddingY: 1, paddingX: 2, borderColor: "blue", borderStyle: "round", width: "100%", children: /* @__PURE__ */ jsxs(Text, { children: [ /* @__PURE__ */ jsx(Text, { bold: true, children: "Settings" }), " - Avatar Configuration" ] }) }), /* @__PURE__ */ jsxs(Box, { marginTop: 2, flexDirection: "column", children: [ /* @__PURE__ */ jsx(Text, { children: currentSetting === "setAura" ? "Enter new Aura avatar (emoji or text):" : "Enter new User avatar (emoji or text):" }), /* @__PURE__ */ jsxs(Box, { marginTop: 1, paddingX: 1, borderColor: "gray", borderStyle: "single", children: [ /* @__PURE__ */ jsx(Text, { color: "blue", children: "> " }), /* @__PURE__ */ jsx( TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleAvatarSubmit, placeholder: "Enter avatar (e.g., 🐤, >, 👾)...", focus: true } ) ] }), /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press Enter to save, or Ctrl+C to cancel" }) }) ] }) ] }); } return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [ /* @__PURE__ */ jsx(Box, { paddingY: 1, paddingX: 2, borderColor: "blue", borderStyle: "round", width: "100%", children: /* @__PURE__ */ jsxs(Text, { children: [ /* @__PURE__ */ jsx(Text, { bold: true, children: "Settings" }), " - Avatar Configuration" ] }) }), /* @__PURE__ */ jsxs(Box, { marginTop: 2, flexDirection: "column", children: [ /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Select an option:" }), /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(SelectInput, { items: menuItems, onSelect: handleSelect }) }) ] }), /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [ "Current: Aura = ", settings.avatars.aura, " User = ", settings.avatars.user ] }) }) ] }); }; const SyncPage = ({ onBack }) => { const [loading, setLoading] = useState(true); const [report, setReport] = useState(null); const [error, setError] = useState(null); const [showMenu, setShowMenu] = useState(false); const [commits, setCommits] = useState([]); useEffect(() => { loadReport(); }, []); const loadReport = async () => { setLoading(true); setError(null); try { const todayCommits = await gitService.getTodayCommits(); setCommits(todayCommits); const formattedCommits = gitService.formatCommitsForAI(todayCommits); const aiReport = await syncAIService.generateDailyReport(formattedCommits); setReport(aiReport); setShowMenu(true); } catch (err) { setError("Failed to generate report: " + err.message); } finally { setLoading(false); } }; const menuItems = [ { label: "📋 Copy as Markdown", value: "copy" }, { label: "🔄 Refresh", value: "refresh" }, { label: "← Back to Main Menu", value: "back" } ]; const handleSelect = async (item) => { if (item.value === "back") { onBack(); } else if (item.value === "refresh") { setShowMenu(false); await loadReport(); } else if (item.value === "copy") { try { const { exec } = await import("child_process"); const { promisify } = await import("util"); const execAsync = promisify(exec); const platform = process.platform; const markdown = report.markdown; if (platform === "darwin") { await execAsync(`echo "${markdown.replace(/"/g, '\\"').replace(/\$/g, "\\$")}" | pbcopy`); } else if (platform === "linux") { await execAsync(`echo "${markdown.replace(/"/g, '\\"').replace(/\$/g, "\\$")}" | xclip -selection clipboard`); } else if (platform === "win32") { await execAsync(`echo "${markdown.replace(/"/g, '\\"').replace(/\$/g, "\\$")}" | clip`); } setError(`✅ Report copied to clipboard!`); setTimeout(() => setError(null), 3e3); } catch (err) { setError("Failed to copy: " + err.message); setTimeout(() => setError(null), 3e3); } } }; if (loading) { return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [ /* @__PURE__ */ jsx(Box, { paddingY: 1, paddingX: 2, borderColor: "blue", borderStyle: "round", children: /* @__PURE__ */ jsxs(Text, { children: [ /* @__PURE__ */ jsx(Text, { bold: true, children: "🤖 AI Daily Sync" }), " - Generating Intelligence Report..." ] }) }), /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingLeft: 2, children: /* @__PURE__ */ jsx(Spinner, { label: "AI is analyzing your commits..." }) }) ] }); } return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [ /* @__PURE__ */ jsx(Box, { paddingY: 1, paddingX: 2, borderColor: "blue", borderStyle: "round", children: /* @__PURE__ */ jsxs(Text, { children: [ /* @__PURE__ */ jsx(Text, { bold: true, children: "🤖 AI Daily Sync" }), " - Progress Intelligence" ] }) }), error && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Alert, { variant: error.startsWith("✅") ? "success" : "error", children: error }) }), report && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingLeft: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: "📊 Executive Summary" }) }), /* @__PURE__ */ jsx(Box, { marginTop: 1, paddingLeft: 1, children: /* @__PURE__ */ jsx(Text, { children: report.summary }) }), report.highlights && report.highlights.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingLeft: 1, children: /* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "✨ Key Achievements" }) }), report.highlights.map((highlight, index) => /* @__PURE__ */ jsx(Box, { paddingLeft: 2, children: /* @__PURE__ */ jsxs(Text, { children: [ "• ", highlight ] }) }, index)) ] }), commits.length > 0 && /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingLeft: 1, children: /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [ "Based on ", commits.length, " commits today" ] }) }), showMenu && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingLeft: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "What would you like to do?" }) }), /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(SelectInput, { items: menuItems, onSelect: handleSelect }) }) ] }) ] }), commits.length === 0 && /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingLeft: 1, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [ /* @__PURE__ */ jsx(Text, { color: "gray", children: "No commits found today yet!" }), /* @__PURE__ */ jsx(Newline, {}), /* @__PURE__ */ jsx(Text, { color: "gray", children: "Start working on your project and come back later." }), /* @__PURE__ */ jsx(Newline, {}), /* @__PURE__ */ jsx(Text, { dimColor: true, children: "💡 AI will analyze and summarize your work intelligently." }) ] }) }) ] }); }; const AddAuraAgentPage = ({ onBack }) => { const [status, setStatus] = useState("installing"); const [error, setError] = useState(null); const [targetPath, setTargetPath] = useState(""); useInput((input, key) => { if (key.return && (status === "success" || status === "error")) { onBack(); } }); useEffect(() => { installAgent(); }, []); const installAgent = async () => { try { const homeDir = os.homedir(); const claudeAgentsDir = path.join(homeDir, ".claude", "agents"); try { await fs.access(claudeAgentsDir); } catch { await fs.mkdir(claudeAgentsDir, { recursive: true }); } const auraAgentSource = `--- name: aura description: Marketing AI agent that uses Aura CLI for product analysis, daily reports, and marketing insights tools: Bash model: sonnet color: cyan --- You are Aura, a marketing AI assistant that uses the Aura CLI tool via npx. ## Quick Command Reference \`\`\`bash # Daily sync report (saves file, prints, copies to clipboard) npx aura-ai sync --json # Marketing consultation npx aura-ai chat "your question" --json # Product analysis (one-time setup) npx aura-ai init --answers "product|audience|value" --json # View settings npx aura-ai settings --list --json \`\`\` ## How to Respond 1. **User says "sync"** → Run: \`npx aura-ai sync --json\` - Creates \`YYYY-M-D-update.md\` file automatically - Prints full report to terminal - Auto-copies to clipboard - Tell user: "Report generated, saved to [filename], and copied to clipboard" 2. **User asks marketing question** → Run: \`npx aura-ai chat "question" --json\` 3. **User wants product analysis** → Check if aura.md exists, if not run: \`npx aura-ai init --answers "..." --json\` ## Important - No installation needed! Uses npx to run directly - Sync command creates dated markdown files (e.g., \`2025-8-8-update.md\`) - All content is visible in terminal output - Reports are automatically saved and copied - Just run commands, don't read files`; const target = path.join(claudeAgentsDir, "aura.md"); await fs.writeFile(target, auraAgentSource); setTargetPath(target); setStatus("success"); } catch (err) { setError(err.message); setStatus("error"); } }; if (status === "installing") { return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [ /* @__PURE__ */ jsx(Box, { paddingY: 1, paddingX: 2, borderColor: "blue", borderStyle: "round", children: /* @__PURE__ */ jsxs(Text, { children: [ /* @__PURE__ */ jsx(Text, { bold: true, children: "Installing Aura Agent" }), " to Claude" ] }) }), /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingLeft: 2, children: /* @__PURE__ */ jsx(Spinner, { label: "Setting up agent..." }) }) ] }); } if (status === "error") { return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [ /* @__PURE__ */ jsx(Box, { paddingY: 1, paddingX: 2, borderColor: "red", borderStyle: "round", children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx(Text, { bold: true, color: "red", children: "Installation Failed" }) }) }), /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Alert, { variant: "error", children: error }) }), /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press Enter to continue..." }) }) ] }); } return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [ /* @__PURE__ */ jsx(Box, { paddingY: 1, paddingX: 2, borderColor: "green", borderStyle: "round", children: /* @__PURE__ */ jsx(Text, { children: /* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: "✅ Aura Agent Installed!" }) }) }), /* @__PURE__ */ jsxs(Box, { marginTop: 2, flexDirection: "column", children: [ /* @__PURE__ */ jsx(Alert, { variant: "success", children: "Agent successfully installed to Claude" }), /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingLeft: 1, children: /* @__PURE__ */ jsxs(Text, { children: [ "📄 Location: ", /* @__PURE__ */ jsx(Text, { color: "cyan", children: targetPath }) ] }) }), /* @__PURE__ */ jsx(Box, { marginTop: 2, paddingX: 2, paddingY: 1, borderColor: "yellow", borderStyle: "single", children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "⚠️ IMPORTANT: Please restart Claude to load the new agent" }) }), /* @__PURE__ */ jsxs(Box, { marginTop: 2, paddingLeft: 1, flexDirection: "column", children: [ /* @__PURE__ */ jsx(Text, { bold: true, children: "🎯 After restarting Claude, you can use:" }), /* @__PURE__ */ jsx(Text, { color: "gray", children: " • @aura sync - Generate daily reports" }), /* @__PURE__ */ jsx(Text, { color: "gray", children: " • @aura help me with marketing - Get marketing advice" }), /* @__PURE__ */ jsx(Text, { color: "gray", children: " • @aura analyze my product - Product analysis" }) ] }), /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Press Enter to continue..." }) }) ] }) ] }); }; const App = () => { const [inputValue, setInputValue] = useState(""); const [exitPrompt, setExitPrompt] = useState(false); const [currentRoute, setCurrentRoute] = useState("home"); const [hasAuraConfig, setHasAuraConfig] = useState(false); const [settings, setSettings] = useState({ avatars: { aura: "🌀", user: ">" } }); const lastCtrlC = useRef(0); const { exit } = useApp(); const [messages, setMessages] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); useEffect(() => { const checkAuraConfig = async () => { try { await fs.access("./aura.md"); setHasAuraConfig(true); } catch { setHasAuraConfig(false); } }; const loadSettings = async () => { try { const data = await fs.readFile("./.aura.json", "utf-8"); setSettings(JSON.parse(data)); } catch { } }; checkAuraConfig(); loadSettings(); }, []); const availableCommands = [ { name: "init", description: "Analyze my product and generate a marketing strategy" }, { name: "sync", description: "Generate today's progress report from git commits" }, { name: "today", description: "[DEMO] Check today's marketing report and recommended actions" }, { name: "post", description: "[DEMO] Tweet, blog post, email, short video, etc" }, { name: "settings", description: "Manage your Aura settings" }, { name: "add-aura-agent", description: "Install Aura agent to Claude for @aura commands" } ]; const handleClearInput = () => { setInputValue(""); setExitPrompt(false); }; const handleExit = () => { const now = Date.now(); if (now - lastCtrlC.current < 2e3) { exit(); } else { setExitPrompt(true); lastCtrlC.current = now; setTimeout(() => { setExitPrompt(false); }, 2e3); } }; const handleSubmit = (value) => { if (value.trim()) { const trimmedValue = value.trim(); if (trimmedValue.startsWith("/")) { const command = trimmedValue.substring(1).toLowerCase(); if (command === "init") { setCurrentRoute("init"); } else if (command === "settings") { setCurrentRoute("settings"); } else if (command === "sync") { setCurrentRoute("sync"); } else if (command === "add-aura-agent") { setCurrentRoute("add-aura-agent"); } setInputValue(""); } else { const userMessage = { id: Date.now().toString(), role: "user", content: trimmedValue }; setMessages((prev) => [...prev, userMessage]); setError(null); setIsLoading(true); chatService.sendMessage([...messages, userMessage]).then(async (stream) => { let fullContent = ""; const assistantMessageId = (Date.now() + 1).toString(); setMessages((prev) => [...prev, { id: assistantMessageId, role: "assistant", content: "" }]); for await (const chunk of stream.textStream) { fullContent += chunk; setMessages((prev) => prev.map( (msg) => msg.id === assistantMessageId ? { ...msg, content: fullContent } : msg )); } setIsLoading(false); }).catch((err) => { console.error("Chat error:", err); setError(err.message); if (err.message.includes("API key not configured")) { setMessages((prev) => [...prev, { id: (Date.now() + 1).toString(), role: "assistant", content: "⚠️ OpenAI API key not configured. Please set OPENAI_API_KEY in your .env file to enable AI chat." }]); } else { setMessages((prev) => [...prev, { id: (Date.now() + 1).toString(), role: "assistant", content: hasAuraConfig ? "Based on your product analysis, I recommend focusing on content marketing to build authority in your niche. Start with educational blog posts that solve your target audience's pain points." : "I'm using demo analysis results. Run /init to analyze your product for personalized marketing insights! Meanwhile, I can help with general marketing strategies." }]); } setIsLoading(false); }); setInputValue(""); } setExitPrompt(false); } }; const handleBack = () => { setCurrentRoute("home"); }; if (currentRoute === "init") { return /* @__PURE__ */ jsx(InitPage, { onBack: handleBack }); } if (currentRoute === "settings") { return /* @__PURE__ */ jsx(SettingsPage, { onBack: () => { const loadSettings = async () => { try { const data = await fs.readFile("./.aura.json", "utf-8"); setSettings(JSON.parse(data)); } catch { } }; loadSettings(); handleBack(); } }); } if (currentRoute === "sync") { return /* @__PURE__ */ jsx(SyncPage, { onBack: handleBack }); } if (currentRoute === "add-aura-agent") { return /* @__PURE__ */ jsx(AddAuraAgentPage, { onBack: handleBack }); } return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, children: [ /* @__PURE__ */ jsx(Box, { paddingY: 1, paddingX: 2, borderColor: "blue", borderStyle: "round", width: "100%", children: /* @__PURE__ */ jsxs(Text, { children: [ "🌀 Welcome to ", /* @__PURE__ */ jsx(Text, { bold: true, children: "Aura!" }), /* @__PURE__ */ jsx(Newline, {}), /* @__PURE__ */ jsx(Newline, {}), /* @__PURE__ */ jsx(Text, { color: "white", dimColor: true, children: "Your AI marketing companion" }) ] }) }), /* @__PURE__ */ jsxs(Box, { marginTop: 1, paddingLeft: 1, flexDirection: "column", children: [ /* @__PURE__ */ jsx(Text, { color: "gray", children: "Tips for getting started:" }), /* @__PURE__ */ jsx(Newline, {}), /* @__PURE__ */ jsx(Text, { color: "gray", children: " 1. Run /init to analyze your product and create a marketing strategy" }), /* @__PURE__ */ jsx(Text, { color: "gray", children: " 2. Chat directly with Aura for marketing insights and recommendations" }), /* @__PURE__ */ jsx(Text, { color: "gray", children: " 3. Be as specific as you would with a marketing expert for best results" }), /* @__PURE__ */ jsx(Text, { color: "gray", children: " 4. ✓ View available commands by typing /" }) ] }), !hasAuraConfig && messages.length > 0 && /* @__PURE__ */ jsx(Static, { items: [{ id: "demo-alert" }], children: () => /* @__PURE__ */ jsx(Box, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsx(Alert, { variant: "warning", children: "You're chatting with demo analysis results. Run /init for personalized insights." }) }) }), error && /* @__PURE__ */ jsx(Static, { items: [{ id: "error-alert" }], children: () => /* @__PURE__ */ jsx(Box, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsx(Alert, { variant: "error", children: error }) }) }), messages.length > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 2, marginBottom: 1, paddingLeft: 1, children: [ messages.filter((m) => m.role !== "system").map((msg) => /* @__PURE__ */ jsxs(Box, { marginBottom: 1, flexDirection: "row", children: [ /* @__PURE__ */ jsx(Box, { width: 2, flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { children: msg.role === "user" ? settings.avatars.user : settings.avatars.aura }) }), /* @__PURE__ */ jsx(Box, { flexGrow: 1, paddingLeft: 1, children: msg.role === "user" ? /* @__PURE__ */ jsx(Text, { children: msg.content }) : /* @__PURE__ */ jsx(Text, { color: "white", children: msg.content }) }) ] }, msg.id)), isLoading && /* @__PURE__ */ jsx(EmojiSpinner, { label: "Aura is thinking..." }) ] }), /* @__PURE__ */ jsx(Box, { marginTop: messages.length === 0 ? 2 : 1, children: /* @__PURE__ */ jsx( CommandInput, { value: inputValue, onChange: setInputValue, onSubmit: handleSubmit, placeholder: "Type a command or message...", commands: availableCommands, exitPrompt, onClearInput: handleClearInput, onExit: handleExit } ) }) ] }); }; function runInteractive() { const { waitUntilExit } = render(/* @__PURE__ */ jsx(App, {}), { exitOnCtrlC: false // Disable automatic exit on Ctrl+C }); return waitUntilExit(); } if (import.meta.url === `file://${process.argv[1]}`) { runInteractive(); } export { runInteractive as default }; //# sourceMappingURL=rina.js.map