import { M as FileMention } from './parts-DIKcC1p6.js';

/**
 * `createSandboxFileIndexRoute` — server side of `@`-file-mentions
 * (companion to sandbox-ui#184's composer mention primitive). Serves a flat,
 * ignore-filtered listing of the workspace sandbox so `useFileMentions`
 * (`/web-react`) can filter it client-side without a round trip per
 * keystroke.
 *
 * Same seam style as `createUploadRoute`: `authorize({ request })` resolves a
 * structural `{ tree(path, opts) }` handle (the shape of the sandbox SDK's
 * `box.fs.tree`) — no SDK import here. `authorize` also carries the
 * cold-box signal: a sandbox that isn't running yet answers `{ status:
 * 'warming' }` directly, never provisions-and-waits inside this route.
 *
 * A box can also be running with its workspace root not yet materialised, which
 * `authorize` cannot see; the route recognises that one signal off `fs.tree`
 * and answers `warming` too, so every consumer gets the retry-and-wait state
 * instead of a 500. Every other `tree()` failure propagates.
 */

/** One entry from a structural `tree()` scan. Mirrors the sandbox SDK's
 *  `FileTreeFile` (`path`, `size`, `mtime`) — `mtime` is unused here so it's
 *  omitted from the structural match. */
interface SandboxTreeFile {
    path: string;
    size: number;
}
/** Structural match of the sandbox SDK's `box.fs.tree` result shape
 *  (`FileTreeResult`). `stats.truncated` is the only stat this route reads;
 *  the rest ride through unread on the real SDK type. */
interface SandboxTreeResult {
    root: string;
    files: SandboxTreeFile[];
    stats: {
        truncated: boolean;
    };
}
/** Structural match of the sandbox SDK's `box.fs` tree surface. */
interface SandboxFileTreeSource {
    tree(path: string, options?: {
        maxDepth?: number;
    }): Promise<SandboxTreeResult>;
}
/** Describe a ready file index response with workspace-relative entries and truncation status */
interface FileIndexReadyResponse {
    status: 'ready';
    /** Workspace-relative entries. Same shape as `FileMention` (`./wire`) so a
     *  client can hand a response entry straight to `fileMentionsToParts` /
     *  `buildMentionPromptBlock` without remapping. */
    files: FileMention[];
    /** True when either the underlying scan truncated (SDK-side cap) or this
     *  route's own `maxEntries` cap trimmed the filtered list. The client
     *  should show "showing first N files" rather than imply completeness. */
    truncated: boolean;
    generatedAt: string;
}
/** Cold-box answer: no provisioning happened, no files were scanned. The
 *  client shows a warming state and retries — this route never blocks on a
 *  box coming up. Two situations produce it: `authorize` reporting a box that
 *  is not running, and a running box whose workspace root does not exist yet
 *  (see `isMissingRootError`). */
interface FileIndexWarmingResponse {
    status: 'warming';
}
/** Resolve a response indicating the file index is either ready or warming up */
type FileIndexResponse = FileIndexReadyResponse | FileIndexWarmingResponse;
/** Short-TTL cache seam so repeat popover opens in the same session don't
 *  re-scan the workspace. Host-provided (e.g. a KV binding); `key` is
 *  whatever `authorize` returns as `cacheKey` — this route treats it opaquely. */
interface FileIndexCache {
    get(key: string): Promise<FileIndexReadyResponse | null> | FileIndexReadyResponse | null;
    put(key: string, value: FileIndexReadyResponse, options?: {
        ttlSeconds?: number;
    }): Promise<void> | void;
}
/** Define authorization details and parameters for indexing a file workspace with optional caching and ignore rules */
type FileIndexAuthorization = {
    status: 'ready';
    /** Structural sandbox `fs` handle, usually `ensureWorkspaceSandbox(...)` → `box.fs`. */
    fs: SandboxFileTreeSource;
    /** Workspace root to index (e.g. `/home/agent`). */
    root: string;
    /** Extra ignore segments for this request, merged with the route's
     *  defaults + `CreateSandboxFileIndexRouteOptions.ignore`. */
    ignore?: string[];
    /** Opaque cache key for the optional cache seam. Omit to skip caching
     *  for this request (e.g. a workspace the host chooses not to cache). */
    cacheKey?: string;
} | {
    status: 'warming';
} | {
    status: 'denied';
    response: Response;
};
/** Define options to authorize and configure sandbox file index route behavior */
interface CreateSandboxFileIndexRouteOptions {
    /** Authenticate the caller, resolve the sandbox `fs` handle, and signal a
     *  cold box — never provisions or waits. */
    authorize(args: {
        request: Request;
    }): Promise<FileIndexAuthorization>;
    /** Extra ignore segments beyond the route's defaults (node_modules, .git,
     *  dotfiles/dot-dirs, common build dirs). Matched as exact path-segment
     *  names, same rule as the defaults. */
    ignore?: string[];
    /** Passed to `fs.tree` as `options.maxDepth`. Default 12. */
    maxDepth?: number;
    /** Hard cap on entries returned after filtering. Default 5000. */
    maxEntries?: number;
    /** Optional host-provided cache seam. */
    cache?: FileIndexCache;
    /** Cache TTL in seconds when `cache` is set. Default 20. */
    cacheTtlSeconds?: number;
}
/** Resolve a sandbox file index route with authorization, caching, and configurable depth and entries limits */
declare function createSandboxFileIndexRoute(options: CreateSandboxFileIndexRouteOptions): (request: Request) => Promise<Response>;

/**
 * Content-based binary/text classification, shared by the attachment upload
 * route (server) and the composer's client-side pre-validation (browser) —
 * both sides must agree on what counts as binary before a byte ever leaves
 * the client. Extension-based allowlists lie (a renamed `.docx`, a PNG saved
 * as `.txt`), so classification reads the actual bytes: a magic-byte table
 * for common binary formats first, then a UTF-8 decode attempt for
 * everything else.
 *
 * Lifted near-verbatim from gtm-agent's `src/lib/binary-sniff.ts` (the
 * source PRs hardened this against real corruption/gate bugs: gtm#584,
 * gtm#592). Import-free by design — `/web-react` re-exports `/chat-routes`
 * modules into browser bundles (`tests/browser-safe-subpaths.test.ts` walks
 * the graph), so nothing here may reach a Node builtin or an engine package.
 */
interface SniffResult {
    binary: boolean;
    mime: string | null;
}
/** Decide whether uploaded bytes are binary or text, and identify the mime
 *  type when it can be determined from content. Magic bytes are checked
 *  first; anything unmatched falls back to a fatal UTF-8 decode. A NUL byte
 *  or a decode failure means binary. Valid UTF-8 that is an SVG document is
 *  binary (byte-identity matters for image tooling). Content that matches
 *  nothing and does not decode as text is binary with an unknown mime —
 *  extension-based guessing happens at the call site, not here. */
declare function sniffBinary(bytes: Uint8Array): SniffResult;

/**
 * Shared attachment validation core — constants, type-gate, and filename
 * sanitization used by BOTH the (server) attachment upload route and the
 * (browser) composer's client-side pre-validation, so a rejection never
 * differs depending on which side classified the bytes first.
 *
 * ≈ gtm-agent's `src/lib/attachment-limits.ts`, minus what agent-app already
 * has (`ATTACHMENT_MAX_COUNT`/`MAX_ATTACHMENT_TOTAL_BYTES`/
 * `attachmentTotalSizeErrorMessage` lived in `./resolve-attachments` and are
 * re-homed here so the whole validation vocabulary — count cap, size caps,
 * and type gate — has one address). Import-free besides `./wire`
 * (`formatBytes`) and `./binary-sniff` (`SniffResult`): `/web-react`
 * re-exports `/chat-routes` modules into browser bundles
 * (`tests/browser-safe-subpaths.test.ts` walks the graph), so nothing here
 * may reach a Node builtin or an engine package.
 */

/** Ceiling on a binary attachment's raw (pre-encoding) byte size. */
declare const MAX_BINARY_ATTACHMENT_BYTES: number;
/** Ceiling on a text attachment's raw byte size. Text hydrates through
 *  inline prompt parts, a separate path that remains proxy-capped (see
 *  `INLINE_PARTS_MAX_BYTES` in `./wire`). */
declare const MAX_TEXT_ATTACHMENT_BYTES: number;
/** Most files a single request may carry: the composer staging cap, the
 *  upload route's per-request cap, and the chat body's `attachments` cap. */
declare const ATTACHMENT_MAX_COUNT = 10;
/** Aggregate raw-byte ceiling across one message's attachments. */
declare const MAX_ATTACHMENT_TOTAL_BYTES: number;
/**
 * Accept list for the composer file picker + type validation, same grammar as
 * the native `<input accept>` attribute. Images plus the text/doc types a
 * product's store actually reads.
 */
declare const ATTACHMENT_ACCEPT = "image/*,.pdf,.txt,.md,.csv,.json,.yaml,.yml,.html";
/** Sniffed-mime counterpart of `ATTACHMENT_ACCEPT`: the binary formats
 *  `sniffBinary` can identify from magic bytes among the accepted types.
 *  Values must match `sniffBinary`'s output strings verbatim, or every
 *  upload of that format fails the type gate. */
declare const ALLOWED_ATTACHMENT_SNIFFED_MIMES: ReadonlySet<string>;
/** Represent the result of checking an attachment's type with success or specific failure details */
type AttachmentTypeCheckResult = {
    succeeded: true;
} | {
    succeeded: false;
    code: 'attachment_type_mismatch' | 'attachment_type_not_allowed';
    message: string;
};
/**
 * Cross-check a filename's extension against its sniffed content.
 *
 * Text content (`sniff.binary === false`) always passes here — it has no
 * magic bytes to compare, so it rides the existing UTF-8 gate instead. For
 * binary content: an extension with an unambiguous magic-byte family (e.g.
 * `.pdf`) must match the sniffed mime, or the upload is a mismatch (a
 * renamed file). Otherwise the sniffed mime must be one of `allowed`
 * (default {@link ALLOWED_ATTACHMENT_SNIFFED_MIMES}), or the upload is
 * rejected outright. The `allowed` param feeds a route's override seam (a
 * product accepting a narrower or wider set than the default).
 */
declare function checkAttachmentType(fileName: string, sniff: SniffResult, allowed?: ReadonlySet<string>): AttachmentTypeCheckResult;
/**
 * Rewrite a filename into the store-path charset (`A-Za-z0-9._-` per
 * segment) — attachment paths double as store keys, sandbox file paths, and
 * in-message path references, none of which tolerate spaces or punctuation.
 * Runs of unsupported characters collapse to one `-`; leading dots/dashes are
 * stripped so the name can't read as a hidden segment. The original name is
 * preserved separately (the returned `ChatAttachmentInput.name`), so
 * sanitization loses nothing.
 */
declare function sanitizeAttachmentFileName(name: string): string;
/** Human-readable error naming both the actual size and the limit that was
 *  exceeded. Shared so the server route and the composer pre-check report
 *  the same message shape. */
declare function attachmentSizeErrorMessage(name: string, actualBytes: number, limitBytes: number): string;
/** Human-readable error for a chat message whose combined attachments exceed
 *  the aggregate raw-byte ceiling. */
declare function attachmentTotalSizeErrorMessage(totalBytes: number, limitBytes: number): string;

export { ALLOWED_ATTACHMENT_SNIFFED_MIMES as A, type CreateSandboxFileIndexRouteOptions as C, type FileIndexAuthorization as F, MAX_ATTACHMENT_TOTAL_BYTES as M, type SandboxFileTreeSource as S, ATTACHMENT_ACCEPT as a, ATTACHMENT_MAX_COUNT as b, type AttachmentTypeCheckResult as c, type FileIndexCache as d, type FileIndexReadyResponse as e, type FileIndexResponse as f, type FileIndexWarmingResponse as g, MAX_BINARY_ATTACHMENT_BYTES as h, MAX_TEXT_ATTACHMENT_BYTES as i, type SandboxTreeFile as j, type SandboxTreeResult as k, type SniffResult as l, attachmentSizeErrorMessage as m, attachmentTotalSizeErrorMessage as n, checkAttachmentType as o, createSandboxFileIndexRoute as p, sniffBinary as q, sanitizeAttachmentFileName as s };
