fix(hooks): add timeout and bypass PowerShell for Cursor hooks on Windows - #225
Open
ralf0131 wants to merge 1 commit into
Open
fix(hooks): add timeout and bypass PowerShell for Cursor hooks on Windows#225ralf0131 wants to merge 1 commit into
ralf0131 wants to merge 1 commit into
Conversation
…dows (#197) - Add timeout: 30 to cursor hook config in agents.d/cursor.json - Add timeout field to AgentHookConfig and HookDefinition types - Implement wrapCursorWin32Command() to invoke node directly via cmd.exe - Add resolveWindowsNodeBin() for node binary resolution on Windows - Add legacyCursorHookCommands() for automatic migration from PowerShell path - Update hook-strategy.ts to route cursor through direct node invocation - Update hook-manager.ts to handle timeout reconciliation and Windows command wrapping - All 43 hook-strategy tests pass
There was a problem hiding this comment.
Pull request overview
This PR addresses Windows Cursor hook timeouts by ensuring hook entries declare an explicit timeout and by reducing hook startup latency on Windows through direct Node invocation (bypassing PowerShell cold start), fitting into the project’s hook-based agent deployment and lifecycle management.
Changes:
- Add an optional per-hook
timeoutfield to deployment hook configs and propagate it into installedhooks.jsonentries (including upgrade-in-place repair). - Introduce Windows Cursor-specific command wrapping to invoke
cursor-hook-processor.mjsviacmd.exe+nodedirectly, and migrate legacy commands. - Update Cursor agent definition to include a default
timeout: 30.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| agents.d/cursor.json | Adds timeout: 30 to Cursor hook configuration. |
| src/types/deployment.ts | Extends hook config typing with optional timeout. |
| src/hooks/hook-manager.ts | Implements timeout reconciliation and Windows Cursor command generation/migration helpers. |
| src/deployment/hook-strategy.ts | Threads timeout into hook definitions and migrates legacy Cursor commands on Windows. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
487
to
527
| @@ -443,6 +521,8 @@ export class HookManager { | |||
| settingsPath, | |||
| hookJsonPath: ['hooks', event], | |||
| hookCommand: command, | |||
| ...(replaceHookCommands ? { replaceHookCommands } : {}), | |||
| timeout: 30, | |||
| historyDir: path.join(baseDir, 'logs', 'cursor', 'history'), | |||
| })); | |||
Comment on lines
+36
to
+46
| export function resolveWindowsNodeBin(dataDir?: string): string | null { | ||
| const baseDir = dataDir ?? resolveHome('~/.loongsuite-pilot'); | ||
| const pinFile = path.join(baseDir, 'node-bin'); | ||
| try { | ||
| if (fsSync.existsSync(pinFile)) { | ||
| const pinned = fsSync.readFileSync(pinFile, 'utf8').trim(); | ||
| if (pinned && fsSync.existsSync(pinned)) return pinned; | ||
| } | ||
| } catch { /* ignore pin read failures */ } | ||
| return process.execPath || null; | ||
| } |
Comment on lines
+61
to
+71
| export function wrapCursorWin32Command(hookScriptPath: string, dataDir?: string): string { | ||
| const nodeBin = resolveWindowsNodeBin(dataDir); | ||
| if (!nodeBin) { | ||
| return `powershell -NoProfile -ExecutionPolicy Bypass -File "${hookScriptPath}"`; | ||
| } | ||
| const processorPath = path.join( | ||
| path.dirname(hookScriptPath), | ||
| 'cursor-hook-processor.mjs', | ||
| ); | ||
| return `cmd.exe /d /s /c ""${nodeBin}" "${processorPath}""`; | ||
| } |
Collaborator
Author
|
CI Passed ✅ — All checks passed. Ready for maintainer review. Automated by "github-manager-bot" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #197
Root Cause
On Windows, Cursor hooks go through a PowerShell 5.1 cold start (1-5s+) then
Resolve-NodeBinprobes (0.3-3s) then processor. Cursor kills the hook at its default timeout (no timeout field in hooks.json), so the chain is terminated before the processor runs.Fix Strategy (3 layers)
Step 1: Write
timeout: 30into hooks.json entries (safety net)timeout?: numbertoAgentHookConfigandHookDefinition"timeout": 30toagents.d/cursor.jsoninstallHookwrites/reconcilestimeout;isHookInstalledchecks matchtimeoutStep 2: Bypass PowerShell on Windows - invoke node directly (latency elimination)
resolveWindowsNodeBin(): reads~/.loongsuite-pilot/node-binpin, falls back toprocess.execPathwrapCursorWin32Command(): emitscmd.exe /d /s /c "<node>" "<hooksDir>/cursor-hook-processor.mjs"legacyCursorHookCommands()- automatic upgrade on next deployStep 3: Reduce .ps1 fallback latency (optional hardening)
Resolve-NodeBinprobe result back tonode-binpin fileFiles Modified
agents.d/cursor.jsonsrc/types/deployment.tssrc/hooks/hook-manager.tssrc/deployment/hook-strategy.tsRisk
Generated by github-manager