fix(grok): harden ACP resume and session lifecycle handling - #11

Open
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume
Open

fix(grok): harden ACP resume and session lifecycle handling#11
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume

Conversation

@justingray0

Copy link
Copy Markdown
Owner

Summary

  • Harden Grok ACP resume/replay handling in XAiAcpExtension, GrokAdapter, and GrokAcpSupport.
  • Align Grok text generation and mock-agent scenarios with resumed session behavior.
  • Add provider runtime lifecycle coverage for activeTurnId sync and JSON-RPC edge cases.

Extracted from the earlier wip/grok-resume-fixes work on top of the merged Cursor resume fixes (#9, #10).

Test plan

  • vp test apps/server/src/provider/acp/XAiAcpExtension.test.ts
  • vp test apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts
  • vp test apps/server/src/provider/Layers/ProviderService.test.ts
  • vp check

Made with Cursor

justingray0and others added 9 commits June 29, 2026 06:52
When Tailscale Serve is enabled it proxies the loopback-bound backend onto
the tailnet, so the server is reachable from other devices even though
`config.host` stays on 127.0.0.1. Previously the auth policy keyed solely
off the bind host and selected a local-only policy in that case, skipping
the one-time-token bootstrap required for remote access.
Treat the server as remote-reachable whenever `tailscaleServeEnabled` is
set, in addition to the existing wildcard / non-loopback host checks, so
remote clients get the `remote-reachable` policy with one-time-token
bootstrap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resuming a grok session against a different working directory than the one
the cursor was recorded in produces a stale/invalid resume, so a thread that
moves to a new worktree must start a fresh session instead of replaying the
old cursor.
- ProviderCommandReactor: when the preferred provider is grok and the cwd
changed, pass an explicit `null` resume cursor (a "discard" sentinel,
distinct from `undefined` which means "use the persisted cursor") when
restarting the session, and log `shouldDiscardResumeCursorForCwdChange`.
- ProviderService: honor the `null` sentinel by dropping the cursor, and
independently refuse to reuse a persisted cursor when an explicit `cwd`
differs from the persisted one. Persisted cwd lookup is hoisted so both
the cursor-reuse guard and `effectiveCwd` share it.
Adds reactor- and service-level regression tests covering the
worktree/cwd-change paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ake stall
The RpcClient and raw ext requests only ever mint numeric request ids, so a
response whose id is not a base-10 number cannot match anything we sent. Some
agents (notably grok) emit unsolicited JSON-RPC responses with symbolic ids
such as "skills-reload" right after `initialize`. Forwarding those to the
RpcClient made it fail while resolving the id, tearing down the response loop
so that subsequent `authenticate` and `session/new` responses were never
delivered and the handshake stalled until the caller timed out.
Route untracked responses through a `forwardUntrackedResponse` guard that only
forwards ids matching `^[0-9]+$` and otherwise drops them with a debug log.
Applies to both the exit-encoded and success/defect response paths.
Adds an in-memory regression test that floods the stream with
`skills-reload` responses after `initialize` and asserts the
initialize/authenticate/session handshake still completes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
effect's default pinger writes a ping every 5s and tears the socket down on
a single missed pong. Over lossy/reordering links (e.g. WireGuard/Tailscale)
that churns the UI WebSocket and causes reconnect flapping.
Patch `makePinger` to:
- ping every 15s instead of 5s, and
- only fail after 3 consecutive missed pongs (`MAX_MISSED_PONGS`) instead of 1,
tracked via a `missedPongs` counter that resets on pong.
The patch also threads optional `onPing`/`onPong` connection hooks through the
pinger. Regenerated `patches/effect@4.0.0-beta.78.patch` and updated the
`patch_hash` references in `pnpm-lock.yaml`. See pingdotgg#3054.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename every workflow file under .github/workflows/ to a `.yml.disabled`
suffix so GitHub Actions no longer recognizes them. This stops all
automatic runs on the fork — including the scheduled `Release` job (which
runs every 3 hours and keeps queuing), CI on push/PR, deploy-relay,
issue-labels, mobile EAS preview, and the pr-size / pr-vouch
`pull_request_target` jobs.
Pure renames with no content changes, so re-enabling is just renaming the
files back to `.yml`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate session/load replay before prompting, recover orphaned provider sessions
on startup, sync active turn state from lifecycle events, and reset assistant
segments in-place when item.started replays within the same turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Cursor reuses provider item ids across turns after restart, append
assistant output to a new turn-scoped message at the end of the thread
instead of mutating an earlier completed message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve Grok adapter resume semantics, xAI ACP extension replay behavior,
and provider runtime turn tracking tests so resumed Grok sessions stay
consistent across restarts.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actionsgithub-actionsBot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 7, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@justingray0
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(grok): harden ACP resume and session lifecycle handling - #11

Open
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume
Open

fix(grok): harden ACP resume and session lifecycle handling#11
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume

Conversation

@justingray0

Copy link
Copy Markdown
Owner

Summary

  • Harden Grok ACP resume/replay handling in XAiAcpExtension, GrokAdapter, and GrokAcpSupport.
  • Align Grok text generation and mock-agent scenarios with resumed session behavior.
  • Add provider runtime lifecycle coverage for activeTurnId sync and JSON-RPC edge cases.

Extracted from the earlier wip/grok-resume-fixes work on top of the merged Cursor resume fixes (#9, #10).

Test plan

  • vp test apps/server/src/provider/acp/XAiAcpExtension.test.ts
  • vp test apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts
  • vp test apps/server/src/provider/Layers/ProviderService.test.ts
  • vp check

Made with Cursor

justingray0and others added 9 commits June 29, 2026 06:52
When Tailscale Serve is enabled it proxies the loopback-bound backend onto
the tailnet, so the server is reachable from other devices even though
`config.host` stays on 127.0.0.1. Previously the auth policy keyed solely
off the bind host and selected a local-only policy in that case, skipping
the one-time-token bootstrap required for remote access.
Treat the server as remote-reachable whenever `tailscaleServeEnabled` is
set, in addition to the existing wildcard / non-loopback host checks, so
remote clients get the `remote-reachable` policy with one-time-token
bootstrap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resuming a grok session against a different working directory than the one
the cursor was recorded in produces a stale/invalid resume, so a thread that
moves to a new worktree must start a fresh session instead of replaying the
old cursor.
- ProviderCommandReactor: when the preferred provider is grok and the cwd
changed, pass an explicit `null` resume cursor (a "discard" sentinel,
distinct from `undefined` which means "use the persisted cursor") when
restarting the session, and log `shouldDiscardResumeCursorForCwdChange`.
- ProviderService: honor the `null` sentinel by dropping the cursor, and
independently refuse to reuse a persisted cursor when an explicit `cwd`
differs from the persisted one. Persisted cwd lookup is hoisted so both
the cursor-reuse guard and `effectiveCwd` share it.
Adds reactor- and service-level regression tests covering the
worktree/cwd-change paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ake stall
The RpcClient and raw ext requests only ever mint numeric request ids, so a
response whose id is not a base-10 number cannot match anything we sent. Some
agents (notably grok) emit unsolicited JSON-RPC responses with symbolic ids
such as "skills-reload" right after `initialize`. Forwarding those to the
RpcClient made it fail while resolving the id, tearing down the response loop
so that subsequent `authenticate` and `session/new` responses were never
delivered and the handshake stalled until the caller timed out.
Route untracked responses through a `forwardUntrackedResponse` guard that only
forwards ids matching `^[0-9]+$` and otherwise drops them with a debug log.
Applies to both the exit-encoded and success/defect response paths.
Adds an in-memory regression test that floods the stream with
`skills-reload` responses after `initialize` and asserts the
initialize/authenticate/session handshake still completes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
effect's default pinger writes a ping every 5s and tears the socket down on
a single missed pong. Over lossy/reordering links (e.g. WireGuard/Tailscale)
that churns the UI WebSocket and causes reconnect flapping.
Patch `makePinger` to:
- ping every 15s instead of 5s, and
- only fail after 3 consecutive missed pongs (`MAX_MISSED_PONGS`) instead of 1,
tracked via a `missedPongs` counter that resets on pong.
The patch also threads optional `onPing`/`onPong` connection hooks through the
pinger. Regenerated `patches/effect@4.0.0-beta.78.patch` and updated the
`patch_hash` references in `pnpm-lock.yaml`. See pingdotgg#3054.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename every workflow file under .github/workflows/ to a `.yml.disabled`
suffix so GitHub Actions no longer recognizes them. This stops all
automatic runs on the fork — including the scheduled `Release` job (which
runs every 3 hours and keeps queuing), CI on push/PR, deploy-relay,
issue-labels, mobile EAS preview, and the pr-size / pr-vouch
`pull_request_target` jobs.
Pure renames with no content changes, so re-enabling is just renaming the
files back to `.yml`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate session/load replay before prompting, recover orphaned provider sessions
on startup, sync active turn state from lifecycle events, and reset assistant
segments in-place when item.started replays within the same turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Cursor reuses provider item ids across turns after restart, append
assistant output to a new turn-scoped message at the end of the thread
instead of mutating an earlier completed message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve Grok adapter resume semantics, xAI ACP extension replay behavior,
and provider runtime turn tracking tests so resumed Grok sessions stay
consistent across restarts.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actionsgithub-actionsBot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 7, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@justingray0
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(grok): harden ACP resume and session lifecycle handling - #11

Open
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume
Open

fix(grok): harden ACP resume and session lifecycle handling#11
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume

Conversation

@justingray0

Copy link
Copy Markdown
Owner

Summary

  • Harden Grok ACP resume/replay handling in XAiAcpExtension, GrokAdapter, and GrokAcpSupport.
  • Align Grok text generation and mock-agent scenarios with resumed session behavior.
  • Add provider runtime lifecycle coverage for activeTurnId sync and JSON-RPC edge cases.

Extracted from the earlier wip/grok-resume-fixes work on top of the merged Cursor resume fixes (#9, #10).

Test plan

  • vp test apps/server/src/provider/acp/XAiAcpExtension.test.ts
  • vp test apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts
  • vp test apps/server/src/provider/Layers/ProviderService.test.ts
  • vp check

Made with Cursor

justingray0and others added 9 commits June 29, 2026 06:52
When Tailscale Serve is enabled it proxies the loopback-bound backend onto
the tailnet, so the server is reachable from other devices even though
`config.host` stays on 127.0.0.1. Previously the auth policy keyed solely
off the bind host and selected a local-only policy in that case, skipping
the one-time-token bootstrap required for remote access.
Treat the server as remote-reachable whenever `tailscaleServeEnabled` is
set, in addition to the existing wildcard / non-loopback host checks, so
remote clients get the `remote-reachable` policy with one-time-token
bootstrap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resuming a grok session against a different working directory than the one
the cursor was recorded in produces a stale/invalid resume, so a thread that
moves to a new worktree must start a fresh session instead of replaying the
old cursor.
- ProviderCommandReactor: when the preferred provider is grok and the cwd
changed, pass an explicit `null` resume cursor (a "discard" sentinel,
distinct from `undefined` which means "use the persisted cursor") when
restarting the session, and log `shouldDiscardResumeCursorForCwdChange`.
- ProviderService: honor the `null` sentinel by dropping the cursor, and
independently refuse to reuse a persisted cursor when an explicit `cwd`
differs from the persisted one. Persisted cwd lookup is hoisted so both
the cursor-reuse guard and `effectiveCwd` share it.
Adds reactor- and service-level regression tests covering the
worktree/cwd-change paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ake stall
The RpcClient and raw ext requests only ever mint numeric request ids, so a
response whose id is not a base-10 number cannot match anything we sent. Some
agents (notably grok) emit unsolicited JSON-RPC responses with symbolic ids
such as "skills-reload" right after `initialize`. Forwarding those to the
RpcClient made it fail while resolving the id, tearing down the response loop
so that subsequent `authenticate` and `session/new` responses were never
delivered and the handshake stalled until the caller timed out.
Route untracked responses through a `forwardUntrackedResponse` guard that only
forwards ids matching `^[0-9]+$` and otherwise drops them with a debug log.
Applies to both the exit-encoded and success/defect response paths.
Adds an in-memory regression test that floods the stream with
`skills-reload` responses after `initialize` and asserts the
initialize/authenticate/session handshake still completes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
effect's default pinger writes a ping every 5s and tears the socket down on
a single missed pong. Over lossy/reordering links (e.g. WireGuard/Tailscale)
that churns the UI WebSocket and causes reconnect flapping.
Patch `makePinger` to:
- ping every 15s instead of 5s, and
- only fail after 3 consecutive missed pongs (`MAX_MISSED_PONGS`) instead of 1,
tracked via a `missedPongs` counter that resets on pong.
The patch also threads optional `onPing`/`onPong` connection hooks through the
pinger. Regenerated `patches/effect@4.0.0-beta.78.patch` and updated the
`patch_hash` references in `pnpm-lock.yaml`. See pingdotgg#3054.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename every workflow file under .github/workflows/ to a `.yml.disabled`
suffix so GitHub Actions no longer recognizes them. This stops all
automatic runs on the fork — including the scheduled `Release` job (which
runs every 3 hours and keeps queuing), CI on push/PR, deploy-relay,
issue-labels, mobile EAS preview, and the pr-size / pr-vouch
`pull_request_target` jobs.
Pure renames with no content changes, so re-enabling is just renaming the
files back to `.yml`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate session/load replay before prompting, recover orphaned provider sessions
on startup, sync active turn state from lifecycle events, and reset assistant
segments in-place when item.started replays within the same turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Cursor reuses provider item ids across turns after restart, append
assistant output to a new turn-scoped message at the end of the thread
instead of mutating an earlier completed message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve Grok adapter resume semantics, xAI ACP extension replay behavior,
and provider runtime turn tracking tests so resumed Grok sessions stay
consistent across restarts.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actionsgithub-actionsBot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 7, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@justingray0
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(grok): harden ACP resume and session lifecycle handling - #11

Open
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume
Open

fix(grok): harden ACP resume and session lifecycle handling#11
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume

Conversation

@justingray0

Copy link
Copy Markdown
Owner

Summary

  • Harden Grok ACP resume/replay handling in XAiAcpExtension, GrokAdapter, and GrokAcpSupport.
  • Align Grok text generation and mock-agent scenarios with resumed session behavior.
  • Add provider runtime lifecycle coverage for activeTurnId sync and JSON-RPC edge cases.

Extracted from the earlier wip/grok-resume-fixes work on top of the merged Cursor resume fixes (#9, #10).

Test plan

  • vp test apps/server/src/provider/acp/XAiAcpExtension.test.ts
  • vp test apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts
  • vp test apps/server/src/provider/Layers/ProviderService.test.ts
  • vp check

Made with Cursor

justingray0and others added 9 commits June 29, 2026 06:52
When Tailscale Serve is enabled it proxies the loopback-bound backend onto
the tailnet, so the server is reachable from other devices even though
`config.host` stays on 127.0.0.1. Previously the auth policy keyed solely
off the bind host and selected a local-only policy in that case, skipping
the one-time-token bootstrap required for remote access.
Treat the server as remote-reachable whenever `tailscaleServeEnabled` is
set, in addition to the existing wildcard / non-loopback host checks, so
remote clients get the `remote-reachable` policy with one-time-token
bootstrap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resuming a grok session against a different working directory than the one
the cursor was recorded in produces a stale/invalid resume, so a thread that
moves to a new worktree must start a fresh session instead of replaying the
old cursor.
- ProviderCommandReactor: when the preferred provider is grok and the cwd
changed, pass an explicit `null` resume cursor (a "discard" sentinel,
distinct from `undefined` which means "use the persisted cursor") when
restarting the session, and log `shouldDiscardResumeCursorForCwdChange`.
- ProviderService: honor the `null` sentinel by dropping the cursor, and
independently refuse to reuse a persisted cursor when an explicit `cwd`
differs from the persisted one. Persisted cwd lookup is hoisted so both
the cursor-reuse guard and `effectiveCwd` share it.
Adds reactor- and service-level regression tests covering the
worktree/cwd-change paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ake stall
The RpcClient and raw ext requests only ever mint numeric request ids, so a
response whose id is not a base-10 number cannot match anything we sent. Some
agents (notably grok) emit unsolicited JSON-RPC responses with symbolic ids
such as "skills-reload" right after `initialize`. Forwarding those to the
RpcClient made it fail while resolving the id, tearing down the response loop
so that subsequent `authenticate` and `session/new` responses were never
delivered and the handshake stalled until the caller timed out.
Route untracked responses through a `forwardUntrackedResponse` guard that only
forwards ids matching `^[0-9]+$` and otherwise drops them with a debug log.
Applies to both the exit-encoded and success/defect response paths.
Adds an in-memory regression test that floods the stream with
`skills-reload` responses after `initialize` and asserts the
initialize/authenticate/session handshake still completes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
effect's default pinger writes a ping every 5s and tears the socket down on
a single missed pong. Over lossy/reordering links (e.g. WireGuard/Tailscale)
that churns the UI WebSocket and causes reconnect flapping.
Patch `makePinger` to:
- ping every 15s instead of 5s, and
- only fail after 3 consecutive missed pongs (`MAX_MISSED_PONGS`) instead of 1,
tracked via a `missedPongs` counter that resets on pong.
The patch also threads optional `onPing`/`onPong` connection hooks through the
pinger. Regenerated `patches/effect@4.0.0-beta.78.patch` and updated the
`patch_hash` references in `pnpm-lock.yaml`. See pingdotgg#3054.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename every workflow file under .github/workflows/ to a `.yml.disabled`
suffix so GitHub Actions no longer recognizes them. This stops all
automatic runs on the fork — including the scheduled `Release` job (which
runs every 3 hours and keeps queuing), CI on push/PR, deploy-relay,
issue-labels, mobile EAS preview, and the pr-size / pr-vouch
`pull_request_target` jobs.
Pure renames with no content changes, so re-enabling is just renaming the
files back to `.yml`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate session/load replay before prompting, recover orphaned provider sessions
on startup, sync active turn state from lifecycle events, and reset assistant
segments in-place when item.started replays within the same turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Cursor reuses provider item ids across turns after restart, append
assistant output to a new turn-scoped message at the end of the thread
instead of mutating an earlier completed message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve Grok adapter resume semantics, xAI ACP extension replay behavior,
and provider runtime turn tracking tests so resumed Grok sessions stay
consistent across restarts.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actionsgithub-actionsBot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 7, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@justingray0
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(grok): harden ACP resume and session lifecycle handling - #11

Open
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume
Open

fix(grok): harden ACP resume and session lifecycle handling#11
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume

Conversation

@justingray0

Copy link
Copy Markdown
Owner

Summary

  • Harden Grok ACP resume/replay handling in XAiAcpExtension, GrokAdapter, and GrokAcpSupport.
  • Align Grok text generation and mock-agent scenarios with resumed session behavior.
  • Add provider runtime lifecycle coverage for activeTurnId sync and JSON-RPC edge cases.

Extracted from the earlier wip/grok-resume-fixes work on top of the merged Cursor resume fixes (#9, #10).

Test plan

  • vp test apps/server/src/provider/acp/XAiAcpExtension.test.ts
  • vp test apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts
  • vp test apps/server/src/provider/Layers/ProviderService.test.ts
  • vp check

Made with Cursor

justingray0and others added 9 commits June 29, 2026 06:52
When Tailscale Serve is enabled it proxies the loopback-bound backend onto
the tailnet, so the server is reachable from other devices even though
`config.host` stays on 127.0.0.1. Previously the auth policy keyed solely
off the bind host and selected a local-only policy in that case, skipping
the one-time-token bootstrap required for remote access.
Treat the server as remote-reachable whenever `tailscaleServeEnabled` is
set, in addition to the existing wildcard / non-loopback host checks, so
remote clients get the `remote-reachable` policy with one-time-token
bootstrap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resuming a grok session against a different working directory than the one
the cursor was recorded in produces a stale/invalid resume, so a thread that
moves to a new worktree must start a fresh session instead of replaying the
old cursor.
- ProviderCommandReactor: when the preferred provider is grok and the cwd
changed, pass an explicit `null` resume cursor (a "discard" sentinel,
distinct from `undefined` which means "use the persisted cursor") when
restarting the session, and log `shouldDiscardResumeCursorForCwdChange`.
- ProviderService: honor the `null` sentinel by dropping the cursor, and
independently refuse to reuse a persisted cursor when an explicit `cwd`
differs from the persisted one. Persisted cwd lookup is hoisted so both
the cursor-reuse guard and `effectiveCwd` share it.
Adds reactor- and service-level regression tests covering the
worktree/cwd-change paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ake stall
The RpcClient and raw ext requests only ever mint numeric request ids, so a
response whose id is not a base-10 number cannot match anything we sent. Some
agents (notably grok) emit unsolicited JSON-RPC responses with symbolic ids
such as "skills-reload" right after `initialize`. Forwarding those to the
RpcClient made it fail while resolving the id, tearing down the response loop
so that subsequent `authenticate` and `session/new` responses were never
delivered and the handshake stalled until the caller timed out.
Route untracked responses through a `forwardUntrackedResponse` guard that only
forwards ids matching `^[0-9]+$` and otherwise drops them with a debug log.
Applies to both the exit-encoded and success/defect response paths.
Adds an in-memory regression test that floods the stream with
`skills-reload` responses after `initialize` and asserts the
initialize/authenticate/session handshake still completes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
effect's default pinger writes a ping every 5s and tears the socket down on
a single missed pong. Over lossy/reordering links (e.g. WireGuard/Tailscale)
that churns the UI WebSocket and causes reconnect flapping.
Patch `makePinger` to:
- ping every 15s instead of 5s, and
- only fail after 3 consecutive missed pongs (`MAX_MISSED_PONGS`) instead of 1,
tracked via a `missedPongs` counter that resets on pong.
The patch also threads optional `onPing`/`onPong` connection hooks through the
pinger. Regenerated `patches/effect@4.0.0-beta.78.patch` and updated the
`patch_hash` references in `pnpm-lock.yaml`. See pingdotgg#3054.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename every workflow file under .github/workflows/ to a `.yml.disabled`
suffix so GitHub Actions no longer recognizes them. This stops all
automatic runs on the fork — including the scheduled `Release` job (which
runs every 3 hours and keeps queuing), CI on push/PR, deploy-relay,
issue-labels, mobile EAS preview, and the pr-size / pr-vouch
`pull_request_target` jobs.
Pure renames with no content changes, so re-enabling is just renaming the
files back to `.yml`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate session/load replay before prompting, recover orphaned provider sessions
on startup, sync active turn state from lifecycle events, and reset assistant
segments in-place when item.started replays within the same turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Cursor reuses provider item ids across turns after restart, append
assistant output to a new turn-scoped message at the end of the thread
instead of mutating an earlier completed message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve Grok adapter resume semantics, xAI ACP extension replay behavior,
and provider runtime turn tracking tests so resumed Grok sessions stay
consistent across restarts.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actionsgithub-actionsBot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 7, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@justingray0
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(grok): harden ACP resume and session lifecycle handling - #11

Open
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume
Open

fix(grok): harden ACP resume and session lifecycle handling#11
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume

Conversation

@justingray0

Copy link
Copy Markdown
Owner

Summary

  • Harden Grok ACP resume/replay handling in XAiAcpExtension, GrokAdapter, and GrokAcpSupport.
  • Align Grok text generation and mock-agent scenarios with resumed session behavior.
  • Add provider runtime lifecycle coverage for activeTurnId sync and JSON-RPC edge cases.

Extracted from the earlier wip/grok-resume-fixes work on top of the merged Cursor resume fixes (#9, #10).

Test plan

  • vp test apps/server/src/provider/acp/XAiAcpExtension.test.ts
  • vp test apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts
  • vp test apps/server/src/provider/Layers/ProviderService.test.ts
  • vp check

Made with Cursor

justingray0and others added 9 commits June 29, 2026 06:52
When Tailscale Serve is enabled it proxies the loopback-bound backend onto
the tailnet, so the server is reachable from other devices even though
`config.host` stays on 127.0.0.1. Previously the auth policy keyed solely
off the bind host and selected a local-only policy in that case, skipping
the one-time-token bootstrap required for remote access.
Treat the server as remote-reachable whenever `tailscaleServeEnabled` is
set, in addition to the existing wildcard / non-loopback host checks, so
remote clients get the `remote-reachable` policy with one-time-token
bootstrap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resuming a grok session against a different working directory than the one
the cursor was recorded in produces a stale/invalid resume, so a thread that
moves to a new worktree must start a fresh session instead of replaying the
old cursor.
- ProviderCommandReactor: when the preferred provider is grok and the cwd
changed, pass an explicit `null` resume cursor (a "discard" sentinel,
distinct from `undefined` which means "use the persisted cursor") when
restarting the session, and log `shouldDiscardResumeCursorForCwdChange`.
- ProviderService: honor the `null` sentinel by dropping the cursor, and
independently refuse to reuse a persisted cursor when an explicit `cwd`
differs from the persisted one. Persisted cwd lookup is hoisted so both
the cursor-reuse guard and `effectiveCwd` share it.
Adds reactor- and service-level regression tests covering the
worktree/cwd-change paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ake stall
The RpcClient and raw ext requests only ever mint numeric request ids, so a
response whose id is not a base-10 number cannot match anything we sent. Some
agents (notably grok) emit unsolicited JSON-RPC responses with symbolic ids
such as "skills-reload" right after `initialize`. Forwarding those to the
RpcClient made it fail while resolving the id, tearing down the response loop
so that subsequent `authenticate` and `session/new` responses were never
delivered and the handshake stalled until the caller timed out.
Route untracked responses through a `forwardUntrackedResponse` guard that only
forwards ids matching `^[0-9]+$` and otherwise drops them with a debug log.
Applies to both the exit-encoded and success/defect response paths.
Adds an in-memory regression test that floods the stream with
`skills-reload` responses after `initialize` and asserts the
initialize/authenticate/session handshake still completes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
effect's default pinger writes a ping every 5s and tears the socket down on
a single missed pong. Over lossy/reordering links (e.g. WireGuard/Tailscale)
that churns the UI WebSocket and causes reconnect flapping.
Patch `makePinger` to:
- ping every 15s instead of 5s, and
- only fail after 3 consecutive missed pongs (`MAX_MISSED_PONGS`) instead of 1,
tracked via a `missedPongs` counter that resets on pong.
The patch also threads optional `onPing`/`onPong` connection hooks through the
pinger. Regenerated `patches/effect@4.0.0-beta.78.patch` and updated the
`patch_hash` references in `pnpm-lock.yaml`. See pingdotgg#3054.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename every workflow file under .github/workflows/ to a `.yml.disabled`
suffix so GitHub Actions no longer recognizes them. This stops all
automatic runs on the fork — including the scheduled `Release` job (which
runs every 3 hours and keeps queuing), CI on push/PR, deploy-relay,
issue-labels, mobile EAS preview, and the pr-size / pr-vouch
`pull_request_target` jobs.
Pure renames with no content changes, so re-enabling is just renaming the
files back to `.yml`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate session/load replay before prompting, recover orphaned provider sessions
on startup, sync active turn state from lifecycle events, and reset assistant
segments in-place when item.started replays within the same turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Cursor reuses provider item ids across turns after restart, append
assistant output to a new turn-scoped message at the end of the thread
instead of mutating an earlier completed message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve Grok adapter resume semantics, xAI ACP extension replay behavior,
and provider runtime turn tracking tests so resumed Grok sessions stay
consistent across restarts.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actionsgithub-actionsBot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 7, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@justingray0
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(grok): harden ACP resume and session lifecycle handling - #11

Open
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume
Open

fix(grok): harden ACP resume and session lifecycle handling#11
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume

Conversation

@justingray0

Copy link
Copy Markdown
Owner

Summary

  • Harden Grok ACP resume/replay handling in XAiAcpExtension, GrokAdapter, and GrokAcpSupport.
  • Align Grok text generation and mock-agent scenarios with resumed session behavior.
  • Add provider runtime lifecycle coverage for activeTurnId sync and JSON-RPC edge cases.

Extracted from the earlier wip/grok-resume-fixes work on top of the merged Cursor resume fixes (#9, #10).

Test plan

  • vp test apps/server/src/provider/acp/XAiAcpExtension.test.ts
  • vp test apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts
  • vp test apps/server/src/provider/Layers/ProviderService.test.ts
  • vp check

Made with Cursor

justingray0and others added 9 commits June 29, 2026 06:52
When Tailscale Serve is enabled it proxies the loopback-bound backend onto
the tailnet, so the server is reachable from other devices even though
`config.host` stays on 127.0.0.1. Previously the auth policy keyed solely
off the bind host and selected a local-only policy in that case, skipping
the one-time-token bootstrap required for remote access.
Treat the server as remote-reachable whenever `tailscaleServeEnabled` is
set, in addition to the existing wildcard / non-loopback host checks, so
remote clients get the `remote-reachable` policy with one-time-token
bootstrap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resuming a grok session against a different working directory than the one
the cursor was recorded in produces a stale/invalid resume, so a thread that
moves to a new worktree must start a fresh session instead of replaying the
old cursor.
- ProviderCommandReactor: when the preferred provider is grok and the cwd
changed, pass an explicit `null` resume cursor (a "discard" sentinel,
distinct from `undefined` which means "use the persisted cursor") when
restarting the session, and log `shouldDiscardResumeCursorForCwdChange`.
- ProviderService: honor the `null` sentinel by dropping the cursor, and
independently refuse to reuse a persisted cursor when an explicit `cwd`
differs from the persisted one. Persisted cwd lookup is hoisted so both
the cursor-reuse guard and `effectiveCwd` share it.
Adds reactor- and service-level regression tests covering the
worktree/cwd-change paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ake stall
The RpcClient and raw ext requests only ever mint numeric request ids, so a
response whose id is not a base-10 number cannot match anything we sent. Some
agents (notably grok) emit unsolicited JSON-RPC responses with symbolic ids
such as "skills-reload" right after `initialize`. Forwarding those to the
RpcClient made it fail while resolving the id, tearing down the response loop
so that subsequent `authenticate` and `session/new` responses were never
delivered and the handshake stalled until the caller timed out.
Route untracked responses through a `forwardUntrackedResponse` guard that only
forwards ids matching `^[0-9]+$` and otherwise drops them with a debug log.
Applies to both the exit-encoded and success/defect response paths.
Adds an in-memory regression test that floods the stream with
`skills-reload` responses after `initialize` and asserts the
initialize/authenticate/session handshake still completes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
effect's default pinger writes a ping every 5s and tears the socket down on
a single missed pong. Over lossy/reordering links (e.g. WireGuard/Tailscale)
that churns the UI WebSocket and causes reconnect flapping.
Patch `makePinger` to:
- ping every 15s instead of 5s, and
- only fail after 3 consecutive missed pongs (`MAX_MISSED_PONGS`) instead of 1,
tracked via a `missedPongs` counter that resets on pong.
The patch also threads optional `onPing`/`onPong` connection hooks through the
pinger. Regenerated `patches/effect@4.0.0-beta.78.patch` and updated the
`patch_hash` references in `pnpm-lock.yaml`. See pingdotgg#3054.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename every workflow file under .github/workflows/ to a `.yml.disabled`
suffix so GitHub Actions no longer recognizes them. This stops all
automatic runs on the fork — including the scheduled `Release` job (which
runs every 3 hours and keeps queuing), CI on push/PR, deploy-relay,
issue-labels, mobile EAS preview, and the pr-size / pr-vouch
`pull_request_target` jobs.
Pure renames with no content changes, so re-enabling is just renaming the
files back to `.yml`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate session/load replay before prompting, recover orphaned provider sessions
on startup, sync active turn state from lifecycle events, and reset assistant
segments in-place when item.started replays within the same turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Cursor reuses provider item ids across turns after restart, append
assistant output to a new turn-scoped message at the end of the thread
instead of mutating an earlier completed message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve Grok adapter resume semantics, xAI ACP extension replay behavior,
and provider runtime turn tracking tests so resumed Grok sessions stay
consistent across restarts.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actionsgithub-actionsBot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 7, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@justingray0
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(grok): harden ACP resume and session lifecycle handling - #11

Open
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume
Open

fix(grok): harden ACP resume and session lifecycle handling#11
justingray0 wants to merge 9 commits into
mainfrom
fix/grok-acp-resume

Conversation

@justingray0

Copy link
Copy Markdown
Owner

Summary

  • Harden Grok ACP resume/replay handling in XAiAcpExtension, GrokAdapter, and GrokAcpSupport.
  • Align Grok text generation and mock-agent scenarios with resumed session behavior.
  • Add provider runtime lifecycle coverage for activeTurnId sync and JSON-RPC edge cases.

Extracted from the earlier wip/grok-resume-fixes work on top of the merged Cursor resume fixes (#9, #10).

Test plan

  • vp test apps/server/src/provider/acp/XAiAcpExtension.test.ts
  • vp test apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts
  • vp test apps/server/src/provider/Layers/ProviderService.test.ts
  • vp check

Made with Cursor

justingray0and others added 9 commits June 29, 2026 06:52
When Tailscale Serve is enabled it proxies the loopback-bound backend onto
the tailnet, so the server is reachable from other devices even though
`config.host` stays on 127.0.0.1. Previously the auth policy keyed solely
off the bind host and selected a local-only policy in that case, skipping
the one-time-token bootstrap required for remote access.
Treat the server as remote-reachable whenever `tailscaleServeEnabled` is
set, in addition to the existing wildcard / non-loopback host checks, so
remote clients get the `remote-reachable` policy with one-time-token
bootstrap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resuming a grok session against a different working directory than the one
the cursor was recorded in produces a stale/invalid resume, so a thread that
moves to a new worktree must start a fresh session instead of replaying the
old cursor.
- ProviderCommandReactor: when the preferred provider is grok and the cwd
changed, pass an explicit `null` resume cursor (a "discard" sentinel,
distinct from `undefined` which means "use the persisted cursor") when
restarting the session, and log `shouldDiscardResumeCursorForCwdChange`.
- ProviderService: honor the `null` sentinel by dropping the cursor, and
independently refuse to reuse a persisted cursor when an explicit `cwd`
differs from the persisted one. Persisted cwd lookup is hoisted so both
the cursor-reuse guard and `effectiveCwd` share it.
Adds reactor- and service-level regression tests covering the
worktree/cwd-change paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ake stall
The RpcClient and raw ext requests only ever mint numeric request ids, so a
response whose id is not a base-10 number cannot match anything we sent. Some
agents (notably grok) emit unsolicited JSON-RPC responses with symbolic ids
such as "skills-reload" right after `initialize`. Forwarding those to the
RpcClient made it fail while resolving the id, tearing down the response loop
so that subsequent `authenticate` and `session/new` responses were never
delivered and the handshake stalled until the caller timed out.
Route untracked responses through a `forwardUntrackedResponse` guard that only
forwards ids matching `^[0-9]+$` and otherwise drops them with a debug log.
Applies to both the exit-encoded and success/defect response paths.
Adds an in-memory regression test that floods the stream with
`skills-reload` responses after `initialize` and asserts the
initialize/authenticate/session handshake still completes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
effect's default pinger writes a ping every 5s and tears the socket down on
a single missed pong. Over lossy/reordering links (e.g. WireGuard/Tailscale)
that churns the UI WebSocket and causes reconnect flapping.
Patch `makePinger` to:
- ping every 15s instead of 5s, and
- only fail after 3 consecutive missed pongs (`MAX_MISSED_PONGS`) instead of 1,
tracked via a `missedPongs` counter that resets on pong.
The patch also threads optional `onPing`/`onPong` connection hooks through the
pinger. Regenerated `patches/effect@4.0.0-beta.78.patch` and updated the
`patch_hash` references in `pnpm-lock.yaml`. See pingdotgg#3054.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rename every workflow file under .github/workflows/ to a `.yml.disabled`
suffix so GitHub Actions no longer recognizes them. This stops all
automatic runs on the fork — including the scheduled `Release` job (which
runs every 3 hours and keeps queuing), CI on push/PR, deploy-relay,
issue-labels, mobile EAS preview, and the pr-size / pr-vouch
`pull_request_target` jobs.
Pure renames with no content changes, so re-enabling is just renaming the
files back to `.yml`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Gate session/load replay before prompting, recover orphaned provider sessions
on startup, sync active turn state from lifecycle events, and reset assistant
segments in-place when item.started replays within the same turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Cursor reuses provider item ids across turns after restart, append
assistant output to a new turn-scoped message at the end of the thread
instead of mutating an earlier completed message.
Co-authored-by: Cursor <cursoragent@cursor.com>
Improve Grok adapter resume semantics, xAI ACP extension replay behavior,
and provider runtime turn tracking tests so resumed Grok sessions stay
consistent across restarts.
Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actionsgithub-actionsBot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Aug 7, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@justingray0