import * as z from "zod/v4"; import { type LoadResult } from "../../config/config-file"; /** * Env marker set by GJC's own programmatic separate-process child spawn sites * (team workers, harness RPC owners) and carrying the spawning session id. * * Presence — not the value — marks a session as GJC-spawned. It is consumed * (read once, then deleted from the child's own env) at startup so it is * per-spawn rather than dynastic: a grandchild is marked only if its own spawn * site marks it, never by inheriting a marked ancestor's environment. */ export declare const SPAWN_PROVENANCE_ENV = "GJC_SPAWNED_BY_SESSION"; /** * Telegram session eligibility: whether a session may own a forum topic and be * admitted by the notification daemon. * * This follows the user's configuration, never how the session was launched. * Gating it on coordinator/lifecycle provenance made every ordinary * interactive session declare itself ineligible, and the daemon refuses an * identity header that does so — so no notification was ever delivered even * though the daemon looked healthy and attached. */ export declare function isTelegramSessionEligible(cfg: NotificationConfig): boolean; export type TelegramActivationState = "inactive" | "blocked"; export type TelegramActivationReason = "saved_inactive" | "identity_mismatch"; /** Non-secret, identity-specific durable Telegram activation state. */ export interface TelegramActivationMarker { identity: string; state: TelegramActivationState; updatedAt: string; reason?: TelegramActivationReason; } export type TelegramActivationMarkers = Record; /** Validate and clone activation markers crossing the settings boundary. */ export declare function readTelegramActivationMarkers(value?: unknown): TelegramActivationMarkers; export type NotificationProvider = "telegram" | "discord" | "slack"; export type NotificationRuntime = "inactive" | "starting" | "ready" | "attached" | "blocked" | "failed"; export type ProviderSecretDisposition = "keep" | "replace" | "remove"; export type ProviderResolutionIssueCode = "missing" | "blank" | "wrong_type" | "invalid_container" | "contradictory"; export interface ProviderResolutionIssue { path: string; code: ProviderResolutionIssueCode; } export type NotificationProviderIssueCode = ProviderResolutionIssueCode; export type NotificationProviderIssue = ProviderResolutionIssue; export interface ProviderResolution { provider: NotificationProvider; configured: boolean; quarantined: boolean; desiredEnabled: boolean; desiredSource: "explicit" | "legacy"; effectiveEnabled: boolean; issues: readonly ProviderResolutionIssue[]; } export interface NotificationSettingsSnapshot { enabled: boolean; telegram: { enabled?: boolean; botToken?: string; chatId?: string; activation?: Record; sound: "all" | "important" | "none"; btw: { enabled: boolean; }; rich: { enabled: boolean; }; richDraft: { enabled: boolean; }; toolActivity: { enabled: boolean; }; streaming: { enabled: boolean; }; topics: { nameTemplate?: string; }; }; discord: { enabled?: boolean; botToken?: string; applicationId?: string; guildId?: string; parentChannelId?: string; }; slack: { enabled?: boolean; botToken?: string; appToken?: string; workspaceId?: string; channelId?: string; authorizedUserId?: string; }; redact: boolean; verbosity: "lean" | "verbose"; sessionScope: "all" | "primary"; idleTimeoutMs: number; /** Safe provider-local validation issues. Raw values never cross this boundary. */ providerIssues?: Partial>; } /** * Narrow settings boundary for remote notification identity and behavior. * Implementations return only user-global values; project settings and runtime * overrides are intentionally excluded. */ export interface NotificationSettingsReader { getNotificationSettingsSnapshot(): NotificationSettingsSnapshot; getAgentDir(): string; } /** Validate and snapshot raw global notification configuration without leaking invalid provider values. */ export declare function parseNotificationSettingsSnapshot(rawConfig?: unknown): NotificationSettingsSnapshot; export interface NotificationConfig { enabled: boolean; botToken?: string; activation?: TelegramActivationMarkers; chatId?: string; /** Optional nested Telegram intent metadata; absent means legacy configuration. */ telegram?: { enabled?: boolean; }; discord: { enabled?: boolean; botToken?: string; applicationId?: string; guildId?: string; parentChannelId?: string; }; slack: { enabled?: boolean; botToken?: string; appToken?: string; workspaceId?: string; channelId?: string; authorizedUserId?: string; }; redact: boolean; verbosity: "lean" | "verbose"; sessionScope: "all" | "primary"; sound: "all" | "important" | "none"; idleTimeoutMs: number; btw: { enabled: boolean; }; rich: { enabled: boolean; }; richDraft: { enabled: boolean; }; toolActivity: { enabled: boolean; }; streaming: { enabled: boolean; }; topics: { nameTemplate?: string; }; providerIssues?: Partial>; } /** Read typed global-only notification config from a narrow settings reader. */ export declare function getNotificationConfig(settings: NotificationSettingsReader): NotificationConfig; declare const notificationConfigSchema: z.ZodObject<{}, z.core.$loose>; type NotificationConfigFile = z.infer; /** Read daemon settings through the canonical validated config-file boundary. */ export declare function loadNotificationConfigFile(agentDir: string): LoadResult; export declare function notificationConfigFromFile(value: NotificationConfigFile): NotificationConfig; export declare function hasNonBlankValue(value: string | undefined): boolean; export declare function isProviderComplete(cfg: NotificationConfig, provider: NotificationProvider): boolean; export declare function isTelegramComplete(cfg: NotificationConfig): cfg is NotificationConfig & { botToken: string; chatId: string; }; export declare function isDiscordComplete(cfg: NotificationConfig): cfg is NotificationConfig & { discord: { botToken: string; applicationId: string; guildId: string; parentChannelId: string; }; }; export declare function isSlackComplete(cfg: NotificationConfig): cfg is NotificationConfig & { slack: { botToken: string; appToken: string; workspaceId: string; channelId: string; }; }; export declare function resolveNotificationProvider(cfg: NotificationConfig, provider: NotificationProvider): ProviderResolution; export declare function isProviderEffectivelyEnabled(cfg: NotificationConfig, provider: NotificationProvider): boolean; export declare function hasAnyCompleteProvider(cfg: NotificationConfig): boolean; export declare function hasAnyEffectivelyEnabledProvider(cfg: NotificationConfig): boolean; /** * Resolve generic live-stream policy. This policy only governs automatic * current-session frames; it never changes durable provider eligibility. */ export type GenericNotificationSessionSource = "hard_opt_out" | "session_local_off" | "explicit_env" | "token_env" | "configured_provider" | "session_scope" | "none"; export interface GenericNotificationSessionEligibility { enabled: boolean; source: GenericNotificationSessionSource; } export type GenericNotificationStreamSource = "session_not_admitted" | "env_on" | "env_off" | "durable_telegram" | "none"; export interface GenericNotificationStreamPolicy { enabled: boolean; source: GenericNotificationStreamSource; } export interface GenericNotificationSessionEligibilityInput { cfg: NotificationConfig; env: NodeJS.ProcessEnv; sessionDisabled: boolean; spawnedByGjc?: boolean; } export declare function resolveGenericNotificationSessionEligibility(input: GenericNotificationSessionEligibilityInput): GenericNotificationSessionEligibility; export declare function resolveGenericNotificationStreamPolicy(input: { cfg: NotificationConfig; env: NodeJS.ProcessEnv; genericSessionEnabled: boolean; }): GenericNotificationStreamPolicy; export declare function completionNotifyDisabledByEnv(env: NodeJS.ProcessEnv): boolean; export interface NotificationHostEligibilityInput { env: NodeJS.ProcessEnv; hostModeSupported?: boolean; taskDepth?: number; parentTaskPrefix?: string; currentAgentType?: string; sessionScope?: NotificationConfig["sessionScope"]; spawnedByGjc?: boolean; } /** Generic host eligibility for the dormant automatic notification surface. */ export declare function isGenericNotificationHostEligible(input: NotificationHostEligibilityInput): boolean; export interface GenericNotificationRegistrationInput { env: NodeJS.ProcessEnv; cfg?: NotificationConfig; taskDepth?: number; parentTaskPrefix?: string; currentAgentType?: string; spawnedByGjc?: boolean; } /** Generic registration admission; direct provider actions do not call this helper. */ export declare function shouldRegisterGenericNotificationsExtension(input: GenericNotificationRegistrationInput): boolean; export declare function isGenericNotificationSessionEnabled(input: GenericNotificationSessionEligibilityInput): boolean; /** Mask a bot token for display: first 4 chars + "…" + "(len N)"; "(unset)" when undefined/empty. Never reveal full token. */ export declare function maskToken(token: string | undefined): string; /** Stable non-reversible fingerprint of a token: sha256 hex, first 12 chars. */ export declare function tokenFingerprint(token: string): string; /** Deterministic non-secret key for one Telegram token/chat identity. */ export declare function telegramActivationIdentity(botToken: string, chatId: string): string; /** Return the durable marker for the currently configured Telegram identity, if any. */ export declare function getCurrentTelegramActivationMarker(cfg: NotificationConfig): TelegramActivationMarker | undefined; /** Short session tag for display, e.g. last 6 chars of sessionId. */ export declare function sessionTag(sessionId: string): string; export interface RedactableAction { id: string; kind: string; sessionId: string; /** Durable workflow-gate correlation metadata; never generic reply authority. */ workflowGateId?: string; question?: string; options?: string[]; /** Selected zero-based option positions for transport-specific multi-select rendering. */ selectedOptionIndices?: number[]; summary?: string; /** Optional zero-based recommendation into the authoritative raw options. */ recommendedIndex?: number; } /** * When redact is true, strip sensitive content for remote delivery: * - ask: NOT redacted. An ask is an interactive prompt the human must read and * answer on the remote surface; redacting its question/options would make it * unanswerable, defeating remote answering. Asks are returned unchanged. * - idle: summary removed, (no question/options). * When redact is false, return the action unchanged. * * Redaction still applies to streamed content frames (turn_stream, context_update, * image_attachment) which are suppressed at their emit sites, not here. Explicit * `telegram_send` file attachments are rejected before the file is read or forwarded. */ export declare function buildRedactedAction(action: RedactableAction, opts: { redact: boolean; }): RedactableAction; export {};