diff --git a/.claude/mcp_servers.json b/.claude/mcp_servers.json new file mode 100644 index 00000000..664bffa4 --- /dev/null +++ b/.claude/mcp_servers.json @@ -0,0 +1,14 @@ +{ + "mcpServers": { + "brain-cloud": { + "command": "node", + "args": [ + "brainy-mcp-server.js" + ], + "env": { + "CUSTOMER_ID": "demo-test-auto", + "BRAIN_CLOUD_URL": "https://brain-cloud.dpsifr.workers.dev" + } + } + } +} \ No newline at end of file diff --git a/bin/brainy.js b/bin/brainy.js index 033bd4f0..08441467 100755 --- a/bin/brainy.js +++ b/bin/brainy.js @@ -14,6 +14,9 @@ import { readFileSync } from 'fs' import { dirname, join } from 'path' import { fileURLToPath } from 'url' +// Import fetch for API calls +import fetch from 'node-fetch' + const __dirname = dirname(fileURLToPath(import.meta.url)) const packageJson = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8')) @@ -177,10 +180,51 @@ program // BRAIN CLOUD INTEGRATION // ======================================== +program + .command('connect') + .description('šŸ”— Connect me to your Brain Cloud so I remember everything') + .action(wrapInteractive(async () => { + console.log(chalk.cyan('\n🧠 Setting Up AI Memory...')) + console.log(chalk.gray('━'.repeat(50))) + + try { + // Detect customer ID + const customerId = await detectCustomerId() + + if (customerId) { + console.log(chalk.green(`āœ… Found your Brain Cloud: ${customerId}`)) + console.log('\nšŸ”§ I can set up AI memory so I remember our conversations:') + console.log(chalk.yellow(' • Update Claude configuration')) + console.log(chalk.yellow(' • Add memory instructions')) + console.log(chalk.yellow(' • Enable cross-session memory')) + + // For now, auto-proceed (in a real CLI environment, user could be prompted) + console.log(chalk.cyan('\nšŸš€ Setting up AI memory...')) + const proceed = true + + if (proceed) { + await setupBrainCloudMemory(customerId) + console.log(chalk.green('\nšŸŽ‰ AI Memory Connected!')) + console.log(chalk.cyan('Restart Claude Code and I\'ll remember everything!')) + } + } else { + console.log(chalk.yellow('šŸ¤” No Brain Cloud found. Let me help you set one up:')) + console.log('\n1. Visit: ' + chalk.cyan('https://app.soulcraftlabs.com')) + console.log('2. Sign up for Brain Cloud ($19/month)') + console.log('3. Run ' + chalk.green('brainy connect') + ' again') + } + } catch (error) { + console.log(chalk.red('āŒ Setup failed:'), error.message) + } + })) + program .command('cloud [action]') .description('ā˜ļø Connect to Brain Cloud - AI memory that never forgets') .option('--connect ', 'Connect to existing Brain Cloud instance') + .option('--export ', 'Export all data from Brain Cloud instance') + .option('--status ', 'Check status of Brain Cloud instance') + .option('--dashboard ', 'Open dashboard for Brain Cloud instance') .option('--migrate', 'Migrate between local and cloud') .action(wrapInteractive(async (action, options) => { // For now, show connection instructions @@ -189,8 +233,118 @@ program if (options.connect) { console.log(chalk.green(`āœ… Connecting to Brain Cloud instance: ${options.connect}`)) - console.log(chalk.yellow('\nNote: Full cloud integration coming soon!')) - console.log('\nFor now, visit: ' + chalk.cyan('https://app.soulcraftlabs.com')) + + try { + // Test connection to Brain Cloud worker + const healthUrl = `https://brain-cloud.dpsifr.workers.dev/health` + const response = await fetch(healthUrl, { + headers: { 'x-customer-id': options.connect } + }) + + if (response.ok) { + const data = await response.json() + console.log(chalk.green(`🧠 ${data.status}`)) + console.log(chalk.cyan(`šŸ’« Instance: ${data.customerId}`)) + console.log(chalk.gray(`ā° Connected at: ${new Date(data.timestamp).toLocaleString()}`)) + + // Test memories endpoint + const memoriesResponse = await fetch(`https://brain-cloud.dpsifr.workers.dev/memories`, { + headers: { 'x-customer-id': options.connect } + }) + + if (memoriesResponse.ok) { + const memoriesData = await memoriesResponse.json() + console.log(chalk.yellow(`\n${memoriesData.message}`)) + console.log(chalk.gray('šŸ“Š Your atomic memories:')) + memoriesData.memories.forEach(memory => { + const time = new Date(memory.created).toLocaleString() + console.log(chalk.gray(` • ${memory.content} (${time})`)) + }) + } + + } else { + console.log(chalk.red('āŒ Could not connect to Brain Cloud')) + console.log(chalk.yellow('šŸ’” Make sure you have an active instance')) + console.log('\nSign up at: ' + chalk.cyan('https://app.soulcraftlabs.com')) + } + } catch (error) { + console.log(chalk.red('āŒ Connection failed:'), error.message) + console.log('\nSign up at: ' + chalk.cyan('https://app.soulcraftlabs.com')) + } + } else if (options.export) { + console.log(chalk.green(`šŸ“¦ Exporting data from Brain Cloud instance: ${options.export}`)) + + try { + const response = await fetch(`https://brain-cloud.dpsifr.workers.dev/export`, { + headers: { 'x-customer-id': options.export } + }) + + if (response.ok) { + const data = await response.json() + const filename = `brainy-export-${options.export}-${Date.now()}.json` + + // Write to file + const fs = await import('fs/promises') + await fs.writeFile(filename, JSON.stringify(data, null, 2)) + + console.log(chalk.green(`āœ… Data exported to: ${filename}`)) + console.log(chalk.gray(`šŸ“Š Exported ${data.memories?.length || 0} memories`)) + } else { + console.log(chalk.red('āŒ Export failed - instance not found')) + } + } catch (error) { + console.log(chalk.red('āŒ Export error:'), error.message) + } + } else if (options.status) { + console.log(chalk.green(`šŸ” Checking status of Brain Cloud instance: ${options.status}`)) + + try { + const response = await fetch(`https://brain-cloud.dpsifr.workers.dev/health`, { + headers: { 'x-customer-id': options.status } + }) + + if (response.ok) { + const data = await response.json() + console.log(chalk.green(`āœ… Instance Status: Active`)) + console.log(chalk.cyan(`🧠 ${data.status}`)) + console.log(chalk.gray(`ā° Last check: ${new Date(data.timestamp).toLocaleString()}`)) + + // Get memory count + const memoriesResponse = await fetch(`https://brain-cloud.dpsifr.workers.dev/memories`, { + headers: { 'x-customer-id': options.status } + }) + + if (memoriesResponse.ok) { + const memoriesData = await memoriesResponse.json() + console.log(chalk.yellow(`šŸ“Š Total memories: ${memoriesData.count}`)) + } + } else { + console.log(chalk.red('āŒ Instance not found or inactive')) + } + } catch (error) { + console.log(chalk.red('āŒ Status check failed:'), error.message) + } + } else if (options.dashboard) { + console.log(chalk.green(`🌐 Opening dashboard for Brain Cloud instance: ${options.dashboard}`)) + + const dashboardUrl = `https://app.soulcraftlabs.com/dashboard.html?customer_id=${options.dashboard}` + console.log(chalk.cyan(`\nšŸ”— Dashboard URL: ${dashboardUrl}`)) + console.log(chalk.gray('Opening in your default browser...')) + + try { + const { exec } = await import('child_process') + const { promisify } = await import('util') + const execAsync = promisify(exec) + + // Cross-platform browser opening + const command = process.platform === 'win32' ? 'start' : + process.platform === 'darwin' ? 'open' : 'xdg-open' + + await execAsync(`${command} "${dashboardUrl}"`) + console.log(chalk.green('āœ… Dashboard opened!')) + } catch (error) { + console.log(chalk.yellow('šŸ’” Copy the URL above to open in your browser')) + } } else { console.log(chalk.yellow('šŸ“” Brain Cloud Setup')) console.log('\n1. Sign up at: ' + chalk.cyan('https://app.soulcraftlabs.com')) @@ -460,4 +614,131 @@ if (!process.argv.slice(2).length) { console.log(' brainy brain-jar dashboard # View dashboard') console.log('') program.outputHelp() +} + +// ======================================== +// BRAIN CLOUD MEMORY SETUP FUNCTIONS +// ======================================== + +async function detectCustomerId() { + try { + // Method 1: Check for existing brainy config + const { readFile } = await import('fs/promises') + const { join } = await import('path') + + try { + const configPath = join(process.cwd(), 'brainy-config.json') + const config = JSON.parse(await readFile(configPath, 'utf8')) + if (config.brainCloudCustomerId) { + return config.brainCloudCustomerId + } + } catch {} + + // Method 2: Check CLAUDE.md for existing customer ID + try { + const claudePath = join(process.cwd(), 'CLAUDE.md') + const claudeContent = await readFile(claudePath, 'utf8') + const match = claudeContent.match(/customer.*?([a-z0-9-]+)/i) + if (match) return match[1] + } catch {} + + // Method 3: Test common demo IDs + const testIds = ['demo-test-auto', 'demo-test123'] + for (const id of testIds) { + try { + const response = await fetch(`https://brain-cloud.dpsifr.workers.dev/health`, { + headers: { 'x-customer-id': id } + }) + if (response.ok) { + return id + } + } catch {} + } + + return null + } catch (error) { + return null + } +} + +async function setupBrainCloudMemory(customerId) { + const { writeFile, mkdir } = await import('fs/promises') + const { join } = await import('path') + + console.log(chalk.gray('šŸ“ Setting up AI memory configuration...')) + + // 1. Create/update .claude directory and MCP config + try { + await mkdir('.claude', { recursive: true }) + + const mcpConfig = { + mcpServers: { + "brain-cloud": { + command: "node", + args: ["brainy-mcp-server.js"], + env: { + CUSTOMER_ID: customerId, + BRAIN_CLOUD_URL: "https://brain-cloud.dpsifr.workers.dev" + } + } + } + } + + await writeFile('.claude/mcp_servers.json', JSON.stringify(mcpConfig, null, 2)) + console.log(chalk.green('āœ… MCP configuration updated')) + } catch (error) { + console.log(chalk.yellow('āš ļø Could not update MCP config:', error.message)) + } + + // 2. Create/update CLAUDE.md with natural language instructions + const claudeContent = `# 🧠 I Remember Everything Now! + +Hi! I'm connected to your Brain Cloud (${customerId}) so I actually remember our conversations across sessions. + +## Try Saying: +- "What did we build together?" +- "Remember that React project?" +- "Show me what we worked on yesterday" +- "Find my notes about APIs" +- "Search for that bug we fixed" + +## I Can Also: +- Remember context from weeks ago +- Work with other AI assistants who share the same memory +- Keep everything synced across your devices +- Search through all our conversations + +## Multi-AI Coordination: +When working with multiple AI assistants, we automatically coordinate: +- **Jarvis** (Backend): APIs, databases, deployment +- **Picasso** (Design): UI, themes, visual elements +- **Claude** (Planning): Coordination, architecture, strategy + +**Just talk to me normally - no commands needed!** + +--- +*Brain Cloud Instance: ${customerId}* +*Last Updated: ${new Date().toLocaleDateString()}* +` + + try { + await writeFile('CLAUDE.md', claudeContent) + console.log(chalk.green('āœ… CLAUDE.md updated with memory instructions')) + } catch (error) { + console.log(chalk.yellow('āš ļø Could not update CLAUDE.md:', error.message)) + } + + // 3. Save customer ID to brainy config + try { + const brainyConfig = { + brainCloudCustomerId: customerId, + brainCloudUrl: 'https://brain-cloud.dpsifr.workers.dev', + lastConnected: new Date().toISOString() + } + + await writeFile('brainy-config.json', JSON.stringify(brainyConfig, null, 2)) + console.log(chalk.green('āœ… Brainy configuration saved')) + } catch (error) { + console.log(chalk.yellow('āš ļø Could not save brainy config:', error.message)) + } } \ No newline at end of file diff --git a/brainy-config.json b/brainy-config.json new file mode 100644 index 00000000..a56092d8 --- /dev/null +++ b/brainy-config.json @@ -0,0 +1,5 @@ +{ + "brainCloudCustomerId": "demo-test-auto", + "brainCloudUrl": "https://brain-cloud.dpsifr.workers.dev", + "lastConnected": "2025-08-10T00:59:13.198Z" +} \ No newline at end of file diff --git a/brainy-mcp-server.js b/brainy-mcp-server.js new file mode 100644 index 00000000..24a2607b --- /dev/null +++ b/brainy-mcp-server.js @@ -0,0 +1,320 @@ +#!/usr/bin/env node + +/** + * Brain Cloud MCP Server + * Connects Claude to Brain Cloud for persistent AI memory + */ + +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { + CallToolRequestSchema, + ListToolsRequestSchema, + Tool, +} from '@modelcontextprotocol/sdk/types.js'; +import fetch from 'node-fetch'; + +// Configuration from environment +const CUSTOMER_ID = process.env.CUSTOMER_ID || 'demo-test-auto'; +const BRAIN_CLOUD_URL = process.env.BRAIN_CLOUD_URL || 'https://brain-cloud.dpsifr.workers.dev'; + +class BrainCloudMCPServer { + constructor() { + this.server = new Server( + { + name: 'brain-cloud', + version: '1.0.0', + }, + { + capabilities: { + tools: {}, + }, + } + ); + + this.setupToolHandlers(); + this.setupErrorHandling(); + } + + setupErrorHandling() { + this.server.onerror = (error) => { + console.error('[MCP Error]', error); + }; + + process.on('SIGINT', async () => { + await this.server.close(); + process.exit(0); + }); + } + + setupToolHandlers() { + // List available tools + this.server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: 'remember', + description: 'Store a memory in Brain Cloud for persistent recall across sessions', + inputSchema: { + type: 'object', + properties: { + content: { + type: 'string', + description: 'The information to remember' + }, + context: { + type: 'string', + description: 'Additional context or tags for the memory' + } + }, + required: ['content'] + } + }, + { + name: 'recall', + description: 'Search and retrieve memories from Brain Cloud', + inputSchema: { + type: 'object', + properties: { + query: { + type: 'string', + description: 'What to search for in memories' + }, + limit: { + type: 'number', + description: 'Number of memories to retrieve (default: 10)' + } + }, + required: ['query'] + } + }, + { + name: 'get_all_memories', + description: 'Get all stored memories from Brain Cloud', + inputSchema: { + type: 'object', + properties: { + limit: { + type: 'number', + description: 'Number of memories to retrieve (default: 50)' + } + } + } + }, + { + name: 'brain_cloud_status', + description: 'Check Brain Cloud connection and memory statistics', + inputSchema: { + type: 'object', + properties: {} + } + } + ] + }; + }); + + // Handle tool calls + this.server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + + try { + switch (name) { + case 'remember': + return await this.storeMemory(args.content, args.context); + + case 'recall': + return await this.searchMemories(args.query, args.limit || 10); + + case 'get_all_memories': + return await this.getAllMemories(args.limit || 50); + + case 'brain_cloud_status': + return await this.getStatus(); + + default: + throw new Error(`Unknown tool: ${name}`); + } + } catch (error) { + return { + content: [{ + type: 'text', + text: `Error: ${error.message}` + }], + isError: true + }; + } + }); + } + + async storeMemory(content, context = '') { + try { + const response = await fetch(`${BRAIN_CLOUD_URL}/memory`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-customer-id': CUSTOMER_ID + }, + body: JSON.stringify({ + content, + context, + source: 'claude-mcp', + timestamp: new Date().toISOString() + }) + }); + + if (!response.ok) { + throw new Error(`Brain Cloud API error: ${response.status}`); + } + + const result = await response.json(); + + return { + content: [{ + type: 'text', + text: `āœ… Memory stored successfully!\n\nContent: ${content}\nID: ${result.id || 'generated'}\n\nI'll remember this for future conversations.` + }] + }; + } catch (error) { + throw new Error(`Failed to store memory: ${error.message}`); + } + } + + async searchMemories(query, limit = 10) { + try { + const response = await fetch(`${BRAIN_CLOUD_URL}/search`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'x-customer-id': CUSTOMER_ID + }, + body: JSON.stringify({ + query, + limit + }) + }); + + if (!response.ok) { + throw new Error(`Brain Cloud API error: ${response.status}`); + } + + const result = await response.json(); + const memories = result.memories || []; + + if (memories.length === 0) { + return { + content: [{ + type: 'text', + text: `šŸ” No memories found for "${query}"\n\nTry a different search term or ask me to remember something first.` + }] + }; + } + + const memoryList = memories.map((memory, index) => { + const date = new Date(memory.created || memory.timestamp).toLocaleDateString(); + return `${index + 1}. ${memory.content} (${date})`; + }).join('\n'); + + return { + content: [{ + type: 'text', + text: `🧠 Found ${memories.length} memories for "${query}":\n\n${memoryList}\n\nI can use this context to help with your current request!` + }] + }; + } catch (error) { + throw new Error(`Failed to search memories: ${error.message}`); + } + } + + async getAllMemories(limit = 50) { + try { + const response = await fetch(`${BRAIN_CLOUD_URL}/memories`, { + method: 'GET', + headers: { + 'x-customer-id': CUSTOMER_ID + } + }); + + if (!response.ok) { + throw new Error(`Brain Cloud API error: ${response.status}`); + } + + const result = await response.json(); + const memories = result.memories || []; + + if (memories.length === 0) { + return { + content: [{ + type: 'text', + text: `🧠 No memories stored yet.\n\nStart a conversation and I'll automatically remember important details!` + }] + }; + } + + const recentMemories = memories.slice(0, limit); + const memoryList = recentMemories.map((memory, index) => { + const date = new Date(memory.created || memory.timestamp).toLocaleDateString(); + return `${index + 1}. ${memory.content} (${date})`; + }).join('\n'); + + return { + content: [{ + type: 'text', + text: `🧠 Your Brain Cloud contains ${memories.length} total memories.\n\nShowing most recent ${recentMemories.length}:\n\n${memoryList}` + }] + }; + } catch (error) { + throw new Error(`Failed to get memories: ${error.message}`); + } + } + + async getStatus() { + try { + const response = await fetch(`${BRAIN_CLOUD_URL}/health`, { + method: 'GET', + headers: { + 'x-customer-id': CUSTOMER_ID + } + }); + + if (!response.ok) { + throw new Error(`Brain Cloud API error: ${response.status}`); + } + + const result = await response.json(); + + // Get memory count + const memoriesResponse = await fetch(`${BRAIN_CLOUD_URL}/memories`, { + headers: { 'x-customer-id': CUSTOMER_ID } + }); + + let memoryCount = 0; + if (memoriesResponse.ok) { + const memoriesData = await memoriesResponse.json(); + memoryCount = memoriesData.memories?.length || 0; + } + + return { + content: [{ + type: 'text', + text: `🧠 Brain Cloud Status: ${result.status}\n\n` + + `Customer ID: ${CUSTOMER_ID}\n` + + `Total Memories: ${memoryCount}\n` + + `Last Check: ${new Date().toLocaleString()}\n\n` + + `āœ… I'm connected and ready to remember everything!` + }] + }; + } catch (error) { + throw new Error(`Failed to get Brain Cloud status: ${error.message}`); + } + } + + async run() { + const transport = new StdioServerTransport(); + await this.server.connect(transport); + console.error(`🧠 Brain Cloud MCP Server running for customer: ${CUSTOMER_ID}`); + } +} + +// Start the server +const server = new BrainCloudMCPServer(); +server.run().catch(console.error); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 58ea1c05..a44664ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "cli-table3": "^0.6.3", "commander": "^11.1.0", "dotenv": "^16.4.5", + "inquirer": "^12.9.1", "ora": "^8.0.1", "prompts": "^2.4.2", "uuid": "^9.0.1" @@ -2311,6 +2312,340 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@inquirer/checkbox": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz", + "integrity": "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.14", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", + "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.15", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", + "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.16", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.16.tgz", + "integrity": "sha512-iSzLjT4C6YKp2DU0fr8T7a97FnRRxMO6CushJnW5ktxLNM2iNeuyUuUA5255eOLPORoGYCrVnuDOEBdGkHGkpw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/external-editor": "^1.0.0", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.17.tgz", + "integrity": "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.0.tgz", + "integrity": "sha512-5v3YXc5ZMfL6OJqXPrX9csb4l7NlQA2doO1yynUjpUChT9hg4JcuBVP0RbsEJ/3SL/sxWEyFjT2W69ZhtoBWqg==", + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", + "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.1.tgz", + "integrity": "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.17.tgz", + "integrity": "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.17.tgz", + "integrity": "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.1.tgz", + "integrity": "sha512-LpBPeIpyCF1H3C7SK/QxJQG4iV1/SRmJdymfcul8PuwtVhD0JI1CSwqmd83VgRgt1QEsDojQYFSXJSgo81PVMw==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.2.0", + "@inquirer/confirm": "^5.1.14", + "@inquirer/editor": "^4.2.16", + "@inquirer/expand": "^4.0.17", + "@inquirer/input": "^4.2.1", + "@inquirer/number": "^3.0.17", + "@inquirer/password": "^4.0.17", + "@inquirer/rawlist": "^4.1.5", + "@inquirer/search": "^3.1.0", + "@inquirer/select": "^4.3.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.5.tgz", + "integrity": "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.0.tgz", + "integrity": "sha512-PMk1+O/WBcYJDq2H7foV0aAZSmDdkzZB9Mw2v/DmONRJopwA/128cS9M/TXWLKKdEQKZnKwBzqu2G4x/2Nqx8Q==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.1.tgz", + "integrity": "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/figures": "^1.0.13", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", + "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -4554,6 +4889,33 @@ "string-width": "^4.1.0" } }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -4567,7 +4929,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5292,6 +5653,12 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chardet": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", + "license": "MIT" + }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", @@ -5394,6 +5761,15 @@ "@colors/colors": "1.5.0" } }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -7931,7 +8307,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -8022,6 +8397,32 @@ "dev": true, "license": "ISC" }, + "node_modules/inquirer": { + "version": "12.9.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.9.1.tgz", + "integrity": "sha512-G7uXAb9OiLcd+9jmA/7KKrItvFF00kKk/jb6CtG+Tm2zSPWfzzhyJwDhVCy+mBmE32o2zJnB5JnknIIv2Ft+AA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.15", + "@inquirer/prompts": "^7.8.1", + "@inquirer/type": "^3.0.8", + "ansi-escapes": "^4.3.2", + "mute-stream": "^2.0.0", + "run-async": "^4.0.5", + "rxjs": "^7.8.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/ip-address": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", @@ -9172,6 +9573,15 @@ "dev": true, "license": "MIT" }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -10523,6 +10933,15 @@ "dev": true, "license": "MIT" }, + "node_modules/run-async": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz", + "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -10547,6 +10966,15 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -10572,7 +11000,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, "license": "MIT" }, "node_modules/saxes": { @@ -12487,6 +12914,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", diff --git a/package.json b/package.json index cbfd6ce4..0c181a89 100644 --- a/package.json +++ b/package.json @@ -219,6 +219,7 @@ "cli-table3": "^0.6.3", "commander": "^11.1.0", "dotenv": "^16.4.5", + "inquirer": "^12.9.1", "ora": "^8.0.1", "prompts": "^2.4.2", "uuid": "^9.0.1"