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

@@ -94,7 +94,7 @@ function connect(token: string, logger: Logger, isResume = false) {
try {
ws = new WebSocket(url);
} catch (err) {
logger.warn(`whispergate: moderator ws constructor failed: ${String(err)}`);
logger.warn(`dirigent: moderator ws constructor failed: ${String(err)}`);
scheduleReconnect(token, logger, false);
return;
}
@@ -119,8 +119,8 @@ function connect(token: string, logger: Logger, isResume = false) {
intents: 0,
properties: {
os: "linux",
browser: "whispergate",
device: "whispergate",
browser: "dirigent",
device: "dirigent",
},
presence: {
status: "online",
@@ -154,19 +154,19 @@ function connect(token: string, logger: Logger, isResume = false) {
if (t === "READY") {
sessionId = d.session_id;
resumeUrl = d.resume_gateway_url;
logger.info("whispergate: moderator bot connected and online");
logger.info("dirigent: moderator bot connected and online");
}
if (t === "RESUMED") {
logger.info("whispergate: moderator bot resumed");
logger.info("dirigent: moderator bot resumed");
}
break;
case 7: // Reconnect request
logger.info("whispergate: moderator bot reconnect requested by Discord");
logger.info("dirigent: moderator bot reconnect requested by Discord");
cleanup();
scheduleReconnect(token, logger, true);
break;
case 9: // Invalid Session
logger.warn(`whispergate: moderator bot invalid session, resumable=${d}`);
logger.warn(`dirigent: moderator bot invalid session, resumable=${d}`);
cleanup();
sessionId = d ? sessionId : null;
// Wait longer before re-identifying
@@ -189,18 +189,18 @@ function connect(token: string, logger: Logger, isResume = false) {
// Non-recoverable codes — stop reconnecting
if (code === 4004) {
logger.warn("whispergate: moderator bot token invalid (4004), stopping");
logger.warn("dirigent: moderator bot token invalid (4004), stopping");
started = false;
return;
}
if (code === 4010 || code === 4011 || code === 4013 || code === 4014) {
logger.warn(`whispergate: moderator bot fatal close (${code}), re-identifying`);
logger.warn(`dirigent: moderator bot fatal close (${code}), re-identifying`);
sessionId = null;
scheduleReconnect(token, logger, false);
return;
}
logger.info(`whispergate: moderator bot disconnected (code=${code}), will reconnect`);
logger.info(`dirigent: moderator bot disconnected (code=${code}), will reconnect`);
const canResume = !!sessionId && code !== 4012;
scheduleReconnect(token, logger, canResume);
};
@@ -220,7 +220,7 @@ function scheduleReconnect(token: string, logger: Logger, resume: boolean) {
const jitter = Math.random() * 1000;
const delay = baseDelay + jitter;
logger.info(`whispergate: moderator reconnect in ${Math.round(delay)}ms (attempt ${reconnectAttempts})`);
logger.info(`dirigent: moderator reconnect in ${Math.round(delay)}ms (attempt ${reconnectAttempts})`);
reconnectTimer = setTimeout(() => {
reconnectTimer = null;
@@ -234,7 +234,7 @@ function scheduleReconnect(token: string, logger: Logger, resume: boolean) {
*/
export function startModeratorPresence(token: string, logger: Logger): void {
if (started) {
logger.info("whispergate: moderator presence already started, skipping");
logger.info("dirigent: moderator presence already started, skipping");
return;
}
started = true;