feat: add /ego-mgr slash command and rename pcexec to pc-exec
Changes: 1. Add /ego-mgr slash command with subcommands: - get, set, list, delete, add-column, add-public-column, show - Uses pcExec to call ego-mgr binary with proper env vars 2. Rename pcexec → pc-exec throughout codebase: - Tool name: pcexec → pc-exec - Function exports: pcexec → pcExec, pcexecSync → pcExecSync - Updated all references in skills and plugin files 3. Translate all Chinese text to English: - ego-mgr-slash.ts responses - slash-commands.ts responses - SKILL.md files remain in English
This commit is contained in:
214
plugin/commands/ego-mgr-slash.ts
Normal file
214
plugin/commands/ego-mgr-slash.ts
Normal file
@@ -0,0 +1,214 @@
|
||||
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<void>;
|
||||
}
|
||||
|
||||
/** Sentinel value injected into every pc-exec 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<void>;
|
||||
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<void> {
|
||||
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: ${error.message || error}`);
|
||||
}
|
||||
}
|
||||
|
||||
private async showUsage(): Promise<void> {
|
||||
const usage = [
|
||||
'**ego-mgr Commands**',
|
||||
'',
|
||||
'`/ego-mgr get <column-name>` - Get field value',
|
||||
'`/ego-mgr set <column-name> <value>` - Set field value',
|
||||
'`/ego-mgr list` - List all field names',
|
||||
'`/ego-mgr delete <column-name>` - Delete a field',
|
||||
'`/ego-mgr add-column <column-name>` - Add an Agent Scope field',
|
||||
'`/ego-mgr add-public-column <column-name>` - Add a Public Scope field',
|
||||
'`/ego-mgr show` - Show all fields and values',
|
||||
'',
|
||||
'Examples:',
|
||||
'`/ego-mgr get name`',
|
||||
'`/ego-mgr set timezone Asia/Shanghai`',
|
||||
].join('\n');
|
||||
await this.onReply(usage);
|
||||
}
|
||||
|
||||
private async handleGet(args: string[]): Promise<void> {
|
||||
if (args.length < 1) {
|
||||
await this.onReply('Usage: `/ego-mgr get <column-name>`');
|
||||
return;
|
||||
}
|
||||
const columnName = args[0];
|
||||
const result = await this.execEgoMgr(['get', columnName]);
|
||||
await this.onReply(`**${columnName}**: ${result || '(empty)'}`);
|
||||
}
|
||||
|
||||
private async handleSet(args: string[]): Promise<void> {
|
||||
if (args.length < 2) {
|
||||
await this.onReply('Usage: `/ego-mgr set <column-name> <value>`');
|
||||
return;
|
||||
}
|
||||
const columnName = args[0];
|
||||
const value = args.slice(1).join(' '); // Support values with spaces
|
||||
await this.execEgoMgr(['set', columnName, value]);
|
||||
await this.onReply(`Set **${columnName}** = \`${value}\``);
|
||||
}
|
||||
|
||||
private async handleList(args: string[]): Promise<void> {
|
||||
const result = await this.execEgoMgr(['list', 'columns']);
|
||||
if (!result.trim()) {
|
||||
await this.onReply('No fields defined');
|
||||
return;
|
||||
}
|
||||
const columns = result.split('\n').filter(Boolean);
|
||||
const lines = ['**Fields**:', ''];
|
||||
for (const col of columns) {
|
||||
lines.push(`• ${col}`);
|
||||
}
|
||||
await this.onReply(lines.join('\n'));
|
||||
}
|
||||
|
||||
private async handleDelete(args: string[]): Promise<void> {
|
||||
if (args.length < 1) {
|
||||
await this.onReply('Usage: `/ego-mgr delete <column-name>`');
|
||||
return;
|
||||
}
|
||||
const columnName = args[0];
|
||||
await this.execEgoMgr(['delete', columnName]);
|
||||
await this.onReply(`Deleted field **${columnName}**`);
|
||||
}
|
||||
|
||||
private async handleAddColumn(args: string[]): Promise<void> {
|
||||
if (args.length < 1) {
|
||||
await this.onReply('Usage: `/ego-mgr add-column <column-name>`');
|
||||
return;
|
||||
}
|
||||
const columnName = args[0];
|
||||
await this.execEgoMgr(['add', 'column', columnName]);
|
||||
await this.onReply(`Added Agent Scope field **${columnName}**`);
|
||||
}
|
||||
|
||||
private async handleAddPublicColumn(args: string[]): Promise<void> {
|
||||
if (args.length < 1) {
|
||||
await this.onReply('Usage: `/ego-mgr add-public-column <column-name>`');
|
||||
return;
|
||||
}
|
||||
const columnName = args[0];
|
||||
await this.execEgoMgr(['add', 'public-column', columnName]);
|
||||
await this.onReply(`Added Public Scope field **${columnName}**`);
|
||||
}
|
||||
|
||||
private async handleShow(): Promise<void> {
|
||||
const result = await this.execEgoMgr(['show']);
|
||||
if (!result.trim()) {
|
||||
await this.onReply('No field data');
|
||||
return;
|
||||
}
|
||||
const lines = ['**Field Data**:', ''];
|
||||
lines.push('```');
|
||||
lines.push(result);
|
||||
lines.push('```');
|
||||
await this.onReply(lines.join('\n'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute ego-mgr binary via pc-exec
|
||||
*/
|
||||
private async execEgoMgr(args: string[]): Promise<string> {
|
||||
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, "'\"'\"'")}'`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user