Skip to content

Instantly share code, notes, and snippets.

@shimondoodkin
Last active October 11, 2025 01:33
Show Gist options
  • Save shimondoodkin/66572c0888fa089e0f87f1b5e705e052 to your computer and use it in GitHub Desktop.
Save shimondoodkin/66572c0888fa089e0f87f1b5e705e052 to your computer and use it in GitHub Desktop.
automating windsurf. auto continue.
// automating windsurf - continuation.
// current variation of this code is for gpt5-codex model when doing spec-kit.
// it was always showing recommended action but not doing them. so this is a nudge to do the next steps and recommended actions
//
// while it automates it pretty well there is still a problem of overloaded context.
// and need to creae a new conversation evey some calls. you will see messed up responses and files.
// Windsurf menu in help, Toggle developer tools.
// in Developer tools, see console Tab, In console select window: windsurf cascade panel
// might need to type allow pasting
//
// paste to browser console the javascript:
// tips:
// if in future versions the selectors not match well.
// 1. may use the js: debugger; put it as first statment in the function
// statment to stop the debugger on it to find which line is not working.
// hold cursor above variable and see if it gets a value after execution.
// 2 to get a new selectror. first click on point and click element selector
// (on left top edge of devtools there is arrow in square) then point on
// the wanted element or section in the ide, then in the elements tab
// right-click on the selected element and from menu: copy> copy js path,
// then paste the copied path to console
// to make the selector useful if selected too deep trim a little bit remove few selectors at the end.
// or if the selector too specific modify it to make it more general.
// or adapt to your needs , i changed it to have nth-last-child(1) selector in few places
getInput = () => {
const button = document.querySelector("#chat > div div.panel-border button[type=submit]");
const buttonEnabled = ![...button.classList].includes("cursor-not-allowed");
const isStop = !!button.querySelector("svg > rect")
const reactProps = button[Object.keys(button).filter(name => name.startsWith('__reactProps'))[0]]
const insertText = (text) => {
const input = document.querySelector("#chat > div div.panel-border button[type=submit]").parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.querySelector("div[contenteditable] p")
input.focus();
document.execCommand("insertText", false, text);
}
const fakeReactClickEvent = {
nativeEvent: new MouseEvent("click"),
preventDefault: () => { },
stopPropagation: () => { },
target: el,
currentTarget: el,
type: "click",
isDefaultPrevented: () => false,
isPropagationStopped: () => false,
};
return { isStop, buttonEnabled, reactProps, insertText, fakeReactClickEvent }
};
getContent = () => {
// in list of responses:
const listOfResponses=document.querySelector("#chat > div > div > div > div.overflow-y-hidden.overflow-x-clip > div.flex > div > div > div > div.flex")
// div:nth-last-child(1)
const lastElement = listOfResponses.children[listOfResponses.children.length-1]
//div:nth-last-child(2)
const preLastElement = listOfResponses.children[listOfResponses.children.length-2]
// if last response contains form for feedback, responding was finished
const feedback = lastElement?.querySelector("div > div.flex.flex-1.flex-row.items-center.justify-between.gap-1 > div.flex.flex-1.flex-row.items-center.gap-1\\.5 > div > span")
let outputCompleted = feedback?.innerText == "Feedback submitted"
let lastResponseTitles = [];
let lastSubResponses = undefined;
let lastSubResponse = undefined;
let lastThinking = undefined;
let lastText = undefined;
let runButton = undefined;
let runButtonReactProps = undefined;
let runCommand = undefined;
let runRow = undefined;
// if last response contains form for feedback then tak one before last
const lastResponse = outputCompleted ? preLastElement : lastElement
if (!lastResponse) {
outputCompleted = false;
}
else {
// each response composed of subresponses = wrapper > children
lastSubResponses = lastResponse?.children[0].children
// each sub response has a wrapper > two elements, [ thinking , response ]
lastSubResponse = lastSubResponses?.[lastSubResponses.length - 1]
if (lastSubResponse?.children[0]?.children?.length == 2) {
lastThinking = lastSubResponse?.children[0]?.children[0]
lastText = lastSubResponse?.children[0]?.children[1]
}
else {
// no thinking
lastThinking = undefined
lastText = lastSubResponse?.children[0]?.children[0]
}
if (lastText) {
lastResponseTitles = [...lastText?.querySelectorAll("h1,h2,h3")].map(x => x.innerText)
}
runButton = [...lastElement?.querySelectorAll("button")]?.filter(x => x?.innerText?.includes("RunAlt+⏎"))?.[0]
if(runButton){
runRow=runButton.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
runCommand = runRow?.querySelector("pre.whitespace-pre-wrap")?.innerHTML?.split('</span>')?.pop()
runButtonReactProps = runButton?.[Object.keys(runButton).filter(name => name.startsWith('__reactProps'))[0]]
}
}
return {
outputCompleted, lastResponseTitles, lastText, runButton, runButtonReactProps, runCommand,
lastElement, preLastElement, feedback, lastResponse, lastSubResponses, lastSubResponse, lastThinking, lastResponse, runRow
}
};
wait = (t) => new Promise(r => setTimeout(r, t));
stop1 = () => { window.continueEnabled = false; if (window.checkContinueTimeout) if (window.checkContinueTimeout) { clearTimeout(window.checkContinueTimeout) } }
checkContinue = async (autoRun) => {
try {
if (window.checkContinueTimeout) { clearTimeout(window.checkContinueTimeout) }
if (autoRun && !window.continueEnabled) {
return
}
else {
window.continueEnabled = true
}
let content = getContent()
if (content.outputCompleted) {
if (content.lastResponseTitles.join('\n').includes('Recommended Actions') && content.lastResponseTitles.join('\n').includes('Next Steps')) {
let input;
input = getInput()
input.insertText("Do the Recommended Actions and Next Steps")
await wait(1000)
input = getInput()
input.reactProps.onClick(input.fakeReactClickEvent)
await wait(3000)
}
else if (content.lastResponseTitles.join('\n').includes('Recommended Actions')) {
let input;
input = getInput()
input.insertText("Do the Recommended Actions")
await wait(1000)
input = getInput()
input.reactProps.onClick(input.fakeReactClickEvent)
await wait(3000)
}
else if (content.lastResponseTitles.join('\n').includes('Next Steps')) {
let input;
input = getInput()
input.insertText("Do the Next Steps")
await wait(1000)
input = getInput()
input.reactProps.onClick(input.fakeReactClickEvent)
await wait(3000)
}
else if (content.lastResponseTitles.join('\n').includes('Remaining Work')) {
let input;
input = getInput()
input.insertText("Do the Remaining Work")
await wait(1000)
input = getInput()
input.reactProps.onClick(input.fakeReactClickEvent)
await wait(3000)
}
else if (content.lastResponseTitles.join('\n').includes('Follow-up')) {
let input;
input = getInput()
input.insertText("Continue")
await wait(1000)
input = getInput()
input.reactProps.onClick(input.fakeReactClickEvent)
await wait(3000)
}
}
else if (content.runCommand) {
if (content.runCommand.startsWith('npx')) content.runButtonReactProps.onClick();
else if (content.runCommand.startsWith('Get-Content')) content.runButtonReactProps.onClick();
else if (content.runCommand.startsWith('flutter')) content.runButtonReactProps.onClick();
else if (content.runCommand.startsWith('dart')) content.runButtonReactProps.onClick();
else if (content.runCommand.startsWith('node')) content.runButtonReactProps.onClick();
await wait(3000)
}
window.checkContinueTimeout = setTimeout(() => checkContinue(true), 1000)
} catch (e) {
console.log('auto continue error', e.stack)
window.continueEnabled = false
}
}
checkContinue()
content1 = getContent()
ainput=getInput()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment