You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by as...@apache.org on 2026/09/13 09:13:44 UTC

(maka) branch fix/grep-completeness updated (baa6f2d856 -> 304b384b2e)

This is an automated email from the ASF dual-hosted git repository.

Astro-Han pushed a change to branch fix/grep-completeness
in repository https://gitbox.apache.org/repos/asf/maka.git


    from baa6f2d856 fix(cli): retain ACP prompts until Stop delivery settles
     new 0157546392 fix(runtime): surface invalidated glob traversal directories
     new 1840d5e4d7 fix(runtime): share ripgrep discovery with bypass searches
     new 304b384b2e ci: track shared ripgrep discovery in Windows checks

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .github/workflows/release-windows-check.yml        |  1 +
 .github/workflows/windows-recovery.yml             |  1 +
 docs/windows-test-inventory.md                     |  5 +-
 packages/runtime/src/__tests__/glob-search.test.ts | 59 ++++++++++++++++++
 .../src/__tests__/workspace-executor.test.ts       | 61 ++++++++++++++++++-
 .../runtime/src/filesystem-worker/launch-spec.ts   | 33 ++--------
 packages/runtime/src/glob-search.ts                | 24 +++++---
 packages/runtime/src/grep-search.ts                |  3 +-
 packages/runtime/src/ripgrep-executable.ts         | 70 ++++++++++++++++++++++
 packages/runtime/src/workspace-executor.ts         | 19 +++++-
 10 files changed, 234 insertions(+), 42 deletions(-)
 create mode 100644 packages/runtime/src/ripgrep-executable.ts


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


(maka) 02/03: fix(runtime): share ripgrep discovery with bypass searches

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

Astro-Han pushed a commit to branch fix/grep-completeness
in repository https://gitbox.apache.org/repos/asf/maka.git

commit 1840d5e4d79a79b2b43cb3f30d86ce78707d8cec
Author: AstroHan <le...@outlook.com>
AuthorDate: Sun Sep 13 17:05:18 2026 +0800

    fix(runtime): share ripgrep discovery with bypass searches
---
 docs/windows-test-inventory.md                     |  5 +-
 .../src/__tests__/workspace-executor.test.ts       | 61 ++++++++++++++++++-
 .../runtime/src/filesystem-worker/launch-spec.ts   | 33 ++--------
 packages/runtime/src/grep-search.ts                |  3 +-
 packages/runtime/src/ripgrep-executable.ts         | 70 ++++++++++++++++++++++
 packages/runtime/src/workspace-executor.ts         | 19 +++++-
 6 files changed, 156 insertions(+), 35 deletions(-)

diff --git a/docs/windows-test-inventory.md b/docs/windows-test-inventory.md
index 27b6625620..acaf8efc3a 100644
--- a/docs/windows-test-inventory.md
+++ b/docs/windows-test-inventory.md
@@ -16,10 +16,10 @@ Locations intentionally omit line numbers so unrelated edits do not invalidate t
 | Classification | Count |
 |---|---:|
 | windows-backend-gap | 27 |
-| portable-candidate | 31 |
+| portable-candidate | 32 |
 | platform-contract | 36 |
 
-Total Windows-excluded declarations: **94**
+Total Windows-excluded declarations: **95**
 
 ## Inventory
 
@@ -86,6 +86,7 @@ Total Windows-excluded declarations: **94**
 | platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` settles after root exit when a detached descendant retains inherited stdout | `process.platform === 'win32' ? 'POSIX detached process-group semantics required' : false` |
 | platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` keeps the first committed lifecycle cause across Stop and timeout races | `process.platform === 'win32' ? 'Windows tree termination has no graceful SIGTERM phase' : false` |
 | platform-contract | `packages/runtime/src/__tests__/shell-run-manager.test.ts` keeps SIGTERM final output and escalates an ignored SIGTERM without leaking slots | `process.platform === 'win32' ? 'Windows tree termination has no graceful SIGTERM phase' : false` |
+| portable-candidate | `packages/runtime/src/__tests__/workspace-executor.test.ts` a bypass Grep finds ripgrep installed after Host startup outside its inherited PATH | `process.platform === 'win32' ? 'POSIX executable fixture' : false` |
 | platform-contract | `packages/runtime/src/__tests__/workspace-executor.test.ts` leaves other spawn failures, such as a non-executable rg, untouched | `process.platform === 'win32' ? 'POSIX execute permissions' : false` |
 | portable-candidate | `packages/storage/src/__tests__/atomic-file-write.test.ts` removes its temp file and rethrows after a chmod failure | `process.platform === 'win32'` |
 | portable-candidate | `packages/storage/src/__tests__/atomic-file-write.test.ts` creates the target 0600 on POSIX | `process.platform === 'win32'` |
diff --git a/packages/runtime/src/__tests__/workspace-executor.test.ts b/packages/runtime/src/__tests__/workspace-executor.test.ts
index aea94a93f1..5b55ea7f5e 100644
--- a/packages/runtime/src/__tests__/workspace-executor.test.ts
+++ b/packages/runtime/src/__tests__/workspace-executor.test.ts
@@ -23,6 +23,7 @@ import { chmod, mkdir, mkdtemp, readFile, rm, truncate, writeFile } from 'node:f
 import { tmpdir } from 'node:os';
 import { join } from 'node:path';
 import { LocalWorkspaceExecutor } from '../workspace-executor.js';
+import { createBoundaryFilesystemExecutor } from '../filesystem-executor.js';
 
 const ONE_PIXEL_IMAGES = [
   [
@@ -280,7 +281,7 @@ describe('LocalWorkspaceExecutor file operations', () => {
   test('reports a missing ripgrep as grep_unavailable with an install hint (#5167)', async () => {
     const cwd = await mkdtemp(join(tmpdir(), 'maka-workspace-grep-no-rg-'));
     const emptyBin = await mkdtemp(join(tmpdir(), 'maka-workspace-grep-empty-path-'));
-    const executor = new LocalWorkspaceExecutor();
+    const executor = new LocalWorkspaceExecutor({ rgCandidates: [] });
 
     await withPath(emptyBin, () =>
       assert.rejects(
@@ -324,12 +325,66 @@ describe('LocalWorkspaceExecutor file operations', () => {
       }),
       (error: NodeJS.ErrnoException) => {
         assert.equal(error.code, 'ENOENT');
-        assert.doesNotMatch(error.message, /ripgrep/);
+        assert.notEqual(error.name, 'RipgrepUnavailableError');
         return true;
       },
     );
   });
 
+  test('a bypass Grep finds ripgrep installed after Host startup outside its inherited PATH', {
+    skip: process.platform === 'win32' ? 'POSIX executable fixture' : false,
+  }, async () => {
+    const cwd = await mkdtemp(join(tmpdir(), 'maka-workspace-bypass-grep-'));
+    const emptyBin = await mkdtemp(join(tmpdir(), 'maka-workspace-bypass-old-path-'));
+    const localAppData = await mkdtemp(join(tmpdir(), 'maka-workspace-bypass-local-app-data-'));
+    try {
+      const executable = join(localAppData, 'Microsoft', 'WinGet', 'Links', 'rg.exe');
+      const filesystem = createBoundaryFilesystemExecutor({
+        workspace: new LocalWorkspaceExecutor({
+          platform: 'win32',
+          hostEnv: { PATH: emptyBin, LOCALAPPDATA: localAppData },
+        }),
+      });
+      const request = {
+        operation: {
+          kind: 'grep' as const,
+          pattern: 'token',
+          path: cwd,
+          maxCountPerFile: 50,
+          limit: 200,
+          timeoutMs: 5_000,
+        },
+        cwd,
+        executionBoundary: { kind: 'bypass' as const, revision: 1 },
+      };
+
+      await withPath(emptyBin, async () => {
+        await assert.rejects(filesystem.execute(request), { code: 'grep_unavailable' });
+
+        await mkdir(join(localAppData, 'Microsoft', 'WinGet', 'Links'), { recursive: true });
+        await writeFile(
+          executable,
+          `#!/bin/sh\nprintf '%s\\n' '{"type":"summary","data":{"stats":{"matched_lines":0}}}'\n`,
+          'utf8',
+        );
+        await chmod(executable, 0o755);
+
+        assert.deepEqual(await filesystem.execute(request), {
+          kind: 'grep',
+          matches: [],
+          matchedLines: 0,
+          returnedLines: 0,
+          omittedLines: 0,
+          truncated: false,
+        });
+      });
+    } finally {
+      await Promise.all(
+        [cwd, emptyBin, localAppData].map((path) => rm(path, { recursive: true, force: true })),
+      );
+    }
+  });
+
   test('leaves other spawn failures, such as a non-executable rg, untouched', {
     skip: process.platform === 'win32' ? 'POSIX execute permissions' : false,
   }, async () => {
@@ -337,7 +392,7 @@ describe('LocalWorkspaceExecutor file operations', () => {
     const bin = await mkdtemp(join(tmpdir(), 'maka-workspace-grep-noexec-bin-'));
     await writeFile(join(bin, 'rg'), '#!/bin/sh\n', 'utf8');
     await chmod(join(bin, 'rg'), 0o644);
-    const executor = new LocalWorkspaceExecutor();
+    const executor = new LocalWorkspaceExecutor({ rgCandidates: [join(bin, 'rg')] });
 
     await withPath(bin, () =>
       assert.rejects(
diff --git a/packages/runtime/src/filesystem-worker/launch-spec.ts b/packages/runtime/src/filesystem-worker/launch-spec.ts
index ca5e5c10f6..107bb24a74 100644
--- a/packages/runtime/src/filesystem-worker/launch-spec.ts
+++ b/packages/runtime/src/filesystem-worker/launch-spec.ts
@@ -19,7 +19,7 @@
 
 import { constants } from 'node:fs';
 import { access, realpath } from 'node:fs/promises';
-import { delimiter, dirname, isAbsolute, join, resolve } from 'node:path';
+import { dirname, isAbsolute, resolve } from 'node:path';
 
 import {
   resolveFilesystemWorkerBundle,
@@ -34,6 +34,7 @@ import {
   formatRipgrepEnvironmentArg,
   type RipgrepEnvironment,
 } from '../ripgrep-guidance.js';
+import { defaultRipgrepCandidates, resolveRipgrepCandidates } from '../ripgrep-executable.js';
 
 export interface FilesystemWorkerLaunchSpec {
   program: string;
@@ -79,7 +80,7 @@ export function createFilesystemWorkerLaunchSpecProvider(
     if (!resolved.ok) return resolved;
     const grep =
       operation.kind === 'grep'
-        ? await resolveRipgrepExecutable(
+        ? await resolveWorkerRipgrep(
             input.rgCandidates ?? defaultRipgrepCandidates(input.hostEnv ?? process.env, platform),
             platform,
             input.inspectMacosExecutableDependencies ?? resolveMacosExecutableDependencies,
@@ -246,18 +247,14 @@ function composeLaunchSpec(
   };
 }
 
-async function resolveRipgrepExecutable(
+async function resolveWorkerRipgrep(
   candidates: readonly string[],
   platform: NodeJS.Platform,
   inspectMacosExecutableDependencies: (
     executable: string,
   ) => Promise<MacosExecutableDependencyResolution>,
 ): Promise<RipgrepResolution | undefined> {
-  const inspected = new Set<string>();
-  for (const candidate of candidates) {
-    const executable = await resolveExecutable(candidate);
-    if (!executable || inspected.has(executable)) continue;
-    inspected.add(executable);
+  for await (const executable of resolveRipgrepCandidates(candidates)) {
     if (platform !== 'darwin') {
       return { executable, runtimeReadableRoots: [], executableRoots: [] };
     }
@@ -290,26 +287,6 @@ async function resolveReadableRoot(candidate: string): Promise<string | undefine
   }
 }
 
-function defaultRipgrepCandidates(
-  env: NodeJS.ProcessEnv,
-  platform: NodeJS.Platform = process.platform,
-): readonly string[] {
-  const executableName = platform === 'win32' ? 'rg.exe' : 'rg';
-  return [
-    ...(env.PATH ?? '')
-      .split(delimiter)
-      .filter(Boolean)
-      .map((directory) => join(directory, executableName)),
-    ...(platform === 'win32' ? [] : ['/opt/homebrew/bin/rg', '/usr/local/bin/rg', '/usr/bin/rg']),
-    // winget links portable packages here and adds the directory to PATH for
-    // processes started afterwards; a running Host still has the old PATH, so
-    // look here too or "install, then retry" would not find the install.
-    ...(platform === 'win32' && env.LOCALAPPDATA
-      ? [join(env.LOCALAPPDATA, 'Microsoft', 'WinGet', 'Links', executableName)]
-      : []),
-  ];
-}
-
 async function resolveRuntimeDependencyRoots(program: string): Promise<readonly string[]> {
   const candidates = program.startsWith('/opt/homebrew/')
     ? ['/opt/homebrew/opt', '/opt/homebrew/Cellar']
diff --git a/packages/runtime/src/grep-search.ts b/packages/runtime/src/grep-search.ts
index 51854ab820..ef8e61f31b 100644
--- a/packages/runtime/src/grep-search.ts
+++ b/packages/runtime/src/grep-search.ts
@@ -149,7 +149,8 @@ export async function searchFiles(
 }
 
 async function runRipgrep(input: GrepRunInput): Promise<GrepRunResult> {
-  input.abortSignal?.throwIfAborted();
+  if (input.abortSignal?.aborted)
+    throw new GrepSearchError('Grep was cancelled; search totals are unknown.');
   return await new Promise((resolve, reject) => {
     const child = spawn(input.executable, [...input.args], {
       cwd: input.cwd,
diff --git a/packages/runtime/src/ripgrep-executable.ts b/packages/runtime/src/ripgrep-executable.ts
new file mode 100644
index 0000000000..b5fb778be8
--- /dev/null
+++ b/packages/runtime/src/ripgrep-executable.ts
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { constants } from 'node:fs';
+import { access, realpath } from 'node:fs/promises';
+import { delimiter, isAbsolute, join } from 'node:path';
+
+export function defaultRipgrepCandidates(
+  env: NodeJS.ProcessEnv,
+  platform: NodeJS.Platform = process.platform,
+): readonly string[] {
+  const executableName = platform === 'win32' ? 'rg.exe' : 'rg';
+  return [
+    ...(env.PATH ?? '')
+      .split(delimiter)
+      .filter(Boolean)
+      .map((directory) => join(directory, executableName)),
+    ...(platform === 'win32' ? [] : ['/opt/homebrew/bin/rg', '/usr/local/bin/rg', '/usr/bin/rg']),
+    // winget adds this directory to PATH only for processes started after the
+    // install. A running Host must probe it explicitly for install-and-retry.
+    ...(platform === 'win32' && env.LOCALAPPDATA
+      ? [join(env.LOCALAPPDATA, 'Microsoft', 'WinGet', 'Links', executableName)]
+      : []),
+  ];
+}
+
+export async function* resolveRipgrepCandidates(
+  candidates: readonly string[],
+): AsyncGenerator<string> {
+  const resolved = new Set<string>();
+  for (const candidate of candidates) {
+    const executable = await resolveExecutable(candidate);
+    if (!executable || resolved.has(executable)) continue;
+    resolved.add(executable);
+    yield executable;
+  }
+}
+
+export async function resolveRipgrepExecutable(
+  candidates: readonly string[],
+): Promise<string | undefined> {
+  for await (const executable of resolveRipgrepCandidates(candidates)) return executable;
+  return undefined;
+}
+
+async function resolveExecutable(candidate: string): Promise<string | undefined> {
+  if (!candidate || !isAbsolute(candidate)) return undefined;
+  try {
+    await access(candidate, constants.X_OK);
+    return await realpath(candidate);
+  } catch {
+    return undefined;
+  }
+}
diff --git a/packages/runtime/src/workspace-executor.ts b/packages/runtime/src/workspace-executor.ts
index 65369a6d28..d431b7f2dd 100644
--- a/packages/runtime/src/workspace-executor.ts
+++ b/packages/runtime/src/workspace-executor.ts
@@ -47,6 +47,7 @@ import { isSupportedImagePath, readWorkspaceImage } from './image-file.js';
 import type { ImageMimeType } from './image-file.js';
 import { readTextLineWindow } from './text-line-window.js';
 import { searchFiles, type GrepResult } from './grep-search.js';
+import { defaultRipgrepCandidates, resolveRipgrepExecutable } from './ripgrep-executable.js';
 
 const execAsync = promisify(exec);
 
@@ -296,9 +297,18 @@ export interface WorkspaceExecutor
     Partial<WorkspaceApplyPatchExecutor>,
     Partial<WorkspaceReadModifyWriteExecutor> {}
 
+/** @internal Test seams for deterministic executable-discovery coverage. */
+export interface LocalWorkspaceExecutorInput {
+  platform?: NodeJS.Platform;
+  hostEnv?: NodeJS.ProcessEnv;
+  rgCandidates?: readonly string[];
+}
+
 export class LocalWorkspaceExecutor implements WorkspaceExecutor {
   readonly facts = LOCAL_WORKSPACE_EXECUTOR_FACTS;
 
+  constructor(private readonly input: LocalWorkspaceExecutorInput = {}) {}
+
   async exec(input: WorkspaceExecInput): Promise<WorkspaceExecResult> {
     const options = {
       cwd: input.cwd,
@@ -440,8 +450,15 @@ export class LocalWorkspaceExecutor implements WorkspaceExecutor {
   }
 
   async grepFiles(input: WorkspaceGrepInput): Promise<WorkspaceGrepResult> {
+    const executable = await resolveRipgrepExecutable(
+      this.input.rgCandidates ??
+        defaultRipgrepCandidates(
+          this.input.hostEnv ?? process.env,
+          this.input.platform ?? process.platform,
+        ),
+    );
     try {
-      return await searchFiles({ ...input, executable: 'rg' });
+      return await searchFiles({ ...input, executable: executable ?? 'rg' });
     } catch (error: any) {
       // Node reports a missing spawn cwd exactly like a missing executable
       // (both `spawn rg ENOENT`), so only blame ripgrep once the cwd exists.


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


(maka) 01/03: fix(runtime): surface invalidated glob traversal directories

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

Astro-Han pushed a commit to branch fix/grep-completeness
in repository https://gitbox.apache.org/repos/asf/maka.git

commit 01575463928881092e59b385a8e519a1cb016cb9
Author: AstroHan <le...@outlook.com>
AuthorDate: Sun Sep 13 17:03:20 2026 +0800

    fix(runtime): surface invalidated glob traversal directories
---
 packages/runtime/src/__tests__/glob-search.test.ts | 59 ++++++++++++++++++++++
 packages/runtime/src/glob-search.ts                | 24 ++++++---
 2 files changed, 76 insertions(+), 7 deletions(-)

diff --git a/packages/runtime/src/__tests__/glob-search.test.ts b/packages/runtime/src/__tests__/glob-search.test.ts
index f4549b0199..f2c635e397 100644
--- a/packages/runtime/src/__tests__/glob-search.test.ts
+++ b/packages/runtime/src/__tests__/glob-search.test.ts
@@ -18,6 +18,8 @@
  */
 
 import assert from 'node:assert/strict';
+import nodeFs from 'node:fs';
+import { syncBuiltinESMExports } from 'node:module';
 import {
   chmod,
   glob,
@@ -25,6 +27,7 @@ import {
   mkdtemp,
   readdir,
   realpath,
+  rename,
   rm,
   symlink,
   writeFile,
@@ -36,6 +39,61 @@ import { executeFilesystemOperation } from '../filesystem-worker/operations.js';
 import { globFiles } from '../glob-search.js';
 import { LocalWorkspaceExecutor } from '../workspace-executor.js';
 
+test('Glob reports a resolved cwd disappearing before traversal', async (t) => {
+  const root = await mkdtemp(join(tmpdir(), 'maka-glob-disappeared-'));
+  t.after(() => rm(root, { recursive: true, force: true }));
+  const cwd = join(root, 'cwd');
+  await mkdir(cwd);
+  const local = new LocalWorkspaceExecutor();
+  const resolved = await local.resolveExistingPath({
+    cwd,
+    path: '.',
+    label: 'Glob cwd',
+    scope: 'workspace',
+  });
+  await rename(cwd, join(root, 'moved'));
+  await assert.rejects(local.globFiles({ cwd: resolved.path, pattern: '**/*' }), {
+    code: 'ENOENT',
+  });
+});
+
+test('Glob reports an enumerated directory disappearing or changing type during traversal', async (t) => {
+  const root = await realpath(await mkdtemp(join(tmpdir(), 'maka-glob-race-')));
+  t.after(() => rm(root, { recursive: true, force: true }));
+  const originalReaddir = nodeFs.readdir;
+  for (const replaceWithFile of [false, true]) {
+    const cwd = join(root, replaceWithFile ? 'replaced' : 'disappeared');
+    const queued = join(cwd, 'queued');
+    await mkdir(queued, { recursive: true });
+    await writeFile(join(queued, 'hidden.txt'), 'hidden');
+    let changed = false;
+    t.mock.method(nodeFs, 'readdir', ((
+      path: string,
+      options: { withFileTypes: true },
+      callback: (error: NodeJS.ErrnoException | null, entries: nodeFs.Dirent[]) => void,
+    ) => {
+      originalReaddir(path, options, (error, entries) => {
+        if (String(path) === cwd && !error && !changed) {
+          changed = true;
+          nodeFs.renameSync(queued, join(root, `moved-${replaceWithFile}`));
+          if (replaceWithFile) nodeFs.writeFileSync(queued, 'now a file');
+        }
+        callback(error, entries);
+      });
+    }) as typeof nodeFs.readdir);
+    syncBuiltinESMExports();
+    try {
+      await assert.rejects(globFiles({ cwd, pattern: '**/*.txt' }), {
+        code: replaceWithFile ? 'ENOTDIR' : 'ENOENT',
+      });
+      assert.equal(changed, true);
+    } finally {
+      t.mock.restoreAll();
+      syncBuiltinESMExports();
+    }
+  }
+});
+
 test('both Glob paths report permission failures and recover after permissions are restored', {
   skip: process.platform === 'win32' || process.getuid?.() === 0,
 }, async (t) => {
@@ -99,6 +157,7 @@ test('Glob retains native pattern membership, including hidden entries and expli
     'src/@(a|b).*',
     'src/.*',
     'missing/*.ts',
+    'src/a.ts/*.ts',
     'src',
     '**',
   ];
diff --git a/packages/runtime/src/glob-search.ts b/packages/runtime/src/glob-search.ts
index 20fdeb8b17..f4cc832019 100644
--- a/packages/runtime/src/glob-search.ts
+++ b/packages/runtime/src/glob-search.ts
@@ -18,6 +18,7 @@
  */
 
 import { promises as fs, readdir } from 'node:fs';
+import { resolve } from 'node:path';
 import { globIterate } from 'glob';
 
 export async function globFiles(input: {
@@ -26,10 +27,13 @@ export async function globFiles(input: {
   limit?: number;
 }): Promise<{ files: string[] }> {
   let failure: NodeJS.ErrnoException | undefined;
-  function record(error: NodeJS.ErrnoException): void {
-    // Missing literal matches and non-directory pattern components are normal.
-    // glob otherwise suppresses I/O failures too, which would hide incomplete walks.
-    if (error.code !== 'ENOENT' && error.code !== 'ENOTDIR') failure ??= error;
+  const directories = new Set([resolve(input.cwd)]);
+  function record(error: NodeJS.ErrnoException, path: string): void {
+    // Speculative literal components may miss. A directory already admitted by
+    // cwd, stat, or enumeration disappearing instead makes this walk incomplete.
+    if (directories.has(resolve(path)) || (error.code !== 'ENOENT' && error.code !== 'ENOTDIR')) {
+      failure ??= error;
+    }
   }
   const files: string[] = [];
   for await (const file of globIterate(input.pattern, {
@@ -38,16 +42,22 @@ export async function globFiles(input: {
     fs: {
       readdir(path, options, callback) {
         readdir(path, options, (error, entries) => {
-          if (error) record(error);
+          if (error) record(error, path as string);
+          else
+            for (const entry of entries) {
+              if (entry.isDirectory()) directories.add(resolve(path as string, entry.name));
+            }
           callback(error, entries);
         });
       },
       promises: {
         async lstat(path) {
           try {
-            return await fs.lstat(path);
+            const stat = await fs.lstat(path);
+            if (stat.isDirectory()) directories.add(resolve(path as string));
+            return stat;
           } catch (error) {
-            record(error as NodeJS.ErrnoException);
+            record(error as NodeJS.ErrnoException, path as string);
             throw error;
           }
         },


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org


(maka) 03/03: ci: track shared ripgrep discovery in Windows checks

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

Astro-Han pushed a commit to branch fix/grep-completeness
in repository https://gitbox.apache.org/repos/asf/maka.git

commit 304b384b2ee869f0440ffbf2a8cef7f77b867346
Author: AstroHan <le...@outlook.com>
AuthorDate: Sun Sep 13 17:06:51 2026 +0800

    ci: track shared ripgrep discovery in Windows checks
---
 .github/workflows/release-windows-check.yml | 1 +
 .github/workflows/windows-recovery.yml      | 1 +
 2 files changed, 2 insertions(+)

diff --git a/.github/workflows/release-windows-check.yml b/.github/workflows/release-windows-check.yml
index a7d5757363..8121eea41d 100644
--- a/.github/workflows/release-windows-check.yml
+++ b/.github/workflows/release-windows-check.yml
@@ -74,6 +74,7 @@ on:
       - 'packages/runtime/src/sandbox/**'
       - 'packages/runtime/src/path-containment.ts'
       - 'packages/runtime/src/ripgrep-guidance.ts'
+      - 'packages/runtime/src/ripgrep-executable.ts'
       - 'packages/runtime/src/grep-search.ts'
       - 'packages/runtime/src/glob-search.ts'
       - 'packages/runtime/src/sandbox-boundary-path.ts'
diff --git a/.github/workflows/windows-recovery.yml b/.github/workflows/windows-recovery.yml
index ba123522e1..27f19c0677 100644
--- a/.github/workflows/windows-recovery.yml
+++ b/.github/workflows/windows-recovery.yml
@@ -105,6 +105,7 @@ on:
       - 'packages/runtime/src/process-tree-terminator.ts'
       - 'packages/runtime/src/pty-process-driver.ts'
       - 'packages/runtime/src/ripgrep-guidance.ts'
+      - 'packages/runtime/src/ripgrep-executable.ts'
       - 'packages/runtime/src/sandbox-boundary-declaration.ts'
       - 'packages/runtime/src/sandbox/default-sandbox-manager.ts'
       - 'packages/runtime/src/sandbox/sandbox-manager.ts'


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org