Skip to content

fix(skill-registry): attach error handler to recursive skill watchers - #963

Open
jvan0 wants to merge 1 commit into
Gentleman-Programming:mainfrom
jvan0:fix/skill-registry-watcher-error-handler
Open

jvan0 wants to merge 1 commit into
Gentleman-Programming:mainfrom
jvan0:fix/skill-registry-watcher-error-handler

Conversation

@jvan0

@jvan0 jvan0 commented Sep 13, 2026

Copy link
Copy Markdown

Closes #962

PR Type

  • Bug fix

Summary

  • Attaches an 'error' listener to every recursive skill-registry FSWatcher so Node cannot rethrow an unhandled 'error' as an uncaughtException and kill Pi.
  • Reproduces the crash deterministically: emitting an 'error' on the recursive watchers with zero listeners kills the process; with the listener attached the process survives.
  • Exposes the active watchers under __testing.activeWatchers() and adds a regression test that asserts each watcher carries an error listener.

Changes

File Change
extensions/skill-registry.ts Attach watcher.on("error", ...) when starting skill-registry watchers; expose __testing.activeWatchers()
tests/skill-registry.test.ts Add regression test: watchers survive an 'error' event instead of crashing the process

Test Plan

  • node --experimental-strip-types --test tests/*.test.ts — 2325 pass, 0 fail
  • node scripts/check-provider-contract.mjs — pass
  • node --experimental-strip-types tests/runtime-harness.mjs — pass (exit 0)
  • node scripts/build-runtime-modules.mjs --check — runtime modules match TypeScript sources
  • Live smoke test: Pi TUI ran while a mutator removed and recreated a watched skill subdirectory 600 times; Pi survived (no uncaughtException)
  • No shell scripts modified (shellcheck not applicable)

Contributor Checklist

Summary by CodeRabbit

  • Bug Fixes

    • File-watching operations now handle missing-file errors without causing the application to crash.
    • Watchers are properly closed after error conditions.
  • Tests

    • Added regression coverage for watcher error handling and cleanup.

Node's recursive fs.watch can emit 'error' (e.g. ENOENT scandir) when a
watched subdirectory is removed mid-rescan. An 'error' event with no
listener is rethrown by EventEmitter as an uncaughtException that kills
the whole Pi process (observed: 'pi exiting due to uncaughtException:
Error: ENOENT: no such file or directory, scandir
~/.agents/skills/<skill>/storage').

Attach a best-effort error listener per watcher and expose the active
watchers under __testing so the regression test can assert the listener
exists and that emitting 'error' no longer crashes the process.
@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 12428fb1-b63b-46b1-aac9-6f1b4267e548

📥 Commits

Reviewing files that changed from the base of the PR and between 8ec0f98 and d423cd9.

📒 Files selected for processing (2)
  • extensions/skill-registry.ts
  • tests/skill-registry.test.ts

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

Changes

Skill registry watcher handling

Layer / File(s) Summary
Watcher error handling and regression coverage
extensions/skill-registry.ts, tests/skill-registry.test.ts
Recursive skill-directory watchers now attach error listeners. The testing export provides activeWatchers(). Regression coverage emits ENOENT errors and verifies that all watchers close successfully.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: alan-thegentleman

Merge Risk: ⚪ Minimal · up to d423c

Watcher errors are handled without terminating the application, and the regression test covers listener attachment, emitted errors, and cleanup. The change is ready to merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding an error handler to recursive skill-registry watchers.
Linked Issues check ✅ Passed The change satisfies issue #962. startSkillRegistryWatcher attaches an error listener to every recursive FSWatcher, so emitted watcher errors do not become uncaught process exceptions. The watch…
Out of Scope Changes check ✅ Passed All changes support issue #962. The __testing.activeWatchers() accessor enables direct regression coverage of watcher error handling. The added test verifies the required behavior and cleanup. No un…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(skill-registry): recursive skill watcher crashes Pi with uncaughtException ENOENT when a watched skill subdirectory is removed

1 participant