/** * Provider-neutral Repository Capability Contract (DESIGN.md §18, * PRD FR-081, FR-083, FR-086, FR-089; NFR-004, NFR-006, NFR-007). * * This module declares the three repository operations (Search, Read File, * Directory Listing), their provider-neutral request, identity, cache, and * result shapes, and the total normalized cache decoders used by shared * execution. It imports NO concrete Provider, transport, or Adapter. It * does no path canonicalization, raw ZRead parsing, Provider field * mapping, Provider selection, retries, or presentation. * * Scope of this file: * - request, operation, cache-identity, and result type contracts; * - total decoders for the three cacheable normalized result types * (`decodeRepositorySearch`, `decodeRepositoryFile`, * `decodeRepositoryDirectoryListing`); * - the discriminated `RepositoryOperationKind` union shared by shared * execution, retry policy, and diagnostics. * * P6-02 introduces ONLY this contract and the decoders. P6-03 supplies * shared execution, P6-04 the Z.AI Adapter, and P6-05 the Explorer. The * capability surface here is the boundary between those tickets and the * commands; nothing in this file is allowed to widen the boundary. */ import type { ProviderId } from "../providers/types.js"; /** * Discriminated union over the three repository operations. Shared * execution maps each kind to its retry policy branch and diagnostics * inventory. The union is the public source of truth; consumers iterate * by listing each literal explicitly when they need a runtime set. */ export type RepositoryOperationKind = "repository-search" | "repository-read-file" | "repository-list-directory"; /** * Provider-neutral Search request. `language` MUST be supplied explicitly * (default `"en"` applied at the command layer before validation); empty * or whitespace-only `query` is invalid at validate time. */ export interface RepositorySearchRequest { readonly repository: string; readonly query: string; readonly language: "en" | "zh"; } /** * Provider-neutral File request. `path` is a non-empty * repository-relative POSIX path; `path: ""` (root) is invalid for File * and is rejected by the cache decoder. */ export interface RepositoryFileRequest { readonly repository: string; readonly path: string; } /** * Provider-neutral Directory Listing request. `path: ""` is the * repository root; every other path is a non-empty repository-relative * POSIX path. */ export interface RepositoryDirectoryRequest { readonly repository: string; readonly path: string; } /** * Provider-neutral directory or file entry. `name` is the final segment * and `path` is the repository-relative POSIX path of the entry * itself. Both fields are non-empty strings — root-level entries are * impossible because a directory entry sits below the listing's * `path`. Order is Provider-supplied and preserved. */ export interface RepositoryEntry { readonly name: string; readonly path: string; readonly kind: "file" | "directory"; } /** Search excerpt: only text. ZRead does not supply reliable metadata. */ export interface RepositorySearchExcerpt { readonly text: string; } /** * Normalized Provider-derived Search result. `schemaVersion: 1` is the * breaking migration shape from P6 (`data-mode scripting impact`). */ export interface RepositorySearchResult { readonly schemaVersion: 1; readonly repository: string; readonly query: string; readonly language: "en" | "zh"; readonly excerpts: readonly RepositorySearchExcerpt[]; readonly truncated: boolean; readonly originalTextLength: number; } /** * Normalized File result. `path` is a non-empty repository-relative * POSIX path; the cache decoder rejects `path: ""` because File is * always non-root. `truncated` carries the existing ellipsis rule. */ export interface RepositoryFileResult { readonly schemaVersion: 1; readonly repository: string; readonly path: string; readonly content: string; readonly truncated: boolean; readonly originalContentLength: number; } /** * Normalized Directory Listing result. `path: ""` means the * repository root. `entries` is never `null` and preserves sibling * order from the Provider. Each entry's `name` and `path` are * non-empty. */ export interface RepositoryDirectoryListing { readonly repository: string; readonly path: string; readonly entries: readonly RepositoryEntry[]; } /** * Normalized Repository Tree result, composed of provider-ordered * `snapshots`. `path: ""` means tree root. `depth` is the integer * tree depth applied at the Explorer layer. Tree is Explorer * projection and is not a cacheable `RepositoryOperation.decodeCached` * implementation; this type remains public because Explorer surfaces * it. */ export interface RepositoryTreeResult { readonly schemaVersion: 1; readonly repository: string; readonly path: string; readonly depth: number; readonly snapshots: readonly RepositoryDirectoryListing[]; } /** * Sealed v1 probe set. Opening the set later is additive. */ export type RepoBriefFocus = "structure" | "readme" | "manifest" | "files"; /** * Canonical kind set, in canonical priority order (used for cap-4 read * selection; see DESIGN D1, D7). The README is always selected first * when present; the manifests below are selected in this order. */ export type RepoManifestKind = "package.json" | "pyproject.toml" | "Cargo.toml" | "go.mod"; /** * One record per Explorer call the brief attempted, in execution * order. The label set is a closed vocabulary for stable consumer * interpretation: `"tree"` for the tree probe; `"search:readme"` and * `"search:manifest"` for the two search probes; `"read:"` for * each read probe (path is the repository-relative POSIX path that * was requested); and the sentinel `"read:"` for a read stage * that ran no per-path probe (always `skipped` — see `reason`). */ export interface RepoBriefProbeRecord { readonly kind: "tree" | "search" | "read"; readonly label: string; /** * ok — probe ran and returned a normalized result. * failed — probe ran and threw; `error` is set. * skipped — probe did not run: focus-excluded, dependency-failed, * or no-selection (read stage requested, but the * tree-derived selection was empty). */ readonly status: "ok" | "failed" | "skipped"; readonly error?: { readonly code: string; readonly message: string; }; readonly reason?: "focus-excluded" | "dependency-failed" | "no-selection"; } /** * Coverage section of the brief envelope. `probes` is total and * ordered: one terminal record per Explorer call the brief attempted, * plus one `read:` sentinel record whenever the read stage ran * no per-path probe — the stage was skipped (focus-excluded), its * selection input failed (dependency-failed), or it was requested but * the tree-derived selection was empty (no-selection). Consumers can * therefore always read the read stage's outcome from `coverage`, * never by inferring from missing records. */ export interface RepoBriefCoverage { readonly probes: readonly RepoBriefProbeRecord[]; } /** * Evidence entry: a selected key file, content verbatim from the * normalized File result (path + truncation metadata unchanged). */ export interface RepoBriefFileEntry { readonly path: string; readonly content: string; readonly truncated: boolean; readonly originalContentLength: number; } /** * Tree-derived booleans. `null` means the tree probe failed or was * focus-excluded — never guessed from search excerpts. */ export interface RepoBriefDetected { readonly hasReadme: boolean | null; readonly hasManifest: boolean | null; readonly manifestKinds: readonly RepoManifestKind[] | null; } /** * The brief envelope. `schemaVersion` is literally `1`; no * timestamp, no randomness, no environment-derived fields * (byte-determinism; see DESIGN D2). Field presence is governed by * the presence matrix in SCHEMA.md. */ export interface RepositoryBrief { readonly schemaVersion: 1; /** "owner/repo" as validated by `validateRepo`. */ readonly repository: string; /** Requested focus, validated against the sealed set, order preserved. */ readonly focus: readonly RepoBriefFocus[]; readonly coverage: RepoBriefCoverage; /** Present iff `structure` ∈ focus AND the tree probe succeeded. */ readonly tree?: RepositoryTreeResult; /** Present iff `readme` ∈ focus AND search:readme succeeded. */ readonly docs?: RepositorySearchResult; /** Present iff `manifest` ∈ focus AND search:manifest succeeded. */ readonly entryPoints?: RepositorySearchResult; /** * Present iff `files` ∈ focus AND tree `ok` AND ≥1 selected read * succeeded. Order: README first, then manifests in canonical * kind order. */ readonly files?: readonly RepoBriefFileEntry[]; /** Always present; fields null when their derivation input is missing. */ readonly detected: RepoBriefDetected; } /** * Provider-owned legacy cache candidate. Old Z.AI keys encode the * raw v0.2 tool response; the Adapter supplies the decoder so shared * cache code never inspects Provider response shapes. An invalid * decode is a cache miss. */ export interface LegacyRepositoryCacheCandidate { readonly key: string; decode(value: unknown): Result | null; } /** * Identity used to read and write a Provider-partitioned cache entry. * `credentialFingerprint` is the full lowercase SHA-256 hex digest of * the resolved credential and is NEVER re-hashed by cache code. * `request` is the normalized Capability request. */ export interface RepositoryCacheIdentity { readonly provider: ProviderId; readonly capability: "repository-exploration"; readonly operation: RepositoryOperationKind; readonly credentialFingerprint: string; readonly request: Readonly; readonly legacyCandidates: readonly LegacyRepositoryCacheCandidate[]; } /** * Generic operation descriptor. Each Adapter supplies one of these for * each operation it supports. The Adapter owns Provider field mapping, * credentials, transport lifecycle, and error normalization. Commands * and shared execution call only these four methods. */ export interface RepositoryOperation { readonly kind: RepositoryOperationKind; /** * Validate the request before any Provider access. Throws * `ValidationError` for missing required fields and * `UnsupportedOptionError` for Provider-specific options the Adapter * does not accept. Validation MUST occur before credential resolution * or transport construction. */ validate(request: Request): void; /** * Build the cache identity for a request. Called only after * `validate` succeeds. The Adapter resolves its credential once and * returns full fingerprint, canonical request, and zero or more * legacy candidates. Candidate construction MUST NOT read ambient * environment. */ cacheIdentity(request: Request): RepositoryCacheIdentity; /** * Total decoder for cached normalized entries. Accepts an `unknown` * value, validates shape, and returns the typed result or `null`. * NEVER throws, NEVER trusts a generic cast. */ decodeCached(value: unknown): Result | null; /** * Invoke the Provider and return the normalized result. The Adapter * closes its transport and never retries inside this method; * shared execution owns retry policy. * * `signal` is an OPTIONAL cooperative-cancellation channel. When a * caller threads an `AbortSignal` through `executeRepositoryOperation`, * the Adapter MAY observe it to stop early. Operations that have * nothing to abort simply ignore it. */ invoke(request: Request, signal?: AbortSignal): Promise; } /** * Repository Capability contract. Every Adapter that supports * repository exploration implements this interface and exposes it as * `adapter.repository` (P6-04 and beyond). */ export interface RepositoryCapability { readonly search: RepositoryOperation; readonly readFile: RepositoryOperation; readonly listDirectory: RepositoryOperation; } /** * Decode a Search result from the cache. Returns the canonical * `RepositorySearchResult` on success, `null` for any malformed value. */ export declare function decodeRepositorySearch(value: unknown): RepositorySearchResult | null; /** * Decode a File result from the cache. Returns the canonical * `RepositoryFileResult` on success, `null` otherwise. `path` MUST be * non-empty — File is always non-root; `path: ""` is rejected here * without performing any other path canonicalization. */ export declare function decodeRepositoryFile(value: unknown): RepositoryFileResult | null; /** * Decode a Directory Listing from the cache. Returns the canonical * `RepositoryDirectoryListing` on success, `null` otherwise. The * listing's own `path` may be `""` (root); every entry's `name` and * `path` MUST be non-empty. Empty entries arrays are valid (a future * Adapter contract). Each entry preserves Provider sibling order * verbatim. */ export declare function decodeRepositoryDirectoryListing(value: unknown): RepositoryDirectoryListing | null; //# sourceMappingURL=repository.d.ts.map