Rework core integration: validated capability layer, docs, and session state
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Veskslop communication backend — pure logic (no Discord imports).
|
||||
*
|
||||
* Keeps a small ring buffer of trigger-qualifying messages: the last 100 from
|
||||
* trusted users and the last 30 from untrusted ones. Also parses the
|
||||
* `whitelist` commands and normalizes @mentions.
|
||||
*/
|
||||
|
||||
export interface PuppetMessage {
|
||||
id: string;
|
||||
channelId: string;
|
||||
guildId?: string;
|
||||
authorId: string;
|
||||
authorName: string;
|
||||
/** Raw message content as received. */
|
||||
content: string;
|
||||
timestamp: string;
|
||||
trusted: boolean;
|
||||
/** Parsed command text when the message is one. */
|
||||
command?: string;
|
||||
}
|
||||
|
||||
export const TRUSTED_LOG_LIMIT = 100;
|
||||
export const UNTRUSTED_LOG_LIMIT = 30;
|
||||
|
||||
export class MessageLog {
|
||||
trusted: PuppetMessage[] = [];
|
||||
untrusted: PuppetMessage[] = [];
|
||||
|
||||
add(message: PuppetMessage) {
|
||||
const bucket = message.trusted ? this.trusted : this.untrusted;
|
||||
const limit = message.trusted ? TRUSTED_LOG_LIMIT : UNTRUSTED_LOG_LIMIT;
|
||||
|
||||
bucket.push(message);
|
||||
if (bucket.length > limit) bucket.splice(0, bucket.length - limit);
|
||||
}
|
||||
|
||||
snapshot() {
|
||||
return { trusted: [...this.trusted], untrusted: [...this.untrusted] };
|
||||
}
|
||||
}
|
||||
|
||||
const USER_MENTION = /<@!?(\d+)>/g;
|
||||
|
||||
export function extractMentionIds(content: string, mentions?: Array<{ id: string }>): Set<string> {
|
||||
const ids = new Set<string>();
|
||||
for (const mention of mentions ?? []) ids.add(mention.id);
|
||||
for (const match of content.matchAll(USER_MENTION)) ids.add(match[1]);
|
||||
return ids;
|
||||
}
|
||||
|
||||
export function stripMentions(content: string, ids: ReadonlySet<string>): string {
|
||||
return content
|
||||
.replace(USER_MENTION, (full, id) => (ids.has(id) ? "" : full))
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
}
|
||||
|
||||
export interface ParsedCommand {
|
||||
name: string;
|
||||
args: string[];
|
||||
}
|
||||
|
||||
export function parseCommand(text: string): ParsedCommand | undefined {
|
||||
const trimmed = text.trim();
|
||||
if (!trimmed) return undefined;
|
||||
|
||||
const [name, ...args] = trimmed.split(/\s+/);
|
||||
return { name: name.toLowerCase(), args };
|
||||
}
|
||||
|
||||
export function isTrusted(
|
||||
userId: string,
|
||||
ownerId: string | undefined,
|
||||
whitelist: readonly string[] | undefined
|
||||
): boolean {
|
||||
return userId === ownerId || !!whitelist?.includes(userId);
|
||||
}
|
||||
|
||||
/** Same 500-2800 ms pacing used by the control bridge, for autonomous replies. */
|
||||
export function randomActionDelay(): number {
|
||||
return 500 + Math.floor(Math.random() * 2301);
|
||||
}
|
||||
Reference in New Issue
Block a user