mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-18 12:17:26 +00:00
fix(skills): ignore Python venvs and caches in skills watcher (#12399)
* fix(skills): ignore Python venvs and caches in skills watcher Add .venv, venv, __pycache__, .mypy_cache, .pytest_cache, build, and .cache to the default ignored patterns for the skills watcher. This prevents file descriptor exhaustion when a skill contains a Python virtual environment with tens of thousands of files, which was causing EBADF spawn errors on macOS. Fixes #1056 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: add changelog entry for skills watcher ignores * docs: fill changelog PR number --------- Co-authored-by: Kyle Howells <freerunnering@gmail.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: CLAWDINATOR Bot <clawdinator[bot]@users.noreply.github.com>
This commit is contained in:
@@ -105,6 +105,8 @@ Docs: https://docs.openclaw.ai
|
||||
- Heartbeat: allow explicit accountId routing for multi-account channels. (#8702) Thanks @lsh411.
|
||||
- Routing: refresh bindings per message by loading config at route resolution so binding changes apply without restart. (#11372) Thanks @juanpablodlc.
|
||||
- TUI/Gateway: handle non-streaming finals, refresh history for non-local chat runs, and avoid event gap warnings for targeted tool streams. (#8432) Thanks @gumadeiras.
|
||||
- Security: stop exposing Gateway auth tokens via URL query parameters in Control UI entrypoints, and reject hook tokens in query parameters. (#9436) Thanks @coygeek.
|
||||
- Skills: ignore Python venvs and common cache/build folders in the skills watcher to prevent FD exhaustion. (#12399) Thanks @kylehowells.
|
||||
- Shell completion: auto-detect and migrate slow dynamic patterns to cached files for faster terminal startup; add completion health checks to doctor/update/onboard.
|
||||
- Telegram: honor session model overrides in inline model selection. (#8193) Thanks @gildo.
|
||||
- Web UI: fix agent model selection saves for default/non-default agents and wrap long workspace paths. Thanks @Takhoffman.
|
||||
|
||||
@@ -12,7 +12,7 @@ vi.mock("chokidar", () => {
|
||||
});
|
||||
|
||||
describe("ensureSkillsWatcher", () => {
|
||||
it("ignores node_modules, dist, and .git by default", async () => {
|
||||
it("ignores node_modules, dist, .git, and Python venvs by default", async () => {
|
||||
const mod = await import("./refresh.js");
|
||||
mod.ensureSkillsWatcher({ workspaceDir: "/tmp/workspace" });
|
||||
|
||||
@@ -21,11 +21,35 @@ describe("ensureSkillsWatcher", () => {
|
||||
|
||||
expect(opts.ignored).toBe(mod.DEFAULT_SKILLS_WATCH_IGNORED);
|
||||
const ignored = mod.DEFAULT_SKILLS_WATCH_IGNORED;
|
||||
|
||||
// Node/JS paths
|
||||
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);
|
||||
|
||||
// Python virtual environments and caches
|
||||
expect(ignored.some((re) => re.test("/tmp/workspace/skills/scripts/.venv/bin/python"))).toBe(
|
||||
true,
|
||||
);
|
||||
expect(ignored.some((re) => re.test("/tmp/workspace/skills/venv/lib/python3.10/site.py"))).toBe(
|
||||
true,
|
||||
);
|
||||
expect(ignored.some((re) => re.test("/tmp/workspace/skills/__pycache__/module.pyc"))).toBe(
|
||||
true,
|
||||
);
|
||||
expect(ignored.some((re) => re.test("/tmp/workspace/skills/.mypy_cache/3.10/foo.json"))).toBe(
|
||||
true,
|
||||
);
|
||||
expect(ignored.some((re) => re.test("/tmp/workspace/skills/.pytest_cache/v/cache"))).toBe(true);
|
||||
|
||||
// Build artifacts and caches
|
||||
expect(ignored.some((re) => re.test("/tmp/workspace/skills/build/output.js"))).toBe(true);
|
||||
expect(ignored.some((re) => re.test("/tmp/workspace/skills/.cache/data.json"))).toBe(true);
|
||||
|
||||
// Should NOT ignore normal skill files
|
||||
expect(ignored.some((re) => re.test("/tmp/.hidden/skills/index.md"))).toBe(false);
|
||||
expect(ignored.some((re) => re.test("/tmp/workspace/skills/my-skill/SKILL.md"))).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,6 +29,15 @@ export const DEFAULT_SKILLS_WATCH_IGNORED: RegExp[] = [
|
||||
/(^|[\\/])\.git([\\/]|$)/,
|
||||
/(^|[\\/])node_modules([\\/]|$)/,
|
||||
/(^|[\\/])dist([\\/]|$)/,
|
||||
// Python virtual environments and caches
|
||||
/(^|[\\/])\.venv([\\/]|$)/,
|
||||
/(^|[\\/])venv([\\/]|$)/,
|
||||
/(^|[\\/])__pycache__([\\/]|$)/,
|
||||
/(^|[\\/])\.mypy_cache([\\/]|$)/,
|
||||
/(^|[\\/])\.pytest_cache([\\/]|$)/,
|
||||
// Build artifacts and caches
|
||||
/(^|[\\/])build([\\/]|$)/,
|
||||
/(^|[\\/])\.cache([\\/]|$)/,
|
||||
];
|
||||
|
||||
function bumpVersion(current: number): number {
|
||||
|
||||
Reference in New Issue
Block a user