Summary
useSlashCommandProcessor adds and removes its IDE status listener through separate async calls to IdeClient.getInstance(). If the hook unmounts before the instance resolves, cleanup can run before registration and the listener can remain attached.
Evidence
In packages/cli/src/ui/hooks/slashCommandProcessor.ts, the effect adds the listener inside an async IIFE and removes it in another async IIFE from the cleanup function. There is no shared resolved-client state or cancellation guard tying the registration and cleanup together.
Impact
This can leak IDE status listeners and trigger redundant reloadCommands() calls after the hook has unmounted or reinitialized, especially in flows where command processors are recreated.
Expected behavior
Listener registration and removal should be coordinated by the effect so that cleanup always removes the exact listener that was successfully attached, and no listener is added after unmount.
Suggested fix
Track the resolved IdeClient instance inside the effect and gate registration on a local cancelled flag, similar to other async React subscription patterns.
Summary
useSlashCommandProcessoradds and removes its IDE status listener through separate async calls toIdeClient.getInstance(). If the hook unmounts before the instance resolves, cleanup can run before registration and the listener can remain attached.Evidence
In
packages/cli/src/ui/hooks/slashCommandProcessor.ts, the effect adds the listener inside an async IIFE and removes it in another async IIFE from the cleanup function. There is no shared resolved-client state or cancellation guard tying the registration and cleanup together.Impact
This can leak IDE status listeners and trigger redundant
reloadCommands()calls after the hook has unmounted or reinitialized, especially in flows where command processors are recreated.Expected behavior
Listener registration and removal should be coordinated by the effect so that cleanup always removes the exact listener that was successfully attached, and no listener is added after unmount.
Suggested fix
Track the resolved
IdeClientinstance inside the effect and gate registration on a local cancelled flag, similar to other async React subscription patterns.