import { type RuntimeScopeCarrier } from "@pinet/transport-core"; import type { ReactionCommandSettings } from "./reaction-triggers.js"; import type { AgentSessionSummary } from "./broker/types.js"; export interface SlackIngressGuardSettings { requireMention?: { /** Slack channel IDs where every actionable message must explicitly mention the bot. */ channels?: string[]; /** Require mention in Pinet-owned threads once anyone outside trustedUsers + the bot participates. */ mixedParticipantThreads?: { enabled?: boolean; trustedUsers?: string[]; }; }; } export interface SlackBridgeSettings { botToken?: string; appToken?: string; appId?: string; appConfigToken?: string; allowedUsers?: string[]; allowAllWorkspaceUsers?: boolean; ingressGuard?: SlackIngressGuardSettings; defaultChannel?: string; logChannel?: string; logLevel?: "errors" | "actions" | "verbose"; suggestedPrompts?: { title: string; message: string; }[]; reactionCommands?: ReactionCommandSettings; runtimeMode?: "off" | "single" | "broker" | "follower"; brokerPrompt?: string; autoConnect?: boolean; autoFollow?: boolean; ralphLoopIntervalMs?: number; ralphSnoozeAfterEmptyCycles?: number; ralphSnoozeDurationMs?: number; skinTheme?: string; slackCommandName?: string; slackCommandNames?: string[]; agentName?: string; agentEmoji?: string; meshSecret?: string; meshSecretPath?: string; imessage?: { enabled?: boolean; }; security?: { readOnly?: boolean; requireConfirmation?: string[]; blockedTools?: string[]; }; } export interface ResolvedPinetMeshAuthSettings { meshSecret: string | null; meshSecretPath: string | null; } export declare function buildSlackCompatibilityScope(options?: { teamId?: string | null; channelId?: string | null; installId?: string | null; instanceId?: string | null; instanceName?: string | null; }): RuntimeScopeCarrier; export declare function resolvePinetMeshAuth(settings: SlackBridgeSettings, env?: NodeJS.ProcessEnv): ResolvedPinetMeshAuthSettings; export declare function loadSettings(settingsPath?: string): SlackBridgeSettings; export declare function resolveAllowAllWorkspaceUsers(settings: SlackBridgeSettings, envVar?: string | undefined): boolean; export declare function buildAllowlist(settings: SlackBridgeSettings, envVar?: string, allowAllEnvVar?: string | undefined): Set | null; export declare function describeSlackUserAccess(allowlist: Set | null, options?: { allowAllWorkspaceUsers?: boolean; }): string; export declare function getSlackUserAccessWarning(allowlist: Set | null): string | null; export declare function isUserAllowed(allowlist: Set | null, userId: string): boolean; export interface InboxMessage { channel: string; threadTs: string; userId: string; text: string; timestamp: string; isChannelMention?: boolean; brokerInboxId?: number; metadata?: Record | null; scope?: RuntimeScopeCarrier | null; } export interface SqliteJournalModeResult { journal_mode?: string | null; } export declare function getSqliteJournalMode(result?: SqliteJournalModeResult): string; export declare function isSqliteWalEnabled(result?: SqliteJournalModeResult): boolean; export declare function buildSqliteWalFallbackWarning(component: string, result?: SqliteJournalModeResult): string; export declare function formatInboxMessages(messages: InboxMessage[], userNames: { get(key: string): string | undefined; }): string; export declare function isTerminalPinetStandDownMessage(body: string | null | undefined): boolean; export declare function formatPinetInboxMessages(entries: FollowerInboxEntry[]): string; export type PinetControlCommand = "interrupt" | "reload" | "exit"; export interface PinetRemoteControlState { currentCommand: PinetControlCommand | null; queuedCommand: PinetControlCommand | null; } export interface PinetRemoteControlRequestResult extends PinetRemoteControlState { accepted: boolean; shouldStartNow: boolean; status: "start" | "queued" | "covered"; scheduledCommand: PinetControlCommand; ackDisposition: "immediate" | "on_start"; } export declare function parsePinetControlCommand(value: unknown): PinetControlCommand | null; export declare function queuePinetRemoteControl(state: PinetRemoteControlState, command: PinetControlCommand): PinetRemoteControlRequestResult; export declare function finishPinetRemoteControl(state: PinetRemoteControlState): PinetRemoteControlState & { nextCommand: PinetControlCommand | null; }; export interface PinetRuntimeReloader { getCurrentRole: () => "broker" | "follower" | null; snapshotState: () => State; restoreState: (snapshot: State) => void; refreshState: () => void; validateRefreshedState: () => void | Promise; stopRuntime: () => Promise; startRuntime: (role: "broker" | "follower") => Promise; } export declare function reloadPinetRuntimeSafely(reloader: PinetRuntimeReloader): Promise; export interface PinetControlEnvelope { type: "pinet:control"; action: PinetControlCommand; } export declare function getPinetControlCommandFromText(text: string | undefined): PinetControlCommand | null; export declare function buildPinetControlMetadata(command: PinetControlCommand): PinetControlEnvelope; export declare function buildPinetControlMessage(command: PinetControlCommand): string; export declare function normalizeOutgoingPinetControlMessage(body: string, metadata?: Record): { body: string; metadata: Record; } | null; export type PinetSkinStatusKey = "idle" | "working" | "healthy" | "stale" | "ghost" | "resumable"; export type PinetSkinStatusVocabulary = Partial>; export declare function extractPinetControlCommand(message: { threadId?: string; body?: string; metadata?: Record | null; }): PinetControlCommand | null; export declare const FORM_METHODS: Set; export declare function buildSlackRequest(method: string, token: string, body?: Record): { url: string; init: RequestInit; }; export interface AbortableOperationTracker { run(operation: (signal: AbortSignal) => Promise): Promise; abortAndWait(): Promise; isAborting(): boolean; } export declare function createAbortError(message?: string): Error; export declare function isAbortError(error: unknown): boolean; export declare function abortableDelay(ms: number, signal: AbortSignal): Promise; export declare function createAbortableOperationTracker(): AbortableOperationTracker; export declare function stripBotMention(text: string, botUserId: string): string; export declare function isChannelId(nameOrId: string): boolean; export interface AgentCapabilities { repo?: string; repoRoot?: string; branch?: string; workdirDirty?: boolean; role?: string; tools?: string[]; tags?: string[]; scope?: RuntimeScopeCarrier | null; } export type AgentHealth = "healthy" | "stale" | "ghost" | "resumable"; export interface AgentDisplayInfo { emoji: string; name: string; id: string; pid?: number; stableId?: string | null; session?: AgentSessionSummary | null; status: "working" | "idle"; metadata?: { cwd?: string; branch?: string; workdirDirty?: boolean; workdirDirtyFileCount?: number; gitProbeFailed?: boolean; gitProbedAt?: string; host?: string; repo?: string; role?: string; worktreePath?: string; worktreeKind?: "main" | "linked"; brokerManaged?: boolean; brokerManagedBy?: string; launchSource?: string; tmuxSession?: string; brokerManagedAt?: string; parentAgentId?: string; rootAgentId?: string; treeDepth?: number; supervisionState?: string; subtreeRole?: string; laneId?: string; skinTheme?: string; personality?: string; skinStatusVocabulary?: PinetSkinStatusVocabulary; capabilities?: AgentCapabilities | null; scope?: RuntimeScopeCarrier | null; } | null; lastHeartbeat?: string; leaseExpiresAt?: string | null; heartbeatAgeMs?: number | null; heartbeatSummary?: string | null; leaseSummary?: string | null; health?: AgentHealth; ghost?: boolean; stuck?: boolean; idleSince?: string | null; lastActivity?: string | null; idleDuration?: string | null; lastActivityAge?: string | null; outboundCount?: number | null; pendingInboxCount?: number | null; capabilityTags?: string[]; routingScore?: number; routingReasons?: string[]; } export interface AgentVisibilityInput { emoji: string; name: string; id: string; pid?: number; stableId?: string | null; session?: AgentSessionSummary | null; status: "working" | "idle"; metadata?: Record | null; lastHeartbeat?: string; lastSeen?: string; disconnectedAt?: string | null; resumableUntil?: string | null; idleSince?: string | null; lastActivity?: string | null; outboundCount?: number | null; pendingInboxCount?: number | null; parentAgentId?: string | null; rootAgentId?: string | null; treeDepth?: number; supervisionState?: string; subtreeRole?: string | null; laneId?: string | null; } export interface AgentVisibilityOptions { now?: number; heartbeatTimeoutMs?: number; heartbeatIntervalMs?: number; } export interface AgentRoutingHint { repo?: string; branch?: string; role?: string; requiredTools?: string[]; task?: string; } export declare function shortenPath(p: string, homedir: string): string; export declare function extractAgentCapabilities(metadata: Record | null | undefined): AgentCapabilities; export declare function buildAgentCapabilityTags(capabilities: AgentCapabilities): string[]; export interface MeshVisibilityOptions { includeGhosts?: boolean; now?: number; recentDisconnectWindowMs: number; } export declare function isAgentVisibleInMesh(agent: { disconnectedAt?: string | null; }, options: MeshVisibilityOptions): boolean; export declare function filterAgentsForMeshVisibility(agents: T[], options: MeshVisibilityOptions): T[]; export declare function buildAgentDisplayInfo(agent: AgentVisibilityInput, options?: AgentVisibilityOptions): AgentDisplayInfo; export declare function rankAgentsForRouting(agents: AgentDisplayInfo[], hint: AgentRoutingHint): AgentDisplayInfo[]; export declare const DEFAULT_RALPH_LOOP_INTERVAL_MS: number; export declare const DEFAULT_RALPH_LOOP_IDLE_WITH_WORK_THRESHOLD_MS = 60000; export declare const DEFAULT_RALPH_LOOP_NUDGE_COOLDOWN_MS: number; export declare const DEFAULT_RALPH_LOOP_FOLLOW_UP_COOLDOWN_MS = 60000; export declare const DEFAULT_RALPH_LOOP_STUCK_WORKING_THRESHOLD_MS: number; export declare const MIN_RALPH_LOOP_INTERVAL_MS = 1000; export declare const MAX_RALPH_LOOP_INTERVAL_MS = 2147483647; export declare const DEFAULT_RALPH_SNOOZE_DURATION_MS: number; export declare const MIN_RALPH_SNOOZE_DURATION_MS = 60000; export declare const MAX_RALPH_SNOOZE_DURATION_MS: number; export declare const DEFAULT_RALPH_SNOOZE_AFTER_EMPTY_CYCLES = 0; export declare const MAX_RALPH_SNOOZE_AFTER_EMPTY_CYCLES = 100; export declare function resolveRalphLoopIntervalMs(settings?: SlackBridgeSettings): number; export declare function resolveRalphSnoozeDurationMs(settings?: SlackBridgeSettings): number; export declare function resolveRalphSnoozeAfterEmptyCycles(settings?: SlackBridgeSettings): number; export interface RalphLoopAgentWorkload extends AgentVisibilityInput { lastSeen?: string; pendingInboxCount: number; ownedThreadCount: number; } export interface RalphLoopEvaluationOptions extends AgentVisibilityOptions { idleWithWorkThresholdMs?: number; stuckWorkingThresholdMs?: number; pendingBacklogCount?: number; currentBranch?: string | null; expectedMainBranch?: string; brokerHeartbeatActive?: boolean; brokerMaintenanceActive?: boolean; brokerAgentId?: string; } export interface RalphLoopEvaluationResult { ghostAgentIds: string[]; nudgeAgentIds: string[]; idleDrainAgentIds: string[]; stuckAgentIds: string[]; anomalies: string[]; } export interface RalphLoopGhostAnomalyRewriteResult { evaluation: RalphLoopEvaluationResult; nonGhostAnomalies: string[]; newGhostIds: string[]; clearedGhostIds: string[]; nextReportedGhostIds: string[]; } export declare function evaluateRalphLoopCycle(workloads: RalphLoopAgentWorkload[], options?: RalphLoopEvaluationOptions): RalphLoopEvaluationResult; export interface RalphLoopGhostAnomalyRewriteOptions { suppressedGhostIds?: Iterable; } export declare function rewriteRalphLoopGhostAnomalies(evaluation: RalphLoopEvaluationResult, previousGhostIds?: Iterable, options?: RalphLoopGhostAnomalyRewriteOptions): RalphLoopGhostAnomalyRewriteResult; export declare function buildRalphLoopNudgeMessage(pendingInboxCount: number, ownedThreadCount: number, cycleStartedAt?: string): string; export declare function buildRalphLoopAnomalySignature(evaluation: RalphLoopEvaluationResult): string; export declare function buildRalphLoopStatusMessage(summary: string, cycleStartedAt: string): string; export interface RalphLoopFollowUpDeliveryOptions { signature: string; lastDeliveredSignature?: string; lastDeliveredAt?: number; now?: number; cooldownMs?: number; pending?: boolean; idle?: boolean; } export declare function shouldDeliverRalphLoopFollowUp(options: RalphLoopFollowUpDeliveryOptions): boolean; export declare function buildRalphLoopFollowUpMessage(evaluation: RalphLoopEvaluationResult, cycleStartedAt: string): string | null; export interface RalphLoopCycleNotifications { followUpPrompt: string | null; anomalyStatus: string | null; recoveryStatus: string; } export declare function buildRalphLoopCycleNotifications(evaluation: RalphLoopEvaluationResult, cycleStartedAt: string): RalphLoopCycleNotifications; export declare function buildBrokerProtocolGuardrailsPrompt(): string; export declare function buildWorkerPromptGuidelines(): string[]; export declare function buildPinetSkinPromptGuideline(theme: string | null | undefined, personality: string | null | undefined): string | null; export declare function buildIdentityReplyGuidelines(agentEmoji: string, agentName: string, location: string): [string, string, string]; export interface AgentPersonalityProfile { descriptor?: string; animal?: string; traits: string[]; } export declare function resolveAgentPersonality(agentName: string): AgentPersonalityProfile; export declare function buildAgentPersonalityGuidelines(agentName: string): string[]; export declare function resolvePersistedAgentIdentity(settings: SlackBridgeSettings, persistedName?: string, persistedEmoji?: string, envNickname?: string, seed?: string, role?: AgentIdentityRole): { name: string; emoji: string; }; export declare function buildAgentStableId(sessionFile?: string, host?: string, cwd?: string, leafId?: string): string; export declare function resolveAgentStableId(persistedStableId?: string, sessionFile?: string, host?: string, cwd?: string, leafId?: string): string; export declare function buildBrokerStableId(host?: string, cwd?: string): string; export declare function resolveBrokerStableId(persistedStableId?: string, host?: string, cwd?: string): string; export interface PinetRegistrationContext { sessionHeader?: { parentSession?: string; } | null; sessionFile?: string; leafId?: string; argv?: string[]; hasUI?: boolean; stdinIsTTY?: boolean; stdoutIsTTY?: boolean; } export declare function isLikelyLocalSubagentContext(context?: PinetRegistrationContext): boolean; export interface FollowerThreadState { channelId: string; threadTs: string; userId: string; source?: string; owner?: string; } export interface FollowerInboxEntry { inboxId?: number; message: { threadId?: string; source?: string; sender?: string; body?: string; createdAt?: string; metadata: Record | null; }; } export interface FollowerInboxSyncResult { inboxMessages: InboxMessage[]; threadUpdates: FollowerThreadState[]; lastDmChannel: string | null; changed: boolean; } export interface TransferredSlackThreadSyncResult { threadUpdates: FollowerThreadState[]; changed: boolean; } export interface BrokerInboxControlEntry { inboxId: number; command: PinetControlCommand; } export interface BrokerInboxSyncResult { controlEntries: BrokerInboxControlEntry[]; inboxMessages: InboxMessage[]; } export declare function isDirectMessageChannel(channel: string): boolean; export declare function syncTransferredSlackThreadContexts(entries: FollowerInboxEntry[], existingThreads: ReadonlyMap, agentOwner: string): TransferredSlackThreadSyncResult; export declare function syncFollowerInboxEntries(entries: FollowerInboxEntry[], existingThreads: ReadonlyMap, agentOwner: string, lastDmChannel: string | null): FollowerInboxSyncResult; export declare function syncBrokerInboxEntries(entries: FollowerInboxEntry[]): BrokerInboxSyncResult; export interface FollowerThreadChannelResolution { channelId: string | null; threadUpdate?: FollowerThreadState; changed: boolean; } export declare function resolveFollowerThreadChannel(threadTs: string | undefined, existingThread: FollowerThreadState | undefined, resolveThread?: (threadTs: string) => Promise): Promise; export type FollowerRuntimeDiagnosticKind = "broker_disconnect" | "poll_failure" | "registration_refresh_failure" | "reconnect_stopped"; export type FollowerRuntimeDiagnosticState = "reconnecting" | "degraded" | "error"; export interface FollowerRuntimeDiagnostic { kind: FollowerRuntimeDiagnosticKind; state: FollowerRuntimeDiagnosticState; reason: string; nextStep: string; detail?: string; } export declare function buildFollowerRuntimeDiagnostic(kind: FollowerRuntimeDiagnosticKind, options?: { detail?: string | null; connected?: boolean; }): FollowerRuntimeDiagnostic; export declare function formatFollowerRuntimeDiagnosticHealth(diagnostic: FollowerRuntimeDiagnostic | null): string; export declare function formatFollowerRuntimeDiagnosticNextStep(diagnostic: FollowerRuntimeDiagnostic | null): string; export interface FollowerReconnectUiUpdate { nextWasDisconnected: boolean; notify?: { level: "warning" | "info"; message: string; }; } export declare function getFollowerReconnectUiUpdate(event: "disconnect" | "reconnect", wasDisconnected: boolean): FollowerReconnectUiUpdate; export declare function agentOwnsThread(owner: string | undefined, agentName: string, agentAliases?: Iterable, ownerToken?: string): boolean; export declare function normalizeOwnedThreads(threads: Iterable<{ owner?: string; }>, agentName: string, ownerToken: string, agentAliases?: Iterable): boolean; export declare function getFollowerOwnedThreadClaims(threads: ReadonlyMap>, agentName: string, agentAliases?: Iterable, ownerToken?: string): Array<{ threadTs: string; channelId: string; source?: string; }>; export declare function getFollowerOwnedThreadReclaims(threads: ReadonlyMap>, agentName: string, agentAliases?: Iterable, ownerToken?: string): Array<{ threadTs: string; channelId: string; source: string; }>; /** * Cache a thread from a broker inbound message in the local threads map. * The broker DB remains the source of truth; this is only a read-through * cache so Slack tools can resolve channels without hitting the DB every time. */ export declare function trackBrokerInboundThread(threads: Map, inMsg: { threadId: string; channel: string; userId?: string; source?: string; }, owner?: string): void; export declare function formatAgentList(agents: AgentDisplayInfo[], homedir: string): string; export type AgentIdentityRole = "broker" | "worker"; export declare function buildPinetOwnerToken(stableId: string): string; export declare function generateAgentName(seed?: string, role?: AgentIdentityRole): { name: string; emoji: string; }; export type PinetSkinRole = "broker" | "worker"; export interface PinetSkinAssignment { theme: string; role: PinetSkinRole; name: string; emoji: string; personality: string; statusVocabulary?: PinetSkinStatusVocabulary; } export declare const DEFAULT_PINET_SKIN_THEME = "default"; export declare const FOUNDATION_PINET_SKIN_THEME = "foundation"; export declare const COSMERE_PINET_SKIN_THEME = "cosmere"; export declare function normalizePinetSkinTheme(theme: string | undefined): string | null; export declare function buildPinetSkinAssignment(options: { theme: string; role: PinetSkinRole; seed: string; }): PinetSkinAssignment; export declare function resolveAgentIdentity(settings: SlackBridgeSettings, envNickname?: string, seed?: string, role?: AgentIdentityRole): { name: string; emoji: string; }; export declare function alignAgentIdentityToRole(currentIdentity: { name: string; emoji: string; }, settings: SlackBridgeSettings, envNickname?: string, seed?: string, role?: AgentIdentityRole): { name: string; emoji: string; }; export declare function resolveRuntimeAgentIdentity(currentIdentity: { name: string; emoji: string; }, settings: SlackBridgeSettings, envNickname?: string, seed?: string, role?: AgentIdentityRole): { name: string; emoji: string; }; export interface ConfirmationRequest { toolPattern: string; action: string; requestedAt: number; } export interface ThreadConfirmationState { pending: ConfirmationRequest[]; approved: ConfirmationRequest[]; rejected: ConfirmationRequest[]; } export interface RegisterThreadConfirmationRequestResult { state: ThreadConfirmationState; status: "created" | "refreshed" | "conflict"; conflict?: ConfirmationRequest; } export declare const DEFAULT_CONFIRMATION_REQUEST_TTL_MS: number; export declare function normalizeThreadConfirmationState(state: ThreadConfirmationState, now?: number, ttlMs?: number): ThreadConfirmationState; export declare function isThreadConfirmationStateEmpty(state: ThreadConfirmationState): boolean; export declare function confirmationRequestMatches(request: ConfirmationRequest, toolName: string, action: string): boolean; export declare function consumeMatchingConfirmationRequest(list: ConfirmationRequest[], toolName: string, action: string): ConfirmationRequest | null; export declare function registerThreadConfirmationRequest(state: ThreadConfirmationState, request: ConfirmationRequest, now?: number): RegisterThreadConfirmationRequestResult; /** * Standard Slack API response shape. */ export interface SlackResult { ok: boolean; error?: string; [key: string]: unknown; } export interface CallSlackAPIOptions { signal?: AbortSignal; retryCount?: number; } export declare function callSlackAPI(method: string, token: string, body?: Record, options?: CallSlackAPIOptions): Promise; export declare function isRalphNudgeEntry(entry: { message: { metadata?: Record | null; }; }): boolean; export declare function isAgentToAgentEntry(entry: { message: { threadId?: string; metadata?: Record | null; }; }): boolean; export declare function partitionFollowerInboxEntries | null; }; }>(entries: T[]): { nudges: T[]; agentMessages: T[]; regular: T[]; }; export interface RalphCycleRecord { id?: number; startedAt: string; completedAt: string | null; durationMs: number | null; ghostAgentIds: string[]; nudgeAgentIds: string[]; idleDrainAgentIds: string[]; stuckAgentIds: string[]; anomalies: string[]; anomalySignature: string; followUpDelivered: boolean; agentCount: number; backlogCount: number; }