From 6209c2999d393755eb22bed187df31376c174226 Mon Sep 17 00:00:00 2001 From: Udaya Tejas Date: Mon, 24 Aug 2026 13:18:56 -0500 Subject: [PATCH] fix(runtime): end Grep options before the pattern in the sandboxed worker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The filesystem worker appended the model-supplied Grep pattern as a bare positional, so ripgrep parsed a pattern beginning with `-` as flags. An option-like pattern such as `-webkit-box` exits 1, which this worker reports as `{ kind: 'grep', matches: [] }` — the model is told the string is absent from a file that contains it, with no error anywhere. The host-local sibling already passes `--` first (packages/runtime/src/workspace-executor.ts). That separator was added by its argv unchanged, so the two search paths have disagreed since. The worker is the default path on macOS and Linux for every boundary except bypass and external. Signed-off-by: Udaya Tejas Generated-by: Claude Code --- .../src/__tests__/filesystem-worker.test.ts | 34 +++++++++++++++++++ .../src/filesystem-worker/operations.ts | 2 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/__tests__/filesystem-worker.test.ts b/packages/runtime/src/__tests__/filesystem-worker.test.ts index d056b7a76d..f337e02bf9 100644 --- a/packages/runtime/src/__tests__/filesystem-worker.test.ts +++ b/packages/runtime/src/__tests__/filesystem-worker.test.ts @@ -243,6 +243,40 @@ describe('filesystem worker operations', () => { }); }); + test('ends Grep options before the pattern so an option-like pattern still searches', async () => { + const root = await temporaryDirectory('maka-worker-grep-separator-'); + const target = join(root, 'style.css'); + await writeFile(target, 'a { display: -webkit-box; }', 'utf8'); + let grepArgs: readonly string[] | undefined; + + const response = await executeFilesystemWorkerRequest( + await requestFor( + { + kind: 'grep', + cwd: root, + path: target, + pattern: '-webkit-box', + maxCountPerFile: 50, + limit: 200, + timeoutMs: 1_000, + }, + { enforcementPath: target, access: 'read', scope: 'exact', targetType: 'file' }, + ), + { + grepExecutable: '/usr/bin/rg', + runGrep: async (input) => { + grepArgs = input.args; + return { exitCode: 0, stdout: '1:a { display: -webkit-box; }\n', stderrTail: '' }; + }, + }, + ); + + // Without the separator ripgrep reads `-webkit-box` as flags: it exits 1, + // which this worker reports as "no matches" for a string that is present. + assert.deepEqual(grepArgs?.slice(-3), ['--', '-webkit-box', target]); + assert.equal(response.ok, true); + }); + test('returns no Grep matches for exit code 1 and surfaces bounded stderr for failures', async () => { const root = await temporaryDirectory('maka-worker-grep-result-'); const target = join(root, 'file.ts'); diff --git a/packages/runtime/src/filesystem-worker/operations.ts b/packages/runtime/src/filesystem-worker/operations.ts index 1c9475c78f..40f956aeeb 100644 --- a/packages/runtime/src/filesystem-worker/operations.ts +++ b/packages/runtime/src/filesystem-worker/operations.ts @@ -413,7 +413,7 @@ export async function executeFilesystemOperation( throw operationError('grep_unavailable', 'Grep is unavailable in this runtime.'); const args = ['-n', '--no-heading', `--max-count=${operation.maxCountPerFile}`]; if (operation.glob) args.push('--glob', operation.glob); - args.push(operation.pattern, path); + args.push('--', operation.pattern, path); const result = await (dependencies.runGrep ?? runRipgrep)({ executable: dependencies.grepExecutable, args,