import { EffectiveTree } from './effective-tree';
import { BlockedResult } from './types';
/**
* L1 row 5: git/gh commands must run from the repo root of the tree they act on, where the guards can
* reason about git state coherently. guards/L1-location.md carries the table and the use cases; change
* this predicate and that file is stale until you update it.
*
* ONE variable decides it: `tree.effectiveCwd` — the directory the command actually runs in, which is
* the shell's cwd unless the command leads with `cd
&&`. Root or not-root, nothing else.
*
* It used to be `shellAtRoot || cdsToRoot`, two variables OR'd, and that produced opposite verdicts for
* the same destination: `git status` with the shell in packages/http/ was BLOCKED, while
* `cd packages/http && git status` from the root was ALLOWED, because shellAtRoot short-circuited before
* the destination was ever considered. An agent that cd's INTO a subdir has the same broken mental model
* as one stranded there, so it gets the same answer now.
*
* The remedy is ONE runnable line, `cd && `, not "cd first, then re-run" — that advice
* made this guard print the very command it had just rejected, and a `cd` is unreliable in both
* directions (INTO this repo it sticks; OUT of it the harness resets it).
*
* It goes through remedyAtRoot(), NOT bare atRoot(), and that is load-bearing: A REMEDY MUST SATISFY THE
* PREDICATE THAT PRINTED IT. Prefixing `cd '' &&` onto a command already leading with
* `cd &&` left effectiveCwd in ``, so the identical block fired on the remedy with
* the prefix doubled, then tripled. remedyAtRoot REPLACES the leading `cd` run instead, and
* effective-tree.spec.ts asserts that property for every L1 remedy, not just this one.
*/
export declare class ForceToRootGuard {
private readonly resolver;
/** The deny report, or null to allow. */
block(command: string, tree: EffectiveTree, isGitOrGh: boolean): string | null;
}
export declare function gitFromSubdirBlock(command: string, tree: EffectiveTree, isGitOrGh: boolean): BlockedResult | null;