/** * Bash command pattern matching `git commit` (with optional pre-subcommand * flag slots like `git -C /path commit ...`). Shared by `no-main-commit` * and `no-main-commit-github` so the family stays byte-equal as the * regex evolves; reorderings that touch one rule's pattern can't * silently drift from the other. * * Exported so tests can pin each rule's `pattern` field against this * constant by value (`noMainCommit.pattern === GIT_COMMIT_PATTERN`). * That catches accidental divergence between the two rules' patterns * (e.g. one drops a `\b`, the other doesn't) and removal/rename of * the constant itself. It does NOT catch a future inlining of the * literal at a rule's definition site with the SAME bytes — string * primitives compare by value, so byte-equal copy-pasted literals * pass `===`. Plugin authors who need true shared-reference pinning * should use a `RegExp` (object) constant instead of a string source. */ export declare const GIT_COMMIT_PATTERN = "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b"; /** * Protected branch names that the gitPlugin's commit-on-main rules * block by default (`main`, `master`, `mainline`, `trunk`). Shared by * `no-main-commit` and `no-main-commit-github` so the protected- * branch list stays uniform across the rule family — adding an alias * here (e.g. a vendor-specific default-branch name) automatically * propagates to both rules. * * `RegExp` (object) constant rather than a string source: that gives * true shared-reference pinning at the test layer * (`noMainCommit.when.branch === PROTECTED_BRANCH_PATTERN`), which * also catches a future inline of the SAME bytes at a rule's * definition site — something the string-source `GIT_COMMIT_PATTERN` * pin can't do (see its JSDoc for the value-vs-reference tradeoff). */ export declare const PROTECTED_BRANCH_PATTERN: RegExp; /** * `no-main-commit` - block direct commits to a protected branch * (main / master / mainline / trunk). * * Fires on: * - `git commit -m "..."` when the current branch is one of the * protected names, * - `git checkout main && git commit ...` (the branch tracker folds * the checkout into the branch state for the commit), * - `sh -c 'git commit ...'` (wrapper expansion), * - `git -C /other commit ...` where the repo at `/other` is on * main (the `branch` predicate queries git at the effective cwd). * * Does NOT fire on: * - `git commit` while on a feature branch, * - `git log --grep="commit"` (anchored to `git commit`, not * arbitrary git subcommands), * - `echo 'git commit -m "x"'` (extraction anchors to the * basename). * * Fail-closed on unresolvable branch: if the branch predicate can't * determine the current branch (detached HEAD, not a repo, or the * tracker collapsed to `unknown` via `git checkout $VAR`), the rule * fires by default. Authors who want the allow-through behavior * supply the object form explicitly: * * `when: { branch: { pattern: /.../, onUnknown: "allow" } }` * * Reason text is dynamic via {@link ReasonFn}: when the branch * tracker has resolved a concrete branch name for the guarded * command (statically from a `git checkout ` earlier in the * chain), the name is injected into the block message so the agent * sees "You are on 'main'" instead of a generic reminder. The * ReasonFn filters out the tracker's internal sentinels * (`NO_CHECKOUT_IN_CHAIN` — no in-chain checkout, exec-fallback * path; `"unknown"` — dynamic checkout the walker couldn't * resolve) so those strings never leak into the agent-facing * message; the static actionable tail still guides the agent to a * feature branch in those cases. * * Pairs with {@link noMainCommitGithub} (specialization for * github.com clones, placed BEFORE this rule in the rule array so * first-match-wins routes the github-flavored guidance to github * users; non-github contexts fall through to this generic rule). * * Override: allowed (the rule is overridable via a * `# steering-override: no-main-commit` comment). This is a workflow * rule, not an inherent-destructiveness rule - authors override when * the commit is intentional (e.g. release process on `main`). */ export declare const noMainCommit: { readonly name: "no-main-commit"; readonly tool: "bash"; readonly field: "command"; readonly pattern: "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b"; readonly when: { readonly branch: RegExp; }; readonly reason: (ctx: import("../../schema.ts").PredicateContext) => string; readonly noOverride: false; }; /** * `no-main-commit-github` — block direct commits to a protected * branch (main / master / mainline / trunk) on github.com clones. * Specialization of {@link noMainCommit} that emits PR-flow guidance * instead of the generic feature-branch reminder. * * Pairs with {@link noMainCommit}: this rule is more specific (adds * `remote:` check), placed BEFORE `noMainCommit` in the plugin's * rule array so first-match-wins routing surfaces the github- * flavored reason on github clones. Non-github contexts (Brazil * packages, vault paths, /tmp scratch repos with non-github remotes) * fall through to the generic `noMainCommit`. * * Override: allowed (intentionally overridable for legitimate cases * like release-process commits to main). User can: * - Disable: `disabledRules: ["no-main-commit-github"]` * - Per-invocation: `# steering-override: no-main-commit-github` comment * - Customize: see gitPlugin's README "Customization" section * * @remarks Both `https://github.com/...` and `git@github.com:...` * clone URLs are matched (the `remote:` regex's `[/:]` * character class accepts both the HTTPS path separator * and the SSH user-host separator). * * @remarks `remote:` is configured as `{ pattern, onUnknown: "allow" }`. * The `onUnknown: "allow"` argument governs the case where * the walker resolved cwd but the inner exec couldn't * determine the remote URL — i.e. a known-cwd repo with no * `origin` remote configured (fresh-init, repo with * `upstream` but no `origin`, or other exec failure). In that * case the predicate skips and the engine falls through to * the generic `noMainCommit` (correct generic message). * The branch predicate stays at default `onUnknown: "block"` * (fail-closed) so protected-branch detection isn't weakened. * * Walker-unknown cwd: the `remote:` leaf surfaces trinary * `"unknown"` (via the inline walker-unknown-cwd guard at the top of * the handler) before the inner exec runs whenever * `walkerState.cwd === "unknown"`. The engine's leaf-level * `onUnknown:` policy reads the `"allow"` set on the leaf, projects * `"unknown" → false`, and the github rule SKIPS. The engine then * falls through to the generic {@link noMainCommit} (only `branch:` * leaf), which fires fail-CLOSED and emits the generic * protected-branch reason. The github-specific rule deliberately * does NOT fire under walker-unknown cwd — a github-flavored reason * would overstate what the engine has confirmed. * * Walker-unknown branch state: when `walkerState.cwd` is known but * the branch tracker collapses to its `"unknown"` sentinel (dynamic * checkout the walker couldn't resolve), the reason fn routes to a * "could not verify the current branch" message rather than * asserting a specific protected branch the engine hasn't * confirmed. * * Pattern is shared with `noMainCommit` via the exported * {@link GIT_COMMIT_PATTERN} constant so the two rules' bash- * command applicability stays byte-equal as the family evolves. * * @see {@link noMainCommit} */ export declare const noMainCommitGithub: { readonly name: "no-main-commit-github"; readonly tool: "bash"; readonly field: "command"; readonly pattern: "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b"; readonly when: { readonly branch: RegExp; readonly remote: { readonly pattern: RegExp; readonly onUnknown: "allow"; }; }; readonly reason: (ctx: import("../../schema.ts").PredicateContext) => string; readonly noOverride: false; }; /** * Suggested rules for the git plugin. * * **Order matters — first-match-wins.** The github-specific rule * (`no-main-commit-github`) is placed BEFORE the generic * (`no-main-commit`) so on github clones + on main, the github * rule's `remote:` predicate matches → fires first → user gets * PR-flow guidance. On non-github contexts (Brazil packages, vault * paths, scratch repos with non-github remotes) the github rule's * `remote:` predicate doesn't match → the engine falls through to * the generic `no-main-commit`. Reordering for stylistic reasons * breaks this routing; pinned via a unit test in `./rules.test.ts`. */ export declare const rules: readonly [{ readonly name: "no-main-commit-github"; readonly tool: "bash"; readonly field: "command"; readonly pattern: "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b"; readonly when: { readonly branch: RegExp; readonly remote: { readonly pattern: RegExp; readonly onUnknown: "allow"; }; }; readonly reason: (ctx: import("../../schema.ts").PredicateContext) => string; readonly noOverride: false; }, { readonly name: "no-main-commit"; readonly tool: "bash"; readonly field: "command"; readonly pattern: "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b"; readonly when: { readonly branch: RegExp; }; readonly reason: (ctx: import("../../schema.ts").PredicateContext) => string; readonly noOverride: false; }]; //# sourceMappingURL=rules.d.ts.map