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 Translate all Chinese text to English in responses. Note: pcexec tool name and function names remain unchanged.
183 lines
5.0 KiB
TypeScript
183 lines
5.0 KiB
TypeScript
import { StatusManager } from '../core/status-manager';
|
|
|
|
export interface SlashCommandOptions {
|
|
statusManager: StatusManager;
|
|
/** List of authorized user IDs */
|
|
authorizedUsers: string[];
|
|
/** Cooldown duration in seconds */
|
|
cooldownSeconds?: number;
|
|
/** Callback for replies */
|
|
onReply: (message: string) => Promise<void>;
|
|
}
|
|
|
|
interface CommandState {
|
|
passMgrEnabled: boolean;
|
|
safeRestartEnabled: boolean;
|
|
lastToggle: {
|
|
'pass-mgr': number;
|
|
'safe-restart': number;
|
|
};
|
|
}
|
|
|
|
export class SlashCommandHandler {
|
|
private statusManager: StatusManager;
|
|
private authorizedUsers: string[];
|
|
private cooldownMs: number;
|
|
private onReply: (message: string) => Promise<void>;
|
|
private state: CommandState;
|
|
|
|
constructor(options: SlashCommandOptions) {
|
|
this.statusManager = options.statusManager;
|
|
this.authorizedUsers = options.authorizedUsers;
|
|
this.cooldownMs = (options.cooldownSeconds || 10) * 1000;
|
|
this.onReply = options.onReply;
|
|
|
|
this.state = {
|
|
passMgrEnabled: true,
|
|
safeRestartEnabled: true,
|
|
lastToggle: {
|
|
'pass-mgr': 0,
|
|
'safe-restart': 0,
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Handle a slash command
|
|
*/
|
|
async handle(command: string, userId: string): Promise<void> {
|
|
// Check authorization
|
|
if (!this.authorizedUsers.includes(userId)) {
|
|
await this.onReply('Unauthorized');
|
|
return;
|
|
}
|
|
|
|
const parts = command.trim().split(/\s+/);
|
|
const subcommand = parts[1];
|
|
const feature = parts[2] as 'pass-mgr' | 'safe-restart';
|
|
|
|
switch (subcommand) {
|
|
case 'status':
|
|
await this.handleStatus();
|
|
break;
|
|
case 'enable':
|
|
await this.handleEnable(feature);
|
|
break;
|
|
case 'disable':
|
|
await this.handleDisable(feature);
|
|
break;
|
|
default:
|
|
await this.onReply(
|
|
'Usage:\n' +
|
|
'`/padded-cell-ctrl status` - Show status\n' +
|
|
'`/padded-cell-ctrl enable pass-mgr|safe-restart` - Enable feature\n' +
|
|
'`/padded-cell-ctrl disable pass-mgr|safe-restart` - Disable feature'
|
|
);
|
|
}
|
|
}
|
|
|
|
private async handleStatus(): Promise<void> {
|
|
const global = this.statusManager.getGlobalStatus();
|
|
const agents = this.statusManager.getAllAgents();
|
|
|
|
const lines = [
|
|
'**PaddedCell Status**',
|
|
'',
|
|
`Secret Manager: ${this.state.passMgrEnabled ? 'Enabled' : 'Disabled'}`,
|
|
`Safe Restart: ${this.state.safeRestartEnabled ? 'Enabled' : 'Disabled'}`,
|
|
'',
|
|
'**Agent Status:**',
|
|
];
|
|
|
|
for (const agent of agents) {
|
|
const emoji = this.getStateEmoji(agent.state);
|
|
lines.push(`${emoji} ${agent.agentId}: ${agent.state}`);
|
|
}
|
|
|
|
if (agents.length === 0) {
|
|
lines.push('(No agents registered)');
|
|
}
|
|
|
|
if (global.restartStatus !== 'idle') {
|
|
lines.push('');
|
|
lines.push(`Restart Status: ${global.restartStatus}`);
|
|
if (global.restartScheduledBy) {
|
|
lines.push(` Initiated by ${global.restartScheduledBy}`);
|
|
}
|
|
}
|
|
|
|
await this.onReply(lines.join('\n'));
|
|
}
|
|
|
|
private async handleEnable(feature: 'pass-mgr' | 'safe-restart'): Promise<void> {
|
|
if (!this.isValidFeature(feature)) {
|
|
await this.onReply('Unknown feature. Available: pass-mgr, safe-restart');
|
|
return;
|
|
}
|
|
|
|
if (this.isOnCooldown(feature)) {
|
|
await this.onReply('This feature was recently modified. Please try again later.');
|
|
return;
|
|
}
|
|
|
|
if (feature === 'pass-mgr') {
|
|
this.state.passMgrEnabled = true;
|
|
} else {
|
|
this.state.safeRestartEnabled = true;
|
|
}
|
|
|
|
this.state.lastToggle[feature] = Date.now();
|
|
await this.onReply(`Enabled ${feature}`);
|
|
}
|
|
|
|
private async handleDisable(feature: 'pass-mgr' | 'safe-restart'): Promise<void> {
|
|
if (!this.isValidFeature(feature)) {
|
|
await this.onReply('Unknown feature. Available: pass-mgr, safe-restart');
|
|
return;
|
|
}
|
|
|
|
if (this.isOnCooldown(feature)) {
|
|
await this.onReply('This feature was recently modified. Please try again later.');
|
|
return;
|
|
}
|
|
|
|
if (feature === 'pass-mgr') {
|
|
this.state.passMgrEnabled = false;
|
|
} else {
|
|
this.state.safeRestartEnabled = false;
|
|
}
|
|
|
|
this.state.lastToggle[feature] = Date.now();
|
|
await this.onReply(`Disabled ${feature}`);
|
|
}
|
|
|
|
private isValidFeature(feature: string): feature is 'pass-mgr' | 'safe-restart' {
|
|
return feature === 'pass-mgr' || feature === 'safe-restart';
|
|
}
|
|
|
|
private isOnCooldown(feature: 'pass-mgr' | 'safe-restart'): boolean {
|
|
const lastToggle = this.state.lastToggle[feature];
|
|
return Date.now() - lastToggle < this.cooldownMs;
|
|
}
|
|
|
|
private getStateEmoji(state: string): string {
|
|
switch (state) {
|
|
case 'idle': return '💤';
|
|
case 'busy': return '⚡';
|
|
case 'focus': return '🎯';
|
|
case 'freeze': return '🧊';
|
|
case 'pre-freeze': return '⏳';
|
|
case 'pre-freeze-focus': return '📝';
|
|
default: return '❓';
|
|
}
|
|
}
|
|
|
|
isPassMgrEnabled(): boolean {
|
|
return this.state.passMgrEnabled;
|
|
}
|
|
|
|
isSafeRestartEnabled(): boolean {
|
|
return this.state.safeRestartEnabled;
|
|
}
|
|
}
|