├── LICENSE ├── INSTALLATION.md ├── cursor-auto-resume.min.js ├── cursor-auto-resume.js └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /INSTALLATION.md: -------------------------------------------------------------------------------- 1 | # Installation Guide for Cursor Auto Resume 2 | 3 | This guide provides step-by-step instructions for setting up the Cursor Auto Resume tool. 4 | 5 | ## Installation Steps 6 | 7 | 1. Open Cursor IDE 8 | 2. Click "Help" in the menu bar 9 | 3. Select "Toggle Developer Tools" 10 | 4. Click the "Console" tab at the top 11 | 5. Copy the entire code from [cursor-auto-resume.js](cursor-auto-resume.js) 12 | 6. Paste it into the console 13 | 7. Press Enter to run it 14 | 8. Close DevTools by clicking the X in the corner (optional) 15 | 9. A small button will appear in the bottom-right corner showing the tool is active 16 | 17 | ## Troubleshooting 18 | 19 | ### Nothing happens when I run the script 20 | - Check if there are any errors in the Console tab 21 | - Make sure you're running it in Cursor IDE, not another window 22 | - Try refreshing Cursor and running the script again 23 | 24 | ### The indicator appears but doesn't click the "resume" link 25 | - The script looks for specific text patterns. If Cursor changes these patterns, the script may need updating 26 | - Check if the rate limit message contains "stop the agent after 25 tool calls" or similar text 27 | 28 | ### The indicator disappears after a while 29 | - The indicator is attached to the current page. If Cursor refreshes or navigates, you'll need to run the script again 30 | 31 | ## Uninstalling 32 | 33 | Close and reopen Cursor IDE. 34 | 35 | ## Next Steps 36 | 37 | For more advanced usage and customization options, check the [README.md](README.md) file. -------------------------------------------------------------------------------- /cursor-auto-resume.min.js: -------------------------------------------------------------------------------- 1 | !function(){console.log("Cursor Auto Resume: Running");let t=0,e=Date.now();const n=18e5;let o;function r(){e=Date.now(),console.log("Cursor Auto Resume: Timer reset")}function c(){const r=Date.now();if(r-e>n)return console.log("Cursor Auto Resume: 30 minutes elapsed, stopping auto-click"),void clearInterval(o);if(!(r-t<3e3)){const e=document.querySelector('section[data-markdown-raw*="stop the agent after"]');if(e){const n=e.querySelector('span.markdown-link[data-link*="composer.resumeCurrentChat"]');if(n&&"resume the conversation"===n.textContent.trim())return console.log('Clicking "resume the conversation" link (markdown section)'),n.click(),void(t=r)}const n=document.evaluate("//text()[contains(., 'stop the agent after') or contains(., 'Note: By default, we stop')]",document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);for(let e=0;e maxDuration) { 27 | console.log('Cursor Auto Resume: 30 minutes elapsed, stopping auto-click'); 28 | clearInterval(intervalId); 29 | return; 30 | } 31 | 32 | // Prevent clicking too frequently (3 second cooldown) 33 | if (now - lastClickTime < 3000) return; 34 | 35 | // --- Scenario 1: "stop the agent after..." - Updated approach --- 36 | // First try to find the markdown section with the data-markdown-raw attribute 37 | const markdownSection = document.querySelector('section[data-markdown-raw*="stop the agent after"]'); 38 | 39 | if (markdownSection) { 40 | // Look for the resume link within this section 41 | const resumeLink = markdownSection.querySelector('span.markdown-link[data-link*="composer.resumeCurrentChat"]'); 42 | if (resumeLink && resumeLink.textContent.trim() === 'resume the conversation') { 43 | console.log('Clicking "resume the conversation" link (markdown section)'); 44 | resumeLink.click(); 45 | lastClickTime = now; 46 | return; 47 | } 48 | } 49 | 50 | // Fallback: Original XPath approach with corrected text patterns 51 | const toolLimitXpath = document.evaluate( 52 | "//text()[contains(., 'stop the agent after') or contains(., 'Note: By default, we stop')]", 53 | document, 54 | null, 55 | XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, 56 | null 57 | ); 58 | 59 | for (let i = 0; i < toolLimitXpath.snapshotLength; i++) { 60 | const textNode = toolLimitXpath.snapshotItem(i); 61 | const el = textNode.parentElement; 62 | 63 | if (!el || !el.textContent) continue; 64 | 65 | // Double-check with regex for "stop the agent after X tool calls" pattern 66 | const text = el.textContent; 67 | const hasRateLimitText = ( 68 | /stop the agent after \d+ tool calls/i.test(text) || 69 | text.includes('Note: By default, we stop') 70 | ); 71 | 72 | if (hasRateLimitText) { 73 | // Find the resume link inside this element or its parent section 74 | const section = el.closest('section') || el; 75 | const links = section.querySelectorAll('a, span.markdown-link, [role="link"], [data-link]'); 76 | for (const link of links) { 77 | if (link.textContent.trim() === 'resume the conversation') { 78 | console.log('Clicking "resume the conversation" link (fallback)'); 79 | link.click(); 80 | lastClickTime = now; 81 | return; // Exit after successful click 82 | } 83 | } 84 | } 85 | } 86 | 87 | // --- Scenarios 2 & 3: Popup errors in chat window --- 88 | const chatWindow = document.querySelector("div[class*='composer-bar']")?.closest("div[class*='full-input-box']"); 89 | if (!chatWindow) return; 90 | 91 | const errorScenarios = [ 92 | { 93 | errorText: "We're having trouble connecting to the model provider", 94 | buttonText: 'Resume', 95 | logMessage: 'Clicking "Resume" button for connection error.' 96 | }, 97 | { 98 | errorText: "We're experiencing high demand for", 99 | buttonText: 'Try again', 100 | logMessage: 'Clicking "Try again" button for high demand error.' 101 | }, 102 | { 103 | errorText: "Connection failed. If the problem persists, please check your internet connection", 104 | buttonText: 'Try again', 105 | logMessage: 'Clicking "Try again" button for connection failed error.' 106 | } 107 | ]; 108 | 109 | for (const scenario of errorScenarios) { 110 | const errorXpath = `.//section[contains(@data-markdown-raw, "${scenario.errorText}")] | .//div[contains(., "${scenario.errorText}")] | .//span[contains(., "${scenario.errorText}")]`; 111 | const errorElementResult = document.evaluate(errorXpath, chatWindow, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; 112 | 113 | if (errorElementResult) { 114 | const buttonXpath = `(.//div[contains(@class, 'anysphere-secondary-button')]//span[text()='${scenario.buttonText}']/.. | .//button[contains(., '${scenario.buttonText}')])[last()]`; 115 | const button = document.evaluate(buttonXpath, chatWindow, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; 116 | 117 | if (button) { 118 | console.log(scenario.logMessage); 119 | button.click(); 120 | lastClickTime = now; 121 | return; // Exit after successful click 122 | } 123 | } 124 | } 125 | } 126 | 127 | // Run periodically 128 | intervalId = setInterval(clickResumeLink, 1000); 129 | 130 | // Also run once immediately 131 | clickResumeLink(); 132 | 133 | // Log timer info 134 | console.log('Cursor Auto Resume: Will stop after 30 minutes. Call click_reset() to reset timer.'); 135 | 136 | })(); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cursor Auto Resume 2 | 3 | ![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg) 4 | ![Version](https://img.shields.io/badge/Version-1.1.0-green.svg) 5 | 6 | A simple tool that automatically clicks the "resume the conversation" link when Cursor IDE hits its API rate limits. 7 | 8 | ## Important Note on Usage 9 | 10 | This tool is created with the intention of helping developers maintain their workflow efficiency while using Cursor IDE. It is designed to automate a manual action that Cursor explicitly allows (clicking the "resume conversation" link) and does not attempt to bypass or circumvent any actual rate limits or security measures. 11 | 12 | We respect Cursor's services and their need for rate limiting. This tool: 13 | - Only automates an action that users are explicitly allowed to perform 14 | - Maintains the same cooldown periods as manual clicking 15 | - Does not attempt to bypass actual API limits or quotas 16 | - Simply reduces the manual interruption of having to click the resume link 17 | 18 | The goal is to enhance developer productivity while working within Cursor's intended usage patterns. 19 | 20 | ## Why This Tool Exists 21 | 22 | When using Cursor's AI features extensively during development, you often hit rate limits after about 25 tool calls. Normally, you'd see a message like this: 23 | 24 | ``` 25 | Note: By default, we stop the agent after 25 tool calls. You can resume the conversation. 26 | ``` 27 | 28 | This tool automatically detects this message and clicks the "resume the conversation" link for you, allowing you to maintain focus on your development tasks without manual interruption. 29 | 30 | ## Features 31 | 32 | - **Auto-click**: Automatically clicks the "resume the conversation" link when rate limits appear 33 | - **Enhanced DOM targeting**: Uses advanced selectors to accurately find rate limit messages in Cursor's interface 34 | - **Multi-scenario support**: Handles various error scenarios including connection issues and high demand errors 35 | - **Anti-spam**: 3-second cooldown between clicks to prevent issues 36 | - **Auto-stop**: Automatically stops after 30 minutes to prevent indefinite running 37 | - **Timer reset**: Call `click_reset()` in the console to reset the 30-minute timer 38 | - **Fallback mechanisms**: Multiple approaches to ensure compatibility with different Cursor versions 39 | 40 | ## Technical Details 41 | 42 | ### Tech Stack 43 | - **JavaScript (ES6+)**: Core scripting language 44 | - **XPath**: Advanced DOM querying for fallback scenarios 45 | - **CSS Selectors**: Primary DOM targeting method 46 | - **Browser Console API**: For debugging and user interaction 47 | 48 | ### How It Works 49 | 50 | The script uses a sophisticated multi-layered approach: 51 | 52 | 1. **Primary Detection**: Uses CSS selectors to find markdown sections with `data-markdown-raw` attributes containing rate limit messages 53 | 2. **Fallback Detection**: XPath queries to locate rate limit text patterns in the DOM 54 | 3. **Link Targeting**: Specifically targets `span.markdown-link` elements with `data-link` attributes for the resume action 55 | 4. **Error Handling**: Detects and handles various error scenarios like connection failures and high demand messages 56 | 5. **Timer Management**: 30-minute auto-stop with user-controlled reset functionality 57 | 58 | ## How to Use 59 | 60 | Permanent installation: 61 | 62 | 1. Install [Custom CSS and JS Loader](https://marketplace.visualstudio.com/items?itemName=be5invis.vscode-custom-css) 63 | 2. Clone this repo to your home directory 64 | 3. Add this to your `settings.json`: 65 | 66 | ``` 67 | "vscode_custom_css.imports": [ 68 | "file://${userHome}/cursor-auto-resume/cursor-auto-resume.js" 69 | ] 70 | ``` 71 | 72 | 4. Restart Cursor with proper permissions to modify itself (your user should own it) 73 | 5. Activate command "Reload Custom CSS and JS" 74 | 6. Reload window 75 | 76 | Step 5 + 6 must be repeated on each Cursor update. 77 | 78 | One time installation: 79 | 80 | 1. In Cursor, click "Help" in the menu bar and select "Toggle Developer Tools" 81 | 2. Click the "Console" tab 82 | 3. Copy the entire code from [cursor-auto-resume.js](cursor-auto-resume.js) 83 | 4. Paste it into the console and press Enter 84 | 5. Close DevTools by clicking the X in the corner (optional) 85 | 86 | The script will now automatically click the "resume the conversation" link whenever it appears. 87 | 88 | ### Advanced Usage 89 | 90 | - **Reset Timer**: If you want to reset the 30-minute timer, type `click_reset()` in the browser console 91 | - **Monitor Activity**: The script logs all its actions to the console for debugging purposes 92 | - **Manual Stop**: The script will automatically stop after 30 minutes, or you can reload the page/window 93 | 94 | ## FAQ 95 | 96 | ### Is this safe to use? 97 | Yes, the script only runs in your Cursor IDE and only clicks the specific "resume the conversation" link when rate limits are hit. It doesn't modify any core functionality or bypass any security measures. 98 | 99 | ### Will this work with future versions of Cursor? 100 | The script is designed with multiple fallback mechanisms and enhanced DOM targeting to maintain compatibility. As long as Cursor continues to use similar rate limit messages and "resume the conversation" links, the script should continue to work. If Cursor's interface changes, we'll update the tool to maintain compatibility while respecting their service. 101 | 102 | ### How do I disable it? 103 | Close and reopen Cursor IDE, or refresh the window. The script automatically stops after 30 minutes. 104 | 105 | ### Does this bypass Cursor's rate limits? 106 | No. This tool only automates clicking the "resume the conversation" link that Cursor explicitly provides. It respects all cooldown periods and doesn't bypass any actual API limits. It simply automates an action that users are already permitted to perform manually. 107 | 108 | ### Why does the script stop after 30 minutes? 109 | This is a safety feature to prevent indefinite running. You can reset the timer by calling `click_reset()` in the console if needed. 110 | 111 | ## License 112 | 113 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 114 | 115 | ## Contributing 116 | 117 | Contributions are welcome! Please feel free to submit a pull request. When contributing, please maintain the tool's core principle of respecting Cursor's service while helping developers be more productive. 118 | 119 | 1. Fork the repository 120 | 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 121 | 3. Commit your changes (`git commit -m 'Add some amazing feature'`) 122 | 4. Push to the branch (`git push origin feature/amazing-feature`) 123 | 5. Open a Pull Request --------------------------------------------------------------------------------