From ac1d48e0dd088f00f4a93ce51c537747a0f3535b Mon Sep 17 00:00:00 2001 From: Gemini AI Date: Sun, 14 Dec 2025 20:48:48 +0400 Subject: [PATCH] TUI5: Added command processor with /remember /memory /skills /skill /debug /help commands --- bin/opencode-ink.mjs | 1 + lib/command-processor.mjs | 212 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 lib/command-processor.mjs diff --git a/bin/opencode-ink.mjs b/bin/opencode-ink.mjs index 7458968..b781808 100644 --- a/bin/opencode-ink.mjs +++ b/bin/opencode-ink.mjs @@ -50,6 +50,7 @@ import { getSessionMemory } from '../lib/session-memory.mjs'; import { getContextManager } from '../lib/context-manager.mjs'; import { getAllSkills, getSkill, executeSkill, getSkillListDisplay } from '../lib/skills.mjs'; import { getDebugLogger, initFromArgs } from '../lib/debug-logger.mjs'; +import { processCommand, isCommand } from '../lib/command-processor.mjs'; // Initialize debug logger from CLI args const debugLogger = initFromArgs(); diff --git a/lib/command-processor.mjs b/lib/command-processor.mjs new file mode 100644 index 0000000..efdc2d5 --- /dev/null +++ b/lib/command-processor.mjs @@ -0,0 +1,212 @@ +/** + * Command Processor - Handles slash commands for TUI 5 + * Integrates Session Memory, Skills, Debug Logger, etc. + * + * Original implementation for OpenQode TUI + */ + +import { getSessionMemory } from './session-memory.mjs'; +import { getContextManager } from './context-manager.mjs'; +import { getAllSkills, getSkill, executeSkill, getSkillListDisplay } from './skills.mjs'; +import { getDebugLogger } from './debug-logger.mjs'; + +/** + * Process a slash command + * @param {string} input - User input + * @returns {Object|null} - { handled: boolean, response: string, action?: string } + */ +export async function processCommand(input) { + const trimmed = input.trim(); + if (!trimmed.startsWith('/')) { + return null; // Not a command + } + + const parts = trimmed.split(/\s+/); + const command = parts[0].toLowerCase(); + const args = parts.slice(1).join(' '); + + switch (command) { + // ═══════════════════════════════════════════════════════════════ + // SESSION MEMORY COMMANDS + // ═══════════════════════════════════════════════════════════════ + case '/remember': { + if (!args) { + return { + handled: true, + response: '❌ Usage: /remember \nExample: /remember User prefers TypeScript over JavaScript' + }; + } + const memory = getSessionMemory(); + await memory.load(); + const entry = await memory.remember(args); + return { + handled: true, + response: `✅ Remembered: "${args}"\n📝 Fact #${memory.facts.length} saved to session memory.` + }; + } + + case '/forget': { + if (!args) { + return { + handled: true, + response: '❌ Usage: /forget \nExample: /forget 1' + }; + } + const memory = getSessionMemory(); + await memory.load(); + const index = parseInt(args, 10); + const removed = await memory.forget(index); + if (removed) { + return { + handled: true, + response: `✅ Forgot fact #${index}: "${removed.fact}"` + }; + } + return { + handled: true, + response: `❌ Fact #${index} not found. Use /memory to see all facts.` + }; + } + + case '/memory': { + const memory = getSessionMemory(); + await memory.load(); + const facts = memory.getDisplayList(); + if (facts.length === 0) { + return { + handled: true, + response: '📭 No facts in session memory.\nUse /remember to add one.' + }; + } + const list = facts.map(f => `${f.index}. [${f.category}] ${f.fact} (${f.displayDate})`).join('\n'); + return { + handled: true, + response: `📝 **Session Memory** (${facts.length} facts)\n\n${list}\n\nUse /forget to remove a fact.` + }; + } + + case '/clearmemory': { + const memory = getSessionMemory(); + await memory.clear(); + return { + handled: true, + response: '🗑️ Session memory cleared.' + }; + } + + // ═══════════════════════════════════════════════════════════════ + // SKILLS COMMANDS + // ═══════════════════════════════════════════════════════════════ + case '/skills': { + const display = getSkillListDisplay(); + return { + handled: true, + response: `🎯 **Available Skills**\n${display}\nUsage: /skill then describe your task` + }; + } + + case '/skill': { + if (!args) { + const skills = getAllSkills(); + const names = skills.map(s => s.id).join(', '); + return { + handled: true, + response: `❌ Usage: /skill \nAvailable: ${names}` + }; + } + const skillName = args.split(/\s+/)[0]; + const skill = getSkill(skillName); + if (!skill) { + const skills = getAllSkills(); + const names = skills.map(s => s.id).join(', '); + return { + handled: true, + response: `❌ Unknown skill: "${skillName}"\nAvailable: ${names}` + }; + } + return { + handled: true, + response: `🎯 **Activated: ${skill.name}**\n${skill.description}\n\nNow describe your task and I'll apply this skill.`, + action: 'activate_skill', + skill: skill + }; + } + + // ═══════════════════════════════════════════════════════════════ + // DEBUG COMMANDS + // ═══════════════════════════════════════════════════════════════ + case '/debug': { + const logger = getDebugLogger(); + const nowEnabled = logger.toggle(); + return { + handled: true, + response: nowEnabled + ? `🔧 Debug logging **ENABLED**\nLogs: ${logger.getPath()}` + : '🔧 Debug logging **DISABLED**' + }; + } + + case '/debugclear': { + const logger = getDebugLogger(); + await logger.clear(); + return { + handled: true, + response: '🗑️ Debug log cleared.' + }; + } + + // ═══════════════════════════════════════════════════════════════ + // CONTEXT COMMANDS + // ═══════════════════════════════════════════════════════════════ + case '/context': { + const ctx = getContextManager(); + // This will be enhanced when we have access to messages + return { + handled: true, + response: `📊 **Context Manager**\nToken limit: ${ctx.tokenLimit.toLocaleString()}\nSummarize at: ${ctx.summarizeThreshold * 100}%\n\nContext will auto-summarize when usage exceeds threshold.` + }; + } + + // ═══════════════════════════════════════════════════════════════ + // HELP + // ═══════════════════════════════════════════════════════════════ + case '/help': { + return { + handled: true, + response: `📚 **Available Commands** + +**Memory** + /remember - Save a fact to session memory + /memory - View all remembered facts + /forget <#> - Remove a fact by number + /clearmemory - Clear all memory + +**Skills** + /skills - List available skills + /skill - Activate a skill + +**Debug** + /debug - Toggle debug logging + /debugclear - Clear debug log + +**Context** + /context - View context usage stats + +**Other** + /help - Show this help` + }; + } + + default: + return null; // Not a recognized command + } +} + +/** + * Check if input is a command (starts with /) + */ +export function isCommand(input) { + return input?.trim().startsWith('/'); +} + +export default { processCommand, isCommand };