import { Duration, Effect, Layer } from "effect";
import { type HttpClient } from "effect/unstable/http";
import type { OAuthEndpointUrlPolicy } from "./oauth-helpers";
import { type FumaDb, type FumaTables, type StorageFailure } from "./fuma-runtime";
import { ConnectionRef, ConnectionRefreshError, type CreateConnectionInput, type RemoveConnectionInput, type UpdateConnectionTokensInput } from "./connections";
import { type CredentialBindingRef, type CredentialBindingsFacade, type RemoveSourceCredentialBindingInput, type ReplaceSourceCredentialBindingsInput, type SetSourceCredentialBindingInput, type SourceCredentialBindingSlotInput, type SourceCredentialBindingSourceInput } from "./credential-bindings";
import { ElicitationDeclinedError, type ElicitationHandler } from "./elicitation";
import { ConnectionInUseError, ConnectionNotFoundError, ConnectionProviderNotRegisteredError, ConnectionReauthRequiredError, ConnectionRefreshNotSupportedError, NoHandlerError, PluginNotLoadedError, SecretInUseError, SecretOwnedByConnectionError, SourceRemovalNotAllowedError, ToolBlockedError, ToolInvocationError, ToolNotFoundError } from "./errors";
import { ScopeId } from "./ids";
import type { OAuthService } from "./oauth";
import { type CreateToolPolicyInput, type PolicyMatch, type RemoveToolPolicyInput, type ToolPolicy, type UpdateToolPolicyInput } from "./policies";
import type { AnyPlugin, PluginExtensions } from "./plugin";
import type { Scope } from "./scope";
import { RemoveSecretInput, SecretRef, SetSecretInput } from "./secrets";
import { Usage } from "./usages";
import { ToolSchema, type RefreshSourceInput, type RemoveSourceInput, type Source, type SourceDetectionResult, type Tool, type ToolListFilter } from "./types";
export type OnElicitation = ElicitationHandler | "accept-all";
export interface InvokeOptions {
    /** Override the executor-level handler for this single call. */
    readonly onElicitation?: OnElicitation;
}
export type Executor<TPlugins extends readonly AnyPlugin[] = readonly []> = {
    /**
     * Precedence-ordered scope stack this executor was configured with.
     * Innermost first. Consumers that need "the display scope" typically
     * pick `scopes.at(-1)` (outermost, e.g. the organization) or
     * `scopes[0]` (innermost, e.g. the current user-in-org) depending on
     * what they're rendering.
     */
    readonly scopes: readonly Scope[];
    readonly tools: {
        readonly list: (filter?: ToolListFilter) => Effect.Effect<readonly Tool[], StorageFailure>;
        /** Fetch a tool's schema view: JSON schemas with `$defs`
         *  attached from the core `definition` table, plus TypeScript
         *  preview strings. Returns `null` for unknown tool ids. */
        readonly schema: (toolId: string) => Effect.Effect<ToolSchema | null, StorageFailure>;
        /** Every `$defs` entry across every source, grouped by source id.
         *  Used for bulk schema export and downstream TypeScript rendering. */
        readonly definitions: () => Effect.Effect<Record<string, Record<string, unknown>>, StorageFailure>;
        readonly invoke: (toolId: string, args: unknown, options?: InvokeOptions) => Effect.Effect<unknown, ToolNotFoundError | ToolBlockedError | PluginNotLoadedError | NoHandlerError | ToolInvocationError | ElicitationDeclinedError | StorageFailure>;
    };
    readonly sources: {
        readonly list: () => Effect.Effect<readonly Source[], StorageFailure>;
        readonly remove: (input: RemoveSourceInput) => Effect.Effect<void, SourceRemovalNotAllowedError | StorageFailure>;
        readonly refresh: (input: RefreshSourceInput) => Effect.Effect<void, StorageFailure>;
        /** URL autodetection — fans out to every plugin's `detect` hook
         *  (if declared), returns every high/medium/low-confidence match.
         *  UI picks a winner from the list. */
        readonly detect: (url: string) => Effect.Effect<readonly SourceDetectionResult[], StorageFailure>;
        /** All `$defs` registered for a single source, keyed by def name. */
        readonly definitions: (sourceId: string) => Effect.Effect<Record<string, unknown>, StorageFailure>;
        readonly configure: (input: {
            readonly source: {
                readonly id: string;
                readonly scope: ScopeId | string;
            };
            readonly scope: ScopeId | string;
            readonly type?: string;
            readonly config: unknown;
        }) => Effect.Effect<unknown, StorageFailure>;
        readonly listBindings: (input: SourceCredentialBindingSourceInput) => Effect.Effect<readonly CredentialBindingRef[], StorageFailure>;
        readonly resolveBinding: (input: SourceCredentialBindingSlotInput) => Effect.Effect<CredentialBindingRef | null, StorageFailure>;
        readonly setBinding: (input: SetSourceCredentialBindingInput) => Effect.Effect<CredentialBindingRef, StorageFailure>;
        readonly removeBinding: (input: RemoveSourceCredentialBindingInput) => Effect.Effect<void, StorageFailure>;
        readonly replaceBindings: (input: ReplaceSourceCredentialBindingsInput) => Effect.Effect<readonly CredentialBindingRef[], StorageFailure>;
    };
    readonly secrets: {
        readonly get: (id: string) => Effect.Effect<string | null, SecretOwnedByConnectionError | StorageFailure>;
        readonly getAtScope: (id: string, scope: string) => Effect.Effect<string | null, SecretOwnedByConnectionError | StorageFailure>;
        /** Fast-path existence check — hits the core `secret` routing table
         *  only, never calls the provider. Use this for UI state ("secret
         *  missing, prompt to add") to avoid keychain permission prompts
         *  or 1password IPC roundtrips on a pre-flight check. */
        readonly status: (id: string) => Effect.Effect<"resolved" | "missing", StorageFailure>;
        readonly set: (input: SetSecretInput) => Effect.Effect<SecretRef, StorageFailure>;
        /** Delete a bare (non-connection-owned) secret. Connection-owned
         *  secrets are rejected with `SecretOwnedByConnectionError` — use
         *  `connections.remove` instead. Refuses with `SecretInUseError`
         *  if any plugin reports the secret as in use; the caller should
         *  show the `usages(id)` list and ask the user to detach first. */
        readonly remove: (input: RemoveSecretInput) => Effect.Effect<void, SecretOwnedByConnectionError | SecretInUseError | StorageFailure>;
        readonly list: () => Effect.Effect<readonly SecretRef[], StorageFailure>;
        /** Management view of visible secret rows. Unlike `list`, this does
         *  not collapse same-id rows across scopes, so UI that writes exact
         *  credential targets can show both personal and shared rows. */
        readonly listAll: () => Effect.Effect<readonly SecretRef[], StorageFailure>;
        /** All places this secret is referenced — fans out across every
         *  plugin's `usagesForSecret`. Used by the Secrets-tab "Used by"
         *  list and by `remove` for its RESTRICT check. */
        readonly usages: (id: string) => Effect.Effect<readonly Usage[], StorageFailure>;
        readonly providers: () => Effect.Effect<readonly string[]>;
    };
    readonly connections: {
        readonly get: (id: string) => Effect.Effect<ConnectionRef | null, StorageFailure>;
        readonly getAtScope: (id: string, scope: string) => Effect.Effect<ConnectionRef | null, StorageFailure>;
        readonly list: () => Effect.Effect<readonly ConnectionRef[], StorageFailure>;
        readonly create: (input: CreateConnectionInput) => Effect.Effect<ConnectionRef, ConnectionProviderNotRegisteredError | StorageFailure>;
        readonly updateTokens: (input: UpdateConnectionTokensInput) => Effect.Effect<ConnectionRef, ConnectionNotFoundError | StorageFailure>;
        readonly setIdentityLabel: (id: string, label: string | null) => Effect.Effect<void, ConnectionNotFoundError | StorageFailure>;
        readonly accessToken: (id: string) => Effect.Effect<string, ConnectionNotFoundError | ConnectionProviderNotRegisteredError | ConnectionRefreshNotSupportedError | ConnectionReauthRequiredError | ConnectionRefreshError | StorageFailure>;
        readonly accessTokenAtScope: (id: string, scope: string) => Effect.Effect<string, ConnectionNotFoundError | ConnectionProviderNotRegisteredError | ConnectionRefreshNotSupportedError | ConnectionReauthRequiredError | ConnectionRefreshError | StorageFailure>;
        /** Refuses with `ConnectionInUseError` if any plugin reports the
         *  connection as in use. */
        readonly remove: (input: RemoveConnectionInput) => Effect.Effect<void, ConnectionInUseError | StorageFailure>;
        /** All places this connection is referenced — fans out across every
         *  plugin's `usagesForConnection`. */
        readonly usages: (id: string) => Effect.Effect<readonly Usage[], StorageFailure>;
        readonly providers: () => Effect.Effect<readonly string[]>;
    };
    /** Shared credential slot bindings. Plugins decide what slot keys mean;
     *  core owns scoped storage, resolution status, and usage visibility. */
    readonly credentialBindings: CredentialBindingsFacade;
    /** Shared OAuth service. Hosts use this through the core HTTP OAuth group;
     *  plugins see the same service as `ctx.oauth`. */
    readonly oauth: OAuthService;
    readonly policies: {
        /** All policies visible across the executor's scope stack, sorted
         *  by (innermost-scope-first, position ascending) — i.e. the order
         *  in which they're evaluated by first-match-wins. */
        readonly list: () => Effect.Effect<readonly ToolPolicy[], StorageFailure>;
        /** Create a new policy. Defaults to the top of the target scope's
         *  list (highest precedence) when `position` is omitted. */
        readonly create: (input: CreateToolPolicyInput) => Effect.Effect<ToolPolicy, StorageFailure>;
        readonly update: (input: UpdateToolPolicyInput) => Effect.Effect<ToolPolicy, StorageFailure>;
        readonly remove: (input: RemoveToolPolicyInput) => Effect.Effect<void, StorageFailure>;
        /** Resolve the effective policy for a tool id by walking the scope-
         *  stacked policy list with first-match-wins semantics. Returns
         *  `undefined` when no rule matches (caller falls back to the
         *  plugin's `resolveAnnotations` output). */
        readonly resolve: (toolId: string) => Effect.Effect<PolicyMatch | undefined, StorageFailure>;
    };
    readonly close: () => Effect.Effect<void, StorageFailure>;
} & PluginExtensions<TPlugins>;
export interface ExecutorDb {
    readonly db: FumaDb<any>;
    readonly close?: () => Effect.Effect<void, StorageFailure> | Promise<void> | void;
}
export type ExecutorDbInput = FumaDb<any> | ExecutorDb;
export type ExecutorDbFactory = (config: {
    readonly tables: FumaTables;
}) => ExecutorDbInput | Effect.Effect<ExecutorDbInput, StorageFailure>;
export interface ExecutorConfig<TPlugins extends readonly AnyPlugin[] = readonly []> {
    /**
     * Precedence-ordered scope stack. Innermost first; typical shape is
     * `[userInOrgScope, orgScope]`. Reads on scoped tables walk the
     * stack (first hit wins for shadow-by-id consumers like secrets and
     * blobs); writes require callers to name an explicit target scope.
     * Must be non-empty.
     */
    readonly scopes: readonly Scope[];
    readonly db?: ExecutorDbInput | ExecutorDbFactory;
    readonly plugins?: TPlugins;
    /**
     * How to respond when a tool requests user input mid-invocation. Pass
     * `"accept-all"` for tests / non-interactive hosts, or a handler
     * `(ctx) => Effect<ElicitationResponse>` for interactive ones.
     * Required at construction so per-invoke calls don't have to thread
     * an options arg.
     */
    readonly onElicitation: OnElicitation;
    readonly httpClientLayer?: Layer.Layer<HttpClient.HttpClient>;
    readonly oauthEndpointUrlPolicy?: OAuthEndpointUrlPolicy;
    readonly sourceDetection?: {
        readonly maxUrlLength?: number;
        readonly maxDetectors?: number;
        readonly maxResults?: number;
        readonly timeout?: Duration.Input;
        readonly hostedOutboundPolicy?: boolean;
    };
    /**
     * Enable the built-in `core-tools` plugin which contributes
     * agent-facing static tools (`scopes.list`, `secrets.list`,
     * `secrets.create`). The `webBaseUrl` is where the executor's web
     * UI lives; `secrets.create` builds a URL elicitation that points
     * the user at `${webBaseUrl}/secrets?...` so the plaintext value
     * never crosses the agent.
     *
     * Omit to skip registration (tests, MCP-only hosts that don't
     * surface a web UI, etc.).
     */
    readonly coreTools?: {
        readonly webBaseUrl: string;
    };
}
export declare const collectTables: (plugins: readonly AnyPlugin[]) => FumaTables;
export declare const createExecutor: <const TPlugins extends readonly AnyPlugin[] = readonly []>(config: ExecutorConfig<TPlugins>) => Effect.Effect<Executor<TPlugins>, StorageFailure>;
//# sourceMappingURL=executor.d.ts.map