diff --git a/packages/cli/src/ui/utils/policyUtils.test.ts b/packages/cli/src/ui/utils/policyUtils.test.ts index 0c24174a66..816fa4fcd6 100644 --- a/packages/cli/src/ui/utils/policyUtils.test.ts +++ b/packages/cli/src/ui/utils/policyUtils.test.ts @@ -19,6 +19,12 @@ describe('formatArgsPattern', () => { expect(formatArgsPattern(pattern)).toBe('git diff*'); }); + it('should parse commandPrefix with escaped quotes (git show)', () => { + // buildArgsPatterns uses escapeRegex() which escapes quotes to \" + const pattern = new RegExp('\\"command\\":\\"git\\ show(?:[\\s"]|\\\\")'); + expect(formatArgsPattern(pattern)).toBe('git show*'); + }); + it('should parse commandPrefix with special chars (npm run test:ci)', () => { // escapeRegex escapes the colon const pattern = new RegExp( @@ -37,6 +43,11 @@ describe('formatArgsPattern', () => { expect(formatArgsPattern(pattern)).toBe('npm run .*'); }); + it('should parse commandRegex with escaped quotes', () => { + const pattern = new RegExp('\\"command\\":\\"npm run .*'); + expect(formatArgsPattern(pattern)).toBe('npm run .*'); + }); + it('should parse file_path pattern', () => { const pattern = new RegExp('"file_path":".*\\/plans\\/.*"'); expect(formatArgsPattern(pattern)).toBe('path: .*\\/plans\\/.*'); diff --git a/packages/cli/src/ui/utils/policyUtils.ts b/packages/cli/src/ui/utils/policyUtils.ts index 3f60812117..33da5c108f 100644 --- a/packages/cli/src/ui/utils/policyUtils.ts +++ b/packages/cli/src/ui/utils/policyUtils.ts @@ -65,16 +65,23 @@ export function formatArgsPattern( const source = argsPattern.source; - // 1. commandPrefix: "command":"(?:[\s"]|\\")" + // buildArgsPatterns uses escapeRegex() which escapes quotes to \", so the + // regex source contains escaped quotes. We support both escaped (\") and + // unescaped (") formats for robustness. + const cmdPrefix = /^\\?"command\\?":\\?"(.+?)\(\?:\[\\s"]\|\\\\"?\)$/; + + // 1. commandPrefix: \"command\":\"(?:[\s"]|\\")" // The lookahead ensures the prefix is word-bounded in JSON. - const prefixMatch = source.match(/^"command":"(.+?)\(\?:\[\\s"\]\|\\\\"?\)$/); + const prefixMatch = source.match(cmdPrefix); if (prefixMatch) { return unescapeRegex(prefixMatch[1]) + '*'; } - // 2. commandRegex: starts with "command":" - if (source.startsWith('"command":"')) { - const regex = source.slice('"command":"'.length); + // 2. commandRegex: starts with "command":" or \"command\":\" + const cmdRegexPrefix = /^\\?"command\\?":\\?"/; + const cmdRegexMatch = source.match(cmdRegexPrefix); + if (cmdRegexMatch) { + const regex = source.slice(cmdRegexMatch[0].length); return regex; }