Files
PaddedCell/plugin/core/api.ts
zhi 787d88cd33 chore: convert plugin to ESM and migrate to current openclaw plugin SDK
ESM conversion:
- package.json: add "type": "module"; drop stale "main": "index.ts"
- tsconfig.json: switch module/moduleResolution to "nodenext"
- plugin/index.ts: replace `module.exports = { register }` and
  `module.exports.X = X` with `export default definePluginEntry({ ... })`
  plus named ESM re-exports; replace `require('os')`/`require('path')`
  with proper imports.
- plugin/tools/pcexec.ts: replace `require('child_process')` with import
  from "node:child_process".
- plugin/commands/ego-mgr-slash.ts: replace `require('path')` with
  proper path import.
- All relative imports/exports across plugin/ now carry .js extensions
  as required by Node ESM (nodenext module resolution).

Plugin SDK convention update:
- Wrap default export with definePluginEntry({ id, name, description,
  register }) per the current openclaw authoring contract.
- Type api parameter as OpenClawPluginApi (was `any`); the non-standard
  api.registerSlashCommand call is preserved behind a guarded any-cast,
  so the plugin remains a no-op for slash commands when the host doesn't
  expose that hook (matches the previous defensive guard).
- Add openclaw as a devDependency (file:/usr/lib/node_modules/openclaw)
  so tsc can resolve openclaw/plugin-sdk/* subpath types at build time.
- Modernize openclaw.plugin.json: drop entry/version, add
  activation.onStartup so gateway_start fires for this plugin at boot,
  declare contracts.tools listing pcexec/proxy-pcexec/safe_restart.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:02:30 +00:00

101 lines
2.3 KiB
TypeScript

import express from 'express';
import { StatusManager } from './status-manager.js';
export interface ApiOptions {
port?: number;
statusManager: StatusManager;
}
/**
* Creates and starts the REST API server for query-restart
*/
export function createApiServer(options: ApiOptions): express.Application {
const { port = 8765, statusManager } = options;
const app = express();
app.use(express.json());
// POST /query-restart
app.post('/query-restart', (req, res) => {
const { requesterAgentId, requesterSessionKey } = req.body;
if (!requesterAgentId || !requesterSessionKey) {
return res.status(400).json({
error: 'Missing required fields: requesterAgentId, requesterSessionKey',
});
}
const result = statusManager.queryRestart(requesterAgentId, requesterSessionKey);
res.json({
status: result,
timestamp: Date.now(),
});
});
// POST /restart-result
app.post('/restart-result', (req, res) => {
const { status, log } = req.body;
if (!status || !['ok', 'failed'].includes(status)) {
return res.status(400).json({
error: 'Invalid status. Must be "ok" or "failed"',
});
}
statusManager.completeRestart(status === 'ok', log);
res.json({
success: true,
timestamp: Date.now(),
});
});
// GET /status
app.get('/status', (req, res) => {
const agents = statusManager.getAllAgents();
const global = statusManager.getGlobalStatus();
res.json({
agents,
global,
timestamp: Date.now(),
});
});
// GET /agent/:agentId
app.get('/agent/:agentId', (req, res) => {
const { agentId } = req.params;
const agent = statusManager.getAgent(agentId);
if (!agent) {
return res.status(404).json({
error: `Agent ${agentId} not found`,
});
}
res.json({
agent,
timestamp: Date.now(),
});
});
return app;
}
export function startApiServer(options: ApiOptions): Promise<void> {
const { port = 8765 } = options;
const app = createApiServer(options);
return new Promise((resolve, reject) => {
const server = app.listen(port, () => {
console.log(`Safe-restart API server listening on port ${port}`);
resolve();
});
server.on('error', (err) => {
reject(err);
});
});
}