Not only did my agentic YOLO behavior for some reason come to an end (it never executes commands etc automatically any longer, but allows me to manually press the “Run command” button), but the most annoying part is that some commands are immediately cancelled, every time.
For example:
$ npx npm-check-updates
Need to install the following packages: [email protected]
Ok to proceed? (y) ^Cnpm ERR! canceled
npm ERR! A complete log of this run can be found in:
npm ERR! /home/username/.npm/_logs/2025-02-03T11_02_55_336Z-debug-0.log
Hey, you can probably add something in your "Rules for AI’ to instruct it to not use CTRL+C / SIGINT to try to stop the program, and explain you are able to do it yourself!
We do hope to improve the out of the box behaviour on this soon!
Seems to help actually. The agentic behavior is still gone as soon as it has to execute a command, which it refuses, but instead “normal” and “agent” mode now has the exact same behavior. No difference what-so-ever as far as I can see. Unless this is a known error I can just attempt to reinstall I suppose.
Hmmm, I’m suspecting this is not agentic at all, but built into the editor and based on how it handles the output from command executions. The problem has increased again, and my previous positivity was probably either caused by a bug or just wishful thinking.
This is SUPER frustrating, but I’ve had some success by adding this rule to .cursor/rules:
---
description:
globs:
alwaysApply: true
---
ALWAYS pipe terminal commands to cat and then redirect the output to a temporary file in the directory .ai/terminal.
ALWAYS append a random string (using your own ability as an LLM without any use of other tools) to the temporary file's name to ensure you never overwrite other logs and remember the filename so you can access it later.
ALWAYS ignore the signal you receive from the terminal command (such as "command canceled by user" or perceived command failures) and instead read the contents of the temporary file.
ALWAYS append a concurrent 10s sleep to the end of the command to give it time to run to completion.
NEVER cancel the terminal execution yourself.
NEVER attempt to create the .ai/terminal directory; assume it already exists.
NEVER redirect to `2>&1`.
The Agent's terminal environment in Cursor AI is notoriously unreliable and this method significantly improves reliability.
Additionally, I have a script that I run in the developer console that automatically resumes after the 25 calls and automatically clicks “Skip” after 10 seconds (I consistently get hanging on terminal commands and have to click “Skip” myself. YMMV here depending on how long your typical terminal commands take in your codebase. I find 10s is sufficient for most of what I do.
// Stop any existing instance
window.cursorSkipWatcher?.stop?.();
window.cursorSkipWatcher = (() => {
console.log('🚀 Cursor Skip + Resume Watchdog: Running');
let skipButton = null;
let skipAppearedAt = null;
let lastResumeClick = 0;
let intervalId = null;
const SKIP_DELAY = 10000; // 10 seconds
const RESUME_COOLDOWN = 3000; // 3 seconds
function findSkipButton() {
const candidates = Array.from(document.querySelectorAll('span'))
.filter(span => span.textContent?.includes('⇧⌫ Skip'));
return candidates.length > 0
? candidates[0].closest('div.anysphere-text-button')
: null;
}
function checkAndClickSkip() {
const currentButton = findSkipButton();
if (currentButton) {
if (skipButton !== currentButton) {
skipButton = currentButton;
skipAppearedAt = Date.now();
console.log('⏳ Skip button appeared');
} else {
const elapsed = Date.now() - skipAppearedAt;
if (elapsed >= SKIP_DELAY) {
console.log('⏩ Clicking Skip after 10s');
skipButton.click();
skipButton = null;
skipAppearedAt = null;
}
}
} else {
skipButton = null;
skipAppearedAt = null;
}
}
function checkAndClickResume() {
const now = Date.now();
if (now - lastResumeClick < RESUME_COOLDOWN) return;
const elements = document.querySelectorAll('body *');
for (const el of elements) {
if (!el?.textContent) continue;
if (
el.textContent.includes('stop the agent after 25 tool calls') ||
el.textContent.includes('Note: we default stop')
) {
const links = el.querySelectorAll('a, span.markdown-link, [role="link"], [data-link]');
for (const link of links) {
if (link.textContent.trim().toLowerCase() === 'resume the conversation') {
console.log('🔁 Clicking "resume the conversation"');
link.click();
lastResumeClick = now;
return;
}
}
}
}
}
function watchdogLoop() {
checkAndClickSkip();
checkAndClickResume();
}
intervalId = setInterval(watchdogLoop, 1000);
watchdogLoop();
return {
stop() {
clearInterval(intervalId);
console.log('🛑 Cursor Skip + Resume Watchdog: Stopped');
}
};
})();
Again, YMMV with all this – I’ve tried several approaches similar to this and this is just the latest and seemingly (so far) most successful one I’ve tried. Hope it helps some folks and if you have any trouble with it or find ways to improve it, please do share!!