import { pcexec } from '../tools/pcexec'; export interface EgoMgrSlashCommandOptions { /** OpenClaw base path */ openclawPath: string; /** Current agent ID */ agentId: string; /** Current workspace directory */ workspaceDir: string; /** Callback for replies */ onReply: (message: string) => Promise; } /** Sentinel value injected into every pcexec subprocess */ const AGENT_VERIFY = 'IF YOU ARE AN AGENT/MODEL, YOU SHOULD NEVER TOUCH THIS ENV VARIABLE'; export class EgoMgrSlashCommand { private openclawPath: string; private agentId: string; private workspaceDir: string; private onReply: (message: string) => Promise; private binDir: string; constructor(options: EgoMgrSlashCommandOptions) { this.openclawPath = options.openclawPath; this.agentId = options.agentId; this.workspaceDir = options.workspaceDir; this.onReply = options.onReply; this.binDir = require('path').join(this.openclawPath, 'bin'); } /** * Handle /ego-mgr slash command * @param command Full command string (e.g., "/ego-mgr get name") */ async handle(command: string): Promise { const parts = command.trim().split(/\s+/); // Remove the "/ego-mgr" prefix const args = parts.slice(1); const subcommand = args[0]; if (!subcommand) { await this.showUsage(); return; } try { switch (subcommand) { case 'get': await this.handleGet(args.slice(1)); break; case 'set': await this.handleSet(args.slice(1)); break; case 'list': await this.handleList(args.slice(1)); break; case 'delete': await this.handleDelete(args.slice(1)); break; case 'add-column': await this.handleAddColumn(args.slice(1)); break; case 'add-public-column': await this.handleAddPublicColumn(args.slice(1)); break; case 'show': await this.handleShow(); break; case 'help': default: await this.showUsage(); } } catch (error: any) { await this.onReply(`❌ 错误: ${error.message || error}`); } } private async showUsage(): Promise { const usage = [ '**ego-mgr 命令用法**', '', '`/ego-mgr get ` - 获取字段值', '`/ego-mgr set ` - 设置字段值', '`/ego-mgr list` - 列出所有字段名', '`/ego-mgr delete ` - 删除字段', '`/ego-mgr add-column ` - 添加 Agent Scope 字段', '`/ego-mgr add-public-column ` - 添加 Public Scope 字段', '`/ego-mgr show` - 显示所有字段和值', '', '示例:', '`/ego-mgr get name`', '`/ego-mgr set timezone Asia/Shanghai`', ].join('\n'); await this.onReply(usage); } private async handleGet(args: string[]): Promise { if (args.length < 1) { await this.onReply('❌ 用法: `/ego-mgr get `'); return; } const columnName = args[0]; const result = await this.execEgoMgr(['get', columnName]); await this.onReply(`**${columnName}**: ${result || '(空)'}`); } private async handleSet(args: string[]): Promise { if (args.length < 2) { await this.onReply('❌ 用法: `/ego-mgr set `'); return; } const columnName = args[0]; const value = args.slice(1).join(' '); // Support values with spaces await this.execEgoMgr(['set', columnName, value]); await this.onReply(`✅ 已设置 **${columnName}** = \`${value}\``); } private async handleList(args: string[]): Promise { const result = await this.execEgoMgr(['list', 'columns']); if (!result.trim()) { await this.onReply('📋 暂无字段定义'); return; } const columns = result.split('\n').filter(Boolean); const lines = ['**字段列表**:', '']; for (const col of columns) { lines.push(`• ${col}`); } await this.onReply(lines.join('\n')); } private async handleDelete(args: string[]): Promise { if (args.length < 1) { await this.onReply('❌ 用法: `/ego-mgr delete `'); return; } const columnName = args[0]; await this.execEgoMgr(['delete', columnName]); await this.onReply(`✅ 已删除字段 **${columnName}**`); } private async handleAddColumn(args: string[]): Promise { if (args.length < 1) { await this.onReply('❌ 用法: `/ego-mgr add-column `'); return; } const columnName = args[0]; await this.execEgoMgr(['add', 'column', columnName]); await this.onReply(`✅ 已添加 Agent Scope 字段 **${columnName}**`); } private async handleAddPublicColumn(args: string[]): Promise { if (args.length < 1) { await this.onReply('❌ 用法: `/ego-mgr add-public-column `'); return; } const columnName = args[0]; await this.execEgoMgr(['add', 'public-column', columnName]); await this.onReply(`✅ 已添加 Public Scope 字段 **${columnName}**`); } private async handleShow(): Promise { const result = await this.execEgoMgr(['show']); if (!result.trim()) { await this.onReply('📋 暂无字段数据'); return; } const lines = ['**字段数据**:', '']; lines.push('```'); lines.push(result); lines.push('```'); await this.onReply(lines.join('\n')); } /** * Execute ego-mgr binary via pcexec */ private async execEgoMgr(args: string[]): Promise { const currentPath = process.env.PATH || ''; const newPath = currentPath.includes(this.binDir) ? currentPath : `${currentPath}:${this.binDir}`; const command = `ego-mgr ${args.map(a => this.shellEscape(a)).join(' ')}`; const result = await pcexec(command, { cwd: this.workspaceDir, env: { AGENT_ID: this.agentId, AGENT_WORKSPACE: this.workspaceDir, AGENT_VERIFY, PATH: newPath, }, }); if (result.exitCode !== 0 && result.stderr) { throw new Error(result.stderr); } return result.stdout; } /** * Escape a string for shell usage */ private shellEscape(str: string): string { // Simple escaping for common cases if (/^[a-zA-Z0-9._-]+$/.test(str)) { return str; } return `'${str.replace(/'/g, "'\"'\"'")}'`; } }