import { ProjectContext } from "./project-context.js";
import { ProjectRegistry } from "./project-registry.js";
import type { GoalTriggerDispatcher } from "./goal-trigger-dispatcher.js";
import type { PersistedGoal } from "./goal-store.js";
import type { PersistedSession } from "./session-store.js";
import type { SearchResults } from "../search/types.js";
/**
 * Minimal session-resolver surface needed by the search orphan filter.
 * Kept as a structural type to avoid a circular import with session-manager.
 */
interface SessionResolver {
    getPersistedSession(id: string): PersistedSession | undefined;
}
/**
 * Central registry of ProjectContext instances.
 *
 * Manages per-project state contexts and provides aggregation methods
 * for cross-project queries (goals, sessions, search).
 */
export declare class ProjectContextManager {
    private contexts;
    private registry;
    private sessionResolver;
    private _sessionResolverWarned;
    /**
     * Shared dispatcher for `goal_created` / `goal_archived` staff triggers.
     * Wired post-boot by `server.ts` once the staff/inbox managers exist.
     * Stored here so every existing AND every future-lazy-created
     * ProjectContext gets the same dispatcher reference.
     */
    private goalTriggerDispatcher;
    constructor(registry: ProjectRegistry);
    /**
     * Wire dependencies used by cross-project services (notably the search
     * orphan filter). Called once during boot after the SessionManager is
     * instantiated. The manager itself is still constructed with only the
     * registry so existing callers need no change.
     */
    setDependencies(deps: {
        sessionManager: SessionResolver;
    }): void;
    /** Initialize contexts for all registered projects. */
    initAll(): void;
    /** Get or lazily create a ProjectContext. */
    getOrCreate(projectId: string): ProjectContext | null;
    /**
     * Late-bound: register the shared `GoalTriggerDispatcher` and wire it into
     * every existing context. Subsequent `getOrCreate` calls will pick up the
     * dispatcher automatically. Safe to call before or after `initAll()`.
     */
    setGoalTriggerDispatcher(dispatcher: GoalTriggerDispatcher | null): void;
    /** Get the underlying project registry. */
    getRegistry(): ProjectRegistry;
    /** Resolve which project a goal belongs to by scanning all contexts. */
    getContextForGoal(goalId: string): ProjectContext | null;
    /** Resolve which project a session belongs to by scanning all contexts. */
    getContextForSession(sessionId: string): ProjectContext | null;
    /** All live (non-archived) goals across all projects, sorted by updatedAt desc. */
    getAllLiveGoals(): PersistedGoal[];
    /** All live (non-archived) sessions across all projects. */
    getAllLiveSessions(): PersistedSession[];
    /** All goals (including archived) across all projects. */
    getAllGoals(): PersistedGoal[];
    /** All sessions (including archived) across all projects. */
    getAllSessions(): PersistedSession[];
    /** Aggregate search across all (or filtered) project indexes. */
    searchAll(query: string, opts?: {
        type?: string;
        limit?: number;
        offset?: number;
        projectId?: string;
        projectNames?: Map<string, string>;
    }): Promise<SearchResults>;
    /**
     * Orphan existence check. Returns false for hits whose backing entity
     * (goal, session, message's parent session, staff) no longer exists, or
     * whose project is no longer registered.
     */
    private _hitExists;
    /**
     * Fire-and-forget: when a hit is dropped as orphaned, enqueue a removal
     * from the owning project's search index so subsequent queries don't
     * return the same orphan row. Not awaited.
     */
    /** One-time warning when the session resolver wiring is missing. */
    private _warnSessionResolverMissing;
    private _scheduleOpportunisticCleanup;
    /** Sum of all goal store generations — any single project change is detected. */
    getGoalGeneration(): number;
    /** Sum of all session store generations — any single project change is detected. */
    getSessionGeneration(): number;
    /** Close all contexts on shutdown. */
    closeAll(): void;
    /** Remove a context when a project is unregistered. */
    remove(projectId: string): void;
    /**
     * Iterate **every** context the manager owns, including hidden ones
     * (e.g. the synthetic system project registered for system-scope
     * tool-assistant sessions).
     *
     * Use this for callers that legitimately need every context:
     * `getContextForSession`, `findStoreForStaff`, MCP discovery, etc.
     *
     * If you are iterating to do worktree/pool/UI work where the system
     * project must be skipped, use {@link visible} instead.
     */
    all(): IterableIterator<ProjectContext>;
    /**
     * Iterate only **visible** contexts — i.e. excluding `hidden: true`
     * projects (the synthetic system project).
     *
     * Use this for worktree sweepers, worktree-pool init, goal/task
     * pool-resolver wiring, maintenance endpoints, and user-facing
     * listings/aggregations. The hidden system project must never
     * participate in any of these flows; iterating it caused
     * `pool/_pool-*` branches to be allocated in unrelated host repos
     * when the bobbit state dir was nested inside one (see
     * `tests/system-project-pool-leak.test.ts`).
     */
    visible(): IterableIterator<ProjectContext>;
    /** Number of initialized project contexts. */
    get size(): number;
}
export {};
//# sourceMappingURL=project-context-manager.d.ts.map