UNPKG

trace.ai-cli

Version:

A powerful AI-powered CLI tool

286 lines (247 loc) 8.99 kB
const chalk = require('chalk'); const gradientModule = require('gradient-string'); const { createSpinner } = require('nanospinner'); const gradient = gradientModule.default || gradientModule; const STYLED_OUTPUT = Boolean(process.stdout && process.stdout.isTTY); const INTERACTIVE_OUTPUT = STYLED_OUTPUT && Boolean(process.stdin && process.stdin.isTTY); const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const tone = (formatter) => (value) => { const text = String(value); return STYLED_OUTPUT ? formatter(text) : text; }; const applyGradient = (renderer, text) => { const value = String(text); return STYLED_OUTPUT ? renderer(value) : value; }; const applyGradientMultiline = (renderer, text) => { const value = String(text); return STYLED_OUTPUT ? renderer.multiline(value) : value; }; const palette = { text: tone(chalk.hex('#E7EEF7')), muted: tone(chalk.hex('#7E8A9A')), subtle: tone(chalk.hex('#A7B4C2')), border: tone(chalk.hex('#4E4A86')), accent: tone(chalk.hex('#FF5FD2')), accentSoft: tone(chalk.hex('#8DA2FF')), success: tone(chalk.hex('#3DDB9A')), warning: tone(chalk.hex('#FFBF69')), danger: tone(chalk.hex('#FF7B72')), focusBg: tone(chalk.bgHex('#261C4D').hex('#F8F5FF')), chipBg: tone(chalk.bgHex('#1C1A45').hex('#B3C0FF')), command: tone(chalk.hex('#C793FF').bold), heading: tone(chalk.hex('#9EB6FF').bold), label: tone(chalk.hex('#C1B6F8')), }; const brandGradient = gradient(['#FF5FD2', '#6EA8FF', '#8B5CFF']); const accentGradient = gradient(['#F472E6', '#7AA2FF', '#A78BFA']); function divider(width = 72) { return palette.border('-'.repeat(Math.max(24, Math.min(width, 88)))); } function highlight(text) { return palette.focusBg(` ${text} `); } function commandRow(cmd, desc, width = 25) { return ` ${palette.command(cmd.padEnd(width))} ${palette.muted(desc)}`; } function sectionHeader(title, width = 58) { return `${palette.heading(title.toUpperCase())}\n${divider(width)}`; } function infoLine(label, value, valueTone = palette.text) { return `${palette.label(`${label}:`)} ${valueTone(value)}`; } function prompt(activeCount, totalCount) { const context = activeCount > 0 ? palette.chipBg(` ${activeCount}/${totalCount} ctx `) : ''; const spacer = context ? ' ' : ''; return `${applyGradient(brandGradient, 'Trace.AI')}${spacer}${context} ${palette.border('>')} `; } function promptPlain(activeCount, totalCount) { const context = activeCount > 0 ? `[${activeCount}/${totalCount} ctx] ` : ''; return `Trace.AI ${context}> `; } function hero(asciiArt, version) { const lines = [ applyGradientMultiline(brandGradient, asciiArt), palette.heading('AI powered CLI Platform'), palette.muted(`v${version} | Powered by Mixkey`), divider(process.stdout.columns || 72), ]; return lines.join('\n'); } function welcomeBlock(commands) { const lines = [ sectionHeader('Quick Start', 54), `${palette.accent('1.')} ${palette.text('Run ')}${palette.command('/help')}${palette.text(' to inspect the full command surface.')}`, `${palette.accent('2.')} ${palette.text('Add files or folders as memory before asking targeted questions.')}`, `${palette.accent('3.')} ${palette.text('Use clear, task-shaped prompts for better agent execution.')}`, '', sectionHeader('Available Commands', 54), ...commands.map(({ cmd, desc }) => commandRow(cmd, desc)), divider(54), ]; return lines.join('\n'); } function statusBlock({ userName, modeName, contextCount, activeCount }) { const lines = [ '', sectionHeader('Session', 54), `${palette.label('User')} ${palette.text(userName)} ${palette.border('|')} ${palette.label('Mode')} ${palette.accentSoft(modeName)} ${palette.border('|')} ${palette.label('Memories')} ${palette.text(String(contextCount))} ${palette.border('|')} ${palette.label('Active')} ${palette.text(String(activeCount))}`, divider(54), ]; return lines.join('\n'); } function memoriesBlock(contexts, activeMemories) { const lines = []; if (contexts.length === 0) { lines.push('', highlight('NO MEMORY'), palette.muted('Add a file, folder, or quoted text to build reusable context.')); } else { lines.push('', sectionHeader('Memories', 54)); contexts.forEach((ctx, index) => { const num = index + 1; const isActive = activeMemories.has(num); const preview = ctx.content.substring(0, 80).replace(/\n/g, ' '); const truncated = ctx.content.length > 80 ? '...' : ''; lines.push(`${isActive ? palette.success('[active]') : palette.border('[idle]')} ${palette.command(`[${num}]`)} ${palette.muted(ctx.timestamp)}`); lines.push(` ${palette.text(preview)}${palette.muted(truncated)}`); if (index < contexts.length - 1) lines.push(''); }); lines.push(divider(54)); } return lines.join('\n'); } function statsBlock({ minutes, seconds, queryCount, contextCount, width, startedAt }) { const lines = [ '', sectionHeader('Session Statistics', 42), infoLine('Session Duration', `${minutes}m ${seconds}s`), infoLine('Total Queries', String(queryCount)), infoLine('Active Memories', String(contextCount)), infoLine('Terminal Width', String(width)), infoLine('Started', startedAt), divider(42), ]; return lines.join('\n'); } function resultHeader(title, filePath) { const lines = [ '', applyGradient(accentGradient, title.toUpperCase()), filePath ? palette.muted(`Source: ${filePath}`) : null, divider(60), ].filter(Boolean); return lines.join('\n'); } function resultFooter() { return `${divider(60)}\n`; } function errorBlock(message) { return `\n${palette.danger('Error:')} ${palette.text(message)}\n`; } function helpBlock(commands, title = 'All Available Commands', width = 60) { const lines = [ '', sectionHeader(title, width), ...commands.map(({ cmd, desc }) => commandRow(cmd, desc)), divider(width), ]; return lines.join('\n'); } function dropdownHint(text) { return palette.muted(text); } function dropdownGroup(label) { return palette.heading(` ${label}/`); } function dropdownFileItem(name, selected, checked) { const prefix = selected ? palette.accent(' > ') : ' '; const check = checked ? palette.success('[x]') : palette.border('[ ]'); const label = selected ? highlight(name) : palette.text(name); return `${prefix}${check} ${label}`; } function dropdownAgentItem(name, desc, selected) { const prefix = selected ? palette.accent(' > ') : ' '; const label = selected ? highlight(name) : palette.text(name); return `${prefix}${label} ${palette.muted(desc)}`; } function dropdownCommandItem(cmd, desc, selected, width = 20) { const prefix = selected ? palette.accent(' ') : ' '; const line = `${cmd.padEnd(width)} ${desc}`; return `${prefix}${selected ? highlight(line) : palette.muted(line)}`; } async function playBootSequence(messages) { if (messages.length === 0) { return; } if (!INTERACTIVE_OUTPUT) { process.stdout.write(`${palette.success('Ready')} ${palette.text('Trace.AI initialized successfully')}\n`); return; } const spinner = createSpinner(palette.text(messages[0])).start(); for (let index = 1; index < messages.length; index++) { await wait(360); spinner.update({ text: palette.text(messages[index]) }); } await wait(240); spinner.success({ text: `${palette.success('Ready')} ${palette.text('Trace.AI initialized successfully')}` }); } async function playTaglineAnimation(text, duration = 700) { if (!INTERACTIVE_OUTPUT) { process.stdout.write(`${text}\n`); return; } await wait(Math.min(duration, 180)); process.stdout.write(`${palette.heading(text)}\n`); } function startSpinner(message) { if (!INTERACTIVE_OUTPUT) { return { success: ({ text }) => process.stdout.write(`${text}\n`), error: ({ text }) => process.stdout.write(`${text}\n`), }; } return createSpinner(palette.text(message)).start(); } function stopSpinnerSuccess(spinner, message) { spinner.success({ text: `${palette.text(message)} ${palette.muted('- complete')}` }); } function stopSpinnerError(spinner, message) { spinner.error({ text: `${palette.text(message)} ${palette.muted('- failed')}` }); } function farewell(asciiArt, summary) { const lines = [ '', applyGradientMultiline(accentGradient, asciiArt), divider(54), palette.heading('Session Closed'), ...summary.map((line) => palette.muted(line)), divider(54), palette.accent('traceai.netlify.app'), ]; return lines.join('\n'); } module.exports = { palette, divider, prompt, promptPlain, hero, welcomeBlock, statusBlock, memoriesBlock, statsBlock, resultHeader, resultFooter, errorBlock, helpBlock, dropdownHint, dropdownGroup, dropdownFileItem, dropdownAgentItem, dropdownCommandItem, playBootSequence, playTaglineAnimation, startSpinner, stopSpinnerSuccess, stopSpinnerError, farewell, };