Skip to content

Commit 2d02fcc

Browse files
authored
Merge pull request #39 from AxmeAI/feat/gate-cleanup-20260407
refactor: simplify gate hook, fix marker-in-message edge case
2 parents 58762bd + 4a0ee04 commit 2d02fcc

3 files changed

Lines changed: 290 additions & 59 deletions

File tree

src/hooks/pre-tool-use.ts

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -149,44 +149,13 @@ function handlePreToolUse(sessionOrigin: string, event: HookInput): void {
149149
const rules = loadRulesForBash();
150150
verdict = checkBash(rules, command);
151151
if (!verdict.allowed) break;
152-
// Track effective cwd through cd/pushd segments, then check each git
153-
// segment with the correct cwd. If cwd cannot be determined (variables,
154-
// subshells), block with instruction to use git -C.
155-
// If chain contains git checkout (branch switch), skip merged-PR check
156-
// because the hook runs BEFORE execution - current branch will change.
152+
// Split chained commands and check each git segment independently.
153+
// No cwd tracking needed - #!axme gate carries repo/PR explicitly.
157154
const segments = splitCommandSegments(command);
158-
const hasCheckout = segments.some(s => /^\s*git\s+(checkout|switch)\b/.test(s.trim()));
159-
let effectiveCwd = process.cwd();
160-
let cwdResolved = true;
161155
for (const seg of segments) {
162156
const trimmed = seg.trim();
163-
// Track cd/pushd
164-
const cdMatch = trimmed.match(/^(?:cd|pushd)\s+["']?([^\s"']+)["']?$/);
165-
if (cdMatch) {
166-
const target = cdMatch[1];
167-
if (target.includes("$") || target.includes("`")) {
168-
cwdResolved = false;
169-
} else {
170-
const { resolve: pathResolve } = require("node:path");
171-
const expanded = target.startsWith("~") ? target.replace("~", process.env.HOME || "") : target;
172-
effectiveCwd = pathResolve(effectiveCwd, expanded);
173-
}
174-
continue;
175-
}
176-
// Check git segments
177157
if (/^\s*git\b/.test(trimmed)) {
178-
// Parse git -C override
179-
const cFlagMatch = trimmed.match(/git\s+-C\s+["']?([^\s"']+)["']?/);
180-
let gitCwd = effectiveCwd;
181-
if (cFlagMatch) {
182-
const { resolve: pathResolve } = require("node:path");
183-
gitCwd = pathResolve(effectiveCwd, cFlagMatch[1]);
184-
} else if (!cwdResolved) {
185-
verdict = { allowed: false, reason: `Cannot determine target directory for git command. Use explicit path: git -C /absolute/path ${trimmed.replace(/^git\s+/, '')}` };
186-
break;
187-
}
188-
// Skip merged-PR check if chain includes checkout (branch will change)
189-
verdict = checkGit(rules, trimmed, gitCwd, hasCheckout);
158+
verdict = checkGit(rules, trimmed);
190159
if (!verdict.allowed) break;
191160
}
192161
}

src/storage/safety.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,11 @@ export function checkBash(rules: SafetyRules, command: string): SafetyVerdict {
329329
* Returns null if no #!axme marker found.
330330
*/
331331
export function parseAxmeGate(command: string): { pr: string; repo: string } | null {
332-
const match = command.match(/#!axme\s+(.*)/);
332+
// Use the LAST occurrence of #!axme (the suffix), not one inside a commit message.
333+
const lastIdx = command.lastIndexOf("#!axme");
334+
if (lastIdx === -1) return null;
335+
const suffix = command.slice(lastIdx);
336+
const match = suffix.match(/^#!axme\s+(.*)/);
333337
if (!match) return null;
334338
const pairs = match[1].trim();
335339
const prMatch = pairs.match(/\bpr=(\S+)/);
@@ -400,7 +404,7 @@ function checkAxmeGate(fullCommand: string): SafetyVerdict | null {
400404
* and the `+refspec` form (`git push origin +main`) are all recognized;
401405
* `-fixes` and similar substrings are not.
402406
*/
403-
export function checkGit(rules: SafetyRules, command: string, cwd?: string, skipMergedCheck?: boolean): SafetyVerdict {
407+
export function checkGit(rules: SafetyRules, command: string, _cwd?: string, skipMergedCheck?: boolean): SafetyVerdict {
404408
// Strip "git -C <path>" so startsWith checks work: "git -C foo commit" -> "git commit"
405409
const stripped = stripQuoted(command.trim()).replace(/^(git\s+)(?:-C\s+\S+\s+)+/, "$1");
406410
if (!rules.git.allowForcePush && stripped.startsWith("git push")) {

0 commit comments

Comments
 (0)