/**
 * User Manager — multi-user identity resolution.
 *
 * Maps incoming messages to known users based on their channels.
 * Same agent, same repo, different relationship per user.
 */
import type { UserProfile, UserChannel, Message } from '../core/types.js';
/**
 * WS2.6 user-record replication emit seam (injected, dark by default). server.ts late-binds a
 * journal-backed emitter ONLY when `multiMachine.stateSync.userRegistry.enabled` is true; absent
 * ⇒ strict no-op (single-machine, byte-identical). The emitter NEVER throws into the manager
 * (it swallows + counts internally), so the manager calls it best-effort.
 *
 * CRITICAL: emitDelete MUST fire for every user REMOVED (the removeUser() path) — else a peer
 * re-replicates the locally-removed user forever (resurrection). The emitter keys the tombstone
 * on the SAME channel-set recordKey the put used, so the delete reaches the same human on every
 * machine even though the local ids differ. emitPut carries the disclosure-minimized projection
 * only — never the local `userId`.
 */
export interface UserReplicationEmitter {
    /** Emit a `put` for a persisted user profile (called from the persist funnel). */
    emitPut(record: UserProfile): void;
    /** Emit a `delete` tombstone for a removed user, keyed on their channel set. */
    emitDelete(channels: UserChannel[], deletedAt: string): void;
}
export declare class UserManager {
    private users;
    private channelIndex;
    private usersFile;
    /** WS2.6 user-record replication emitter (injected, dark by default). Absent ⇒ strict no-op. */
    private userReplication;
    constructor(stateDir: string, initialUsers?: UserProfile[]);
    /**
     * Late-bind the WS2.6 user-record replication emitter (server.ts constructs the journal/clock
     * AFTER the manager). Idempotent; passing undefined/null detaches (back to single-machine
     * no-op). The emit funnel checks `this.userReplication` per write, so attaching mid-life takes
     * effect on the next upsert/remove.
     */
    setUserReplicationEmitter(emitter: UserReplicationEmitter | null | undefined): void;
    /**
     * Resolve a user from an incoming message.
     * Returns the user profile if the sender is recognized.
     */
    resolveFromMessage(message: Message): UserProfile | null;
    /**
     * Resolve a user from a channel identifier.
     */
    resolveFromChannel(channel: UserChannel): UserProfile | null;
    /**
     * Resolve a user by their Telegram numeric user ID.
     * Scans all profiles for matching telegramUserId field.
     *
     * This is the primary resolution path for incoming Telegram messages,
     * since telegramUserId is stored as a direct field on UserProfile
     * (not a channel — channels use topic IDs).
     */
    resolveFromTelegramUserId(telegramUserId: number): UserProfile | null;
    /**
     * Resolve a user profile from a verified Slack user ID (U…).
     *
     * The authenticated Slack user ID is the basis of Slack identity (Know Your
     * Principal) — never a name in message content. Prefers the direct
     * `slackUserId` field, falling back to a `slack`-typed channel identifier for
     * profiles registered before the field existed.
     */
    resolveFromSlackUserId(slackUserId: string): UserProfile | null;
    /**
     * Get a user by ID.
     */
    getUser(userId: string): UserProfile | null;
    /**
     * List all registered users.
     */
    listUsers(): UserProfile[];
    /**
     * Add or update a user.
     */
    upsertUser(profile: UserProfile): void;
    /**
     * Remove a user.
     */
    removeUser(userId: string): boolean;
    /**
     * Check if a user has a specific permission.
     */
    hasPermission(userId: string, permission: string): boolean;
    /**
     * Add a user interactively (with defaults applied).
     * Returns the full profile.
     */
    addUserInteractive(partialProfile: Partial<UserProfile> & {
        id: string;
        name: string;
    }): UserProfile;
    /**
     * List users formatted for wizard display.
     * Returns name + id pairs suitable for selection prompts.
     */
    listUsersForSelection(): Array<{
        name: string;
        value: string;
        description: string;
    }>;
    /**
     * Find admin users.
     */
    getAdmins(): UserProfile[];
    private validateProfile;
    private loadUsers;
    private persistUsers;
}
//# sourceMappingURL=UserManager.d.ts.map