feat: rewrite plugin as v2 with globalThis-based turn management
Complete rewrite of the Dirigent plugin turn management system to work correctly with OpenClaw's VM-context-per-session architecture: - All turn state stored on globalThis (persists across VM context hot-reloads) - Hooks registered unconditionally on every api instance; event-level dedup (runId Set for agent_end, WeakSet for before_model_resolve) prevents double-processing - Gateway lifecycle events (gateway_start/stop) guarded once via globalThis flag - Shared initializingChannels lock prevents concurrent channel init across VM contexts in message_received and before_model_resolve - New ChannelStore and IdentityRegistry replace old policy/session-state modules - Added agent_end hook with tail-match polling for Discord delivery confirmation - Added web control page, padded-cell auto-scan, discussion tool support - Removed obsolete v1 modules: channel-resolver, channel-modes, discussion-service, session-state, turn-bootstrap, policy/store, rules, decision-input Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { buildUserIdToAccountIdMap } from "./identity.js";
|
||||
import type { IdentityRegistry } from "./identity-registry.js";
|
||||
|
||||
const PERM_VIEW_CHANNEL = 1n << 10n;
|
||||
const PERM_ADMINISTRATOR = 1n << 3n;
|
||||
@@ -84,7 +84,14 @@ function canViewChannel(member: any, guildId: string, guildRoles: Map<string, bi
|
||||
return (perms & PERM_VIEW_CHANNEL) !== 0n;
|
||||
}
|
||||
|
||||
function getAnyDiscordToken(api: OpenClawPluginApi): string | undefined {
|
||||
function getDiscoveryToken(api: OpenClawPluginApi): string | undefined {
|
||||
// Prefer moderator bot token from pluginConfig — it has guild member access
|
||||
const pluginCfg = (api.pluginConfig as Record<string, unknown>) || {};
|
||||
const moderatorToken = pluginCfg.moderatorBotToken;
|
||||
if (typeof moderatorToken === "string" && moderatorToken) {
|
||||
return moderatorToken;
|
||||
}
|
||||
// Fall back to any discord account token
|
||||
const root = (api.config as Record<string, unknown>) || {};
|
||||
const channels = (root.channels as Record<string, unknown>) || {};
|
||||
const discord = (channels.discord as Record<string, unknown>) || {};
|
||||
@@ -95,8 +102,15 @@ function getAnyDiscordToken(api: OpenClawPluginApi): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export async function fetchVisibleChannelBotAccountIds(api: OpenClawPluginApi, channelId: string): Promise<string[]> {
|
||||
const token = getAnyDiscordToken(api);
|
||||
/**
|
||||
* Returns agentIds for all agents visible in the channel, resolved via the identity registry.
|
||||
*/
|
||||
export async function fetchVisibleChannelBotAccountIds(
|
||||
api: OpenClawPluginApi,
|
||||
channelId: string,
|
||||
identityRegistry?: IdentityRegistry,
|
||||
): Promise<string[]> {
|
||||
const token = getDiscoveryToken(api);
|
||||
if (!token) return [];
|
||||
|
||||
const ch = await discordRequest(token, "GET", `/channels/${channelId}`);
|
||||
@@ -131,11 +145,13 @@ export async function fetchVisibleChannelBotAccountIds(api: OpenClawPluginApi, c
|
||||
.map((m) => String(m?.user?.id || ""))
|
||||
.filter(Boolean);
|
||||
|
||||
const userToAccount = buildUserIdToAccountIdMap(api);
|
||||
const out = new Set<string>();
|
||||
for (const uid of visibleUserIds) {
|
||||
const aid = userToAccount.get(uid);
|
||||
if (aid) out.add(aid);
|
||||
if (identityRegistry) {
|
||||
const discordToAgent = identityRegistry.buildDiscordToAgentMap();
|
||||
for (const uid of visibleUserIds) {
|
||||
const aid = discordToAgent.get(uid);
|
||||
if (aid) out.add(aid);
|
||||
}
|
||||
}
|
||||
return [...out];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user