diff --git a/src/agents/skills/refresh.test.ts b/src/agents/skills/refresh.test.ts new file mode 100644 index 000000000..b4091ed76 --- /dev/null +++ b/src/agents/skills/refresh.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it, vi } from "vitest"; + +const watchMock = vi.fn(() => ({ + on: vi.fn(), + close: vi.fn(async () => undefined), +})); + +vi.mock("chokidar", () => { + return { + default: { watch: watchMock }, + }; +}); + +describe("ensureSkillsWatcher", () => { + it("ignores node_modules and dist by default", async () => { + const mod = await import("./refresh.js"); + mod.ensureSkillsWatcher({ workspaceDir: "/tmp/workspace" }); + + expect(watchMock).toHaveBeenCalledTimes(1); + const opts = watchMock.mock.calls[0]?.[1] as { ignored?: unknown }; + + expect(Array.isArray(opts.ignored)).toBe(true); + const ignored = opts.ignored as RegExp[]; + expect(ignored.some((re) => re.test("/tmp/workspace/skills/node_modules/pkg/index.js"))).toBe( + true, + ); + expect(ignored.some((re) => re.test("/tmp/workspace/skills/dist/index.js"))).toBe(true); + expect(ignored.some((re) => re.test("/tmp/workspace/skills/.git/config"))).toBe(true); + }); +}); diff --git a/src/agents/skills/refresh.ts b/src/agents/skills/refresh.ts index f22690b7d..12e0b5f5f 100644 --- a/src/agents/skills/refresh.ts +++ b/src/agents/skills/refresh.ts @@ -125,6 +125,13 @@ export function ensureSkillsWatcher(params: { workspaceDir: string; config?: Cla stabilityThreshold: debounceMs, pollInterval: 100, }, + // Avoid FD exhaustion on macOS when a workspace contains huge trees. + // This watcher only needs to react to skill changes. + ignored: [ + /(^|[\\/])\../, // dotfiles (includes .git) + /(^|[\\/])node_modules([\\/]|$)/, + /(^|[\\/])dist([\\/]|$)/, + ], }); const state: SkillsWatchState = { watcher, pathsKey, debounceMs };