@@ -329,7 +329,22 @@ export function checkBash(rules: SafetyRules, command: string): SafetyVerdict {
329329 * sees the full command before execution and parses the metadata.
330330 *
331331 * Returns null if no #!axme marker found.
332+ *
333+ * Value capture: `[^\s"'` + "`" + `]+` rather than `\S+`, so a stray
334+ * closing quote/backtick from a surrounding `-m "..."` string doesn't
335+ * get glued onto the captured value (B-008). Trailing punctuation
336+ * (`)`, `,`, `;`, `.`) is stripped defensively for the same reason —
337+ * common when the marker ends up inside a HEREDOC or after a `$(...)`.
332338 */
339+ const GATE_VALUE = / [ ^ \s " ' ` ] + / . source ;
340+ const PR_RE = new RegExp ( `\\bpr=(${ GATE_VALUE } )` ) ;
341+ const REPO_RE = new RegExp ( `\\brepo=(${ GATE_VALUE } )` ) ;
342+ const TRAILING_PUNCT_RE = / [ ) \] , ; . ] + $ / ;
343+
344+ function cleanGateValue ( raw : string ) : string {
345+ return raw . replace ( TRAILING_PUNCT_RE , "" ) ;
346+ }
347+
333348export function parseAxmeGate ( command : string ) : { pr : string ; repo : string } | null {
334349 // Use the LAST occurrence of #!axme (the suffix), not one inside a commit message.
335350 const lastIdx = command . lastIndexOf ( "#!axme" ) ;
@@ -338,16 +353,21 @@ export function parseAxmeGate(command: string): { pr: string; repo: string } | n
338353 const match = suffix . match ( / ^ # ! a x m e \s + ( .* ) / ) ;
339354 if ( ! match ) return null ;
340355 const pairs = match [ 1 ] . trim ( ) ;
341- const prMatch = pairs . match ( / \b p r = ( \S + ) / ) ;
342- const repoMatch = pairs . match ( / \b r e p o = ( \S + ) / ) ;
356+ const prMatch = pairs . match ( PR_RE ) ;
357+ const repoMatch = pairs . match ( REPO_RE ) ;
343358 if ( ! prMatch || ! repoMatch ) return null ;
344- return { pr : prMatch [ 1 ] , repo : repoMatch [ 1 ] } ;
359+ const pr = cleanGateValue ( prMatch [ 1 ] ) ;
360+ const repo = cleanGateValue ( repoMatch [ 1 ] ) ;
361+ if ( ! pr || ! repo ) return null ;
362+ return { pr, repo } ;
345363}
346364
347365const AXME_GATE_INSTRUCTION =
348366 'BLOCKED: git commit/push requires #!axme safety metadata. ' +
349367 'Retry with: `<your command> #!axme pr=<PR_NUMBER|none> repo=<OWNER/REPO>` ' +
350- '(pr=none if no PR created yet).' ;
368+ '(pr=none if no PR created yet). ' +
369+ 'Place the marker AFTER the closing `"` of any `-m "..."` argument, ' +
370+ 'not inside it — otherwise the closing quote gets parsed as part of the repo name.' ;
351371
352372/**
353373 * Check if a PR is merged via gh CLI. Returns true if merged, false otherwise.
0 commit comments