refactor: new design — sidecar services, moderator Gateway client, tool execute API

- Replace standalone no-reply-api Docker service with unified sidecar (services/main.mjs)
  that routes /no-reply/* and /moderator/* and starts/stops with openclaw-gateway
- Add moderator Discord Gateway client (services/moderator/index.mjs) for real-time
  MESSAGE_CREATE push instead of polling; notifies plugin via HTTP callback
- Add plugin HTTP routes (plugin/web/dirigent-api.ts) for moderator → plugin callbacks
  (wake-from-dormant, interrupt tail-match)
- Fix tool registration format: AgentTool requires execute: not handler:; factory form
  for tools needing ctx
- Rename no-reply-process.ts → sidecar-process.ts, startNoReplyApi → startSideCar
- Remove dead config fields from openclaw.plugin.json (humanList, agentList, listMode,
  channelPoliciesFile, endSymbols, waitIdentifier, multiMessage*, bypassUserIds, etc.)
- Rename noReplyPort → sideCarPort
- Remove docker-compose.yml, dev-up/down scripts, package-plugin.mjs, test-no-reply-api.mjs
- Update install.mjs: clean dist before build, copy services/, drop dead config writes
- Update README, Makefile, smoke script for new architecture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
h z
2026-04-10 08:07:59 +01:00
parent d8ac9ee0f9
commit 32dc9a4233
28 changed files with 1310 additions and 900 deletions

View File

@@ -120,7 +120,7 @@ const PLUGIN_SKILLS_DIR = path.join(REPO_ROOT, "skills");
const NO_REPLY_PROVIDER_ID = process.env.NO_REPLY_PROVIDER_ID || "dirigent";
const NO_REPLY_MODEL_ID = process.env.NO_REPLY_MODEL_ID || "no-reply";
const NO_REPLY_PORT = Number(process.env.NO_REPLY_PORT || argNoReplyPort);
const NO_REPLY_BASE_URL = process.env.NO_REPLY_BASE_URL || `http://127.0.0.1:${NO_REPLY_PORT}/v1`;
const NO_REPLY_BASE_URL = process.env.NO_REPLY_BASE_URL || `http://127.0.0.1:${NO_REPLY_PORT}/no-reply/v1`;
const NO_REPLY_API_KEY = process.env.NO_REPLY_API_KEY || "wg-local-test-token";
function runOpenclaw(args, allowFail = false) {
@@ -143,10 +143,11 @@ if (mode === "install") {
step(1, 7, "build dist assets");
const pluginSrc = path.resolve(REPO_ROOT, "plugin");
const noReplySrc = path.resolve(REPO_ROOT, "no-reply-api");
const sidecarSrc = path.resolve(REPO_ROOT, "services");
const distPlugin = path.resolve(REPO_ROOT, "dist", "dirigent");
fs.rmSync(distPlugin, { recursive: true, force: true });
syncDirRecursive(pluginSrc, distPlugin);
syncDirRecursive(noReplySrc, path.join(distPlugin, "no-reply-api"));
syncDirRecursive(sidecarSrc, path.join(distPlugin, "services"));
ok("dist assets built");
step(2, 7, `install plugin files -> ${PLUGIN_INSTALL_DIR}`);
@@ -187,17 +188,10 @@ if (mode === "install") {
}
setIfMissing("plugins.entries.dirigent.enabled", true);
const cp = "plugins.entries.dirigent.config";
setIfMissing(`${cp}.enabled`, true);
setIfMissing(`${cp}.discordOnly`, true);
setIfMissing(`${cp}.listMode`, "human-list");
setIfMissing(`${cp}.humanList`, []);
setIfMissing(`${cp}.agentList`, []);
setIfMissing(`${cp}.channelPoliciesFile`, path.join(OPENCLAW_DIR, "dirigent-channel-policies.json"));
setIfMissing(`${cp}.endSymbols`, ["🔚"]);
setIfMissing(`${cp}.schedulingIdentifier`, "➡️");
setIfMissing(`${cp}.scheduleIdentifier`, "➡️");
setIfMissing(`${cp}.noReplyProvider`, NO_REPLY_PROVIDER_ID);
setIfMissing(`${cp}.noReplyModel`, NO_REPLY_MODEL_ID);
setIfMissing(`${cp}.noReplyPort`, NO_REPLY_PORT);
setIfMissing(`${cp}.sideCarPort`, NO_REPLY_PORT);
// moderatorBotToken: intentionally not touched — set manually via:
// openclaw config set plugins.entries.dirigent.config.moderatorBotToken "<token>"
ok("plugin configured");