fix(server): full-access OpenCode threads no longer ask for approvals - #9282

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals
Sep 3, 2026
Merged

fix(server): full-access OpenCode threads no longer ask for approvals#9282
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals

Conversation

@shivamhwp

@shivamhwpshivamhwp commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

A user reported that OpenCode threads set to full access still pop approval dialogs. I reproduced it live against OpenCode 1.18.26 with a ChatGPT subscription. Ordinary tool calls are fine, but two paths in OpenCode ignore the session-level allow we send:

  • Doom loop. When the model repeats the same tool call three times, OpenCode evaluates the ask against the agent ruleset only, so our wildcard allow is never consulted. This showed up in the UI as an "unknown" approval.
  • Subagents. Child sessions spawned by the task tool keep only deny and external-directory rules from the parent, so a subagent reading *.env or hitting any agent default prompts. Since fix(opencode): handle child approvals, stops, and model catalogs #8480 routes child asks to the thread, this also shows a dialog.

Both are upstream OpenCode behavior, and full access means the user already said yes. The adapter now answers any permission ask that arrives while the session is in full access, and swallows the matching replied event so nothing reaches the UI. If the reply call fails, it falls back to showing the approval as before. Other modes are untouched.

The reply is "once", not "always". OpenCode stores "always" grants per directory, so on a shared external server an "always" from a full-access thread would widen what a supervised thread on the same directory is allowed to do.

Product note. Auto-answering the doom-loop ask means a full-access thread can repeat the same tool call without a guard. That matches what the docs promise for full access ("runs unattended") and what Codex and Claude do today, so it is intentional.

Tests cover the doom-loop ask on the parent session, a child-session ask, the failed-reply fallback, and a failed reply whose terminal event landed while the reply was in flight. The final ordering change (no yield between the terminal check and the publish) is a scheduler-interleaving race that the mock cannot reproduce deterministically, so it has no dedicated test.

Work done by Claude Fable 5.1 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes permission handling and event emission for full-access OpenCode sessions; incorrect suppression or fallback could hide needed approvals or leave stuck dialogs, though other runtime modes are unchanged and tests cover key races.

Overview
Full-access OpenCode threads no longer surface approval dialogs for permission asks that upstream ignores the session ruleset on—doom-loop detection and subagent sessions. The adapter calls permission.reply with once (not always, to avoid widening grants for other threads on a shared directory), tracks auto-replied IDs, and suppresses matching request.opened / request.resolved UI events. If the SDK reply fails, behavior falls back to showing the approval dialog; failed in-flight replies after a terminal event must not reopen the request.

Implementation adds autoReplyFullAccess, autoRepliedRequestIds, and emitUnsafe so request.opened is not published after a terminal permission.replied lands between an async check and enqueue. Tests extend the mock with a configurable permission-reply hook and cover auto-approve (parent doom-loop + child session), reply failure fallback, and terminal/reply ordering. Docs note why full-access auto-answers these asks and why replies use once.

Reviewed by Cursor Bugbot for commit 4d250db. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix full-access OpenCode threads to auto-approve permissions without dialogs

  • Full-access sessions now automatically reply once to permission asks (doom-loop and subagent) instead of surfacing an approval dialog, using a one-time grant rather than a persistent directory-scoped grant
  • A synchronous enqueue helper (emitUnsafe) prevents an async gap between the terminal-event check and publishing request.opened, eliminating a race where a terminal reply arrives during event construction
  • Failed auto-replies remove the auto-reply marker but keep a resolved marker so the request falls through to the dialog without reopening from recovered duplicate asks; terminal events for successful auto-replies are swallowed (no request.resolved)
  • Behavioral Change: emitTerminalOpenCodeRequest now suppresses terminal events for request IDs in the auto-reply set; reviewers should verify that no request.resolved or request.opened is emitted for successfully auto-replied asks in OpenCodeAdapter.ts
  • Documents full-access adapter behavior in providers.md

Macroscope summarized 4d250db.

OpenCode ignores the session ruleset for doom-loop checks and drops the
parent's wildcard allow when it spawns subagent sessions, so full-access
threads still surfaced approval dialogs for those asks. Auto-reply
"always" to any permission ask while the session is in full access and
swallow the matching replied event, falling back to the dialog if the
reply call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The server now automatically grants and suppresses OpenCode permission requests in full-access sessions, including requests that bypass upstream rules and the doom-loop safeguard. This is a localized, tested change, but it materially alters production authorization behavior and its side effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

A retry or recovery fiber could re-enter the pending-request path, or the
matching permission.replied could land, while the auto-reply SDK call was
still in flight. That raced to emit a duplicate request.opened or a stray
request.resolved. Record the resolved and auto-replied ids synchronously
before awaiting, and roll them back if the reply fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
shivamhwpand others added 3 commits September 2, 2026 23:25
… resolved
If the auto-reply SDK call fails locally but OpenCode still resolved the
permission, the terminal permission.replied lands and is swallowed while the
reply is in flight, consuming the terminal slot. The failure path then rolled
back and opened a dialog that could never resolve. Guard the fallback: if the
terminal event already landed, keep the request resolved and do not reopen it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guard against a regression where the fallback retries the reply instead of
surfacing the dialog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ace0116. Configure here.

Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts
shivamhwpand others added 2 commits September 3, 2026 04:57
…its terminal check
On a retry or recovery fiber, the event pump can deliver the terminal
permission.replied between the emittedTerminalRequestIds check and the
request.opened offer, so request.resolved lands first and the fallback
dialog can never close. Build the event first, then check and offer in one
synchronous step. The failed auto-reply also keeps the id in
resolvedRequestIds: pendingPermissions already gates re-asks while the
dialog is open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o-reply path
OpenCode stores "always" grants per directory, not per session. On a shared
external server an "always" from a full-access thread would silently widen
what a supervised thread on the same directory is allowed to do, so reply
"once" instead. Every ask in full access is auto-answered anyway.
Also extract the full-access branch into autoReplyFullAccess so the id
bookkeeping has a name and a boundary, add an emitUnsafe sibling next to
emit for the one publish that must not yield after its terminal check,
collapse the two identical auto-approve tests into one parameterized case,
and note the upstream ruleset quirk in the provider internals doc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@shivamhwp

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the review in 605dcff.

  1. Reply is now "once". Confirmed against upstream Permission.reply: it returns before touching the per-directory approved list on "once" and appends to it on "always".
  2. Full-access branch extracted into autoReplyFullAccess returning replied | fallback | already-terminal. Added emitUnsafe next to emit with the one-line reason. Comments trimmed to the why.
  3. Tests 1 and 2 collapsed into one it.effect.each case. Sentinel is commented. The blind yieldNow pair in test 4 is replaced with a single microtask drain. PR body now says the final ordering change has no dedicated test.
  4. One line added to docs/internals/providers.md on the upstream ruleset quirk.

PR body rewritten: bot summary blocks removed, doom-loop product decision stated explicitly.

shivamhwpand others added 2 commits September 3, 2026 13:26
…back
autoReplyFullAccess returned a tri-state whose "already-terminal" branch
duplicated the emittedTerminalRequestIds check the caller performs right
before publishing. Only the publish-site check is load-bearing, since it
must sit next to the enqueue with no yield in between, so the helper now
returns whether the reply landed and the caller keeps the one guard.
Also moves the internals note out of "Attachment access", where it was
tacked onto a paragraph about attachment directories, into the OpenCode
section beside the existing per-directory MCP note, and records the
"once" rationale there.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@juliusmarminge
juliusmarminge enabled auto-merge (squash) September 3, 2026 20:37
@juliusmarminge
juliusmarminge merged commit d2b6f3b into pingdotgg:mainSep 3, 2026
25 checks passed
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(web): make right panel tabs easier to scroll by @maria-rcks in pingdotgg/t3code#9461
* fix(web): render transparent previews on white by @UtkarshUsername in pingdotgg/t3code#9463
* fix(mobile): show loading and syncing in the working pill by @juliusmarminge in pingdotgg/t3code#9466
* fix(server): keep a/ and b/ prefixes in rendered git patches by @Mnigos in pingdotgg/t3code#9438
* fix(server): full-access OpenCode threads no longer ask for approvals by @shivamhwp in pingdotgg/t3code#9282
* fix(web): reuse pull request list data while loading by @maria-rcks in pingdotgg/t3code#9467
* feat(web): let users turn off composer collapse on blur and scroll by @juliusmarminge in pingdotgg/t3code#9469
## New Contributors
* @Mnigos made their first contribution in pingdotgg/t3code#9438
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1272...v0.0.39-nightly.20260903.1273
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1273
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 4, 2026
…ity ACP, browser import, settings reorg, limits tab)
Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity
via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie
import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg
(pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context
compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access
OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457).
Unification decisions (keep-both unless noted):
- BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI
unwrap, writeCookies); fork's Safari engine ported in (jar definition,
candidate path, profile listing, running check, count skip, import branch,
FullDiskAccess wizard step + SafariCookies kept, domain widened only for
dotted hosts).
- Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding
ported (providerDisabledMessage), AntigravitySettings unified (fork fields +
upstream auth fields; enabled stays default-on).
- contracts/model: Antigravity defaults follow upstream's manifest model.
- ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to
upstream's compactedUsage to match downstream.
- Claude capabilities probe: fork's timeout races kept; upstream's raw usage
fetch added under the same timeout so stalled usage still degrades.
- Codex provider: upstream's withCodexAppServerClient + enriched rate-limits
probe win (fork title branding already inside buildCodexInitializeParams).
- ProviderCommandReactor: fork goal-continuation + correction-aware first-turn
kept; upstream compact-command exclusion added.
- OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept;
upstream full-access autoReply + terminal guard + emitUnsafe added.
- makeManagedServerProvider: fork probe-timeout protection kept; upstream
usage-limits reconciliation applied to the checked snapshot.
- Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept;
upstream wcDebugger hardening applied.
- mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers
loading/sync presentation); outbox deliveryMode + goal handling kept.
- Usage: fork client-version projection kept; upstream pricing()/refreshRates
adopted on both clients.
- Settings: fork sections (MT Teams+badge, voice, notifications, account
sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted.
- README: fork copy kept; Antigravity added to provider lists.
- Cursor skill test macOS /var-vs-/private/var path failure is pre-existing
upstream breakage, unrelated to this merge.
Fork guard script OK.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).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.

2 participants

@shivamhwp@juliusmarminge
, '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(server): full-access OpenCode threads no longer ask for approvals - #9282

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals
Sep 3, 2026
Merged

fix(server): full-access OpenCode threads no longer ask for approvals#9282
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals

Conversation

@shivamhwp

@shivamhwpshivamhwp commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

A user reported that OpenCode threads set to full access still pop approval dialogs. I reproduced it live against OpenCode 1.18.26 with a ChatGPT subscription. Ordinary tool calls are fine, but two paths in OpenCode ignore the session-level allow we send:

  • Doom loop. When the model repeats the same tool call three times, OpenCode evaluates the ask against the agent ruleset only, so our wildcard allow is never consulted. This showed up in the UI as an "unknown" approval.
  • Subagents. Child sessions spawned by the task tool keep only deny and external-directory rules from the parent, so a subagent reading *.env or hitting any agent default prompts. Since fix(opencode): handle child approvals, stops, and model catalogs #8480 routes child asks to the thread, this also shows a dialog.

Both are upstream OpenCode behavior, and full access means the user already said yes. The adapter now answers any permission ask that arrives while the session is in full access, and swallows the matching replied event so nothing reaches the UI. If the reply call fails, it falls back to showing the approval as before. Other modes are untouched.

The reply is "once", not "always". OpenCode stores "always" grants per directory, so on a shared external server an "always" from a full-access thread would widen what a supervised thread on the same directory is allowed to do.

Product note. Auto-answering the doom-loop ask means a full-access thread can repeat the same tool call without a guard. That matches what the docs promise for full access ("runs unattended") and what Codex and Claude do today, so it is intentional.

Tests cover the doom-loop ask on the parent session, a child-session ask, the failed-reply fallback, and a failed reply whose terminal event landed while the reply was in flight. The final ordering change (no yield between the terminal check and the publish) is a scheduler-interleaving race that the mock cannot reproduce deterministically, so it has no dedicated test.

Work done by Claude Fable 5.1 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes permission handling and event emission for full-access OpenCode sessions; incorrect suppression or fallback could hide needed approvals or leave stuck dialogs, though other runtime modes are unchanged and tests cover key races.

Overview
Full-access OpenCode threads no longer surface approval dialogs for permission asks that upstream ignores the session ruleset on—doom-loop detection and subagent sessions. The adapter calls permission.reply with once (not always, to avoid widening grants for other threads on a shared directory), tracks auto-replied IDs, and suppresses matching request.opened / request.resolved UI events. If the SDK reply fails, behavior falls back to showing the approval dialog; failed in-flight replies after a terminal event must not reopen the request.

Implementation adds autoReplyFullAccess, autoRepliedRequestIds, and emitUnsafe so request.opened is not published after a terminal permission.replied lands between an async check and enqueue. Tests extend the mock with a configurable permission-reply hook and cover auto-approve (parent doom-loop + child session), reply failure fallback, and terminal/reply ordering. Docs note why full-access auto-answers these asks and why replies use once.

Reviewed by Cursor Bugbot for commit 4d250db. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix full-access OpenCode threads to auto-approve permissions without dialogs

  • Full-access sessions now automatically reply once to permission asks (doom-loop and subagent) instead of surfacing an approval dialog, using a one-time grant rather than a persistent directory-scoped grant
  • A synchronous enqueue helper (emitUnsafe) prevents an async gap between the terminal-event check and publishing request.opened, eliminating a race where a terminal reply arrives during event construction
  • Failed auto-replies remove the auto-reply marker but keep a resolved marker so the request falls through to the dialog without reopening from recovered duplicate asks; terminal events for successful auto-replies are swallowed (no request.resolved)
  • Behavioral Change: emitTerminalOpenCodeRequest now suppresses terminal events for request IDs in the auto-reply set; reviewers should verify that no request.resolved or request.opened is emitted for successfully auto-replied asks in OpenCodeAdapter.ts
  • Documents full-access adapter behavior in providers.md

Macroscope summarized 4d250db.

OpenCode ignores the session ruleset for doom-loop checks and drops the
parent's wildcard allow when it spawns subagent sessions, so full-access
threads still surfaced approval dialogs for those asks. Auto-reply
"always" to any permission ask while the session is in full access and
swallow the matching replied event, falling back to the dialog if the
reply call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The server now automatically grants and suppresses OpenCode permission requests in full-access sessions, including requests that bypass upstream rules and the doom-loop safeguard. This is a localized, tested change, but it materially alters production authorization behavior and its side effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

A retry or recovery fiber could re-enter the pending-request path, or the
matching permission.replied could land, while the auto-reply SDK call was
still in flight. That raced to emit a duplicate request.opened or a stray
request.resolved. Record the resolved and auto-replied ids synchronously
before awaiting, and roll them back if the reply fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
shivamhwpand others added 3 commits September 2, 2026 23:25
… resolved
If the auto-reply SDK call fails locally but OpenCode still resolved the
permission, the terminal permission.replied lands and is swallowed while the
reply is in flight, consuming the terminal slot. The failure path then rolled
back and opened a dialog that could never resolve. Guard the fallback: if the
terminal event already landed, keep the request resolved and do not reopen it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guard against a regression where the fallback retries the reply instead of
surfacing the dialog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ace0116. Configure here.

Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts
shivamhwpand others added 2 commits September 3, 2026 04:57
…its terminal check
On a retry or recovery fiber, the event pump can deliver the terminal
permission.replied between the emittedTerminalRequestIds check and the
request.opened offer, so request.resolved lands first and the fallback
dialog can never close. Build the event first, then check and offer in one
synchronous step. The failed auto-reply also keeps the id in
resolvedRequestIds: pendingPermissions already gates re-asks while the
dialog is open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o-reply path
OpenCode stores "always" grants per directory, not per session. On a shared
external server an "always" from a full-access thread would silently widen
what a supervised thread on the same directory is allowed to do, so reply
"once" instead. Every ask in full access is auto-answered anyway.
Also extract the full-access branch into autoReplyFullAccess so the id
bookkeeping has a name and a boundary, add an emitUnsafe sibling next to
emit for the one publish that must not yield after its terminal check,
collapse the two identical auto-approve tests into one parameterized case,
and note the upstream ruleset quirk in the provider internals doc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@shivamhwp

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the review in 605dcff.

  1. Reply is now "once". Confirmed against upstream Permission.reply: it returns before touching the per-directory approved list on "once" and appends to it on "always".
  2. Full-access branch extracted into autoReplyFullAccess returning replied | fallback | already-terminal. Added emitUnsafe next to emit with the one-line reason. Comments trimmed to the why.
  3. Tests 1 and 2 collapsed into one it.effect.each case. Sentinel is commented. The blind yieldNow pair in test 4 is replaced with a single microtask drain. PR body now says the final ordering change has no dedicated test.
  4. One line added to docs/internals/providers.md on the upstream ruleset quirk.

PR body rewritten: bot summary blocks removed, doom-loop product decision stated explicitly.

shivamhwpand others added 2 commits September 3, 2026 13:26
…back
autoReplyFullAccess returned a tri-state whose "already-terminal" branch
duplicated the emittedTerminalRequestIds check the caller performs right
before publishing. Only the publish-site check is load-bearing, since it
must sit next to the enqueue with no yield in between, so the helper now
returns whether the reply landed and the caller keeps the one guard.
Also moves the internals note out of "Attachment access", where it was
tacked onto a paragraph about attachment directories, into the OpenCode
section beside the existing per-directory MCP note, and records the
"once" rationale there.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@juliusmarminge
juliusmarminge enabled auto-merge (squash) September 3, 2026 20:37
@juliusmarminge
juliusmarminge merged commit d2b6f3b into pingdotgg:mainSep 3, 2026
25 checks passed
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(web): make right panel tabs easier to scroll by @maria-rcks in pingdotgg/t3code#9461
* fix(web): render transparent previews on white by @UtkarshUsername in pingdotgg/t3code#9463
* fix(mobile): show loading and syncing in the working pill by @juliusmarminge in pingdotgg/t3code#9466
* fix(server): keep a/ and b/ prefixes in rendered git patches by @Mnigos in pingdotgg/t3code#9438
* fix(server): full-access OpenCode threads no longer ask for approvals by @shivamhwp in pingdotgg/t3code#9282
* fix(web): reuse pull request list data while loading by @maria-rcks in pingdotgg/t3code#9467
* feat(web): let users turn off composer collapse on blur and scroll by @juliusmarminge in pingdotgg/t3code#9469
## New Contributors
* @Mnigos made their first contribution in pingdotgg/t3code#9438
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1272...v0.0.39-nightly.20260903.1273
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1273
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 4, 2026
…ity ACP, browser import, settings reorg, limits tab)
Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity
via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie
import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg
(pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context
compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access
OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457).
Unification decisions (keep-both unless noted):
- BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI
unwrap, writeCookies); fork's Safari engine ported in (jar definition,
candidate path, profile listing, running check, count skip, import branch,
FullDiskAccess wizard step + SafariCookies kept, domain widened only for
dotted hosts).
- Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding
ported (providerDisabledMessage), AntigravitySettings unified (fork fields +
upstream auth fields; enabled stays default-on).
- contracts/model: Antigravity defaults follow upstream's manifest model.
- ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to
upstream's compactedUsage to match downstream.
- Claude capabilities probe: fork's timeout races kept; upstream's raw usage
fetch added under the same timeout so stalled usage still degrades.
- Codex provider: upstream's withCodexAppServerClient + enriched rate-limits
probe win (fork title branding already inside buildCodexInitializeParams).
- ProviderCommandReactor: fork goal-continuation + correction-aware first-turn
kept; upstream compact-command exclusion added.
- OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept;
upstream full-access autoReply + terminal guard + emitUnsafe added.
- makeManagedServerProvider: fork probe-timeout protection kept; upstream
usage-limits reconciliation applied to the checked snapshot.
- Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept;
upstream wcDebugger hardening applied.
- mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers
loading/sync presentation); outbox deliveryMode + goal handling kept.
- Usage: fork client-version projection kept; upstream pricing()/refreshRates
adopted on both clients.
- Settings: fork sections (MT Teams+badge, voice, notifications, account
sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted.
- README: fork copy kept; Antigravity added to provider lists.
- Cursor skill test macOS /var-vs-/private/var path failure is pre-existing
upstream breakage, unrelated to this merge.
Fork guard script OK.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).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.

2 participants

@shivamhwp@juliusmarminge
, '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(server): full-access OpenCode threads no longer ask for approvals - #9282

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals
Sep 3, 2026
Merged

fix(server): full-access OpenCode threads no longer ask for approvals#9282
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals

Conversation

@shivamhwp

@shivamhwpshivamhwp commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

A user reported that OpenCode threads set to full access still pop approval dialogs. I reproduced it live against OpenCode 1.18.26 with a ChatGPT subscription. Ordinary tool calls are fine, but two paths in OpenCode ignore the session-level allow we send:

  • Doom loop. When the model repeats the same tool call three times, OpenCode evaluates the ask against the agent ruleset only, so our wildcard allow is never consulted. This showed up in the UI as an "unknown" approval.
  • Subagents. Child sessions spawned by the task tool keep only deny and external-directory rules from the parent, so a subagent reading *.env or hitting any agent default prompts. Since fix(opencode): handle child approvals, stops, and model catalogs #8480 routes child asks to the thread, this also shows a dialog.

Both are upstream OpenCode behavior, and full access means the user already said yes. The adapter now answers any permission ask that arrives while the session is in full access, and swallows the matching replied event so nothing reaches the UI. If the reply call fails, it falls back to showing the approval as before. Other modes are untouched.

The reply is "once", not "always". OpenCode stores "always" grants per directory, so on a shared external server an "always" from a full-access thread would widen what a supervised thread on the same directory is allowed to do.

Product note. Auto-answering the doom-loop ask means a full-access thread can repeat the same tool call without a guard. That matches what the docs promise for full access ("runs unattended") and what Codex and Claude do today, so it is intentional.

Tests cover the doom-loop ask on the parent session, a child-session ask, the failed-reply fallback, and a failed reply whose terminal event landed while the reply was in flight. The final ordering change (no yield between the terminal check and the publish) is a scheduler-interleaving race that the mock cannot reproduce deterministically, so it has no dedicated test.

Work done by Claude Fable 5.1 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes permission handling and event emission for full-access OpenCode sessions; incorrect suppression or fallback could hide needed approvals or leave stuck dialogs, though other runtime modes are unchanged and tests cover key races.

Overview
Full-access OpenCode threads no longer surface approval dialogs for permission asks that upstream ignores the session ruleset on—doom-loop detection and subagent sessions. The adapter calls permission.reply with once (not always, to avoid widening grants for other threads on a shared directory), tracks auto-replied IDs, and suppresses matching request.opened / request.resolved UI events. If the SDK reply fails, behavior falls back to showing the approval dialog; failed in-flight replies after a terminal event must not reopen the request.

Implementation adds autoReplyFullAccess, autoRepliedRequestIds, and emitUnsafe so request.opened is not published after a terminal permission.replied lands between an async check and enqueue. Tests extend the mock with a configurable permission-reply hook and cover auto-approve (parent doom-loop + child session), reply failure fallback, and terminal/reply ordering. Docs note why full-access auto-answers these asks and why replies use once.

Reviewed by Cursor Bugbot for commit 4d250db. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix full-access OpenCode threads to auto-approve permissions without dialogs

  • Full-access sessions now automatically reply once to permission asks (doom-loop and subagent) instead of surfacing an approval dialog, using a one-time grant rather than a persistent directory-scoped grant
  • A synchronous enqueue helper (emitUnsafe) prevents an async gap between the terminal-event check and publishing request.opened, eliminating a race where a terminal reply arrives during event construction
  • Failed auto-replies remove the auto-reply marker but keep a resolved marker so the request falls through to the dialog without reopening from recovered duplicate asks; terminal events for successful auto-replies are swallowed (no request.resolved)
  • Behavioral Change: emitTerminalOpenCodeRequest now suppresses terminal events for request IDs in the auto-reply set; reviewers should verify that no request.resolved or request.opened is emitted for successfully auto-replied asks in OpenCodeAdapter.ts
  • Documents full-access adapter behavior in providers.md

Macroscope summarized 4d250db.

OpenCode ignores the session ruleset for doom-loop checks and drops the
parent's wildcard allow when it spawns subagent sessions, so full-access
threads still surfaced approval dialogs for those asks. Auto-reply
"always" to any permission ask while the session is in full access and
swallow the matching replied event, falling back to the dialog if the
reply call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The server now automatically grants and suppresses OpenCode permission requests in full-access sessions, including requests that bypass upstream rules and the doom-loop safeguard. This is a localized, tested change, but it materially alters production authorization behavior and its side effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

A retry or recovery fiber could re-enter the pending-request path, or the
matching permission.replied could land, while the auto-reply SDK call was
still in flight. That raced to emit a duplicate request.opened or a stray
request.resolved. Record the resolved and auto-replied ids synchronously
before awaiting, and roll them back if the reply fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
shivamhwpand others added 3 commits September 2, 2026 23:25
… resolved
If the auto-reply SDK call fails locally but OpenCode still resolved the
permission, the terminal permission.replied lands and is swallowed while the
reply is in flight, consuming the terminal slot. The failure path then rolled
back and opened a dialog that could never resolve. Guard the fallback: if the
terminal event already landed, keep the request resolved and do not reopen it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guard against a regression where the fallback retries the reply instead of
surfacing the dialog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ace0116. Configure here.

Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts
shivamhwpand others added 2 commits September 3, 2026 04:57
…its terminal check
On a retry or recovery fiber, the event pump can deliver the terminal
permission.replied between the emittedTerminalRequestIds check and the
request.opened offer, so request.resolved lands first and the fallback
dialog can never close. Build the event first, then check and offer in one
synchronous step. The failed auto-reply also keeps the id in
resolvedRequestIds: pendingPermissions already gates re-asks while the
dialog is open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o-reply path
OpenCode stores "always" grants per directory, not per session. On a shared
external server an "always" from a full-access thread would silently widen
what a supervised thread on the same directory is allowed to do, so reply
"once" instead. Every ask in full access is auto-answered anyway.
Also extract the full-access branch into autoReplyFullAccess so the id
bookkeeping has a name and a boundary, add an emitUnsafe sibling next to
emit for the one publish that must not yield after its terminal check,
collapse the two identical auto-approve tests into one parameterized case,
and note the upstream ruleset quirk in the provider internals doc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@shivamhwp

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the review in 605dcff.

  1. Reply is now "once". Confirmed against upstream Permission.reply: it returns before touching the per-directory approved list on "once" and appends to it on "always".
  2. Full-access branch extracted into autoReplyFullAccess returning replied | fallback | already-terminal. Added emitUnsafe next to emit with the one-line reason. Comments trimmed to the why.
  3. Tests 1 and 2 collapsed into one it.effect.each case. Sentinel is commented. The blind yieldNow pair in test 4 is replaced with a single microtask drain. PR body now says the final ordering change has no dedicated test.
  4. One line added to docs/internals/providers.md on the upstream ruleset quirk.

PR body rewritten: bot summary blocks removed, doom-loop product decision stated explicitly.

shivamhwpand others added 2 commits September 3, 2026 13:26
…back
autoReplyFullAccess returned a tri-state whose "already-terminal" branch
duplicated the emittedTerminalRequestIds check the caller performs right
before publishing. Only the publish-site check is load-bearing, since it
must sit next to the enqueue with no yield in between, so the helper now
returns whether the reply landed and the caller keeps the one guard.
Also moves the internals note out of "Attachment access", where it was
tacked onto a paragraph about attachment directories, into the OpenCode
section beside the existing per-directory MCP note, and records the
"once" rationale there.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@juliusmarminge
juliusmarminge enabled auto-merge (squash) September 3, 2026 20:37
@juliusmarminge
juliusmarminge merged commit d2b6f3b into pingdotgg:mainSep 3, 2026
25 checks passed
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(web): make right panel tabs easier to scroll by @maria-rcks in pingdotgg/t3code#9461
* fix(web): render transparent previews on white by @UtkarshUsername in pingdotgg/t3code#9463
* fix(mobile): show loading and syncing in the working pill by @juliusmarminge in pingdotgg/t3code#9466
* fix(server): keep a/ and b/ prefixes in rendered git patches by @Mnigos in pingdotgg/t3code#9438
* fix(server): full-access OpenCode threads no longer ask for approvals by @shivamhwp in pingdotgg/t3code#9282
* fix(web): reuse pull request list data while loading by @maria-rcks in pingdotgg/t3code#9467
* feat(web): let users turn off composer collapse on blur and scroll by @juliusmarminge in pingdotgg/t3code#9469
## New Contributors
* @Mnigos made their first contribution in pingdotgg/t3code#9438
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1272...v0.0.39-nightly.20260903.1273
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1273
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 4, 2026
…ity ACP, browser import, settings reorg, limits tab)
Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity
via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie
import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg
(pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context
compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access
OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457).
Unification decisions (keep-both unless noted):
- BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI
unwrap, writeCookies); fork's Safari engine ported in (jar definition,
candidate path, profile listing, running check, count skip, import branch,
FullDiskAccess wizard step + SafariCookies kept, domain widened only for
dotted hosts).
- Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding
ported (providerDisabledMessage), AntigravitySettings unified (fork fields +
upstream auth fields; enabled stays default-on).
- contracts/model: Antigravity defaults follow upstream's manifest model.
- ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to
upstream's compactedUsage to match downstream.
- Claude capabilities probe: fork's timeout races kept; upstream's raw usage
fetch added under the same timeout so stalled usage still degrades.
- Codex provider: upstream's withCodexAppServerClient + enriched rate-limits
probe win (fork title branding already inside buildCodexInitializeParams).
- ProviderCommandReactor: fork goal-continuation + correction-aware first-turn
kept; upstream compact-command exclusion added.
- OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept;
upstream full-access autoReply + terminal guard + emitUnsafe added.
- makeManagedServerProvider: fork probe-timeout protection kept; upstream
usage-limits reconciliation applied to the checked snapshot.
- Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept;
upstream wcDebugger hardening applied.
- mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers
loading/sync presentation); outbox deliveryMode + goal handling kept.
- Usage: fork client-version projection kept; upstream pricing()/refreshRates
adopted on both clients.
- Settings: fork sections (MT Teams+badge, voice, notifications, account
sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted.
- README: fork copy kept; Antigravity added to provider lists.
- Cursor skill test macOS /var-vs-/private/var path failure is pre-existing
upstream breakage, unrelated to this merge.
Fork guard script OK.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).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.

2 participants

@shivamhwp@juliusmarminge
, '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(server): full-access OpenCode threads no longer ask for approvals - #9282

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals
Sep 3, 2026
Merged

fix(server): full-access OpenCode threads no longer ask for approvals#9282
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals

Conversation

@shivamhwp

@shivamhwpshivamhwp commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

A user reported that OpenCode threads set to full access still pop approval dialogs. I reproduced it live against OpenCode 1.18.26 with a ChatGPT subscription. Ordinary tool calls are fine, but two paths in OpenCode ignore the session-level allow we send:

  • Doom loop. When the model repeats the same tool call three times, OpenCode evaluates the ask against the agent ruleset only, so our wildcard allow is never consulted. This showed up in the UI as an "unknown" approval.
  • Subagents. Child sessions spawned by the task tool keep only deny and external-directory rules from the parent, so a subagent reading *.env or hitting any agent default prompts. Since fix(opencode): handle child approvals, stops, and model catalogs #8480 routes child asks to the thread, this also shows a dialog.

Both are upstream OpenCode behavior, and full access means the user already said yes. The adapter now answers any permission ask that arrives while the session is in full access, and swallows the matching replied event so nothing reaches the UI. If the reply call fails, it falls back to showing the approval as before. Other modes are untouched.

The reply is "once", not "always". OpenCode stores "always" grants per directory, so on a shared external server an "always" from a full-access thread would widen what a supervised thread on the same directory is allowed to do.

Product note. Auto-answering the doom-loop ask means a full-access thread can repeat the same tool call without a guard. That matches what the docs promise for full access ("runs unattended") and what Codex and Claude do today, so it is intentional.

Tests cover the doom-loop ask on the parent session, a child-session ask, the failed-reply fallback, and a failed reply whose terminal event landed while the reply was in flight. The final ordering change (no yield between the terminal check and the publish) is a scheduler-interleaving race that the mock cannot reproduce deterministically, so it has no dedicated test.

Work done by Claude Fable 5.1 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes permission handling and event emission for full-access OpenCode sessions; incorrect suppression or fallback could hide needed approvals or leave stuck dialogs, though other runtime modes are unchanged and tests cover key races.

Overview
Full-access OpenCode threads no longer surface approval dialogs for permission asks that upstream ignores the session ruleset on—doom-loop detection and subagent sessions. The adapter calls permission.reply with once (not always, to avoid widening grants for other threads on a shared directory), tracks auto-replied IDs, and suppresses matching request.opened / request.resolved UI events. If the SDK reply fails, behavior falls back to showing the approval dialog; failed in-flight replies after a terminal event must not reopen the request.

Implementation adds autoReplyFullAccess, autoRepliedRequestIds, and emitUnsafe so request.opened is not published after a terminal permission.replied lands between an async check and enqueue. Tests extend the mock with a configurable permission-reply hook and cover auto-approve (parent doom-loop + child session), reply failure fallback, and terminal/reply ordering. Docs note why full-access auto-answers these asks and why replies use once.

Reviewed by Cursor Bugbot for commit 4d250db. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix full-access OpenCode threads to auto-approve permissions without dialogs

  • Full-access sessions now automatically reply once to permission asks (doom-loop and subagent) instead of surfacing an approval dialog, using a one-time grant rather than a persistent directory-scoped grant
  • A synchronous enqueue helper (emitUnsafe) prevents an async gap between the terminal-event check and publishing request.opened, eliminating a race where a terminal reply arrives during event construction
  • Failed auto-replies remove the auto-reply marker but keep a resolved marker so the request falls through to the dialog without reopening from recovered duplicate asks; terminal events for successful auto-replies are swallowed (no request.resolved)
  • Behavioral Change: emitTerminalOpenCodeRequest now suppresses terminal events for request IDs in the auto-reply set; reviewers should verify that no request.resolved or request.opened is emitted for successfully auto-replied asks in OpenCodeAdapter.ts
  • Documents full-access adapter behavior in providers.md

Macroscope summarized 4d250db.

OpenCode ignores the session ruleset for doom-loop checks and drops the
parent's wildcard allow when it spawns subagent sessions, so full-access
threads still surfaced approval dialogs for those asks. Auto-reply
"always" to any permission ask while the session is in full access and
swallow the matching replied event, falling back to the dialog if the
reply call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The server now automatically grants and suppresses OpenCode permission requests in full-access sessions, including requests that bypass upstream rules and the doom-loop safeguard. This is a localized, tested change, but it materially alters production authorization behavior and its side effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

A retry or recovery fiber could re-enter the pending-request path, or the
matching permission.replied could land, while the auto-reply SDK call was
still in flight. That raced to emit a duplicate request.opened or a stray
request.resolved. Record the resolved and auto-replied ids synchronously
before awaiting, and roll them back if the reply fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
shivamhwpand others added 3 commits September 2, 2026 23:25
… resolved
If the auto-reply SDK call fails locally but OpenCode still resolved the
permission, the terminal permission.replied lands and is swallowed while the
reply is in flight, consuming the terminal slot. The failure path then rolled
back and opened a dialog that could never resolve. Guard the fallback: if the
terminal event already landed, keep the request resolved and do not reopen it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guard against a regression where the fallback retries the reply instead of
surfacing the dialog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ace0116. Configure here.

Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts
shivamhwpand others added 2 commits September 3, 2026 04:57
…its terminal check
On a retry or recovery fiber, the event pump can deliver the terminal
permission.replied between the emittedTerminalRequestIds check and the
request.opened offer, so request.resolved lands first and the fallback
dialog can never close. Build the event first, then check and offer in one
synchronous step. The failed auto-reply also keeps the id in
resolvedRequestIds: pendingPermissions already gates re-asks while the
dialog is open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o-reply path
OpenCode stores "always" grants per directory, not per session. On a shared
external server an "always" from a full-access thread would silently widen
what a supervised thread on the same directory is allowed to do, so reply
"once" instead. Every ask in full access is auto-answered anyway.
Also extract the full-access branch into autoReplyFullAccess so the id
bookkeeping has a name and a boundary, add an emitUnsafe sibling next to
emit for the one publish that must not yield after its terminal check,
collapse the two identical auto-approve tests into one parameterized case,
and note the upstream ruleset quirk in the provider internals doc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@shivamhwp

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the review in 605dcff.

  1. Reply is now "once". Confirmed against upstream Permission.reply: it returns before touching the per-directory approved list on "once" and appends to it on "always".
  2. Full-access branch extracted into autoReplyFullAccess returning replied | fallback | already-terminal. Added emitUnsafe next to emit with the one-line reason. Comments trimmed to the why.
  3. Tests 1 and 2 collapsed into one it.effect.each case. Sentinel is commented. The blind yieldNow pair in test 4 is replaced with a single microtask drain. PR body now says the final ordering change has no dedicated test.
  4. One line added to docs/internals/providers.md on the upstream ruleset quirk.

PR body rewritten: bot summary blocks removed, doom-loop product decision stated explicitly.

shivamhwpand others added 2 commits September 3, 2026 13:26
…back
autoReplyFullAccess returned a tri-state whose "already-terminal" branch
duplicated the emittedTerminalRequestIds check the caller performs right
before publishing. Only the publish-site check is load-bearing, since it
must sit next to the enqueue with no yield in between, so the helper now
returns whether the reply landed and the caller keeps the one guard.
Also moves the internals note out of "Attachment access", where it was
tacked onto a paragraph about attachment directories, into the OpenCode
section beside the existing per-directory MCP note, and records the
"once" rationale there.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@juliusmarminge
juliusmarminge enabled auto-merge (squash) September 3, 2026 20:37
@juliusmarminge
juliusmarminge merged commit d2b6f3b into pingdotgg:mainSep 3, 2026
25 checks passed
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(web): make right panel tabs easier to scroll by @maria-rcks in pingdotgg/t3code#9461
* fix(web): render transparent previews on white by @UtkarshUsername in pingdotgg/t3code#9463
* fix(mobile): show loading and syncing in the working pill by @juliusmarminge in pingdotgg/t3code#9466
* fix(server): keep a/ and b/ prefixes in rendered git patches by @Mnigos in pingdotgg/t3code#9438
* fix(server): full-access OpenCode threads no longer ask for approvals by @shivamhwp in pingdotgg/t3code#9282
* fix(web): reuse pull request list data while loading by @maria-rcks in pingdotgg/t3code#9467
* feat(web): let users turn off composer collapse on blur and scroll by @juliusmarminge in pingdotgg/t3code#9469
## New Contributors
* @Mnigos made their first contribution in pingdotgg/t3code#9438
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1272...v0.0.39-nightly.20260903.1273
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1273
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 4, 2026
…ity ACP, browser import, settings reorg, limits tab)
Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity
via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie
import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg
(pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context
compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access
OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457).
Unification decisions (keep-both unless noted):
- BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI
unwrap, writeCookies); fork's Safari engine ported in (jar definition,
candidate path, profile listing, running check, count skip, import branch,
FullDiskAccess wizard step + SafariCookies kept, domain widened only for
dotted hosts).
- Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding
ported (providerDisabledMessage), AntigravitySettings unified (fork fields +
upstream auth fields; enabled stays default-on).
- contracts/model: Antigravity defaults follow upstream's manifest model.
- ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to
upstream's compactedUsage to match downstream.
- Claude capabilities probe: fork's timeout races kept; upstream's raw usage
fetch added under the same timeout so stalled usage still degrades.
- Codex provider: upstream's withCodexAppServerClient + enriched rate-limits
probe win (fork title branding already inside buildCodexInitializeParams).
- ProviderCommandReactor: fork goal-continuation + correction-aware first-turn
kept; upstream compact-command exclusion added.
- OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept;
upstream full-access autoReply + terminal guard + emitUnsafe added.
- makeManagedServerProvider: fork probe-timeout protection kept; upstream
usage-limits reconciliation applied to the checked snapshot.
- Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept;
upstream wcDebugger hardening applied.
- mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers
loading/sync presentation); outbox deliveryMode + goal handling kept.
- Usage: fork client-version projection kept; upstream pricing()/refreshRates
adopted on both clients.
- Settings: fork sections (MT Teams+badge, voice, notifications, account
sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted.
- README: fork copy kept; Antigravity added to provider lists.
- Cursor skill test macOS /var-vs-/private/var path failure is pre-existing
upstream breakage, unrelated to this merge.
Fork guard script OK.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).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.

2 participants

@shivamhwp@juliusmarminge
, '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(server): full-access OpenCode threads no longer ask for approvals - #9282

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals
Sep 3, 2026
Merged

fix(server): full-access OpenCode threads no longer ask for approvals#9282
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals

Conversation

@shivamhwp

@shivamhwpshivamhwp commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

A user reported that OpenCode threads set to full access still pop approval dialogs. I reproduced it live against OpenCode 1.18.26 with a ChatGPT subscription. Ordinary tool calls are fine, but two paths in OpenCode ignore the session-level allow we send:

  • Doom loop. When the model repeats the same tool call three times, OpenCode evaluates the ask against the agent ruleset only, so our wildcard allow is never consulted. This showed up in the UI as an "unknown" approval.
  • Subagents. Child sessions spawned by the task tool keep only deny and external-directory rules from the parent, so a subagent reading *.env or hitting any agent default prompts. Since fix(opencode): handle child approvals, stops, and model catalogs #8480 routes child asks to the thread, this also shows a dialog.

Both are upstream OpenCode behavior, and full access means the user already said yes. The adapter now answers any permission ask that arrives while the session is in full access, and swallows the matching replied event so nothing reaches the UI. If the reply call fails, it falls back to showing the approval as before. Other modes are untouched.

The reply is "once", not "always". OpenCode stores "always" grants per directory, so on a shared external server an "always" from a full-access thread would widen what a supervised thread on the same directory is allowed to do.

Product note. Auto-answering the doom-loop ask means a full-access thread can repeat the same tool call without a guard. That matches what the docs promise for full access ("runs unattended") and what Codex and Claude do today, so it is intentional.

Tests cover the doom-loop ask on the parent session, a child-session ask, the failed-reply fallback, and a failed reply whose terminal event landed while the reply was in flight. The final ordering change (no yield between the terminal check and the publish) is a scheduler-interleaving race that the mock cannot reproduce deterministically, so it has no dedicated test.

Work done by Claude Fable 5.1 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes permission handling and event emission for full-access OpenCode sessions; incorrect suppression or fallback could hide needed approvals or leave stuck dialogs, though other runtime modes are unchanged and tests cover key races.

Overview
Full-access OpenCode threads no longer surface approval dialogs for permission asks that upstream ignores the session ruleset on—doom-loop detection and subagent sessions. The adapter calls permission.reply with once (not always, to avoid widening grants for other threads on a shared directory), tracks auto-replied IDs, and suppresses matching request.opened / request.resolved UI events. If the SDK reply fails, behavior falls back to showing the approval dialog; failed in-flight replies after a terminal event must not reopen the request.

Implementation adds autoReplyFullAccess, autoRepliedRequestIds, and emitUnsafe so request.opened is not published after a terminal permission.replied lands between an async check and enqueue. Tests extend the mock with a configurable permission-reply hook and cover auto-approve (parent doom-loop + child session), reply failure fallback, and terminal/reply ordering. Docs note why full-access auto-answers these asks and why replies use once.

Reviewed by Cursor Bugbot for commit 4d250db. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix full-access OpenCode threads to auto-approve permissions without dialogs

  • Full-access sessions now automatically reply once to permission asks (doom-loop and subagent) instead of surfacing an approval dialog, using a one-time grant rather than a persistent directory-scoped grant
  • A synchronous enqueue helper (emitUnsafe) prevents an async gap between the terminal-event check and publishing request.opened, eliminating a race where a terminal reply arrives during event construction
  • Failed auto-replies remove the auto-reply marker but keep a resolved marker so the request falls through to the dialog without reopening from recovered duplicate asks; terminal events for successful auto-replies are swallowed (no request.resolved)
  • Behavioral Change: emitTerminalOpenCodeRequest now suppresses terminal events for request IDs in the auto-reply set; reviewers should verify that no request.resolved or request.opened is emitted for successfully auto-replied asks in OpenCodeAdapter.ts
  • Documents full-access adapter behavior in providers.md

Macroscope summarized 4d250db.

OpenCode ignores the session ruleset for doom-loop checks and drops the
parent's wildcard allow when it spawns subagent sessions, so full-access
threads still surfaced approval dialogs for those asks. Auto-reply
"always" to any permission ask while the session is in full access and
swallow the matching replied event, falling back to the dialog if the
reply call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The server now automatically grants and suppresses OpenCode permission requests in full-access sessions, including requests that bypass upstream rules and the doom-loop safeguard. This is a localized, tested change, but it materially alters production authorization behavior and its side effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

A retry or recovery fiber could re-enter the pending-request path, or the
matching permission.replied could land, while the auto-reply SDK call was
still in flight. That raced to emit a duplicate request.opened or a stray
request.resolved. Record the resolved and auto-replied ids synchronously
before awaiting, and roll them back if the reply fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
shivamhwpand others added 3 commits September 2, 2026 23:25
… resolved
If the auto-reply SDK call fails locally but OpenCode still resolved the
permission, the terminal permission.replied lands and is swallowed while the
reply is in flight, consuming the terminal slot. The failure path then rolled
back and opened a dialog that could never resolve. Guard the fallback: if the
terminal event already landed, keep the request resolved and do not reopen it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guard against a regression where the fallback retries the reply instead of
surfacing the dialog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ace0116. Configure here.

Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts
shivamhwpand others added 2 commits September 3, 2026 04:57
…its terminal check
On a retry or recovery fiber, the event pump can deliver the terminal
permission.replied between the emittedTerminalRequestIds check and the
request.opened offer, so request.resolved lands first and the fallback
dialog can never close. Build the event first, then check and offer in one
synchronous step. The failed auto-reply also keeps the id in
resolvedRequestIds: pendingPermissions already gates re-asks while the
dialog is open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o-reply path
OpenCode stores "always" grants per directory, not per session. On a shared
external server an "always" from a full-access thread would silently widen
what a supervised thread on the same directory is allowed to do, so reply
"once" instead. Every ask in full access is auto-answered anyway.
Also extract the full-access branch into autoReplyFullAccess so the id
bookkeeping has a name and a boundary, add an emitUnsafe sibling next to
emit for the one publish that must not yield after its terminal check,
collapse the two identical auto-approve tests into one parameterized case,
and note the upstream ruleset quirk in the provider internals doc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@shivamhwp

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the review in 605dcff.

  1. Reply is now "once". Confirmed against upstream Permission.reply: it returns before touching the per-directory approved list on "once" and appends to it on "always".
  2. Full-access branch extracted into autoReplyFullAccess returning replied | fallback | already-terminal. Added emitUnsafe next to emit with the one-line reason. Comments trimmed to the why.
  3. Tests 1 and 2 collapsed into one it.effect.each case. Sentinel is commented. The blind yieldNow pair in test 4 is replaced with a single microtask drain. PR body now says the final ordering change has no dedicated test.
  4. One line added to docs/internals/providers.md on the upstream ruleset quirk.

PR body rewritten: bot summary blocks removed, doom-loop product decision stated explicitly.

shivamhwpand others added 2 commits September 3, 2026 13:26
…back
autoReplyFullAccess returned a tri-state whose "already-terminal" branch
duplicated the emittedTerminalRequestIds check the caller performs right
before publishing. Only the publish-site check is load-bearing, since it
must sit next to the enqueue with no yield in between, so the helper now
returns whether the reply landed and the caller keeps the one guard.
Also moves the internals note out of "Attachment access", where it was
tacked onto a paragraph about attachment directories, into the OpenCode
section beside the existing per-directory MCP note, and records the
"once" rationale there.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@juliusmarminge
juliusmarminge enabled auto-merge (squash) September 3, 2026 20:37
@juliusmarminge
juliusmarminge merged commit d2b6f3b into pingdotgg:mainSep 3, 2026
25 checks passed
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(web): make right panel tabs easier to scroll by @maria-rcks in pingdotgg/t3code#9461
* fix(web): render transparent previews on white by @UtkarshUsername in pingdotgg/t3code#9463
* fix(mobile): show loading and syncing in the working pill by @juliusmarminge in pingdotgg/t3code#9466
* fix(server): keep a/ and b/ prefixes in rendered git patches by @Mnigos in pingdotgg/t3code#9438
* fix(server): full-access OpenCode threads no longer ask for approvals by @shivamhwp in pingdotgg/t3code#9282
* fix(web): reuse pull request list data while loading by @maria-rcks in pingdotgg/t3code#9467
* feat(web): let users turn off composer collapse on blur and scroll by @juliusmarminge in pingdotgg/t3code#9469
## New Contributors
* @Mnigos made their first contribution in pingdotgg/t3code#9438
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1272...v0.0.39-nightly.20260903.1273
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1273
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 4, 2026
…ity ACP, browser import, settings reorg, limits tab)
Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity
via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie
import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg
(pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context
compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access
OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457).
Unification decisions (keep-both unless noted):
- BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI
unwrap, writeCookies); fork's Safari engine ported in (jar definition,
candidate path, profile listing, running check, count skip, import branch,
FullDiskAccess wizard step + SafariCookies kept, domain widened only for
dotted hosts).
- Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding
ported (providerDisabledMessage), AntigravitySettings unified (fork fields +
upstream auth fields; enabled stays default-on).
- contracts/model: Antigravity defaults follow upstream's manifest model.
- ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to
upstream's compactedUsage to match downstream.
- Claude capabilities probe: fork's timeout races kept; upstream's raw usage
fetch added under the same timeout so stalled usage still degrades.
- Codex provider: upstream's withCodexAppServerClient + enriched rate-limits
probe win (fork title branding already inside buildCodexInitializeParams).
- ProviderCommandReactor: fork goal-continuation + correction-aware first-turn
kept; upstream compact-command exclusion added.
- OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept;
upstream full-access autoReply + terminal guard + emitUnsafe added.
- makeManagedServerProvider: fork probe-timeout protection kept; upstream
usage-limits reconciliation applied to the checked snapshot.
- Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept;
upstream wcDebugger hardening applied.
- mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers
loading/sync presentation); outbox deliveryMode + goal handling kept.
- Usage: fork client-version projection kept; upstream pricing()/refreshRates
adopted on both clients.
- Settings: fork sections (MT Teams+badge, voice, notifications, account
sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted.
- README: fork copy kept; Antigravity added to provider lists.
- Cursor skill test macOS /var-vs-/private/var path failure is pre-existing
upstream breakage, unrelated to this merge.
Fork guard script OK.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).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.

2 participants

@shivamhwp@juliusmarminge
, '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(server): full-access OpenCode threads no longer ask for approvals - #9282

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals
Sep 3, 2026
Merged

fix(server): full-access OpenCode threads no longer ask for approvals#9282
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals

Conversation

@shivamhwp

@shivamhwpshivamhwp commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

A user reported that OpenCode threads set to full access still pop approval dialogs. I reproduced it live against OpenCode 1.18.26 with a ChatGPT subscription. Ordinary tool calls are fine, but two paths in OpenCode ignore the session-level allow we send:

  • Doom loop. When the model repeats the same tool call three times, OpenCode evaluates the ask against the agent ruleset only, so our wildcard allow is never consulted. This showed up in the UI as an "unknown" approval.
  • Subagents. Child sessions spawned by the task tool keep only deny and external-directory rules from the parent, so a subagent reading *.env or hitting any agent default prompts. Since fix(opencode): handle child approvals, stops, and model catalogs #8480 routes child asks to the thread, this also shows a dialog.

Both are upstream OpenCode behavior, and full access means the user already said yes. The adapter now answers any permission ask that arrives while the session is in full access, and swallows the matching replied event so nothing reaches the UI. If the reply call fails, it falls back to showing the approval as before. Other modes are untouched.

The reply is "once", not "always". OpenCode stores "always" grants per directory, so on a shared external server an "always" from a full-access thread would widen what a supervised thread on the same directory is allowed to do.

Product note. Auto-answering the doom-loop ask means a full-access thread can repeat the same tool call without a guard. That matches what the docs promise for full access ("runs unattended") and what Codex and Claude do today, so it is intentional.

Tests cover the doom-loop ask on the parent session, a child-session ask, the failed-reply fallback, and a failed reply whose terminal event landed while the reply was in flight. The final ordering change (no yield between the terminal check and the publish) is a scheduler-interleaving race that the mock cannot reproduce deterministically, so it has no dedicated test.

Work done by Claude Fable 5.1 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes permission handling and event emission for full-access OpenCode sessions; incorrect suppression or fallback could hide needed approvals or leave stuck dialogs, though other runtime modes are unchanged and tests cover key races.

Overview
Full-access OpenCode threads no longer surface approval dialogs for permission asks that upstream ignores the session ruleset on—doom-loop detection and subagent sessions. The adapter calls permission.reply with once (not always, to avoid widening grants for other threads on a shared directory), tracks auto-replied IDs, and suppresses matching request.opened / request.resolved UI events. If the SDK reply fails, behavior falls back to showing the approval dialog; failed in-flight replies after a terminal event must not reopen the request.

Implementation adds autoReplyFullAccess, autoRepliedRequestIds, and emitUnsafe so request.opened is not published after a terminal permission.replied lands between an async check and enqueue. Tests extend the mock with a configurable permission-reply hook and cover auto-approve (parent doom-loop + child session), reply failure fallback, and terminal/reply ordering. Docs note why full-access auto-answers these asks and why replies use once.

Reviewed by Cursor Bugbot for commit 4d250db. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix full-access OpenCode threads to auto-approve permissions without dialogs

  • Full-access sessions now automatically reply once to permission asks (doom-loop and subagent) instead of surfacing an approval dialog, using a one-time grant rather than a persistent directory-scoped grant
  • A synchronous enqueue helper (emitUnsafe) prevents an async gap between the terminal-event check and publishing request.opened, eliminating a race where a terminal reply arrives during event construction
  • Failed auto-replies remove the auto-reply marker but keep a resolved marker so the request falls through to the dialog without reopening from recovered duplicate asks; terminal events for successful auto-replies are swallowed (no request.resolved)
  • Behavioral Change: emitTerminalOpenCodeRequest now suppresses terminal events for request IDs in the auto-reply set; reviewers should verify that no request.resolved or request.opened is emitted for successfully auto-replied asks in OpenCodeAdapter.ts
  • Documents full-access adapter behavior in providers.md

Macroscope summarized 4d250db.

OpenCode ignores the session ruleset for doom-loop checks and drops the
parent's wildcard allow when it spawns subagent sessions, so full-access
threads still surfaced approval dialogs for those asks. Auto-reply
"always" to any permission ask while the session is in full access and
swallow the matching replied event, falling back to the dialog if the
reply call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The server now automatically grants and suppresses OpenCode permission requests in full-access sessions, including requests that bypass upstream rules and the doom-loop safeguard. This is a localized, tested change, but it materially alters production authorization behavior and its side effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

A retry or recovery fiber could re-enter the pending-request path, or the
matching permission.replied could land, while the auto-reply SDK call was
still in flight. That raced to emit a duplicate request.opened or a stray
request.resolved. Record the resolved and auto-replied ids synchronously
before awaiting, and roll them back if the reply fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
shivamhwpand others added 3 commits September 2, 2026 23:25
… resolved
If the auto-reply SDK call fails locally but OpenCode still resolved the
permission, the terminal permission.replied lands and is swallowed while the
reply is in flight, consuming the terminal slot. The failure path then rolled
back and opened a dialog that could never resolve. Guard the fallback: if the
terminal event already landed, keep the request resolved and do not reopen it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guard against a regression where the fallback retries the reply instead of
surfacing the dialog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ace0116. Configure here.

Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts
shivamhwpand others added 2 commits September 3, 2026 04:57
…its terminal check
On a retry or recovery fiber, the event pump can deliver the terminal
permission.replied between the emittedTerminalRequestIds check and the
request.opened offer, so request.resolved lands first and the fallback
dialog can never close. Build the event first, then check and offer in one
synchronous step. The failed auto-reply also keeps the id in
resolvedRequestIds: pendingPermissions already gates re-asks while the
dialog is open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o-reply path
OpenCode stores "always" grants per directory, not per session. On a shared
external server an "always" from a full-access thread would silently widen
what a supervised thread on the same directory is allowed to do, so reply
"once" instead. Every ask in full access is auto-answered anyway.
Also extract the full-access branch into autoReplyFullAccess so the id
bookkeeping has a name and a boundary, add an emitUnsafe sibling next to
emit for the one publish that must not yield after its terminal check,
collapse the two identical auto-approve tests into one parameterized case,
and note the upstream ruleset quirk in the provider internals doc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@shivamhwp

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the review in 605dcff.

  1. Reply is now "once". Confirmed against upstream Permission.reply: it returns before touching the per-directory approved list on "once" and appends to it on "always".
  2. Full-access branch extracted into autoReplyFullAccess returning replied | fallback | already-terminal. Added emitUnsafe next to emit with the one-line reason. Comments trimmed to the why.
  3. Tests 1 and 2 collapsed into one it.effect.each case. Sentinel is commented. The blind yieldNow pair in test 4 is replaced with a single microtask drain. PR body now says the final ordering change has no dedicated test.
  4. One line added to docs/internals/providers.md on the upstream ruleset quirk.

PR body rewritten: bot summary blocks removed, doom-loop product decision stated explicitly.

shivamhwpand others added 2 commits September 3, 2026 13:26
…back
autoReplyFullAccess returned a tri-state whose "already-terminal" branch
duplicated the emittedTerminalRequestIds check the caller performs right
before publishing. Only the publish-site check is load-bearing, since it
must sit next to the enqueue with no yield in between, so the helper now
returns whether the reply landed and the caller keeps the one guard.
Also moves the internals note out of "Attachment access", where it was
tacked onto a paragraph about attachment directories, into the OpenCode
section beside the existing per-directory MCP note, and records the
"once" rationale there.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@juliusmarminge
juliusmarminge enabled auto-merge (squash) September 3, 2026 20:37
@juliusmarminge
juliusmarminge merged commit d2b6f3b into pingdotgg:mainSep 3, 2026
25 checks passed
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(web): make right panel tabs easier to scroll by @maria-rcks in pingdotgg/t3code#9461
* fix(web): render transparent previews on white by @UtkarshUsername in pingdotgg/t3code#9463
* fix(mobile): show loading and syncing in the working pill by @juliusmarminge in pingdotgg/t3code#9466
* fix(server): keep a/ and b/ prefixes in rendered git patches by @Mnigos in pingdotgg/t3code#9438
* fix(server): full-access OpenCode threads no longer ask for approvals by @shivamhwp in pingdotgg/t3code#9282
* fix(web): reuse pull request list data while loading by @maria-rcks in pingdotgg/t3code#9467
* feat(web): let users turn off composer collapse on blur and scroll by @juliusmarminge in pingdotgg/t3code#9469
## New Contributors
* @Mnigos made their first contribution in pingdotgg/t3code#9438
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1272...v0.0.39-nightly.20260903.1273
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1273
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 4, 2026
…ity ACP, browser import, settings reorg, limits tab)
Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity
via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie
import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg
(pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context
compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access
OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457).
Unification decisions (keep-both unless noted):
- BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI
unwrap, writeCookies); fork's Safari engine ported in (jar definition,
candidate path, profile listing, running check, count skip, import branch,
FullDiskAccess wizard step + SafariCookies kept, domain widened only for
dotted hosts).
- Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding
ported (providerDisabledMessage), AntigravitySettings unified (fork fields +
upstream auth fields; enabled stays default-on).
- contracts/model: Antigravity defaults follow upstream's manifest model.
- ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to
upstream's compactedUsage to match downstream.
- Claude capabilities probe: fork's timeout races kept; upstream's raw usage
fetch added under the same timeout so stalled usage still degrades.
- Codex provider: upstream's withCodexAppServerClient + enriched rate-limits
probe win (fork title branding already inside buildCodexInitializeParams).
- ProviderCommandReactor: fork goal-continuation + correction-aware first-turn
kept; upstream compact-command exclusion added.
- OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept;
upstream full-access autoReply + terminal guard + emitUnsafe added.
- makeManagedServerProvider: fork probe-timeout protection kept; upstream
usage-limits reconciliation applied to the checked snapshot.
- Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept;
upstream wcDebugger hardening applied.
- mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers
loading/sync presentation); outbox deliveryMode + goal handling kept.
- Usage: fork client-version projection kept; upstream pricing()/refreshRates
adopted on both clients.
- Settings: fork sections (MT Teams+badge, voice, notifications, account
sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted.
- README: fork copy kept; Antigravity added to provider lists.
- Cursor skill test macOS /var-vs-/private/var path failure is pre-existing
upstream breakage, unrelated to this merge.
Fork guard script OK.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).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.

2 participants

@shivamhwp@juliusmarminge
, '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(server): full-access OpenCode threads no longer ask for approvals - #9282

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals
Sep 3, 2026
Merged

fix(server): full-access OpenCode threads no longer ask for approvals#9282
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals

Conversation

@shivamhwp

@shivamhwpshivamhwp commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

A user reported that OpenCode threads set to full access still pop approval dialogs. I reproduced it live against OpenCode 1.18.26 with a ChatGPT subscription. Ordinary tool calls are fine, but two paths in OpenCode ignore the session-level allow we send:

  • Doom loop. When the model repeats the same tool call three times, OpenCode evaluates the ask against the agent ruleset only, so our wildcard allow is never consulted. This showed up in the UI as an "unknown" approval.
  • Subagents. Child sessions spawned by the task tool keep only deny and external-directory rules from the parent, so a subagent reading *.env or hitting any agent default prompts. Since fix(opencode): handle child approvals, stops, and model catalogs #8480 routes child asks to the thread, this also shows a dialog.

Both are upstream OpenCode behavior, and full access means the user already said yes. The adapter now answers any permission ask that arrives while the session is in full access, and swallows the matching replied event so nothing reaches the UI. If the reply call fails, it falls back to showing the approval as before. Other modes are untouched.

The reply is "once", not "always". OpenCode stores "always" grants per directory, so on a shared external server an "always" from a full-access thread would widen what a supervised thread on the same directory is allowed to do.

Product note. Auto-answering the doom-loop ask means a full-access thread can repeat the same tool call without a guard. That matches what the docs promise for full access ("runs unattended") and what Codex and Claude do today, so it is intentional.

Tests cover the doom-loop ask on the parent session, a child-session ask, the failed-reply fallback, and a failed reply whose terminal event landed while the reply was in flight. The final ordering change (no yield between the terminal check and the publish) is a scheduler-interleaving race that the mock cannot reproduce deterministically, so it has no dedicated test.

Work done by Claude Fable 5.1 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes permission handling and event emission for full-access OpenCode sessions; incorrect suppression or fallback could hide needed approvals or leave stuck dialogs, though other runtime modes are unchanged and tests cover key races.

Overview
Full-access OpenCode threads no longer surface approval dialogs for permission asks that upstream ignores the session ruleset on—doom-loop detection and subagent sessions. The adapter calls permission.reply with once (not always, to avoid widening grants for other threads on a shared directory), tracks auto-replied IDs, and suppresses matching request.opened / request.resolved UI events. If the SDK reply fails, behavior falls back to showing the approval dialog; failed in-flight replies after a terminal event must not reopen the request.

Implementation adds autoReplyFullAccess, autoRepliedRequestIds, and emitUnsafe so request.opened is not published after a terminal permission.replied lands between an async check and enqueue. Tests extend the mock with a configurable permission-reply hook and cover auto-approve (parent doom-loop + child session), reply failure fallback, and terminal/reply ordering. Docs note why full-access auto-answers these asks and why replies use once.

Reviewed by Cursor Bugbot for commit 4d250db. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix full-access OpenCode threads to auto-approve permissions without dialogs

  • Full-access sessions now automatically reply once to permission asks (doom-loop and subagent) instead of surfacing an approval dialog, using a one-time grant rather than a persistent directory-scoped grant
  • A synchronous enqueue helper (emitUnsafe) prevents an async gap between the terminal-event check and publishing request.opened, eliminating a race where a terminal reply arrives during event construction
  • Failed auto-replies remove the auto-reply marker but keep a resolved marker so the request falls through to the dialog without reopening from recovered duplicate asks; terminal events for successful auto-replies are swallowed (no request.resolved)
  • Behavioral Change: emitTerminalOpenCodeRequest now suppresses terminal events for request IDs in the auto-reply set; reviewers should verify that no request.resolved or request.opened is emitted for successfully auto-replied asks in OpenCodeAdapter.ts
  • Documents full-access adapter behavior in providers.md

Macroscope summarized 4d250db.

OpenCode ignores the session ruleset for doom-loop checks and drops the
parent's wildcard allow when it spawns subagent sessions, so full-access
threads still surfaced approval dialogs for those asks. Auto-reply
"always" to any permission ask while the session is in full access and
swallow the matching replied event, falling back to the dialog if the
reply call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The server now automatically grants and suppresses OpenCode permission requests in full-access sessions, including requests that bypass upstream rules and the doom-loop safeguard. This is a localized, tested change, but it materially alters production authorization behavior and its side effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

A retry or recovery fiber could re-enter the pending-request path, or the
matching permission.replied could land, while the auto-reply SDK call was
still in flight. That raced to emit a duplicate request.opened or a stray
request.resolved. Record the resolved and auto-replied ids synchronously
before awaiting, and roll them back if the reply fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
shivamhwpand others added 3 commits September 2, 2026 23:25
… resolved
If the auto-reply SDK call fails locally but OpenCode still resolved the
permission, the terminal permission.replied lands and is swallowed while the
reply is in flight, consuming the terminal slot. The failure path then rolled
back and opened a dialog that could never resolve. Guard the fallback: if the
terminal event already landed, keep the request resolved and do not reopen it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guard against a regression where the fallback retries the reply instead of
surfacing the dialog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ace0116. Configure here.

Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts
shivamhwpand others added 2 commits September 3, 2026 04:57
…its terminal check
On a retry or recovery fiber, the event pump can deliver the terminal
permission.replied between the emittedTerminalRequestIds check and the
request.opened offer, so request.resolved lands first and the fallback
dialog can never close. Build the event first, then check and offer in one
synchronous step. The failed auto-reply also keeps the id in
resolvedRequestIds: pendingPermissions already gates re-asks while the
dialog is open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o-reply path
OpenCode stores "always" grants per directory, not per session. On a shared
external server an "always" from a full-access thread would silently widen
what a supervised thread on the same directory is allowed to do, so reply
"once" instead. Every ask in full access is auto-answered anyway.
Also extract the full-access branch into autoReplyFullAccess so the id
bookkeeping has a name and a boundary, add an emitUnsafe sibling next to
emit for the one publish that must not yield after its terminal check,
collapse the two identical auto-approve tests into one parameterized case,
and note the upstream ruleset quirk in the provider internals doc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@shivamhwp

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the review in 605dcff.

  1. Reply is now "once". Confirmed against upstream Permission.reply: it returns before touching the per-directory approved list on "once" and appends to it on "always".
  2. Full-access branch extracted into autoReplyFullAccess returning replied | fallback | already-terminal. Added emitUnsafe next to emit with the one-line reason. Comments trimmed to the why.
  3. Tests 1 and 2 collapsed into one it.effect.each case. Sentinel is commented. The blind yieldNow pair in test 4 is replaced with a single microtask drain. PR body now says the final ordering change has no dedicated test.
  4. One line added to docs/internals/providers.md on the upstream ruleset quirk.

PR body rewritten: bot summary blocks removed, doom-loop product decision stated explicitly.

shivamhwpand others added 2 commits September 3, 2026 13:26
…back
autoReplyFullAccess returned a tri-state whose "already-terminal" branch
duplicated the emittedTerminalRequestIds check the caller performs right
before publishing. Only the publish-site check is load-bearing, since it
must sit next to the enqueue with no yield in between, so the helper now
returns whether the reply landed and the caller keeps the one guard.
Also moves the internals note out of "Attachment access", where it was
tacked onto a paragraph about attachment directories, into the OpenCode
section beside the existing per-directory MCP note, and records the
"once" rationale there.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@juliusmarminge
juliusmarminge enabled auto-merge (squash) September 3, 2026 20:37
@juliusmarminge
juliusmarminge merged commit d2b6f3b into pingdotgg:mainSep 3, 2026
25 checks passed
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(web): make right panel tabs easier to scroll by @maria-rcks in pingdotgg/t3code#9461
* fix(web): render transparent previews on white by @UtkarshUsername in pingdotgg/t3code#9463
* fix(mobile): show loading and syncing in the working pill by @juliusmarminge in pingdotgg/t3code#9466
* fix(server): keep a/ and b/ prefixes in rendered git patches by @Mnigos in pingdotgg/t3code#9438
* fix(server): full-access OpenCode threads no longer ask for approvals by @shivamhwp in pingdotgg/t3code#9282
* fix(web): reuse pull request list data while loading by @maria-rcks in pingdotgg/t3code#9467
* feat(web): let users turn off composer collapse on blur and scroll by @juliusmarminge in pingdotgg/t3code#9469
## New Contributors
* @Mnigos made their first contribution in pingdotgg/t3code#9438
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1272...v0.0.39-nightly.20260903.1273
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1273
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 4, 2026
…ity ACP, browser import, settings reorg, limits tab)
Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity
via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie
import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg
(pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context
compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access
OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457).
Unification decisions (keep-both unless noted):
- BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI
unwrap, writeCookies); fork's Safari engine ported in (jar definition,
candidate path, profile listing, running check, count skip, import branch,
FullDiskAccess wizard step + SafariCookies kept, domain widened only for
dotted hosts).
- Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding
ported (providerDisabledMessage), AntigravitySettings unified (fork fields +
upstream auth fields; enabled stays default-on).
- contracts/model: Antigravity defaults follow upstream's manifest model.
- ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to
upstream's compactedUsage to match downstream.
- Claude capabilities probe: fork's timeout races kept; upstream's raw usage
fetch added under the same timeout so stalled usage still degrades.
- Codex provider: upstream's withCodexAppServerClient + enriched rate-limits
probe win (fork title branding already inside buildCodexInitializeParams).
- ProviderCommandReactor: fork goal-continuation + correction-aware first-turn
kept; upstream compact-command exclusion added.
- OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept;
upstream full-access autoReply + terminal guard + emitUnsafe added.
- makeManagedServerProvider: fork probe-timeout protection kept; upstream
usage-limits reconciliation applied to the checked snapshot.
- Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept;
upstream wcDebugger hardening applied.
- mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers
loading/sync presentation); outbox deliveryMode + goal handling kept.
- Usage: fork client-version projection kept; upstream pricing()/refreshRates
adopted on both clients.
- Settings: fork sections (MT Teams+badge, voice, notifications, account
sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted.
- README: fork copy kept; Antigravity added to provider lists.
- Cursor skill test macOS /var-vs-/private/var path failure is pre-existing
upstream breakage, unrelated to this merge.
Fork guard script OK.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).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.

2 participants

@shivamhwp@juliusmarminge
, '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(server): full-access OpenCode threads no longer ask for approvals - #9282

Merged
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals
Sep 3, 2026
Merged

fix(server): full-access OpenCode threads no longer ask for approvals#9282
juliusmarminge merged 9 commits into
pingdotgg:mainfrom
shivamhwp:t3code/check-opencode-full-access-approvals

Conversation

@shivamhwp

@shivamhwpshivamhwp commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

A user reported that OpenCode threads set to full access still pop approval dialogs. I reproduced it live against OpenCode 1.18.26 with a ChatGPT subscription. Ordinary tool calls are fine, but two paths in OpenCode ignore the session-level allow we send:

  • Doom loop. When the model repeats the same tool call three times, OpenCode evaluates the ask against the agent ruleset only, so our wildcard allow is never consulted. This showed up in the UI as an "unknown" approval.
  • Subagents. Child sessions spawned by the task tool keep only deny and external-directory rules from the parent, so a subagent reading *.env or hitting any agent default prompts. Since fix(opencode): handle child approvals, stops, and model catalogs #8480 routes child asks to the thread, this also shows a dialog.

Both are upstream OpenCode behavior, and full access means the user already said yes. The adapter now answers any permission ask that arrives while the session is in full access, and swallows the matching replied event so nothing reaches the UI. If the reply call fails, it falls back to showing the approval as before. Other modes are untouched.

The reply is "once", not "always". OpenCode stores "always" grants per directory, so on a shared external server an "always" from a full-access thread would widen what a supervised thread on the same directory is allowed to do.

Product note. Auto-answering the doom-loop ask means a full-access thread can repeat the same tool call without a guard. That matches what the docs promise for full access ("runs unattended") and what Codex and Claude do today, so it is intentional.

Tests cover the doom-loop ask on the parent session, a child-session ask, the failed-reply fallback, and a failed reply whose terminal event landed while the reply was in flight. The final ordering change (no yield between the terminal check and the publish) is a scheduler-interleaving race that the mock cannot reproduce deterministically, so it has no dedicated test.

Work done by Claude Fable 5.1 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Changes permission handling and event emission for full-access OpenCode sessions; incorrect suppression or fallback could hide needed approvals or leave stuck dialogs, though other runtime modes are unchanged and tests cover key races.

Overview
Full-access OpenCode threads no longer surface approval dialogs for permission asks that upstream ignores the session ruleset on—doom-loop detection and subagent sessions. The adapter calls permission.reply with once (not always, to avoid widening grants for other threads on a shared directory), tracks auto-replied IDs, and suppresses matching request.opened / request.resolved UI events. If the SDK reply fails, behavior falls back to showing the approval dialog; failed in-flight replies after a terminal event must not reopen the request.

Implementation adds autoReplyFullAccess, autoRepliedRequestIds, and emitUnsafe so request.opened is not published after a terminal permission.replied lands between an async check and enqueue. Tests extend the mock with a configurable permission-reply hook and cover auto-approve (parent doom-loop + child session), reply failure fallback, and terminal/reply ordering. Docs note why full-access auto-answers these asks and why replies use once.

Reviewed by Cursor Bugbot for commit 4d250db. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix full-access OpenCode threads to auto-approve permissions without dialogs

  • Full-access sessions now automatically reply once to permission asks (doom-loop and subagent) instead of surfacing an approval dialog, using a one-time grant rather than a persistent directory-scoped grant
  • A synchronous enqueue helper (emitUnsafe) prevents an async gap between the terminal-event check and publishing request.opened, eliminating a race where a terminal reply arrives during event construction
  • Failed auto-replies remove the auto-reply marker but keep a resolved marker so the request falls through to the dialog without reopening from recovered duplicate asks; terminal events for successful auto-replies are swallowed (no request.resolved)
  • Behavioral Change: emitTerminalOpenCodeRequest now suppresses terminal events for request IDs in the auto-reply set; reviewers should verify that no request.resolved or request.opened is emitted for successfully auto-replied asks in OpenCodeAdapter.ts
  • Documents full-access adapter behavior in providers.md

Macroscope summarized 4d250db.

OpenCode ignores the session ruleset for doom-loop checks and drops the
parent's wildcard allow when it spawns subagent sessions, so full-access
threads still surfaced approval dialogs for those asks. Auto-reply
"always" to any permission ask while the session is in full access and
swallow the matching replied event, falling back to the dialog if the
reply call fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
@macroscopeapp

macroscopeappBot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The server now automatically grants and suppresses OpenCode permission requests in full-access sessions, including requests that bypass upstream rules and the doom-loop safeguard. This is a localized, tested change, but it materially alters production authorization behavior and its side effects warrant human review.

You can add or adjust custom eligibility rules. Learn more.

A retry or recovery fiber could re-enter the pending-request path, or the
matching permission.replied could land, while the auto-reply SDK call was
still in flight. That raced to emit a duplicate request.opened or a stray
request.resolved. Record the resolved and auto-replied ids synchronously
before awaiting, and roll them back if the reply fails.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Sep 2, 2026
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts Outdated
shivamhwpand others added 3 commits September 2, 2026 23:25
… resolved
If the auto-reply SDK call fails locally but OpenCode still resolved the
permission, the terminal permission.replied lands and is swallowed while the
reply is in flight, consuming the terminal slot. The failure path then rolled
back and opened a dialog that could never resolve. Guard the fallback: if the
terminal event already landed, keep the request resolved and do not reopen it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guard against a regression where the fallback retries the reply instead of
surfacing the dialog.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ace0116. Configure here.

Comment threadapps/server/src/provider/Layers/OpenCodeAdapter.ts
shivamhwpand others added 2 commits September 3, 2026 04:57
…its terminal check
On a retry or recovery fiber, the event pump can deliver the terminal
permission.replied between the emittedTerminalRequestIds check and the
request.opened offer, so request.resolved lands first and the fallback
dialog can never close. Build the event first, then check and offer in one
synchronous step. The failed auto-reply also keeps the id in
resolvedRequestIds: pendingPermissions already gates re-asks while the
dialog is open.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o-reply path
OpenCode stores "always" grants per directory, not per session. On a shared
external server an "always" from a full-access thread would silently widen
what a supervised thread on the same directory is allowed to do, so reply
"once" instead. Every ask in full access is auto-answered anyway.
Also extract the full-access branch into autoReplyFullAccess so the id
bookkeeping has a name and a boundary, add an emitUnsafe sibling next to
emit for the one publish that must not yield after its terminal check,
collapse the two identical auto-approve tests into one parameterized case,
and note the upstream ruleset quirk in the provider internals doc.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@shivamhwp

Copy link
Copy Markdown
CollaboratorAuthor

Addressed the review in 605dcff.

  1. Reply is now "once". Confirmed against upstream Permission.reply: it returns before touching the per-directory approved list on "once" and appends to it on "always".
  2. Full-access branch extracted into autoReplyFullAccess returning replied | fallback | already-terminal. Added emitUnsafe next to emit with the one-line reason. Comments trimmed to the why.
  3. Tests 1 and 2 collapsed into one it.effect.each case. Sentinel is commented. The blind yieldNow pair in test 4 is replaced with a single microtask drain. PR body now says the final ordering change has no dedicated test.
  4. One line added to docs/internals/providers.md on the upstream ruleset quirk.

PR body rewritten: bot summary blocks removed, doom-loop product decision stated explicitly.

shivamhwpand others added 2 commits September 3, 2026 13:26
…back
autoReplyFullAccess returned a tri-state whose "already-terminal" branch
duplicated the emittedTerminalRequestIds check the caller performs right
before publishing. Only the publish-site check is load-bearing, since it
must sit next to the enqueue with no yield in between, so the helper now
returns whether the reply landed and the caller keeps the one guard.
Also moves the internals note out of "Attachment access", where it was
tacked onto a paragraph about attachment directories, into the OpenCode
section beside the existing per-directory MCP note, and records the
"once" rationale there.
Co-Authored-By: Claude Code <noreply@anthropic.com>
@juliusmarminge
juliusmarminge enabled auto-merge (squash) September 3, 2026 20:37
@juliusmarminge
juliusmarminge merged commit d2b6f3b into pingdotgg:mainSep 3, 2026
25 checks passed
github-actionsBot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(web): make right panel tabs easier to scroll by @maria-rcks in pingdotgg/t3code#9461
* fix(web): render transparent previews on white by @UtkarshUsername in pingdotgg/t3code#9463
* fix(mobile): show loading and syncing in the working pill by @juliusmarminge in pingdotgg/t3code#9466
* fix(server): keep a/ and b/ prefixes in rendered git patches by @Mnigos in pingdotgg/t3code#9438
* fix(server): full-access OpenCode threads no longer ask for approvals by @shivamhwp in pingdotgg/t3code#9282
* fix(web): reuse pull request list data while loading by @maria-rcks in pingdotgg/t3code#9467
* feat(web): let users turn off composer collapse on blur and scroll by @juliusmarminge in pingdotgg/t3code#9469
## New Contributors
* @Mnigos made their first contribution in pingdotgg/t3code#9438
**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260903.1272...v0.0.39-nightly.20260903.1273
Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260903.1273
sheehanmunim added a commit to munimtechnologies/mtcode that referenced this pull request Sep 4, 2026
…ity ACP, browser import, settings reorg, limits tab)
Brings the fork up to upstream/main fee2e0f. Highlights: Google Antigravity
via the official ACP agent (pingdotgg#9348) + model manifest refreshes, browser-cookie
import (Chrome/Edge/Brave/Firefox, pingdotgg#7255/pingdotgg#7260/pingdotgg#7261), settings page reorg
(pingdotgg#9354), Codex/Claude subscription Limits tab (pingdotgg#9507, pingdotgg#9534), context
compaction command (pingdotgg#9293), async Codex questions (pingdotgg#9512), full-access
OpenCode threads skip approvals (pingdotgg#9282), project icons default (pingdotgg#9457).
Unification decisions (keep-both unless noted):
- BrowserImport: upstream implementation wins (Linux libsecret, Windows DPAPI
unwrap, writeCookies); fork's Safari engine ported in (jar definition,
candidate path, profile listing, running check, count skip, import branch,
FullDiskAccess wizard step + SafariCookies kept, domain widened only for
dotted hosts).
- Antigravity: upstream ACP provider/adapter/driver/textgen win; fork branding
ported (providerDisabledMessage), AntigravitySettings unified (fork fields +
upstream auth fields; enabled stays default-on).
- contracts/model: Antigravity defaults follow upstream's manifest model.
- ClaudeAdapter compact_boundary: fork's resolve helper kept, renamed to
upstream's compactedUsage to match downstream.
- Claude capabilities probe: fork's timeout races kept; upstream's raw usage
fetch added under the same timeout so stalled usage still degrades.
- Codex provider: upstream's withCodexAppServerClient + enriched rate-limits
probe win (fork title branding already inside buildCodexInitializeParams).
- ProviderCommandReactor: fork goal-continuation + correction-aware first-turn
kept; upstream compact-command exclusion added.
- OpenCodeAdapter ask path: fork's pendingGate/acceptingRequests gate kept;
upstream full-access autoReply + terminal guard + emitUnsafe added.
- makeManagedServerProvider: fork probe-timeout protection kept; upstream
usage-limits reconciliation applied to the checked snapshot.
- Manager.ts preview CDP: fork reuse-if-attached + detach resilience kept;
upstream wcDebugger hardening applied.
- mobile threadSyncPhase pill dropped (upstream ThreadDetail redesign covers
loading/sync presentation); outbox deliveryMode + goal handling kept.
- Usage: fork client-version projection kept; upstream pricing()/refreshRates
adopted on both clients.
- Settings: fork sections (MT Teams+badge, voice, notifications, account
sign-in) kept; upstream reorg (ids, submenus, behaviour section) adopted.
- README: fork copy kept; Antigravity added to provider lists.
- Cursor skill test macOS /var-vs-/private/var path failure is pre-existing
upstream breakage, unrelated to this merge.
Fork guard script OK.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).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.

2 participants

@shivamhwp@juliusmarminge