import { b as ConnectorCursor, a as ConnectorDocument } from './framework-CyHYDcri.js';

/**
 * @remnic/core — Live Connectors State Store (issue #683 PR 1/N)
 *
 * Persists per-connector cursor + sync metadata to
 *   `<memoryDir>/state/connectors/<id>.json`
 *
 * Reasons this lives next to memory data, not in user config:
 *   - cursors are *operational* state that should travel with the memory
 *     directory when a user moves it across machines;
 *   - it keeps memory + ingest provenance co-located so tooling that backs up
 *     the memory directory captures cursor state too.
 *
 * Atomic-write contract (CLAUDE.md gotcha #54):
 *   - We NEVER `rmSync(target)` before `renameSync(tmp, target)`.
 *   - Writes go to a sibling tmp file and `rename()` swaps it in.
 *   - On error, the tmp file is best-effort cleaned up; the previous good
 *     state file is left untouched.
 *
 * Privacy: cursors are opaque connector-defined strings. We do not log them
 * and do not surface them through user-visible APIs. Document content NEVER
 * touches this module.
 */

/**
 * Status of the most recent sync attempt for a connector.
 *
 * `"never"` is distinct from `"success"` so callers can detect
 * "registered but never run" without inspecting timestamps. Per CLAUDE.md
 * gotcha #34, we deliberately distinguish empty/unknown from failure states.
 */
type ConnectorSyncStatus = "success" | "error" | "never";
/**
 * Persisted per-connector state.
 *
 * Stored as pretty-printed JSON for human inspection — the file is small
 * (one record per connector) and operators may need to debug stuck cursors
 * by hand.
 */
interface ConnectorState {
    /** Connector id. Matches the filename stem. */
    readonly id: string;
    /** Last persisted cursor, or `null` if the connector has never synced. */
    readonly cursor: ConnectorCursor | null;
    /** ISO 8601 timestamp of the last completed sync attempt, or `null`. */
    readonly lastSyncAt: string | null;
    /** Status of the last completed sync attempt. */
    readonly lastSyncStatus: ConnectorSyncStatus;
    /** Optional error message from the last failed sync. Truncated to 1 KB. */
    readonly lastSyncError?: string;
    /** Cumulative count of documents successfully imported across all syncs. */
    readonly totalDocsImported: number;
    /** ISO 8601 timestamp of when this state record was last written. */
    readonly updatedAt: string;
}
/**
 * Read the persisted state for a single connector.
 *
 * Returns `null` if the file does not exist (ENOENT). Throws on any other
 * I/O error or on shape mismatch — operators should see corruption loudly.
 *
 * Rejects symlinks anywhere on the path so a planted symlink can't redirect
 * reads outside the memory root. (PR #724 review.)
 */
declare function readConnectorState(memoryDir: string, id: string): Promise<ConnectorState | null>;
/**
 * Write state atomically: create-tmp + rename. Never destroys the previous
 * file before the new one is in place — see CLAUDE.md gotcha #54.
 *
 * We accept `Omit<ConnectorState, "updatedAt">` and stamp `updatedAt`
 * ourselves so callers can't accidentally persist a stale timestamp.
 */
declare function writeConnectorState(memoryDir: string, id: string, state: Omit<ConnectorState, "updatedAt">): Promise<ConnectorState>;
/**
 * Enumerate every persisted connector state. Returns an empty array when
 * the directory does not exist yet (clean install, no syncs ever run).
 *
 * Files that do not match the `<id>.json` naming rule are skipped — this
 * keeps stray editor backups (`.json~`, `.swp`) from breaking enumeration.
 *
 * Corruption (unparseable JSON, shape mismatch, id mismatch) is also
 * skipped so one bad file doesn't take down the listing. Operators
 * inspecting `state/connectors/` can still see the offending file by hand.
 *
 * **Genuine I/O failures (`EACCES`, `EIO`, etc.) are NOT swallowed** —
 * silently returning an incomplete state set would make active connectors
 * appear missing and trigger duplicate ingestion on the next scheduler tick.
 * (PR #724 review.)
 */
declare function listConnectorStates(memoryDir: string): Promise<ConnectorState[]>;

/**
 * `remnic connectors` CLI helpers (issue #683 PR 6/N).
 *
 * Three subcommands:
 *
 *   remnic connectors list
 *     Lists all configured live connectors, their enabled state, last poll
 *     time, and last error.  Output formats: text (default), markdown, json.
 *
 *   remnic connectors status
 *     Identical data to `list` but defaults to JSON output so scripts can
 *     reliably parse it.  Accepts `--format` to override.
 *
 *   remnic connectors run <name>
 *     Manually triggers a single `syncIncremental()` pass for the named
 *     connector.  Operator debug surface — useful when you want to test
 *     credentials without waiting for the scheduler tick.  Prints the
 *     number of new documents imported plus any error.
 *
 * Design decisions:
 *
 *   - Pure functions for list / status / run option parsing so they can be
 *     unit-tested without booting an orchestrator (CLAUDE.md rules 14 + 51).
 *   - Rendering lives here (not in cli.ts) so HTTP/MCP surfaces can reuse the
 *     same output without forking formatting (CLAUDE.md rule 22).
 *   - The `run` command requires the caller to pass a `pollFn` callback
 *     (wrapping the actual connector's `syncIncremental`).  This keeps the
 *     helper module free of direct orchestrator / live-connector imports while
 *     still being testable (CLAUDE.md rule 33 — mock signatures must match
 *     production).
 *   - CLAUDE.md rule 51: invalid `--format` throws with listed options; unknown
 *     connector name in `run` throws a descriptive error; `--format` without a
 *     value is caught by Commander's built-in argument check.
 *   - `runConnectorPollOnce` encapsulates the persist-before-cursor-advance
 *     contract (CLAUDE.md gotcha #25, #43) so it can be unit-tested in
 *     isolation without an orchestrator.
 */

/**
 * A lightweight descriptor for one live connector, assembled from the parsed
 * config and any persisted state.  The CLI handler builds this from
 * `orchestrator.config.connectors` + `listConnectorStates(memoryDir)`.
 */
interface ConnectorRow {
    /** Stable connector id (e.g. `"google-drive"`, `"notion"`). */
    id: string;
    /** Human-readable display name. */
    displayName: string;
    /** Whether the operator has enabled this connector in config. */
    enabled: boolean;
    /** Persisted sync state, or `null` if no sync has ever run. */
    state: ConnectorState | null;
}
/**
 * Result returned by the `run` command's poll function.
 */
interface ConnectorRunResult {
    /** Number of new documents imported in this pass. */
    docsImported: number;
    /**
     * Error message if the sync or ingest failed, undefined on full success.
     * When only the cursor write failed after a successful ingest, this field is
     * undefined and `stateWriteError` carries the failure. When persisting error
     * state fails after a sync/ingest error, both fields are set so callers can
     * preserve the primary failure while also reporting stale persisted state.
     */
    error?: string;
    /**
     * Set when cursor/error-state persistence fails. On the success path,
     * `docsImported` reflects the actual count of successfully ingested docs so
     * the operator knows data was persisted even though the cursor did not
     * advance. On the error path, `error` preserves the primary sync/ingest
     * failure and this field reports the secondary persistence failure.
     */
    stateWriteError?: string;
}
declare const CONNECTORS_OUTPUT_FORMATS: readonly ["text", "markdown", "json"];
type ConnectorsOutputFormat = (typeof CONNECTORS_OUTPUT_FORMATS)[number];
/**
 * Validate `--format <fmt>`.  Throws a listed-options error for any value not
 * in `CONNECTORS_OUTPUT_FORMATS`.  Returns the given default when the value is
 * `undefined` (no flag supplied).
 */
declare function parseConnectorsFormat(value: unknown, defaultFormat?: ConnectorsOutputFormat): ConnectorsOutputFormat;
interface ParsedConnectorsListOptions {
    format: ConnectorsOutputFormat;
}
interface ParsedConnectorsStatusOptions {
    /** `status` defaults to JSON for scripting; `--format` can override. */
    format: ConnectorsOutputFormat;
}
/**
 * Validate the option bag for `remnic connectors list`.
 */
declare function parseConnectorsListOptions(options: Record<string, unknown>): ParsedConnectorsListOptions;
/**
 * Validate the option bag for `remnic connectors status`.
 * Defaults to `json` (machine-readable) unless `--format` overrides.
 */
declare function parseConnectorsStatusOptions(options: Record<string, unknown>): ParsedConnectorsStatusOptions;
/**
 * Validate the positional `<name>` argument for `remnic connectors run`.
 */
declare function parseConnectorsRunName(rawName: unknown): string;
/**
 * Render connector rows for `remnic connectors list` / `remnic connectors status`.
 */
declare function renderConnectorsList(rows: readonly ConnectorRow[], format: ConnectorsOutputFormat): string;
/**
 * Render the result of a manual `remnic connectors run <name>` invocation.
 */
declare function renderConnectorsRunResult(connectorId: string, result: ConnectorRunResult, format: ConnectorsOutputFormat): string;
/**
 * Arguments for a single connector poll pass.
 *
 * All I/O is injectable so callers (cli.ts) can supply real implementations
 * and tests can supply lightweight stubs without booting an orchestrator.
 */
interface RunConnectorPollOnceArgs {
    /** Connector identifier (used in error/success state writes). */
    connectorId: string;
    /** Prior persisted state, or `null` on the very first sync. */
    priorState: ConnectorState | null;
    /**
     * Perform a single incremental sync.  Returns newly-fetched documents and
     * the cursor that should be persisted on success.
     */
    syncFn: (cursor: ConnectorCursor | null) => Promise<{
        newDocs: ConnectorDocument[];
        nextCursor: ConnectorCursor;
    }>;
    /**
     * Ingest fetched documents into the memory layer.  Called BEFORE the cursor
     * is advanced.  If this throws the cursor is NOT advanced (CLAUDE.md gotcha
     * #25 — don't destroy old state before confirming new state succeeds).
     */
    ingestFn: (docs: ConnectorDocument[]) => Promise<void>;
    /**
     * Persist connector state (cursor + metadata).  Called after `ingestFn`
     * succeeds (success path) or when `syncFn` / `ingestFn` throws (error path,
     * with old cursor retained).
     */
    writeCursorFn: (state: {
        cursor: ConnectorCursor | null;
        lastSyncStatus: ConnectorSyncStatus;
        lastSyncError?: string;
        totalDocsImported: number;
    }) => Promise<void>;
}
/**
 * Execute one `syncIncremental` pass for a live connector, enforcing the
 * persist-before-advance-cursor contract.
 *
 * Invariant (CLAUDE.md gotcha #25 + #43):
 *   1. `syncFn` fetches new docs and a next cursor.
 *   2. `ingestFn` persists the docs into the memory layer.
 *   3. Only if (2) succeeds does `writeCursorFn` advance the cursor.
 *   4. If (1) or (2) throws, `writeCursorFn` is still called but retains the
 *      **prior** cursor so the next poll re-fetches the same window.
 *
 * Returns the `ConnectorRunResult` that `cli.ts` uses for output rendering.
 */
declare function runConnectorPollOnce(args: RunConnectorPollOnceArgs): Promise<ConnectorRunResult>;

export { CONNECTORS_OUTPUT_FORMATS as C, type ParsedConnectorsListOptions as P, type RunConnectorPollOnceArgs as R, type ConnectorRow as a, type ConnectorRunResult as b, type ConnectorState as c, type ConnectorSyncStatus as d, type ConnectorsOutputFormat as e, type ParsedConnectorsStatusOptions as f, parseConnectorsListOptions as g, parseConnectorsRunName as h, parseConnectorsStatusOptions as i, renderConnectorsList as j, renderConnectorsRunResult as k, listConnectorStates as l, runConnectorPollOnce as m, parseConnectorsFormat as p, readConnectorState as r, writeConnectorState as w };
