import { SmartBuffer } from './buffer.js';
import { S as SearchBackend, a as SearchQueryOptions, b as SearchExecutionOptions } from './port-hqGnoStS.js';
import { StorageManager } from './storage.js';
import { TranscriptManager } from './transcript.js';
import { HourlySummarizer } from './summarizer.js';
import { LocalLlmClient } from './local-llm.js';
import { FallbackLlmClient } from './fallback-llm.js';
import { LiveConnectorsRunSummary } from './live-connectors-runner.js';
import { ModelRegistry } from './model-registry.js';
import { RelevanceStore } from './relevance.js';
import { NegativeExampleStore } from './negative.js';
import { LastRecallStore, TierMigrationStatusStore, GraphRecallExpandedEntry, TierMigrationStatusSnapshot, TierMigrationCycleSummary, LastRecallSnapshot } from './recall-state.js';
import { RecallXraySnapshot } from './recall-xray.js';
import { SessionObserverState } from './session-observer-state.js';
import { EmbeddingFallback } from './embedding-fallback.js';
import { PluginConfig, CodingContext, QmdSearchResult, BehaviorLoopPolicyState, BootstrapOptions, BootstrapResult, ConsolidationObservation, MemoryFile, DaySummaryResult, MemoryActionEvent, RecallPlanMode, MemoryIntent, EntityTimelineEntry, ExtractionResult, MemoryFrontmatter, IdentityInjectionMode } from './types.js';
import { S as SemanticConsolidationResult } from './semantic-consolidation-ByBXb-sf.js';
import { z } from 'zod';
import { RuntimePolicyValues } from './policy-runtime.js';
import { ProfilingCollector } from './profiling.js';

/**
 * Pattern-reinforcement maintenance job (issue #687 PR 2/4).
 *
 * Reads all memories via `StorageManager.readAllMemories()`, clusters
 * non-procedural memories by normalized content, and reinforces the
 * most-recent member of each large-enough cluster:
 *
 *   1. Cluster across active AND already-superseded members.  This is
 *      load-bearing: after the first reinforcement pass, older
 *      duplicates are marked `superseded`, so on the next pass the
 *      "active count" alone would be just `canonical + N-new`.  By
 *      keeping superseded members in the cluster for the threshold
 *      check, an established canonical (count >= minCount) keeps
 *      growing as soon as a single new duplicate arrives.
 *      `forgotten` / `archived` / `quarantined` / `pending_review` /
 *      `rejected` stay excluded per CLAUDE.md rule 53.
 *   2. Pick the most-recent ACTIVE member of each cluster as the
 *      canonical.  Stamp it with `reinforcement_count` (total cluster
 *      size including superseded members) and `last_reinforced_at`.
 *      Record provenance: `derived_from = [...source-ids...]` and
 *      `derived_via = "pattern-reinforcement"`.
 *   3. Mark any still-active duplicates with `status: "superseded"`
 *      and point `supersededBy` at the canonical id.
 *
 * The job is idempotent: re-running on the same corpus does not
 * double-bump `reinforcement_count` (the bump-only-on-change guard
 * compares cluster size to the canonical's previous counter), and
 * already-superseded duplicates simply pass through.
 *
 * Recall integration (boost from `reinforcement_count`) and the CLI
 * surface ship in PR 3/4 and PR 4/4 respectively — this PR only wires
 * the maintenance job and storage plumbing.
 */

interface PatternReinforcementClusterResult {
    /** Memory id of the canonical (most-recent) member. */
    canonicalId: string;
    /** Cluster size at run time (mirrors `reinforcement_count`). */
    count: number;
    /** IDs of the source memories that contributed (canonical + duplicates). */
    sourceIds: readonly string[];
    /** IDs of the older duplicates that were marked superseded. */
    supersededIds: readonly string[];
    /**
     * `true` when the canonical's `reinforcement_count` actually
     * changed during this run.  False when the job converged
     * idempotently (same cluster size as the previous run).
     */
    reinforcementBumped: boolean;
}
interface PatternReinforcementResult {
    /** Number of clusters that met the `minCount` threshold. */
    clustersFound: number;
    /** Number of canonical memories whose reinforcement counter changed. */
    canonicalsUpdated: number;
    /** Total duplicate memories newly marked `status: "superseded"`. */
    duplicatesSuperseded: number;
    /** Per-cluster details for tests / observability. */
    clusters: PatternReinforcementClusterResult[];
}

/**
 * @remnic/core — Write-time semantic dedup guard
 *
 * Complements the exact content-hash check in the orchestrator's write path
 * by detecting near-duplicate candidate facts via embedding cosine similarity.
 *
 * The module intentionally has no dependency on the EmbeddingFallback or QMD
 * classes directly — callers pass in a `lookup` function that returns the
 * top-K nearest neighbors with their cosine scores. This keeps the decision
 * logic pure and trivially testable with synthetic fixtures, and lets the
 * orchestrator reuse whichever backend it already has wired up.
 *
 * Related issue: joshuaswarren/remnic#373
 */
/** A single nearest-neighbor hit from the embedding backend. */
interface SemanticDedupHit {
    /** Memory id of the existing neighbor. */
    id: string;
    /** Cosine similarity score in [0, 1]. */
    score: number;
    /** Optional source path, purely informational. */
    path?: string;
}
/**
 * Lookup function passed by the caller. Must return an array of hits sorted
 * descending by score. Implementations should return an empty array (never
 * throw) when the embedding backend is unavailable — the decision function
 * treats that as "no near duplicate" (fail-open).
 */
type SemanticDedupLookup = (content: string, limit: number) => Promise<SemanticDedupHit[]>;
interface SemanticDedupOptions {
    /** Master switch. When false, `decideSemanticDedup` always returns `keep`. */
    enabled: boolean;
    /** Cosine similarity threshold (0-1). ≥ threshold ⇒ treat as duplicate. */
    threshold: number;
    /** How many nearest neighbors to compare against. */
    candidates: number;
}
type SemanticDedupDecision = {
    action: "keep";
    reason: "disabled" | "backend_unavailable" | "no_candidates" | "no_near_duplicate";
    topScore?: number;
    topId?: string;
} | {
    action: "skip";
    reason: "near_duplicate";
    topScore: number;
    topId: string;
    topPath?: string;
};
/**
 * Pure decision function: given a lookup callback and options, decide whether
 * the candidate content should be written or skipped as a near-duplicate.
 *
 * Contract:
 *   - When `options.enabled` is false → always keep, reason="disabled".
 *   - When the lookup throws (provider down / network error) → keep,
 *     reason="backend_unavailable". Fail-open: a lookup failure must not block
 *     writes.
 *   - When the lookup succeeds but returns 0 hits (empty index or no
 *     neighbors above the score floor) → keep, reason="no_candidates".
 *     This is distinct from backend_unavailable so telemetry dashboards can
 *     correctly distinguish "provider is down" from "index is empty".
 *   - When the top hit's score ≥ threshold → skip with reason="near_duplicate".
 *   - Otherwise → keep with reason="no_near_duplicate".
 */
declare function decideSemanticDedup(content: string, lookup: SemanticDedupLookup, options: SemanticDedupOptions): Promise<SemanticDedupDecision>;

type ReplaySource = "openclaw" | "claude" | "chatgpt";
type ReplayRole = "user" | "assistant";
interface ReplayTurn {
    source: ReplaySource;
    sessionKey: string;
    role: ReplayRole;
    content: string;
    timestamp: string;
    externalId?: string;
    metadata?: Record<string, unknown>;
}
interface ReplayWarning {
    code: string;
    message: string;
    index?: number;
}

interface BulkImportSource {
    turns: ImportTurn[];
    metadata: {
        source: string;
        exportDate: string;
        messageCount: number;
        dateRange: {
            from: string;
            to: string;
        };
    };
}
interface ImportTurn {
    role: "user" | "assistant" | "other";
    content: string;
    timestamp: string;
    participantId?: string;
    participantName?: string;
    replyToId?: string;
}
interface BulkImportOptions {
    batchSize?: number;
    dryRun?: boolean;
    dedup?: boolean;
    trustLevel?: "import";
    namespace?: string;
}
type ImportSourceRole = ImportTurn["role"];
interface BulkImportResult {
    memoriesCreated: number;
    duplicatesSkipped: number;
    entitiesCreated: number;
    turnsProcessed: number;
    batchesProcessed: number;
    errors: BulkImportError[];
}
interface BulkImportError {
    batchIndex: number;
    message: string;
}
interface BulkImportSourceAdapter {
    name: string;
    parse(input: unknown, options?: {
        strict?: boolean;
        platform?: string;
    }): Promise<BulkImportSource> | BulkImportSource;
}
interface ImportTurnValidationIssue {
    code: string;
    message: string;
    index?: number;
}
declare function isImportRole(value: unknown): value is ImportSourceRole;
/**
 * Parse an ISO-8601 / RFC 3339 timestamp used by bulk-import adapters.
 *
 * Accepts variable-precision fractional seconds and either a `Z` suffix or a
 * `[+-]HH:MM` timezone offset, so adapters may preserve their source
 * timestamps verbatim. Returns milliseconds since epoch, or `null` if the
 * string is not a well-formed timestamp (including overflowed calendar dates
 * or out-of-range offsets).
 *
 * Delegates to the shared parser in `utils/iso-timestamp.ts` — do not
 * reimplement locally; extend that helper instead.
 */
declare function parseIsoTimestamp(value: string): number | null;
declare function validateImportTurn(turn: ImportTurn, index?: number): ImportTurnValidationIssue[];

type SummarizeFn = (text: string, targetTokens: number, aggressive: boolean) => Promise<string | null>;

declare class LcmEngine {
    private readonly summarizeFn;
    private db;
    private archive;
    private dag;
    private summarizer;
    private observeQueue;
    private closed;
    private readonly config;
    private readonly memoryDir;
    private initPromise;
    private readonly pendingObserveInitCounts;
    private readonly pendingObserveInitWaiters;
    private readonly pendingObserveInitIdleWaiters;
    constructor(pluginConfig: PluginConfig, summarizeFn: SummarizeFn);
    get enabled(): boolean;
    /** Lazy init — open database on first use. */
    ensureInitialized(): Promise<void>;
    private doInit;
    /**
     * Enqueue messages from agent_end hook.
     * The queue worker performs the archive append and incremental summarization.
     */
    observeMessages(sessionId: string, messages: Array<{
        role: string;
        content: string;
    }>): Promise<void>;
    /** Enqueue an observe job without waiting for worker completion. */
    enqueueObserveMessages(sessionId: string, messages: Array<{
        role: string;
        content: string;
    }>): void;
    private processObserveMessages;
    get observeQueueDepth(): number;
    get observeQueueInFlightCount(): number;
    waitForObserveQueueIdle(): Promise<void>;
    waitForSessionObserveIdle(sessionId: string): Promise<void>;
    private reservePendingObserveInit;
    private releasePendingObserveInit;
    private waitForPendingObserveInitIdle;
    /** Build the compressed history recall section for a session. */
    assembleRecall(sessionId: string, budgetChars: number): Promise<string>;
    /** Flush pending summaries before compaction (called from before_compaction hook). */
    preCompactionFlush(sessionId: string): Promise<void>;
    /** Record a compaction event with real token counts (called from after_compaction hook). */
    recordCompaction(sessionId: string, tokensBefore: number, tokensAfter: number): Promise<void>;
    /** Verify archive coverage after compaction. */
    verifyPostCompaction(sessionId: string): Promise<void>;
    /** Search across all conversation history via FTS (snippet mode). */
    searchContext(query: string, limit: number, sessionId?: string): Promise<Array<{
        turn_index: number;
        role: string;
        snippet: string;
        session_id: string;
    }>>;
    /** Search via FTS returning full message content (not snippets). */
    searchContextFull(query: string, limit: number, sessionId?: string): Promise<Array<{
        id: number;
        turn_index: number;
        role: string;
        content: string;
        session_id: string;
        score: number;
    }>>;
    /** Get a compressed summary of a turn range. */
    describeContext(sessionId: string, fromTurn: number, toTurn: number): Promise<{
        summary: string;
        turn_count: number;
        depth: number;
    } | null>;
    /** Retrieve raw messages for a turn range (lossless expansion). */
    expandContext(sessionId: string, fromTurn: number, toTurn: number, maxTokens: number): Promise<Array<{
        turn_index: number;
        role: string;
        content: string;
    }>>;
    /** Get statistics about the LCM archive. */
    getStats(sessionId?: string): Promise<{
        totalMessages: number;
        totalSummaryNodes: number;
        maxDepth: number;
    }>;
    /** Prune old data beyond retention period. */
    prune(): Promise<{
        messagesPruned: number;
        nodesPruned: number;
    }>;
    /** Close the database connection. */
    close(): void;
}

interface ConversationIndexBackendInspection {
    backend: "qmd" | "faiss";
    status: "ok" | "degraded" | "disabled";
    available: boolean;
    indexPath: string;
    supportsIncrementalUpdate: boolean;
    message?: string;
    metadata: {
        chunkCount: number | null;
        qmdAvailable?: boolean;
        debugStatus?: string;
        hasIndex?: boolean;
        hasMetadata?: boolean;
        hasManifest?: boolean;
        manifest?: {
            version: number;
            modelId: string;
            normalizedModelId: string;
            dimension: number;
            chunkCount: number;
            updatedAt: string;
            lastSuccessfulRebuildAt: string;
        };
    };
}

declare const SharedFeedbackEntrySchema: z.ZodObject<{
    agent: z.ZodString;
    decision: z.ZodEnum<["approved", "approved_with_feedback", "rejected"]>;
    reason: z.ZodString;
    date: z.ZodString;
    learning: z.ZodOptional<z.ZodString>;
    outcome: z.ZodOptional<z.ZodString>;
    severity: z.ZodOptional<z.ZodEnum<["low", "medium", "high"]>>;
    confidence: z.ZodOptional<z.ZodNumber>;
    workflow: z.ZodOptional<z.ZodString>;
    tags: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
    evidenceWindowStart: z.ZodOptional<z.ZodString>;
    evidenceWindowEnd: z.ZodOptional<z.ZodString>;
    refs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
}, "strip", z.ZodTypeAny, {
    decision: "rejected" | "approved" | "approved_with_feedback";
    agent: string;
    date: string;
    reason: string;
    workflow?: string | undefined;
    tags?: string[] | undefined;
    confidence?: number | undefined;
    severity?: "low" | "medium" | "high" | undefined;
    outcome?: string | undefined;
    refs?: string[] | undefined;
    learning?: string | undefined;
    evidenceWindowStart?: string | undefined;
    evidenceWindowEnd?: string | undefined;
}, {
    decision: "rejected" | "approved" | "approved_with_feedback";
    agent: string;
    date: string;
    reason: string;
    workflow?: string | undefined;
    tags?: string[] | undefined;
    confidence?: number | undefined;
    severity?: "low" | "medium" | "high" | undefined;
    outcome?: string | undefined;
    refs?: string[] | undefined;
    learning?: string | undefined;
    evidenceWindowStart?: string | undefined;
    evidenceWindowEnd?: string | undefined;
}>;
type SharedFeedbackEntry = z.infer<typeof SharedFeedbackEntrySchema>;
interface SharedCrossSignalSource {
    agent: string;
    path: string;
    title: string;
    topics: string[];
}
interface SharedCrossSignalOverlap {
    token: string;
    agents: string[];
    sourcePaths: string[];
    agentCount: number;
}
interface SharedCrossSignalReport {
    date: string;
    generatedAt: string;
    sourceCount: number;
    feedbackCount: number;
    feedbackByDecision: Record<"approved" | "approved_with_feedback" | "rejected", number>;
    feedbackEntries: SharedFeedbackEntry[];
    sources: SharedCrossSignalSource[];
    overlaps: SharedCrossSignalOverlap[];
    semantic: {
        enabled: boolean;
        applied: boolean;
        timedOut: boolean;
        candidateCount: number;
        maxCandidates: number;
        addedOverlapCount: number;
    };
}
interface SharedCrossSignalSynthesisResult {
    date: string;
    crossSignalsPath: string;
    crossSignalsMarkdownPath: string;
    overlapCount: number;
    report: SharedCrossSignalReport;
}
interface SharedDailyCurationResult {
    date: string;
    roundtablePath: string;
    crossSignalsPath: string;
    crossSignalsMarkdownPath: string;
    overlapCount: number;
}
declare class SharedContextManager {
    private readonly config;
    readonly dir: string;
    private readonly prioritiesPath;
    private readonly prioritiesInboxPath;
    private readonly outputsDir;
    private readonly roundtableDir;
    private readonly feedbackDir;
    private readonly feedbackInboxPath;
    private readonly crossSignalsDir;
    constructor(config: PluginConfig);
    ensureStructure(): Promise<void>;
    private ensureFile;
    readPriorities(): Promise<string>;
    readLatestRoundtable(): Promise<string>;
    readLatestCrossSignals(): Promise<string>;
    writeAgentOutput(opts: {
        agentId: string;
        title: string;
        content: string;
        createdAt?: Date;
    }): Promise<string>;
    appendFeedback(entry: SharedFeedbackEntry): Promise<void>;
    appendPrioritiesInbox(opts: {
        agentId: string;
        text: string;
    }): Promise<void>;
    synthesizeCrossSignals(opts: {
        date?: string;
        maxSummaryItems?: number;
    }): Promise<SharedCrossSignalSynthesisResult>;
    curateDaily(opts: {
        date?: string;
        maxChars?: number;
    }): Promise<SharedDailyCurationResult>;
}

type MistakesFile = {
    version?: number;
    updatedAt: string;
    patterns: string[];
    registry?: MistakeRegistryEntry[];
};
type ActionOutcomeCounts = {
    applied: number;
    skipped: number;
    failed: number;
};
type ActionOutcomeSummary = {
    action: string;
    counts: ActionOutcomeCounts;
    total: number;
    weightedScore: number;
    provenance: string[];
};
type PromotionCandidate = {
    id: string;
    sourceType: "action-outcome" | "mistake-pattern" | "rubric" | "causal-pattern";
    subject: string;
    category: "principle" | "rule";
    content: string;
    score: number;
    rationale: string;
    outcome: ActionOutcomeCounts | null;
    provenance: string[];
    agent: string | null;
    workflow: string | null;
};
type CompoundingEntrySeverity = "low" | "medium" | "high";
type EvidenceWindow = {
    start: string | null;
    end: string | null;
};
type MistakeRegistryEntry = {
    id: string;
    pattern: string;
    category: "feedback" | "action";
    status: "active" | "retired";
    agent: string | null;
    workflow: string | null;
    tags: string[];
    severity: CompoundingEntrySeverity | null;
    confidence: number | null;
    outcome: string | null;
    provenance: string[];
    firstSeenAt: string;
    lastSeenAt: string;
    recurrenceCount: number;
    lastWeekId: string;
    evidenceWindow: EvidenceWindow;
    mergedFromIds?: string[];
    retiredAt?: string | null;
};
type RubricSnapshotEntry = {
    id: string;
    kind: "agent" | "workflow";
    subject: string;
    observations: string[];
    tags: string[];
    provenance: string[];
    observationEntries?: Array<{
        note: string;
        provenance: string[];
    }>;
    updatedAt: string;
};
type RubricSnapshot = {
    updatedAt: string;
    agents: RubricSnapshotEntry[];
    workflows: RubricSnapshotEntry[];
};
type WeeklyCompoundingArtifact = {
    version: number;
    generatedAt: string;
    weekId: string;
    feedback: {
        count: number;
        byDecision: Record<"approved" | "approved_with_feedback" | "rejected", number>;
        entries: Array<{
            agent: string;
            workflow: string | null;
            decision: SharedFeedbackEntry["decision"];
            reason: string;
            learning: string | null;
            outcome: string | null;
            severity: CompoundingEntrySeverity | null;
            confidence: number | null;
            tags: string[];
            provenance: string;
            evidenceWindow: EvidenceWindow;
        }>;
    };
    mistakes: {
        count: number;
        patterns: string[];
        registry: MistakeRegistryEntry[];
    };
    rubrics: RubricSnapshot;
    outcomes: ActionOutcomeSummary[];
    promotionCandidates: PromotionCandidate[];
    continuity: {
        monthId: string;
        weeklyPath: string | null;
        monthlyPath: string | null;
    };
};
interface CompoundingPromotionReport {
    enabled: boolean;
    dryRun: boolean;
    weekId: string;
    promoted: Array<{
        id: string;
        candidateId: string;
        category: "principle" | "rule";
        content: string;
        confidence: number;
        tags: string[];
        lineage: string[];
    }>;
    skipped: Array<{
        weekId: string;
        candidateId?: string;
        reason: "disabled" | "weekly-artifact-missing" | "candidate-not-found" | "duplicate-guidance";
        existingMemoryId?: string;
    }>;
}
type TierMigrationCycleTrigger = "extraction" | "maintenance";
interface TierMigrationCycleBudget {
    limit: number;
    scanLimit: number;
    minIntervalMs: number;
}
declare class CompoundingEngine {
    private readonly config;
    private readonly storage;
    private readonly weeklyDir;
    private readonly rubricsDir;
    private readonly rubricsIndexPath;
    private readonly rubricsAgentsDir;
    private readonly rubricsWorkflowsDir;
    private readonly rubricsPath;
    private readonly mistakesPath;
    private readonly feedbackInboxPath;
    private readonly identityAuditWeeklyDir;
    private readonly identityAuditMonthlyDir;
    private readonly memoryActionEventsPath;
    constructor(config: PluginConfig, storage?: StorageManager);
    ensureDirs(): Promise<void>;
    synthesizeWeekly(opts?: {
        weekId?: string;
    }): Promise<{
        weekId: string;
        reportPath: string;
        reportJsonPath: string;
        mistakesCount: number;
        rubricsPath: string;
        rubricsIndexPath: string;
        promotionCandidateCount: number;
    }>;
    promoteCandidate(opts: {
        weekId: string;
        candidateId: string;
        dryRun?: boolean;
        storage?: StorageManager;
    }): Promise<CompoundingPromotionReport>;
    synthesizeContinuityAudit(opts?: {
        period?: "weekly" | "monthly";
        key?: string;
    }): Promise<{
        period: "weekly" | "monthly";
        key: string;
        reportPath: string;
    }>;
    readMistakes(): Promise<MistakesFile | null>;
    readRubrics(): Promise<RubricSnapshot | null>;
    readWeeklyArtifact(weekId: string): Promise<WeeklyCompoundingArtifact | null>;
    buildRecallSection(query: string, opts?: {
        maxPatterns?: number;
        maxRubrics?: number;
    }): Promise<string | null>;
    tierMigrationCycleBudget(trigger: TierMigrationCycleTrigger): TierMigrationCycleBudget;
    private readFeedbackEntriesForWeek;
    private buildActionFailurePatterns;
    private readActionEventsForWeek;
    private buildActionOutcomeSummary;
    private derivePromotionCandidates;
    private buildMistakes;
    private formatWeeklyReport;
    private buildRubricSnapshot;
    private formatRubrics;
    private syncRubricArtifacts;
    private replaceRubricDirectory;
    private scoreRubricForQuery;
    private normalizeRubricEntry;
    private getRubricObservationEntries;
    private isSyntheticOutcomeRubricObservation;
    private addRubricObservation;
    private readOptionalIdentityAnchorForAudit;
    private readOptionalImprovementLoopsForAudit;
    private readContinuityIncidentsForAudit;
    private readOptionalIdentityAuditForReference;
    private readContinuityAuditReferences;
}

declare function dedupeEntitySynthesisEvidenceEntries(entries: EntityTimelineEntry[]): EntityTimelineEntry[];
interface GraphRecallSnapshot {
    recordedAt: string;
    mode: RecallPlanMode | string;
    queryHash: string;
    queryLength: number;
    namespaces: string[];
    seedCount: number;
    expandedCount: number;
    seeds: string[];
    expanded: GraphRecallExpandedEntry[];
    status?: "completed" | "skipped" | "aborted";
    reason?: string;
    shadowMode?: boolean;
    queryIntent?: MemoryIntent;
    seedResults?: GraphRecallRankedResult[];
    finalResults?: GraphRecallRankedResult[];
    shadowComparison?: GraphRecallShadowComparison;
}
interface GraphRecallRankedResult {
    path: string;
    score: number;
    docid?: string;
    sourceLabels: string[];
}
interface GraphRecallShadowComparison {
    baselineCount: number;
    graphCount: number;
    overlapCount: number;
    overlapRatio: number;
    averageOverlapDelta: number;
}
interface IntentDebugSnapshot {
    recordedAt: string;
    promptHash: string;
    promptLength: number;
    retrievalQueryHash: string;
    retrievalQueryLength: number;
    plannerEnabled: boolean;
    plannedMode: RecallPlanMode;
    effectiveMode: RecallPlanMode;
    recallResultLimit: number;
    queryIntent: MemoryIntent;
    graphExpandedIntentDetected: boolean;
    graphDecision: {
        status: "not_requested" | "skipped" | "completed" | "aborted";
        reason?: string;
        shadowMode: boolean;
        qmdAvailable: boolean;
        graphRecallEnabled: boolean;
        multiGraphMemoryEnabled: boolean;
    };
}
interface QmdRecallSnapshot {
    recordedAt: string;
    queryHash: string;
    queryLength: number;
    collection?: string;
    namespaces: string[];
    fetchLimit: number;
    primaryResultCount: number;
    hybridResultCount: number;
    queryAwareSeedCount: number;
    resultCount: number;
    intentHint?: string;
    explainEnabled: boolean;
    hybridTopUpUsed: boolean;
    hybridTopUpSkippedReason?: string;
    results: QmdSearchResult[];
}
interface RecallModeDecision {
    plannedMode: RecallPlanMode;
    effectiveMode: RecallPlanMode;
    graphExpandedIntentDetected: boolean;
    graphReason?: string;
}
interface RecallInvocationOptions {
    namespace?: string;
    topK?: number;
    mode?: RecallPlanMode;
    abortSignal?: AbortSignal;
    /**
     * Capture a `RecallXraySnapshot` for this recall (issue #570).  When
     * `true`, the orchestrator builds a snapshot from the data it has
     * already gathered and stashes it in memory, accessible via
     * `getLastXraySnapshot()`.  When `false` or absent, nothing is
     * captured and recall behavior is unchanged (schema-only slice).
     */
    xrayCapture?: boolean;
    /**
     * Per-invocation override for `recallBudgetChars` (issue #570 PR 3/4).
     * Flows through `getRecallBudgetChars()` for this recall only — no
     * shared config mutation, so concurrent recalls on the same
     * orchestrator are not affected (CLAUDE.md rule 47: no shared
     * mutable state across async boundaries).  Must be a non-negative
     * finite integer; non-conforming values are ignored and the
     * configured budget is used.
     */
    budgetCharsOverride?: number;
    /**
     * Per-invocation principal override (issue #570 PR 4).  When set,
     * the orchestrator uses this principal for ACL / namespace checks
     * instead of `resolvePrincipal(sessionKey, config)`.  This is the
     * escape hatch for access surfaces (HTTP / MCP) that have already
     * authenticated the caller upstream — threading an unmapped
     * principal through the session-key-based resolver would otherwise
     * collapse it to `"default"` and produce false denials in
     * namespace-enabled deployments (CLAUDE.md rule 42).
     */
    principalOverride?: string;
    /**
     * Historical recall point (issue #680).  When set, the orchestrator
     * filters out memories whose `valid_at` is after this timestamp OR
     * whose `invalid_at` is at-or-before this timestamp, so callers see
     * the corpus as it existed at `asOf`.  ISO 8601 string; comparisons
     * use `Date.parse()` so timezone-aware values round-trip correctly
     * (CLAUDE.md gotcha — never compare ISO strings lexicographically).
     * Invalid values must be rejected at input boundaries (CLAUDE.md
     * rule 51); the orchestrator does NOT silently fall back here.
     */
    asOf?: string;
    /**
     * Issue #681 — when `true`, bypasses `graphTraversalConfidenceFloor`
     * and includes edges below the floor in graph traversal.  Useful for
     * diagnostic recall queries that need to surface results that would
     * normally be pruned by confidence decay.  Default `false`.
     */
    includeLowConfidence?: boolean;
}
/** Default workspace directory when no per-agent or config workspace is available. */
declare function defaultWorkspaceDir(): string;
/**
 * Produce a collision-resistant, filesystem-safe identifier from a session key.
 *
 * Session keys follow colon-delimited forms (e.g., `agent:gpucodebot:main`).
 * A naive replace (`:` → `_`) is lossy: different keys like `agent:alpha` and
 * `agent/alpha` would collide. Instead we append a short SHA-256 hash of the
 * original key to the human-readable sanitized prefix, guaranteeing uniqueness
 * while keeping filenames debuggable.
 *
 * Format: `<sanitized>-<12-char-hex-hash>`
 * Example: `agent:gpucodebot:main` → `agent_gpucodebot_main-a1b2c3d4e5f6`
 */
declare function sanitizeSessionKeyForFilename(sessionKey: string): string;
declare function isArtifactMemoryPath(filePath: string): boolean;
declare function deriveTopicsFromExtraction(result: ExtractionResult): string[];
declare function buildCompressionGuidelinesMarkdown(events: MemoryActionEvent[], generatedAtIso?: string): string;
declare function formatCompressionGuidelinesForRecall(raw: string, maxLines?: number): string | null;
declare function filterRecallCandidates(candidates: QmdSearchResult[], options: {
    namespacesEnabled: boolean;
    recallNamespaces: string[];
    resolveNamespace: (path: string) => string;
    limit: number;
}): QmdSearchResult[];
declare function shouldFilterLifecycleRecallCandidate(frontmatter: MemoryFrontmatter, options: {
    lifecyclePolicyEnabled: boolean;
    lifecycleFilterStaleEnabled: boolean;
}): boolean;
declare function lifecycleRecallScoreAdjustment(frontmatter: MemoryFrontmatter, options: {
    lifecyclePolicyEnabled: boolean;
}): number;
declare function computeArtifactRecallLimit(recallMode: RecallPlanMode, recallResultLimit: number, verbatimArtifactsMaxRecall: number): number;
declare function resolveEffectiveRecallMode(options: {
    plannerEnabled: boolean;
    graphRecallEnabled: boolean;
    multiGraphMemoryEnabled: boolean;
    graphExpandedIntentEnabled?: boolean;
    prompt: string;
}): RecallPlanMode;
declare function resolveRecallModeDecision(options: {
    plannerEnabled: boolean;
    graphRecallEnabled: boolean;
    multiGraphMemoryEnabled: boolean;
    graphExpandedIntentEnabled?: boolean;
    prompt: string;
}): RecallModeDecision;
declare function hasIdentityRecoveryIntent(prompt: string): boolean;
declare function resolveEffectiveIdentityInjectionMode(options: {
    configuredMode: IdentityInjectionMode;
    recallMode: RecallPlanMode;
    prompt: string;
}): {
    mode: IdentityInjectionMode;
    shouldInject: boolean;
};
declare function computeArtifactCandidateFetchLimit(targetCount: number): number;
declare function computeQmdHybridFetchLimit(recallFetchLimit: number, artifactsEnabled: boolean, maxArtifactRecall: number): number;
declare function mergeGraphExpandedResults(primary: QmdSearchResult[], expanded: QmdSearchResult[]): QmdSearchResult[];
declare function graphPathRelativeToStorage(storageDir: string, candidatePath: string): string | null;
declare function blendGraphExpandedRecallScore(options: {
    graphActivationScore: number;
    seedRecallScore: number;
    activationWeight: number;
    blendMin: number;
    blendMax: number;
}): number;
declare function summarizeGraphShadowComparison(baseline: QmdSearchResult[], merged: QmdSearchResult[], topN: number): {
    baselineCount: number;
    graphCount: number;
    overlapCount: number;
    overlapRatio: number;
    averageOverlapDelta: number;
};
declare function mergeArtifactRecallCandidates(candidatesByNamespace: MemoryFile[][], limit: number): MemoryFile[];
declare function resolveRecentThreadMemoryPaths(options: {
    threadEpisodeIds: string[];
    currentMemoryId: string;
    allMemsForGraph: MemoryFile[] | null | undefined;
    pathById?: Map<string, string>;
    storageDir: string;
    maxRecent: number;
}): string[];
declare function buildMemoryPathById(allMemsForGraph: MemoryFile[] | null | undefined, storageDir: string): Map<string, string>;
declare function appendMemoryToGraphContext(options: {
    allMemsForGraph: MemoryFile[] | null | undefined;
    storageDir: string;
    memoryRelPath: string;
    memoryId: string;
    category: MemoryFile["frontmatter"]["category"];
    content: string;
    entityRef: string | undefined;
}): void;
declare function resolvePersistedMemoryRelativePath(options: {
    memoryId: string;
    pathById: Map<string, string>;
    category: string;
}): string;
declare class Orchestrator {
    readonly storage: StorageManager;
    private readonly storageRouter;
    private readonly namespaceSearchRouter;
    qmd: SearchBackend;
    private readonly conversationQmd?;
    private readonly conversationFaiss?;
    private readonly conversationIndexBackend?;
    readonly sharedContext?: SharedContextManager;
    readonly compounding?: CompoundingEngine;
    readonly buffer: SmartBuffer;
    readonly transcript: TranscriptManager;
    readonly sessionObserver: SessionObserverState;
    readonly summarizer: HourlySummarizer;
    readonly localLlm: LocalLlmClient;
    readonly fastLlm: LocalLlmClient;
    private readonly judgeVerdictCache;
    /**
     * Per-orchestrator defer-counter map (issue #562, PR 2). Tracks how many
     * times the judge has returned `"defer"` for a given candidate content
     * hash so the defer cap can be enforced.
     */
    private readonly judgeDeferCounts;
    /**
     * Side-channel: number of facts deferred in the most recent
     * `persistExtraction` call (issue #562, PR 2). The caller reads this after
     * `persistExtraction` returns to decide whether to retain buffer turns for
     * the next extraction pass. Not part of the return signature because many
     * callers already destructure `persistedIds` by position.
     */
    private lastPersistExtractionDeferredCount;
    private readonly _fastGatewayLlm;
    get fastGatewayLlm(): FallbackLlmClient | null;
    readonly modelRegistry: ModelRegistry;
    readonly relevance: RelevanceStore;
    readonly negatives: NegativeExampleStore;
    readonly lastRecall: LastRecallStore;
    readonly tierMigrationStatus: TierMigrationStatusStore;
    /**
     * In-memory X-ray snapshot from the most recent `recall()` call that
     * was invoked with `xrayCapture: true` (issue #570 PR 1).  Scope is
     * per-process; later slices add CLI/HTTP/MCP surfaces that consume
     * this via the shared renderer.  `null` until the first capture, and
     * NEVER overwritten by a recall that did not request capture —
     * requests without the flag leave prior captures intact so the
     * capturing caller can still read their snapshot back.
     */
    private lastXraySnapshot;
    readonly embeddingFallback: EmbeddingFallback;
    private readonly conversationIndexDir;
    private readonly extraction;
    readonly config: PluginConfig;
    readonly profiler: ProfilingCollector;
    private readonly threading;
    /** v8.2: Per-namespace multi-graph memory indexes (entity/time/causal edges) */
    private readonly graphIndexes;
    /** Per-namespace BoxBuilders, keyed by the namespace root directory path. */
    private readonly boxBuilders;
    /** Temporal Memory Tree builder — builds hour/day/week/persona summary nodes. */
    private readonly tmtBuilder;
    /** Lossless Context Management engine — proactive session archive + DAG summarization. */
    readonly lcmEngine: LcmEngine | null;
    private readonly rerankCache;
    /**
     * Short-TTL cache for Memory Worth counter lookups so interactive recall
     * doesn't trigger a full `readAllMemories` scan per query. Keyed by
     * namespace; the filter unions across namespaces at query time. The TTL
     * is intentionally short (seconds, not minutes) because counters are
     * mutated by `recordMemoryOutcome` asynchronously and we'd rather serve
     * a 30-second-stale worth score than a stable-but-wrong one.
     */
    private readonly memoryWorthCounterCache;
    private static readonly MEMORY_WORTH_CACHE_TTL_MS;
    /**
     * Per-session workspace overrides keyed by sessionKey.
     * Set by the before_agent_start hook so recall() uses the correct
     * agent workspace for BOOT.md injection. Cleared after each recall.
     * Using a Map prevents concurrent sessions from overwriting each other.
     */
    private _recallWorkspaceOverrides;
    /**
     * Per-session coding-agent context (issue #569). Populated by connectors at
     * session-start (PRs 5/6/7) via `setCodingContextForSession`. Used by both
     * the recall path and the write path so that memory routing respects the
     * project/branch scope a session is operating in (rule 42 — read + write
     * through the same namespace layer).
     */
    private readonly _codingContextBySession;
    /**
     * Per-session peer ID registry (issue #679 PR 3/5).
     * Set by connectors / hooks via `setPeerIdForSession` so `recallInternal`
     * can inject the peer's profile into recall context when
     * `peerProfileRecallEnabled` is true. Cleared when the session ends.
     * Keyed by sessionKey so concurrent sessions don't clobber each other
     * (rule 11 — scope globals per plugin ID / session).
     */
    private readonly _peerIdBySession;
    private routingRulesStore;
    private contentHashIndex;
    private readonly artifactSourceStatusCache;
    private static readonly ARTIFACT_STATUS_CACHE_TTL_MS;
    private accessTrackingBuffer;
    private extractionQueue;
    private queueProcessing;
    private heartbeatObserverChains;
    private recentExtractionFingerprints;
    private nonZeroExtractionsSinceConsolidation;
    private lastConsolidationRunAtMs;
    private consolidationInFlight;
    private readonly consolidationObservers;
    private qmdMaintenanceTimer;
    private qmdMaintenancePending;
    private qmdMaintenanceInFlight;
    private lastQmdEmbedAtMs;
    private lastQmdReprobeAtMs;
    private tierMigrationInFlight;
    private lastTierMigrationRunAtMs;
    private readonly conversationIndexLastUpdateAtMs;
    private lastFileHygieneRunAtMs;
    private lastPatternReinforcementAtByNs;
    private lastRecallFailureLogAtMs;
    private lastRecallFailureAtMs;
    private suppressedRecallFailures;
    private readonly policyRuntime;
    private runtimePolicyValues;
    private utilityRuntimeValues;
    private evalShadowWriteChain;
    private directAnswerObservationChain;
    private initPromise;
    private resolveInit;
    /**
     * Resolves when deferred initialization (QMD probe, warmup, caches, cron)
     * completes. CLI and http-serve callers that need `qmd.isAvailable()` to
     * reflect reality should `await orchestrator.deferredReady` after
     * `initialize()`. Gateway callers can ignore it — recall() degrades
     * gracefully when QMD isn't ready yet.
     *
     * Also resolves (without error) when `initialize()` throws before reaching
     * the deferred-init phase, so callers never hang on a permanently-pending
     * promise.
     *
     * Host adapters that need to tie deferred init to their stop() lifecycle
     * should `await orchestrator.deferredReady` before proceeding with teardown
     * to prevent background QMD/warmup/cron tasks from racing with shutdown.
     */
    deferredReady: Promise<void>;
    private resolveDeferredReady;
    private deferredInitAbort;
    /**
     * Whether the deferred init's QMD startup sync completed successfully.
     * When false after deferredReady resolves, the server retry loop should
     * attempt startupSearchSync() even if `qmd.isAvailable()` is true —
     * availability only means probe succeeded, not that the index is current.
     */
    deferredSyncSucceeded: boolean;
    /**
     * Abort deferred initialization so background QMD sync/warmup stops
     * promptly on shutdown. Safe to call multiple times or before init.
     */
    abortDeferredInit(): void;
    private disposeSearchBackendIfNeeded;
    /** Set per-session workspace for the next recall() call (compaction reset). @internal */
    setRecallWorkspaceOverride(sessionKey: string, dir: string): void;
    /** Remove a per-session workspace override (cleanup on error or early return). @internal */
    clearRecallWorkspaceOverride(sessionKey: string): void;
    resolvePrincipal(sessionKey?: string): string;
    resolveSelfNamespace(sessionKey?: string): string;
    /**
     * Attach a coding-agent context to a session (issue #569). Called by the
     * Claude Code / Codex / Cursor connectors at session start after
     * `resolveGitContext(cwd)`. The context is consulted by the recall path
     * and the write path so that memories route to a project- (and optionally
     * branch-) scoped namespace.
     *
     * Pass `null` to clear.
     */
    setCodingContextForSession(sessionKey: string, codingContext: CodingContext | null): void;
    /**
     * Read-only accessor for the coding context attached to a session. Returns
     * `null` when none is set. Used by `remnic doctor` and by tests.
     *
     * Defensive `_codingContextBySession` lookup — legacy orchestrator-flush
     * tests use `Object.create(Orchestrator.prototype)` which does not run
     * class-field initializers, so the Map may be undefined on stubs.
     */
    getCodingContextForSession(sessionKey: string | undefined): CodingContext | null;
    /**
     * Shared helper used by both the recall path and the write path (rule 42).
     *
     * Given a base namespace computed from the principal, returns the overlaid
     * coding namespace when the session has a coding context AND
     * `codingMode.projectScope` is true AND `namespacesEnabled` is true.
     * Otherwise returns `baseNamespace` unchanged — CLAUDE.md #30 escape hatch.
     *
     * Principal isolation (CLAUDE.md rule 42): the overlay is COMBINED with
     * the principal-derived `baseNamespace` rather than replacing it, so two
     * principals working in the same repository do not share memories through
     * a common `project-*` namespace.
     *
     * Namespaces-disabled gate: when `namespacesEnabled` is false, the
     * storage router maps every namespace to the same `memoryDir`. Returning
     * `project-*` in that mode would create apparent route separation with
     * no actual storage isolation — a false-isolation trap. In that mode we
     * return `baseNamespace` unchanged so coding mode degrades to the existing
     * unscoped behavior.
     *
     * @internal
     */
    applyCodingNamespaceOverlay(sessionKey: string | undefined, baseNamespace: string): string;
    /**
     * Register a peer ID for a session so recall can inject the peer's
     * profile into context (issue #679 PR 3/5). Pass `null` to clear.
     *
     * Connectors and the `before_agent_start` hook call this when the
     * session's counter-party is known. The ID is validated against
     * `PEER_ID_PATTERN` before storing.
     *
     * Fail-closed (Codex P1 review): an invalid peerId clears any
     * previously registered mapping for the session rather than silently
     * keeping stale data. This prevents a malformed metadata update from
     * mixing one peer's profile context into another session.
     *
     * Defensive init (Cursor review + rule 16): `Object.create(
     * Orchestrator.prototype)` stubs in legacy tests skip class-field
     * initializers, so `_peerIdBySession` may be undefined. Mirror the
     * same guard used by `setCodingContextForSession`.
     */
    setPeerIdForSession(sessionKey: string, peerId: string | null): void;
    /**
     * Return the peer ID registered for a session, or `null` when none
     * is set. Used by `recallInternal` to inject the peer profile section.
     * Defensive `_peerIdBySession` lookup — legacy orchestrator-flush tests
     * use `Object.create(Orchestrator.prototype)` which skips class-field
     * initializers, so the Map may be undefined on stubs.
     */
    getPeerIdForSession(sessionKey: string | undefined): string | null;
    /**
     * Read-side overlay: returns the list of namespaces a session should read
     * from, including any read fallbacks (branch → project, global root).
     *
     * Returns `null` when:
     *   - `namespacesEnabled` is false (overlay would create false isolation)
     *   - no context attached to the session
     *   - `codingMode.projectScope` is false (CLAUDE.md #30 escape hatch)
     *
     * The returned `namespace` / `readFallbacks` are RAW overlay fragments
     * (e.g. `project-origin-ab12`). Callers MUST combine them with the
     * principal-derived base through `combineNamespaces()` before passing to
     * storage, so principal isolation is preserved (rule 42).
     *
     * @internal
     */
    applyCodingRecallOverlay(sessionKey: string | undefined): {
        namespace: string;
        readFallbacks: string[];
    } | null;
    getStorageForNamespace(namespace?: string): Promise<StorageManager>;
    private configuredNamespaces;
    private buildConfiguredQmdSearchOptions;
    searchAcrossNamespaces(options: {
        query: string;
        namespaces?: string[];
        maxResults?: number;
        mode?: "search" | "hybrid" | "bm25" | "vector";
        searchOptions?: SearchQueryOptions;
        execution?: SearchExecutionOptions;
    }): Promise<QmdSearchResult[]>;
    private isSearchAvailableForNamespaceRouting;
    invalidateLiveContentHashIndex(): void;
    constructor(config: PluginConfig);
    /** Get or create a BoxBuilder for the given namespace storage root (namespace-isolated). */
    private boxBuilderFor;
    private effectiveRecencyWeight;
    private effectiveCronRecallInstructionHeavyTokenCap;
    private currentPolicyVersion;
    private effectiveLifecycleThresholds;
    private routeEngineOptions;
    private getRoutingRulesStore;
    private loadRoutingRules;
    private resolveArtifactSourceStatuses;
    /**
     * Execute a fast-tier LLM chat completion.
     * When gateway model source is active and fastGatewayAgentId is configured,
     * routes through the gateway chain. Otherwise uses the local fast LLM.
     */
    private fastChatCompletion;
    /**
     * Get a fast-tier LLM client compatible with the rerank interface.
     * When gateway model source is active, routes through the gateway fast chain.
     * Otherwise returns the local fast LLM directly.
     */
    get fastLlmForRerank(): {
        chatCompletion: (messages: Array<{
            role: string;
            content: string;
        }>, options?: {
            maxTokens?: number;
            temperature?: number;
            timeoutMs?: number;
            operation?: string;
            priority?: "recall-critical" | "background";
        }) => Promise<{
            content: string;
        } | null>;
    };
    initialize(): Promise<void>;
    private deferredInitialize;
    /**
     * Namespace-aware startup search sync. Re-probes QMD, ensures collections
     * (namespace-aware when namespacesEnabled), runs update, and warms up search.
     * Designed for server retry paths that run after the deferred init completes
     * when QMD was not available during initial startup.
     *
     * Accepts an optional AbortSignal so callers can interrupt the sync during
     * shutdown. The signal is checked between phases and forwarded into the QMD
     * update and warmup search calls so a long-running `qmd update` subprocess
     * is killed promptly rather than left in flight after `httpServer.stop()`.
     *
     * Returns true if the sync succeeded (QMD now available), false otherwise.
     */
    startupSearchSync(signal?: AbortSignal): Promise<boolean>;
    /**
     * Auto-register the engram-day-summary cron job in OpenClaw if it doesn't exist.
     * Fire-and-forget — never blocks init or crashes on failure.
     */
    private autoRegisterDaySummaryCron;
    private autoRegisterNightlyGovernanceCron;
    private autoRegisterProceduralMiningCron;
    private autoRegisterContradictionScanCron;
    private autoRegisterPatternReinforcementCron;
    /**
     * Run the pattern-reinforcement maintenance job (issue #687 PR 2/4).
     *
     * Cadence-gated on `patternReinforcementCadenceMs` so every caller
     * (orchestrator cron path, MCP tool, CLI) shares a single floor —
     * none can call this on a hot loop and burn the corpus.  When the
     * feature is disabled or the cadence has not elapsed, returns a
     * synthetic "skipped" result rather than throwing.
     *
     * Cadence tracking is per-namespace so a tenant-scoped MCP run in
     * one namespace does not silence a cron run in another (PR #730
     * review feedback, Codex P2).  Pass `force: true` for ad-hoc
     * operator runs that must bypass the cadence floor — mirrors the
     * pattern used by other maintenance MCP tools.
     *
     * `force` deliberately does NOT bypass the master
     * `patternReinforcementEnabled` flag (PR #730 review feedback,
     * Cursor Medium).  Operators who have explicitly disabled the
     * feature must not have their corpus mutated by an MCP tool call —
     * the only way to run the job is to enable the feature in config.
     */
    runPatternReinforcement(options?: {
        force?: boolean;
        namespace?: string;
    }): Promise<{
        ran: boolean;
        skippedReason?: "disabled" | "cadence";
        namespace: string;
        result?: PatternReinforcementResult;
    }>;
    private autoRegisterGraphEdgeDecayCron;
    runLiveConnectors(options?: {
        force?: boolean;
        abortSignal?: AbortSignal;
    }): Promise<LiveConnectorsRunSummary>;
    applyBehaviorRuntimePolicy(state: BehaviorLoopPolicyState): Promise<{
        applied: boolean;
        rolledBack: boolean;
        values: RuntimePolicyValues | null;
        reason: string;
    }>;
    rollbackBehaviorRuntimePolicy(): Promise<boolean>;
    maybeRunFileHygiene(): Promise<void>;
    runBootstrap(options: BootstrapOptions): Promise<BootstrapResult>;
    runConsolidationNow(): Promise<{
        memoriesProcessed: number;
        merged: number;
        invalidated: number;
    }>;
    reindexMemoryById(id: string, options?: {
        storage?: StorageManager;
    }): Promise<void>;
    registerConsolidationObserver(observer: (observation: ConsolidationObservation) => Promise<void> | void): () => void;
    runSemanticConsolidationNow(options?: {
        dryRun?: boolean;
        thresholdOverride?: number;
        storage?: StorageManager;
    }): Promise<SemanticConsolidationResult>;
    runDeepSleepGovernanceNow(options?: {
        dryRun?: boolean;
        storage?: StorageManager;
    }): Promise<{
        scannedMemories: number;
        appliedActionCount: number;
        notes?: string;
    }>;
    private runSemanticConsolidation;
    waitForExtractionIdle(timeoutMs?: number): Promise<boolean>;
    waitForConsolidationIdle(timeoutMs?: number): Promise<boolean>;
    getStorage(namespace?: string): Promise<StorageManager>;
    processEntitySynthesisQueue(namespace?: string, maxEntities?: number): Promise<number>;
    generateDaySummary(memories: string | MemoryFile[]): Promise<DaySummaryResult | null>;
    /**
     * Auto-gather today's facts and hourly summaries from storage, then generate a day summary.
     * Returns null if no facts are found for today.
     */
    generateDaySummaryAuto(namespace?: string): Promise<DaySummaryResult | null>;
    /**
     * Read today's facts and hourly summaries from storage, returning them
     * as a formatted string suitable for generateDaySummary().
     */
    gatherTodayFacts(namespace?: string): Promise<string>;
    previewMemoryActionEvent(event: Omit<MemoryActionEvent, "timestamp"> & {
        timestamp?: string;
    }): MemoryActionEvent;
    appendMemoryActionEvent(event: Omit<MemoryActionEvent, "timestamp"> & {
        timestamp?: string;
    }): Promise<boolean>;
    getLastGraphRecallSnapshot(namespace?: string): Promise<GraphRecallSnapshot | null>;
    getLastIntentSnapshot(namespace?: string): Promise<IntentDebugSnapshot | null>;
    getLastQmdRecallSnapshot(namespace?: string): Promise<QmdRecallSnapshot | null>;
    explainLastGraphRecall(options?: {
        namespace?: string;
        maxExpanded?: number;
    }): Promise<string>;
    explainLastIntent(options?: {
        namespace?: string;
    }): Promise<string>;
    explainLastQmdRecall(options?: {
        namespace?: string;
        maxResults?: number;
    }): Promise<string>;
    private searchConversationRecallResults;
    private formatConversationRecallSection;
    private countConversationChunkDocs;
    private buildConversationIndexChunks;
    getConversationIndexHealth(): Promise<{
        enabled: boolean;
        backend: "qmd" | "faiss";
        status: "ok" | "degraded" | "disabled";
        chunkDocCount: number;
        lastUpdateAt: string | null;
        qmdAvailable?: boolean;
        faiss?: {
            ok: boolean;
            status: "ok" | "degraded" | "error";
            indexPath: string;
            message?: string;
            manifest?: {
                version: number;
                modelId: string;
                normalizedModelId: string;
                dimension: number;
                chunkCount: number;
                updatedAt: string;
                lastSuccessfulRebuildAt: string;
            };
        };
    }>;
    inspectConversationIndex(): Promise<ConversationIndexBackendInspection & {
        enabled: boolean;
        chunkDocCount: number;
        lastUpdateAt: string | null;
    }>;
    getRecoverySummary(sessionKey?: string): Promise<{
        generatedAt: string;
        sessionKey?: string;
        healthy: boolean;
        issueCount: number;
        incompleteTurns: number;
        brokenChains: number;
        checkpointHealthy: boolean;
    }>;
    updateConversationIndex(sessionKey: string, hours?: number, opts?: {
        embed?: boolean;
        enforceMinInterval?: boolean;
    }): Promise<{
        chunks: number;
        skipped: boolean;
        reason?: string;
        retryAfterMs?: number;
        embedded?: boolean;
    }>;
    rebuildConversationIndex(sessionKey?: string, hours?: number, opts?: {
        embed?: boolean;
    }): Promise<{
        chunks: number;
        skipped: boolean;
        reason?: string;
        embedded?: boolean;
        rebuilt?: boolean;
    }>;
    /**
     * Validate local LLM model availability and context window compatibility.
     * Warns the user if there's a mismatch.
     */
    private validateLocalLlmModel;
    recall(prompt: string, sessionKey?: string, options?: RecallInvocationOptions): Promise<string>;
    /**
     * Return the most recent X-ray snapshot captured during a
     * `recall()` call that passed `xrayCapture: true` (issue #570 PR 1).
     * Returns `null` when no such capture has occurred on this
     * orchestrator instance.  Returned snapshot is a deep copy so
     * caller mutation cannot tear the stored value.
     */
    getLastXraySnapshot(): RecallXraySnapshot | null;
    /** Clear the captured X-ray snapshot.  Exposed for tests / explicit reset. */
    clearLastXraySnapshot(): void;
    /**
     * Await the in-flight observation-mode direct-answer annotation chain.
     * Resolves to true when settled, false on timeout.
     */
    waitForDirectAnswerObservationIdle(timeoutMs?: number): Promise<boolean>;
    private enqueueDirectAnswerObservation;
    private annotateDirectAnswerTier;
    private logRecallFailure;
    private artifactTypeForCategory;
    private truncateArtifactForRecall;
    private fetchActiveArtifactsForNamespace;
    private recallArtifactsAcrossNamespaces;
    private scopeQueryAwarePaths;
    private buildQueryAwarePrefilter;
    private searchScopedMemoryCandidates;
    private fetchQmdMemoryResultsWithArtifactTopUp;
    private expandResultsViaGraph;
    private recordLastGraphRecallSnapshot;
    private recordLastIntentSnapshot;
    private recordLastQmdRecallSnapshot;
    private recordLastIntentSnapshotForNamespace;
    private resolveStateDirForNamespace;
    private buildGraphRecallRankedResults;
    private getRecallSectionEntry;
    private isRecallSectionEnabled;
    private getRecallSectionMaxChars;
    private getRecallSectionNumber;
    private appendRecallSection;
    private truncateRecallSectionToBudget;
    private protectedRecallSectionIds;
    private protectedRecallReservationChars;
    private estimateReservedRecallBudget;
    private getRecallBudgetChars;
    private assembleRecallSections;
    private recallInternal;
    processTurn(role: "user" | "assistant", content: string, sessionKey?: string, options?: {
        bufferKey?: string;
        logicalSessionKey?: string;
        providerThreadId?: string | null;
        turnFingerprint?: string;
        persistProcessedFingerprint?: boolean;
    }): Promise<void>;
    flushSession(sessionKey: string, options: {
        reason: string;
        abortSignal?: AbortSignal;
        bufferKey?: string;
    }): Promise<void>;
    ingestReplayBatch(turns: ReplayTurn[], options?: {
        deadlineMs?: number;
    }): Promise<void>;
    /**
     * Return the namespace that `ingestBulkImportBatch` writes into (#460).
     *
     * Exposed so host CLIs can snapshot the same storage root that extraction
     * actually writes to, avoiding the "CLI counts files at namespace A while
     * writes land in namespace B" footgun that a naïve
     * `config.defaultNamespace` snapshot could hit when a namespace policy
     * named `"default"` also exists.
     *
     * Today bulk-import is pinned to `config.defaultNamespace`; future
     * per-invocation namespace routing would thread an explicit target here
     * and through `ingestBulkImportBatch`.
     */
    bulkImportWriteNamespace(): string;
    /**
     * Ingest a batch of bulk-import turns (#460). Like ingestReplayBatch, this
     * normalizes user/assistant turns into the extraction buffer and awaits
     * settlement, but it intentionally bypasses the captureMode="explicit"
     * gate because bulk-import is itself an explicit user action — the user
     * ran `bulk-import --source <name> --file ...` and would be surprised to
     * see the command silently no-op when capture is otherwise restricted.
     *
     * Turns with role="other" are skipped (not supported by the extraction
     * pipeline).
     *
     * Two design decisions worth calling out:
     *
     * - **sessionKey is truthy and per-batch-unique.**
     *   `ThreadingManager.shouldStartNewThread` only applies the session-key
     *   boundary check when `turn.sessionKey` is truthy (threading.ts:82);
     *   with an empty string, imported turns could attach to the current
     *   live thread or merge across unrelated import batches. A unique
     *   `bulk-import:batch:<timestamp>-<rand>` key forces a fresh thread per
     *   batch without matching common prefix/map rules in
     *   `principalFromSessionKeyRules`. (Catch-all regex rules could still
     *   remap the principal, but that only affects metadata provenance —
     *   see the next point for why write routing is unaffected.)
     *
     * - **writeNamespaceOverride pins the storage target.**
     *   We pass `writeNamespaceOverride: this.bulkImportWriteNamespace()` to
     *   `queueBufferedExtraction`, which tells `runExtraction` to skip
     *   `defaultNamespaceForPrincipal` and write directly into the
     *   orchestrator's declared bulk-import write namespace. This keeps
     *   writes deterministic even when namespace policies named `"default"`
     *   exist alongside a different `config.defaultNamespace`, and also
     *   guards against regex-catch-all principal rules steering bulk-import
     *   into an unexpected tenant.
     *
     * Per-invocation namespace routing (letting callers target a namespace
     * other than `bulkImportWriteNamespace()`) is a separate feature tracked
     * as a follow-up — the hook is the `writeNamespaceOverride` option, but
     * the CLI surface does not yet expose a `--namespace` flag.
     */
    ingestBulkImportBatch(turns: ImportTurn[], options?: {
        deadlineMs?: number;
    }): Promise<void>;
    observeSessionHeartbeat(sessionKey: string, options?: {
        bufferKey?: string;
    }): Promise<void>;
    private queueBufferedExtraction;
    private normalizeExtractionFingerprintTurns;
    private buildExtractionFingerprint;
    private shouldQueueExtraction;
    /**
     * Background serial queue processor.
     * Processes extractions one at a time to avoid race conditions.
     * Called automatically when items are queued.
     */
    private processQueue;
    /**
     * Classify + log a failure from either the per-task catch inside
     * `processQueue()` or the outer `processQueue().catch(...)` in
     * `queueBufferedExtraction()`.  Issue #549: `throwIfRecallAborted`
     * (used throughout `runExtraction`) raises an Error whose `name` is
     * `"AbortError"`.  That path fires when `before_reset` aborts a
     * queued task to avoid duplicate extraction — it is intentional
     * cancellation, not a failure.  Downgrading the log to debug
     * prevents spurious `error`-level lines that routinely appear
     * right next to a successful `persisted: N facts, M entities` log
     * and that confuse operators into thinking extraction is broken.
     * Genuine extraction failures (network, parse, I/O) still log at
     * `error`.
     *
     * Source differentiates the two call sites so the log message
     * names the right layer (`task` vs `processor`).
     */
    private logExtractionQueueFailure;
    private runExtraction;
    private recordProcessedExtractionFingerprint;
    private runTierMigrationCycle;
    getTierMigrationStatus(): Promise<TierMigrationStatusSnapshot>;
    runTierMigrationNow(options?: {
        dryRun?: boolean;
        limit?: number;
    }): Promise<TierMigrationCycleSummary>;
    private maybeScheduleConsolidation;
    private requestQmdMaintenance;
    /**
     * Public entrypoint for tool-driven QMD maintenance requests.
     * Routes through existing debounced/singleflight maintenance controls.
     */
    requestQmdMaintenanceForTool(reason: string): void;
    private runQmdMaintenance;
    private persistExtraction;
    private indexPersistedMemory;
    /**
     * Build a graph edge for a persisted memory (v8.2).
     * Shared helper used by both the chunked and non-chunked write paths to avoid duplication.
     * Fail-open: caller wraps in try/catch.
     */
    private buildGraphEdge;
    private graphIndexFor;
    /**
     * Batch-update temporal and tag indexes after extraction (v8.1).
     * Reads each persisted memory's path + frontmatter and adds them to
     * state/index_time.json and state/index_tags.json.
     * Fail-open: any error is logged but does not abort extraction.
     */
    private updateTemporalTagIndexes;
    /** IDs of facts persisted in the last extraction */
    private lastPersistedIds;
    private runConsolidation;
    optimizeCompressionGuidelines(options?: {
        dryRun?: boolean;
        eventLimit?: number;
    }): Promise<{
        enabled: boolean;
        dryRun: boolean;
        eventCount: number;
        previousGuidelineVersion: number | null;
        nextGuidelineVersion: number;
        changedRules: number;
        semanticRefinementApplied: boolean;
        persisted: boolean;
        draftContentHash: string | null;
    }>;
    activateCompressionGuidelineDraft(options?: {
        expectedContentHash?: string;
        expectedGuidelineVersion?: number;
    }): Promise<{
        enabled: boolean;
        activated: boolean;
        guidelineVersion: number | null;
        reason?: "disabled" | "missing_draft" | "expected_revision_required" | "content_hash_mismatch" | "guideline_version_mismatch" | "draft_changed";
    }>;
    private runCompressionGuidelineLearningPass;
    private buildCompressionGuidelineRecallSection;
    private parseCompressionSemanticRefinement;
    private actionOutcomePriorDelta;
    private buildLifecycleActionPriors;
    private recordScheduledDreamsPhaseRun;
    runLifecyclePolicyNow(storage?: StorageManager): Promise<{
        memoriesAssessed: number;
    }>;
    private runLifecyclePolicyPass;
    /**
     * Archive old, low-importance, rarely-accessed facts (v6.0).
     * Moves eligible facts from facts/ to archive/YYYY-MM-DD/.
     * Returns the number of archived facts.
     */
    private runFactArchival;
    /**
     * Run memory summarization if memory count exceeds threshold (Phase 4A).
     */
    private runSummarization;
    /**
     * Run topic extraction on all memories (Phase 4B).
     */
    private runTopicExtraction;
    /** Threshold (bytes) at which IDENTITY.md reflections get auto-consolidated */
    private static readonly IDENTITY_CONSOLIDATE_THRESHOLD;
    private autoConsolidateIdentity;
    private formatQmdResults;
    private formatObjectiveStateResults;
    private formatCausalTrajectoryResults;
    private formatTrustZoneResults;
    private formatHarmonicRetrievalResults;
    private formatWorkProductResults;
    private formatVerifiedEpisodeResults;
    private formatVerifiedSemanticRuleResults;
    private summarizeIdentityText;
    private formatOpenIncidentLine;
    private trimIdentitySection;
    private buildIdentityContinuitySection;
    private emitTrace;
    private queueEvalShadowRecall;
    private publishRecallResults;
    /**
     * Apply MMR over the pre-truncation recall candidate pool and then slice
     * the result to `limit`. This is the single place in the pipeline where
     * MMR runs, and it must be called *before* callers throw away candidates
     * that would otherwise sit below the final cutoff. Running MMR post-slice
     * is a no-op in the cases we care about — diverse candidates just below
     * the cutoff are already gone and can never be promoted.
     *
     * Callers must pass the full candidate pool (post-rerank, pre-slice).
     */
    private applyMemoryWorthRerank;
    private diversifyAndLimitRecallResults;
    /**
     * Apply Maximal Marginal Relevance to a section's ordered candidate list.
     *
     * Operates per-section so one redundant cluster cannot dominate a section,
     * and so one section's MMR pass cannot starve other sections. Returns the
     * input unchanged when disabled, when there are fewer than 2 candidates, or
     * when no budget information is available.
     */
    private applyMmrToQmdResults;
    private buildLastRecallBudgetSummary;
    private collectLastRecallSources;
    /**
     * Issue #373 — nearest-neighbor lookup for the write-time semantic dedup
     * guard. Returns the top-K embedding hits against the currently indexed
     * memories, or an empty array when the embedding backend is unavailable.
     * Intentionally does NOT throw; `decideSemanticDedup` treats both "empty"
     * and "error" outcomes as fail-open (keep the candidate).
     *
     * PR #399 P1 fix: when namespaces are enabled the lookup must be scoped
     * to the SAME namespace as the fact being written. Otherwise a
     * high-similarity memory from another namespace can suppress a write in
     * the target namespace — cross-tenant data loss. Callers pass the target
     * storage so we can translate its root directory into the correct index
     * path prefix (and, for the legacy default-namespace layout at
     * `memoryDir` root, an exclusion list for `namespaces/*`).
     */
    semanticDedupLookup(content: string, limit: number, targetStorage: StorageManager): Promise<SemanticDedupHit[]>;
    /**
     * Resolve the namespace-scoped filter to pass into
     * `EmbeddingFallback.search()` for semantic dedup. Returns an empty
     * object (no filter) when namespaces are disabled, preserving the
     * pre-PR #399 behavior for single-tenant installs.
     *
     * Index entries are stored as paths relative to `config.memoryDir`, so:
     *   - A non-default namespace `ns` lives under `namespaces/<ns>/…` and
     *     we include exactly that prefix.
     *   - The default namespace may live at `memoryDir` root (legacy) or at
     *     `memoryDir/namespaces/<default>/…` (migrated). When it lives at
     *     root we include everything but EXCLUDE all `namespaces/…` entries
     *     so facts from non-default namespaces can't cross-match.
     */
    private semanticDedupScopeFor;
    private searchEmbeddingFallback;
    /**
     * Long-term fallback retrieval.
     * Searches archived memories only, and is invoked only when hot recall returns zero hits.
     */
    private searchLongTermArchiveFallback;
    private applyColdFallbackPipeline;
    /**
     * Record that memories were accessed (retrieved).
     * Updates are batched in memory and flushed during consolidation.
     */
    trackMemoryAccess(memoryIds: string[]): void;
    /**
     * Flush access tracking buffer to disk.
     * Called during consolidation or when buffer is full.
     */
    flushAccessTracking(): Promise<void>;
    /**
     * Apply recency, access count, and importance boosting to QMD search results.
     * Returns re-ranked results.
     */
    private boostSearchResults;
    /**
     * Extract memory IDs from QMD search results for access tracking.
     */
    private extractMemoryIdsFromResults;
    recordMemoryFeedback(memoryId: string, vote: "up" | "down", note?: string): Promise<void>;
    recordNotUsefulMemories(memoryIds: string[], note?: string): Promise<void>;
    getLastRecall(sessionKey: string): LastRecallSnapshot | null;
    /**
     * Check if a new memory contradicts an existing one.
     * Uses QMD to find similar memories, then LLM to verify contradiction.
     */
    private checkForContradiction;
    /**
     * Suggest links for a new memory based on similar existing memories.
     */
    private suggestLinksForMemory;
    private namespaceFromPath;
    private namespaceFromStorageDir;
    private readAllMemoriesForNamespaces;
    private readArchivedMemoriesForNamespaces;
}

export { shouldFilterLifecycleRecallCandidate as $, computeArtifactCandidateFetchLimit as A, type BulkImportSource as B, type CompoundingPromotionReport as C, computeArtifactRecallLimit as D, computeQmdHybridFetchLimit as E, dedupeEntitySynthesisEvidenceEntries as F, type GraphRecallSnapshot as G, deriveTopicsFromExtraction as H, type IntentDebugSnapshot as I, filterRecallCandidates as J, formatCompressionGuidelinesForRecall as K, graphPathRelativeToStorage as L, hasIdentityRecoveryIntent as M, isArtifactMemoryPath as N, Orchestrator as O, type PatternReinforcementResult as P, type QmdRecallSnapshot as Q, type ReplaySource as R, type SemanticDedupLookup as S, lifecycleRecallScoreAdjustment as T, mergeArtifactRecallCandidates as U, mergeGraphExpandedResults as V, resolveEffectiveIdentityInjectionMode as W, resolveEffectiveRecallMode as X, resolvePersistedMemoryRelativePath as Y, resolveRecallModeDecision as Z, resolveRecentThreadMemoryPaths as _, type ReplayWarning as a, summarizeGraphShadowComparison as a0, type ImportTurn as b, type BulkImportOptions as c, type BulkImportResult as d, type ReplayTurn as e, type BulkImportSourceAdapter as f, type BulkImportError as g, type ImportSourceRole as h, type ImportTurnValidationIssue as i, type SemanticDedupDecision as j, type SemanticDedupHit as k, type SemanticDedupOptions as l, decideSemanticDedup as m, defaultWorkspaceDir as n, isImportRole as o, parseIsoTimestamp as p, type GraphRecallRankedResult as q, type GraphRecallShadowComparison as r, sanitizeSessionKeyForFilename as s, type RecallInvocationOptions as t, type RecallModeDecision as u, validateImportTurn as v, appendMemoryToGraphContext as w, blendGraphExpandedRecallScore as x, buildCompressionGuidelinesMarkdown as y, buildMemoryPathById as z };
