/** * WHAT THE DELIVER PUSH LEAVES BEHIND — the crew#434 classifier, as one reusable predicate. * * The rules themselves are not new: they have run inside `deliverPrScript`'s generated bash since * crew#434 (an untracked candidate is staged UNLESS it looks like scratch or key material, and * every exclusion is printed with its reason). What is new is that they are now readable from * TypeScript, because a second consumer needs the SAME answer. * * ## Why (F3, ship-proof C7) * * The deliver gate's consent diffstat is computed from `GET /runs/:id/diff`, whose untracked pass * appended every non-ignored untracked path as an all-addition hunk. The push does not carry every * non-ignored untracked path. On a run whose creator left a `tmp/` behind, the gate read * **"109 files changed, +258, -2"** and the commit pushed **4 files, +47, -2** — 27x over, on the * one gate with an irreversible external side effect. The script printed * `deliver: EXCLUDED (scratch-dir): tmp/ (105 files)`, so the exclusion applied to the push and * not to the number the operator approved. * * The number on a consent surface has to be the number that ships, so the diff the gate reads now * runs this classifier over its untracked candidates. * * ## Drift * * There are necessarily TWO implementations — this one runs in the daemon, the other is generated * bash running in the run worktree — and only one of them decides what is actually pushed. The * shell is therefore the source of truth and this module tracks it; they are pinned together by * `tests/deliver-gate-diffstat.test.ts`, which runs the REAL script over a fixture tree and * requires the committed set to equal the set this function keeps. * * It is a GUARD, NOT A SILENT DROP: the script still prints every excluded path with its reason * into the phase output (retained and served on the run wire), and this module only changes which * files a *preview* of the push counts. */ /** * The deliver script's untracked RECOVERY SENTINEL (crew#432): a failed push leaves this empty file * at the worktree root so the engine's terminal reap never removes a worktree whose work was * committed but not delivered, and the next attempt removes it before staging. It is never part of * the push, so it is never part of the consent diffstat either (N2, ship re-proof): the retry gate * read "5 files changed" for a commit of 4 because this predicate did not know the name. The * script's `S=` line is generated FROM this constant, so the name cannot drift between the two. */ export declare const DELIVER_STRANDED_SENTINEL = ".wicked-crew-delivery-stranded"; /** One line a value-free env template may hold (POSIX ERE, shared with the deliver script). */ export declare const ENV_TEMPLATE_SAFE_LINE_ERE = "^[[:space:]]*(#.*)?$|^[[:space:]]*(export[[:space:]]+)?[A-Za-z_][A-Za-z0-9_]*[[:space:]]*=[[:space:]]*(\"\"|''|<[^>]*>)?[[:space:]]*$"; /** Whether a basename names an env template (lowercased, as the ladder compares). */ export declare function isEnvTemplateName(lowerBase: string): boolean; /** Whether an env template's text holds no value (every line {@link ENV_TEMPLATE_SAFE_LINE}). */ export declare function envTemplateIsValueFree(text: string): boolean; /** The scratch/cache directory names the push never carries, at any depth. */ export declare const SCRATCH_DIRS: string[]; /** * The directories a TEST RUNNER or build tool writes its own output into (crew#861): a vitest * JSON reporter's `.vitest/json/output.json` (2.3 MB, left untracked at a studio worktree root by a * creator's read-only re-verify) would have ridden a governed PR had the lift not conflicted first. * These names are never a run's product at any depth; like {@link SCRATCH_DIRS} they are excluded at * enumeration by the script and reported once with a count. */ export declare const TOOL_ARTIFACT_DIRS: string[]; /** The heading under which the deliver script lists what it left behind, in the PR body and the * commit message (crew#861) — the "says what it skipped" half of the guard. */ export declare const DELIVER_NOT_SHIPPED_HEADING = "## Not shipped"; /** Past this, an otherwise-unrecognised file is scratch by size alone (the generic net). */ export declare const OVERSIZE_BYTES = 1048576; /** * Why the deliver push would exclude this path on its NAME alone — the arms that need no `stat`: * the denylist, the `socket` basename, `.DS_Store`, a scratch or tool-artifact directory at any depth, * and a tool's `*.log` (crew#434, crew#861). `null` * means "no name rule fires"; the caller still owes the size rule ({@link deliverExclusionReason}). * * Split out so a caller can classify 100 000 untracked paths without 100 000 synchronous `stat` * calls on the daemon's event loop (codex review of the F3 PR, MEDIUM): only a path that survives * every name rule is ever stat'd, and under a scratch directory none of them are. * * `relPath` is repo-relative with `/` separators — git's own spelling, which * `git status --porcelain -z` and `git ls-files -z` emit on every platform. * * The order of the arms is the script's order, and it matters: a `tmp/x.db` reports * `denylisted-name`, exactly as the shell's `[ -n "$RN" ] ||` guards do. */ export declare function deliverExclusionByName(relPath: string): string | null; /** * Why the deliver push would EXCLUDE this untracked path, or `null` when it rides — the whole * ladder, name rules first and then the size rule. * * `sizeBytes` is the file's size, or `null` when it could not be stat'd; an unknown size is never * treated as oversize (the shell's `wc -c < "$F" 2>/dev/null || echo 0` degrades the same way). * A caller that wants to avoid the `stat` for a path a name rule already rejects calls * {@link deliverExclusionByName} first. */ export declare function deliverExclusionReason(relPath: string, sizeBytes: number | null, /** crew#901: the file's text, for an env template; absent or `null` (unreadable) = excluded. */ readText?: () => string | null): string | null; //# sourceMappingURL=deliver-exclusions.d.ts.map