/** * Package diffing and patch sets. * * ── The property that makes this useful at all ────────────────────────── * * Diffs are computed POST-NORMALIZATION (§8, §15 A9). Upload canonicalizes a * package: files move into `agents/`, `skills/`, `.mcp.json`; ordering is * fixed; undeclared files are dropped. Diffing a raw source tree against a * canonically-packed artifact would therefore show the packer's reshuffling on * every single run, and bury the one line that actually changed under it. * * Two consequences worth having, both used by the cron freshness loop: * * - **Identity is a hash compare, not a diff.** Packages are * content-addressed, so "is this the same?" is free. * - **An empty diff is a TRUE no-op**, which is exactly the signal that * makes an hourly "keep this agent current" cron safe to leave running: * unchanged source → identical hash → empty diff → no publish. * * @module */ import type { ExtractedTarEntry } from "./agent-package-format.js"; /** Beyond this, a file is summarized rather than inlined. */ export declare const DIFF_MAX_FILE_BYTES: number; /** Beyond this many changed files, the set is truncated with a marker. */ export declare const DIFF_MAX_FILES = 200; export interface FilePatch { path: string; status: "added" | "removed" | "modified"; /** Unified diff, or null when the content was not diffable (binary/oversize). */ diff: string | null; /** Why `diff` is null. */ note?: string; binary?: boolean; } export interface PackageDiff { /** True when the two sides are byte-identical after normalization. */ identical: boolean; patches: FilePatch[]; /** Set when DIFF_MAX_FILES cut the list short. */ truncated?: { omitted: number; }; } /** * An entry as either producer spells it. * * TWO shapes reach this module and they do not agree: `readAgentPackageTarGz` * emits `{name, body}`, while a staged edit is built as `{path, content}`. * The union is declared so the compiler checks both — the earlier version read * `path`/`content` through `as any`, which silently dropped every tar entry * (the map came out empty, so file reads reported "not in package" and every * diff reported "identical" even across different hashes). */ export type PackageEntry = ExtractedTarEntry | { path: string; content: Buffer | string; }; /** A tar entry list reduced to path → bytes, ignoring the packer's ordering. */ export declare function entriesToMap(entries: PackageEntry[]): Map; /** * Heuristic binary detection: a NUL byte in the first 8 KiB. * * Binaries are flagged, never inlined — a base64 blob in a diff is unreadable * for a human and pure token cost for a model. */ export declare function looksBinary(buf: Buffer): boolean; /** * Longest-common-subsequence unified diff. * * Small and dependency-free on purpose: this runs inside the worker, on * content that may be attacker-authored, and a diff library is a lot of * surface to take on for a few hundred lines of text. */ export declare function unifiedDiff(oldText: string, newText: string, filePath: string, context?: number): string; /** * Diff two normalized package trees. * * Both sides must already be canonically packed — the caller is responsible * for staging a raw source tree through the same packer first, or the result * is the noise this module exists to avoid. */ export declare function diffPackageTrees(left: PackageEntry[], right: PackageEntry[]): PackageDiff; /** * Render a diff as ordered `.patch` artifacts. * * The numeric prefix is what makes the portal's existing artifact list show * them in intent order rather than alphabetically; it already renders * `.patch` files with gutter markers, so this needs no client work. */ export declare function patchArtifacts(diff: PackageDiff, opts?: { baseSemver?: string; }): Array<{ filename: string; content: string; }>; //# sourceMappingURL=agent-package-diff.d.ts.map