') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); fix(clawde): revive an agent whose tab is the last one in its workspace by Castrozan · Pull Request #22 · Castrozan/clawde · GitHub
Skip to content

fix(clawde): revive an agent whose tab is the last one in its workspace - #22

Merged
Castrozan merged 1 commit into
mainfrom
steward-liveness
Aug 25, 2026
Merged

fix(clawde): revive an agent whose tab is the last one in its workspace#22
Castrozan merged 1 commit into
mainfrom
steward-liveness

Conversation

@Castrozan

Copy link
Copy Markdown
Owner

Kira's steward has been dead for forty hours.

relaunch_wrapper_in_window on the herdr backend closes the agent's tab and then creates a replacement. herdr refuses to close a workspace's last tab:

Error: failed to replace herdr tab 'steward' in workspace 'clawde':
{"error":{"code":"tab_close_failed","message":"cannot close the last tab in a workspace"}}

Once betha-pm and jenny were removed from workspace clawde (outside active hours), steward was the only tab left. Its wrapper died, the supervisor tried to relaunch, the close was refused, and the create was never reached. The supervisor retried every ten seconds and wrote 8.8 MB of that one error.

Fix: create the replacement tab before discarding the superseded one. The workspace never drops to zero tabs, so the last-tab rule cannot block the relaunch. A failed discard now leaves a stale tab plus a logged error rather than a dead agent.

The tmux backend was never affected — respawn-window -k reuses the window in place.

Tests: both new cases fail against the old ordering with the production error and pass with the fix.

The herdr backend replaced a dead agent's tab by closing it and then
creating a fresh one. herdr refuses to close a workspace's last tab, so
once every other agent in the workspace had been removed, the survivor's
relaunch failed on the close and never reached the create. Its tab stayed
a bare shell and the supervisor retried the same failing close every ten
seconds, forever. Kira's steward sat dead that way for forty hours behind
8.8 MB of identical errors.
Create the replacement tab first and discard the superseded one after, so
the workspace never drops to zero tabs and the last-tab rule can no longer
block a relaunch. A failed discard now leaves a stale tab and a logged
error instead of a dead agent.
The tmux backend was never affected: respawn-window -k reuses the window
in place and never removes it.
Agent-Machine: kira
Agent-Resume: claude --resume efee1316-8d94-438e-951e-e9c978626531
@Castrozan
Castrozan merged commit ae9887c into mainAug 25, 2026
3 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Castrozan