feat: complete Dirigent rename + all TASKLIST items

- Task 1: Identity prompt now includes Discord userId
- Task 2: Added configurable schedulingIdentifier (default: ➡️)
- Task 3: Moderator handoff uses <@userId>+identifier instead of semantic messages
- Task 4: All prompts/comments/help text converted to English
- Task 5: Full project rename WhisperGate → Dirigent across all files

Breaking: config key changed from plugins.entries.whispergate to plugins.entries.dirigent
Breaking: channel policies file renamed to dirigent-channel-policies.json
Breaking: tool name changed from whispergate_tools to dirigent_tools
This commit is contained in:
zhi
2026-03-03 10:10:27 +00:00
parent 2afb982c04
commit af33d747d9
32 changed files with 291 additions and 1434 deletions

View File

@@ -4,10 +4,10 @@ set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT_DIR"
echo "[whispergate] building/starting no-reply API container"
docker compose up -d --build whispergate-no-reply-api
echo "[dirigent] building/starting no-reply API container"
docker compose up -d --build dirigent-no-reply-api
echo "[whispergate] health check"
echo "[dirigent] health check"
curl -sS http://127.0.0.1:8787/health
echo "[whispergate] done"
echo "[dirigent] done"

View File

@@ -6,7 +6,7 @@ import { execFileSync } from "node:child_process";
const modeArg = process.argv[2];
if (modeArg !== "--install" && modeArg !== "--uninstall") {
console.error("Usage: install-whispergate-openclaw.mjs --install | --uninstall");
console.error("Usage: install-dirigent-openclaw.mjs --install | --uninstall");
process.exit(2);
}
const mode = modeArg === "--install" ? "install" : "uninstall";
@@ -14,7 +14,7 @@ const mode = modeArg === "--install" ? "install" : "uninstall";
const env = process.env;
const OPENCLAW_CONFIG_PATH = env.OPENCLAW_CONFIG_PATH || path.join(os.homedir(), ".openclaw", "openclaw.json");
const __dirname = path.dirname(new URL(import.meta.url).pathname);
const PLUGIN_PATH = env.PLUGIN_PATH || path.resolve(__dirname, "..", "dist", "whispergate");
const PLUGIN_PATH = env.PLUGIN_PATH || path.resolve(__dirname, "..", "dist", "dirigent");
const NO_REPLY_PROVIDER_ID = env.NO_REPLY_PROVIDER_ID || "whisper-gateway";
const NO_REPLY_MODEL_ID = env.NO_REPLY_MODEL_ID || "no-reply";
const NO_REPLY_BASE_URL = env.NO_REPLY_BASE_URL || "http://127.0.0.1:8787/v1";
@@ -22,19 +22,19 @@ const NO_REPLY_API_KEY = env.NO_REPLY_API_KEY || "wg-local-test-token";
const LIST_MODE = env.LIST_MODE || "human-list";
const HUMAN_LIST_JSON = env.HUMAN_LIST_JSON || '["561921120408698910","1474088632750047324"]';
const AGENT_LIST_JSON = env.AGENT_LIST_JSON || "[]";
const CHANNEL_POLICIES_FILE = (env.CHANNEL_POLICIES_FILE || "~/.openclaw/whispergate-channel-policies.json").replace(/^~(?=$|\/)/, os.homedir());
const CHANNEL_POLICIES_FILE = (env.CHANNEL_POLICIES_FILE || "~/.openclaw/dirigent-channel-policies.json").replace(/^~(?=$|\/)/, os.homedir());
const CHANNEL_POLICIES_JSON = env.CHANNEL_POLICIES_JSON || "{}";
const END_SYMBOLS_JSON = env.END_SYMBOLS_JSON || '["🔚"]';
const STATE_DIR = (env.STATE_DIR || "~/.openclaw/whispergate-install-records").replace(/^~(?=$|\/)/, os.homedir());
const LATEST_RECORD_LINK = (env.LATEST_RECORD_LINK || "~/.openclaw/whispergate-install-record-latest.json").replace(/^~(?=$|\/)/, os.homedir());
const STATE_DIR = (env.STATE_DIR || "~/.openclaw/dirigent-install-records").replace(/^~(?=$|\/)/, os.homedir());
const LATEST_RECORD_LINK = (env.LATEST_RECORD_LINK || "~/.openclaw/dirigent-install-record-latest.json").replace(/^~(?=$|\/)/, os.homedir());
const ts = new Date().toISOString().replace(/[-:TZ.]/g, "").slice(0, 14);
const BACKUP_PATH = `${OPENCLAW_CONFIG_PATH}.bak-whispergate-${mode}-${ts}`;
const RECORD_PATH = path.join(STATE_DIR, `whispergate-${ts}.json`);
const BACKUP_PATH = `${OPENCLAW_CONFIG_PATH}.bak-dirigent-${mode}-${ts}`;
const RECORD_PATH = path.join(STATE_DIR, `dirigent-${ts}.json`);
const PATH_PLUGINS_LOAD = "plugins.load.paths";
const PATH_PLUGIN_ENTRY = "plugins.entries.whispergate";
const PATH_PLUGIN_ENTRY = "plugins.entries.dirigent";
const PATH_PROVIDERS = "models.providers";
function runOpenclaw(args, { allowFail = false } = {}) {
@@ -83,7 +83,7 @@ function findLatestInstallRecord() {
if (!fs.existsSync(STATE_DIR)) return "";
const files = fs
.readdirSync(STATE_DIR)
.filter((f) => /^whispergate-\d+\.json$/.test(f))
.filter((f) => /^dirigent-\d+\.json$/.test(f))
.sort()
.reverse();
for (const f of files) {
@@ -99,18 +99,18 @@ function findLatestInstallRecord() {
}
if (!fs.existsSync(OPENCLAW_CONFIG_PATH)) {
console.error(`[whispergate] config not found: ${OPENCLAW_CONFIG_PATH}`);
console.error(`[dirigent] config not found: ${OPENCLAW_CONFIG_PATH}`);
process.exit(1);
}
if (mode === "install") {
fs.copyFileSync(OPENCLAW_CONFIG_PATH, BACKUP_PATH);
console.log(`[whispergate] backup: ${BACKUP_PATH}`);
console.log(`[dirigent] backup: ${BACKUP_PATH}`);
if (!fs.existsSync(CHANNEL_POLICIES_FILE)) {
fs.mkdirSync(path.dirname(CHANNEL_POLICIES_FILE), { recursive: true });
fs.writeFileSync(CHANNEL_POLICIES_FILE, `${CHANNEL_POLICIES_JSON}\n`);
console.log(`[whispergate] initialized channel policies file: ${CHANNEL_POLICIES_FILE}`);
console.log(`[dirigent] initialized channel policies file: ${CHANNEL_POLICIES_FILE}`);
}
const before = {
@@ -127,7 +127,7 @@ if (mode === "install") {
if (!paths.includes(PLUGIN_PATH)) paths.push(PLUGIN_PATH);
plugins.load.paths = paths;
plugins.entries = plugins.entries && typeof plugins.entries === "object" ? plugins.entries : {};
plugins.entries.whispergate = {
plugins.entries.dirigent = {
enabled: true,
config: {
enabled: true,
@@ -169,23 +169,23 @@ if (mode === "install") {
[PATH_PROVIDERS]: getJson(PATH_PROVIDERS),
};
writeRecord("install", before, after);
console.log("[whispergate] install ok (config written)");
console.log(`[whispergate] record: ${RECORD_PATH}`);
console.log("[whispergate] >>> restart gateway to apply: openclaw gateway restart");
console.log("[dirigent] install ok (config written)");
console.log(`[dirigent] record: ${RECORD_PATH}`);
console.log("[dirigent] >>> restart gateway to apply: openclaw gateway restart");
} catch (e) {
fs.copyFileSync(BACKUP_PATH, OPENCLAW_CONFIG_PATH);
console.error(`[whispergate] install failed; rollback complete: ${String(e)}`);
console.error(`[dirigent] install failed; rollback complete: ${String(e)}`);
process.exit(1);
}
} else {
const recFile = env.RECORD_FILE || findLatestInstallRecord();
if (!recFile || !fs.existsSync(recFile)) {
console.error("[whispergate] no install record found. set RECORD_FILE=<path> to an install record.");
console.error("[dirigent] no install record found. set RECORD_FILE=<path> to an install record.");
process.exit(1);
}
fs.copyFileSync(OPENCLAW_CONFIG_PATH, BACKUP_PATH);
console.log(`[whispergate] backup before uninstall: ${BACKUP_PATH}`);
console.log(`[dirigent] backup before uninstall: ${BACKUP_PATH}`);
const rec = readRecord(recFile);
const before = rec.applied || {};
@@ -200,8 +200,8 @@ if (mode === "install") {
if (target[PATH_PLUGINS_LOAD]?.exists) plugins.load.paths = target[PATH_PLUGINS_LOAD].value;
else delete plugins.load.paths;
if (target[PATH_PLUGIN_ENTRY]?.exists) plugins.entries.whispergate = target[PATH_PLUGIN_ENTRY].value;
else delete plugins.entries.whispergate;
if (target[PATH_PLUGIN_ENTRY]?.exists) plugins.entries.dirigent = target[PATH_PLUGIN_ENTRY].value;
else delete plugins.entries.dirigent;
setJson("plugins", plugins);
@@ -214,11 +214,11 @@ if (mode === "install") {
[PATH_PROVIDERS]: getJson(PATH_PROVIDERS),
};
writeRecord("uninstall", before, after);
console.log("[whispergate] uninstall ok");
console.log(`[whispergate] record: ${RECORD_PATH}`);
console.log("[dirigent] uninstall ok");
console.log(`[dirigent] record: ${RECORD_PATH}`);
} catch (e) {
fs.copyFileSync(BACKUP_PATH, OPENCLAW_CONFIG_PATH);
console.error(`[whispergate] uninstall failed; rollback complete: ${String(e)}`);
console.error(`[dirigent] uninstall failed; rollback complete: ${String(e)}`);
process.exit(1);
}
}

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
exec node "$SCRIPT_DIR/install-whispergate-openclaw.mjs" "$@"
exec node "$SCRIPT_DIR/install-dirigent-openclaw.mjs" "$@"

View File

@@ -3,7 +3,7 @@ import path from "node:path";
const root = process.cwd();
const pluginDir = path.join(root, "plugin");
const outDir = path.join(root, "dist", "whispergate");
const outDir = path.join(root, "dist", "dirigent");
fs.rmSync(outDir, { recursive: true, force: true });
fs.mkdirSync(outDir, { recursive: true });

View File

@@ -1,13 +1,13 @@
const pluginPath = process.argv[2] || "/opt/WhisperGate/plugin";
const pluginPath = process.argv[2] || "/opt/Dirigent/plugin";
const provider = process.argv[3] || "openai";
const model = process.argv[4] || "whispergate-no-reply-v1";
const model = process.argv[4] || "dirigent-no-reply-v1";
const bypass = (process.argv[5] || "").split(",").filter(Boolean);
const payload = {
plugins: {
load: { paths: [pluginPath] },
entries: {
whispergate: {
dirigent: {
enabled: true,
config: {
enabled: true,

View File

@@ -19,14 +19,14 @@ echo "[3] chat/completions"
curl -sS -X POST "${BASE_URL}/v1/chat/completions" \
-H 'Content-Type: application/json' \
"${AUTH_HEADER[@]}" \
-d '{"model":"whispergate-no-reply-v1","messages":[{"role":"user","content":"hello"}]}' \
-d '{"model":"dirigent-no-reply-v1","messages":[{"role":"user","content":"hello"}]}' \
| sed -n '1,20p'
echo "[4] responses"
curl -sS -X POST "${BASE_URL}/v1/responses" \
-H 'Content-Type: application/json' \
"${AUTH_HEADER[@]}" \
-d '{"model":"whispergate-no-reply-v1","input":"hello"}' \
-d '{"model":"dirigent-no-reply-v1","input":"hello"}' \
| sed -n '1,20p'
echo "smoke ok"