Why
The app keeps three independent fs.watch registries, and closing the window releases two of them.
mainWindow.on('closed') kills the session PTYs, tears down the subagent watchers, and — since the editable-Changes work — calls the Changes watcher registry's closeAll(). The watch-file map behind ViewerPanel (watch-file / unwatch-file, main.js) is not in that handler. Its watches are released only when a renderer explicitly calls unwatch-file, which is a path a closing window does not take.
Nothing observable breaks today: on quit the process exits and the OS reclaims the descriptors either way. It matters because the three registries now answer the same question three different ways, and the next person adding a watcher has no single place that tells them which shape is right.
What
Bring the watch-file map into the same teardown as the other two, or state in .ai/contexts/ipc-bridge.md why it deliberately stays out.
Worth deciding at the same time, since it is the reason there are three: whether one registry can serve all three callers, or whether their lifetimes genuinely differ (the Changes watcher is per session and per file, the subagent watcher follows a transcript, watch-file follows whatever the panel last opened).
Not in scope
- Any change to what the watchers do while they are armed.
- Migrating off
fs.watch. That is a separate question — fs.watch goes deaf after a rename-based replace, which the Changes registry works around by re-arming on the rename event; whether the app should use chokidar instead is its own decision with its own cost.
Acceptance
- Closing the window leaves no armed watch in any of the three registries, or the exception is documented with its reason.
.ai/contexts/ipc-bridge.md names the registries and says which handler releases each.
Why
The app keeps three independent
fs.watchregistries, and closing the window releases two of them.mainWindow.on('closed')kills the session PTYs, tears down the subagent watchers, and — since the editable-Changes work — calls the Changes watcher registry'scloseAll(). Thewatch-filemap behindViewerPanel(watch-file/unwatch-file,main.js) is not in that handler. Its watches are released only when a renderer explicitly callsunwatch-file, which is a path a closing window does not take.Nothing observable breaks today: on quit the process exits and the OS reclaims the descriptors either way. It matters because the three registries now answer the same question three different ways, and the next person adding a watcher has no single place that tells them which shape is right.
What
Bring the
watch-filemap into the same teardown as the other two, or state in.ai/contexts/ipc-bridge.mdwhy it deliberately stays out.Worth deciding at the same time, since it is the reason there are three: whether one registry can serve all three callers, or whether their lifetimes genuinely differ (the Changes watcher is per session and per file, the subagent watcher follows a transcript,
watch-filefollows whatever the panel last opened).Not in scope
fs.watch. That is a separate question —fs.watchgoes deaf after a rename-based replace, which the Changes registry works around by re-arming on therenameevent; whether the app should usechokidarinstead is its own decision with its own cost.Acceptance
.ai/contexts/ipc-bridge.mdnames the registries and says which handler releases each.