/**
 * src/agent/directives.ts
 *
 * Parse delivery directives the agent embeds in its response text. Pattern
 * adapted from OpenClaw's `[[reply_to_current]]` model: the agent decides
 * HOW its message should be delivered by prefixing the reply with bracketed
 * markers. The router consumes them and strips before sending to the channel.
 *
 * Why: lets the agent be more nuanced than "always reply" — it can react
 * silently in busy groups, ack with a custom emoji, or stay silent and only
 * journal a thought.
 *
 * Supported directives (any combination, in any order at the START of the reply):
 *   [[reply]]                 — full text reply (default; explicit version)
 *   [[react:<emoji>]]         — react with the emoji to the inbound message, no text
 *   [[ack:<emoji>]]           — react + send a one-line text ack (the rest of the reply)
 *   [[silent]]                — don't deliver anything; just journal
 *   [[delay:<seconds>]]       — wait N seconds before delivering (max 300)
 *   [[forward:<channel>]]     — deliver via this channel instead of the inbound one
 *
 * Multiple directives can stack:
 *   [[react:✅]][[silent]] foo bar  →  react ✅ + don't deliver text
 *
 * Anything before/after that's not a directive becomes the message body.
 */
const DIRECTIVE_RE = /\[\[(reply|react|ack|silent|delay|forward)(?::([^\]]*))?\]\]/g;
export function parseDirectives(raw) {
    let mode = 'reply';
    let reactionEmoji = null;
    let delaySec = 0;
    let forwardChannel = null;
    const rawDirectivesFound = [];
    // Only consume directives at the start of the message (or with whitespace)
    // up to the first non-directive content. This prevents the agent from
    // accidentally parsing legitimate `[[...]]` text that appears mid-reply.
    let body = raw;
    const leadingDirectives = [];
    // eslint-disable-next-line no-constant-condition
    while (true) {
        const trimmed = body.trimStart();
        const m = trimmed.match(/^\[\[(reply|react|ack|silent|delay|forward)(?::([^\]]*))?\]\]/);
        if (!m)
            break;
        leadingDirectives.push(m[0]);
        body = trimmed.slice(m[0].length);
    }
    for (const d of leadingDirectives) {
        rawDirectivesFound.push(d);
        DIRECTIVE_RE.lastIndex = 0;
        const m = DIRECTIVE_RE.exec(d);
        if (!m)
            continue;
        const name = m[1];
        const arg = m[2];
        switch (name) {
            case 'reply':
                mode = 'reply';
                break;
            case 'silent':
                mode = 'silent';
                break;
            case 'react':
                mode = mode === 'reply' ? 'react' : mode;
                reactionEmoji = arg ?? '✅';
                break;
            case 'ack':
                mode = 'ack';
                reactionEmoji = arg ?? '✅';
                break;
            case 'delay':
                delaySec = Math.max(0, Math.min(300, parseInt(arg ?? '0', 10) || 0));
                break;
            case 'forward':
                forwardChannel = arg ?? null;
                break;
        }
    }
    return {
        mode,
        reactionEmoji,
        delaySec,
        forwardChannel,
        bodyText: body.trim(),
        rawDirectivesFound,
    };
}
/**
 * Quick test helper: detect whether a response contains ANY directive at all.
 * Cheaper than full parse; useful as a guard in hot paths.
 */
export function hasDirectives(raw) {
    return /^\s*\[\[(reply|react|ack|silent|delay|forward)/.test(raw);
}
//# sourceMappingURL=directives.js.map