fix(opencode): resume the OpenCode session on follow-ups instead of starting an empty one#3617
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR introduces substantial new runtime behavior: session resumption via durable cursors, session forking when directories change, and new external API calls (session.get/update/fork). While well-tested, these changes fundamentally alter how OpenCode sessions are managed and warrant human review. You can customize Macroscope's approvability policy. Learn more. |
…ass) Addresses review feedback on pingdotgg#3617 (macroscope + Cursor Bugbot + a deep multi-agent review) without widening scope beyond the adapter: - Re-apply permissions on resume. `session.create` is the only place the runtimeMode permission ruleset is set, so re-adopting a session skipped it; the reactor restarts with the persisted cursor on a runtime-mode change, which would leave a resumed OpenCode session on stale (e.g. full-access) permissions. Resume now calls session.update with buildOpenCodePermissionRules(runtimeMode). - Don't resume into the wrong directory. OpenCode routes a prompt to the session's own stored directory, so reusing a session created under a different cwd would silently run there. Resume now starts a fresh session when the re-adopted session's directory differs from the requested cwd. - Distinguish "not found" from transient failures. The SDK client uses throwOnError:true, so session.get rejects on any non-2xx. Only a confirmed 404 / NotFoundError now falls back to creating a fresh session; transport/auth/server errors propagate instead of silently resetting a live thread to an empty session. Tests model throwOnError:true (session.get rejects) and add coverage for the permission re-application, cwd-mismatch fallback, and transient-error propagation paths.
|
Thanks for the reviews — addressed in 7be6629. Three hardening changes, all kept within the adapter:
Tests updated to model |
|
UPDATE: |
|
Pushed a follow-up correcting the directory-mismatch handling that was added during hardening. Problem: the guard that started a fresh session when the resumed session's stored directory differed from the requested cwd was justified by "OpenCode routes a prompt to the session's own stored directory." That premise doesn't hold — OpenCode resolves tool execution, snapshots and file ops from the per-request Fix: when the persisted session exists but was created under a different directory, Verified against the OpenCode source that fork copies all messages/parts with fresh ids and stamps the new session's directory/path from the request context. The former "starts fresh on directory mismatch" test now asserts fork-with-history. |
|
The single issue from Bugbot's Jul 19 review (raw string comparison of the resume directory against the session's stored directory) is fixed in 5741a3b and the inline thread is resolved: |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 061be07. Configure here.
…tarting an empty one The OpenCode adapter always called session.create and never read or emitted a resume cursor, so the upstream ses_… id lived only in memory. When that in-memory binding was lost — the ProviderSessionReaper stopping an idle session (~30 min) or an app/server restart — the next follow-up in the same visible thread was sent to a brand-new, empty OpenCode session. t3code kept rendering its own projection DB, so the user still saw the full history while the model had no context (issue pingdotgg#3604). Mirror the Grok/Cursor/Codex resume pattern, entirely within the adapter: - Emit resumeCursor { schemaVersion, sessionId } on the started ProviderSession (and echo it from sendTurn) so ProviderService persists it into provider_session_runtime.resume_cursor_json. - On startSession, when a cursor is present, validate the id with session.get and re-adopt that session instead of creating a new one. OpenCode scopes history by session id, so prompting the same id restores the full prior conversation. A missing/closed session (or any get failure) falls back to a fresh session so a stale cursor can't wedge the thread. - Only abort the upstream session in the start race-cleanup when we actually created it; never abort a session we merely resumed. The persistence/recovery plumbing is provider-agnostic and already feeds a persisted cursor back into startSession on a reaped/restarted follow-up (ProviderService falls back to the stored binding cursor when the reactor passes none), so no changes outside the adapter are needed. Adds regression tests: fresh-session cursor emission, resume re-adopting the persisted id (no create), follow-up turns targeting the resumed id, stale-cursor fallback to create, and malformed-cursor rejection. Fixes pingdotgg#3604 Co-authored-by: codex <codex@users.noreply.github.com>
…ass) Addresses review feedback on pingdotgg#3617 (macroscope + Cursor Bugbot + a deep multi-agent review) without widening scope beyond the adapter: - Re-apply permissions on resume. `session.create` is the only place the runtimeMode permission ruleset is set, so re-adopting a session skipped it; the reactor restarts with the persisted cursor on a runtime-mode change, which would leave a resumed OpenCode session on stale (e.g. full-access) permissions. Resume now calls session.update with buildOpenCodePermissionRules(runtimeMode). - Don't resume into the wrong directory. OpenCode routes a prompt to the session's own stored directory, so reusing a session created under a different cwd would silently run there. Resume now starts a fresh session when the re-adopted session's directory differs from the requested cwd. - Distinguish "not found" from transient failures. The SDK client uses throwOnError:true, so session.get rejects on any non-2xx. Only a confirmed 404 / NotFoundError now falls back to creating a fresh session; transport/auth/server errors propagate instead of silently resetting a live thread to an empty session. Tests model throwOnError:true (session.get rejects) and add coverage for the permission re-application, cwd-mismatch fallback, and transient-error propagation paths. Co-authored-by: codex <codex@users.noreply.github.com>
Address review (Cursor Bugbot, high): isOpenCodeNotFound only walked the `cause` chain checking a numeric `status`, so it relied on the 404 sitting at one specific nesting and ignored `response.status` and the OpenCodeRuntimeError `detail` string. Reworked it into a bounded BFS that also checks `statusCode`, nested `response.status`, the NotFoundError `name`/`body`, and `message`/`detail` text, descending cause/body/error/data. Export it and add direct unit tests across every shape (incl. the real wrapped-Error production shape and a response.status-only 404), plus the transient/auth/network cases that must still propagate. Co-authored-by: codex <codex@users.noreply.github.com>
…e text Address review (Cursor Bugbot): isOpenCodeNotFound matched the free-text message/detail, so a non-404 error whose text merely contains 'not found' (a 500 saying 'upstream X not found', an auth error, or a serialized body from openCodeRuntimeErrorDetail) was misclassified as a missing session and silently started a fresh one. Decide only on structured signals — a numeric 404 (status/statusCode/nested response.status) or an explicit NotFoundError name — which already cover the real throwOnError:true production shape (cause.status=404 + body.name). Update unit tests to assert free-text-only inputs (incl. a 500 whose message contains 'not found') now propagate. Co-authored-by: codex <codex@users.noreply.github.com>
…ontext The directory-mismatch guard added while hardening this PR started a fresh, EMPTY session whenever the resumed session's stored directory differed from the requested cwd. Its stated rationale -- "OpenCode routes a prompt to the session's own stored directory, so resuming under a different cwd would run in the wrong tree" -- does not hold: OpenCode resolves tool execution, snapshots and file ops from the per-request directory param (instance context), not from session.info.directory. So the guard solved a non-problem and introduced a real one: any time a thread's cwd changes (most commonly when it moves from the project root into a git worktree between turns) the whole conversation was stranded in the old session and the follow-up landed in an empty one -- the exact pingdotgg#3604 symptom this PR set out to fix. Fix: when the persisted session exists but was created under a different directory, fork it INTO the requested directory (client.session.fork({ sessionID, directory })) instead of creating an empty session. OpenCode clones the full message history into a new session bound to the requested worktree, so the follow-up keeps its context and tools still run on the correct tree. The fork id becomes the durable resume cursor. A genuinely missing (404) session still starts fresh, unchanged. Verified against the OpenCode source that fork copies all messages/parts with fresh ids and stamps the new session's directory/path from the request context. Test: the former "starts fresh on directory mismatch" case now asserts the session is forked with history (fork called, no session.create, cursor -> fork id) via a new fork mock; the not-found path still starts fresh. Co-authored-by: codex <codex@users.noreply.github.com>
…ts name A node carrying an explicit non-404 numeric HTTP status now seals its subtree in isOpenCodeNotFound: a 500 whose serialized body is named NotFoundError (or that is itself named UpstreamNotFoundError) propagates instead of silently falling back to session.create and dropping context. Co-authored-by: codex <codex@users.noreply.github.com>
A trailing slash, an unnormalized segment, or a symlinked cwd (macOS /tmp -> /private/tmp) made the resume path misread the same working tree as a cwd change, forking the session and repointing the durable cursor at the clone on every resume. Compare lexically resolved forms first, then realpath both sides, each degrading to its lexical form when resolution fails (deleted directory, external-server path). Co-authored-by: codex <codex@users.noreply.github.com>
…m/Path services Drops the nodeBuiltinImport pragmas: isSameOpenCodeDirectory now takes the FileSystem and Path services (resolved once in makeOpenCodeAdapter, already present in OpenCodeDriverEnv) instead of importing node:fs and node:path directly, and the symlink test fixture moves to makeTempDirectoryScoped/symlink on the FileSystem service. Co-authored-by: codex <codex@users.noreply.github.com>
Comment-only: the resume doc blocks had grown to 17-23 lines while sibling adapters cap around 11; keep the constraints (structured-404-only classification, subtree sealing, fork-preserves-history, race cleanup scope) and drop the narration. Co-authored-by: codex <codex@users.noreply.github.com>
A substring match let any status-less error named *NotFound* (UpstreamNotFoundError, ProviderNotFoundError) pass as a missing session and silently start an empty one. OpenCode's API generates exactly name "NotFoundError" for every 404, so match it exactly. Co-authored-by: codex <codex@users.noreply.github.com>
ea323c0 to
8bfeff6
Compare
* fix(server): resolve Claude SDK executable path on Windows npm installs (pingdotgg#3740) * Fix project action preview settings persistence (pingdotgg#3842) * fix(desktop): allow clipboard writes in the preview browser (pingdotgg#3889) * fix(web): handle sidebar shortcut before editors (pingdotgg#3921) * fix(server): recognize Bedrock-backed Claude as authenticated (pingdotgg#3931) * Fix incorrect pluralization of “entry” (pingdotgg#3933) * feat(server): title background-task work-log rows with the task name (pingdotgg#3751) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix: delegate OpenCode session titles to provider (pingdotgg#3720) * Archive selected threads from the context menu (pingdotgg#3895) * fix(cli): support force removing projects (pingdotgg#3922) * fix: allow sidebar to be shrunk when wider than viewport (pingdotgg#2456) Co-authored-by: Shoaib Ansari <shoaibansari@Shoaibs-Mac-mini.local> Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(codex): show web search query and url in tool call details (pingdotgg#2093) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Add Codex launch arguments setting (pingdotgg#2892) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> Co-authored-by: root <root@localhost.localdomain> * [orchestration] Clear stale active turn when session becomes inactive (pingdotgg#3159) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Regenerate Codex reset credit protocol bindings (pingdotgg#4173) Co-authored-by: codex <codex@users.noreply.github.com> * fix(preview): preserve direct localhost navigation (pingdotgg#3939) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> * Synchronize mobile threads with authoritative shell snapshots (pingdotgg#4163) Co-authored-by: codex <codex@users.noreply.github.com> * Gate iOS glass layout on native support (pingdotgg#4032) Co-authored-by: codex <codex@users.noreply.github.com> * fix(opencode): resume the OpenCode session on follow-ups instead of starting an empty one (pingdotgg#3617) Co-authored-by: codex <codex@users.noreply.github.com> * fix(server): use CLI for OpenCode health check instead of spawning server (pingdotgg#4153) * fix(web): scope timeline minimap hover target to the side gutter (pingdotgg#3869) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * [codex] show complete approval details (pingdotgg#4111) * fix(web): paint text selection over composer chips (pingdotgg#4139) Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> * [codex] preserve custom model slugs (pingdotgg#4168) * fix(web): preview workspace images in the file panel (pingdotgg#3996) Co-authored-by: Rhiz3K <rhiz3k@protonmail.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * feat(web): drag files from the explorer into the chat composer (pingdotgg#4140) Co-authored-by: Julius Marminge <julius0216@outlook.com> Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> * fix(desktop): preserve main window bounds (pingdotgg#3851) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> * perf(orchestration): speed up new-chat propagation and offline catch-up (pingdotgg#4177) Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * Finale: upgrade changed files card to fix various UI issues (pingdotgg#4113) Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(web): always show environment chip for remote projects (pingdotgg#4217) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * chore: reconcile upstream sync (20260721) — typecheck/test fixups Post-cherry-pick reconciliation of the shell/thread sync rewrite: - adopt upstream's client shell.ts + shell-sync.test.ts (drops the fork's superseded #142 replay-gap watchdog; server no longer emits 'caught-up') - remove the orphaned 'caught-up' contract member and obsolete fork shell server tests (upstream's coalescing tests cover the behavior) - keep the fork's thread reconciliation, resubscribing via subscribeDynamic (establish base once; foreground/session resubscribe via the live cursor) - add latestSequence to OrchestrationEngine test mocks; thread dispatch authority in bin.test; narrow stream-item unions past the new 'synchronized' Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: David Whatley <nsxdavid@gmail.com> Co-authored-by: coach007 <6238600+keeperxy@users.noreply.github.com> Co-authored-by: Carlos Rico-Ospina <carlosricojr@gmail.com> Co-authored-by: Andrew Barnes <bortstheboat@gmail.com> Co-authored-by: Pieter van Zyl <20579513+PieterVanZyl-Dev@users.noreply.github.com> Co-authored-by: mel <mcmelon@nodiumhosting.com> Co-authored-by: Theo Browne <me@t3.gg> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Tristan Knight <tris203@gmail.com> Co-authored-by: Christoph Herzog <a.github@omega-id.com> Co-authored-by: Shoaib <shoaib050326@gmail.com> Co-authored-by: Shoaib Ansari <shoaibansari@Shoaibs-Mac-mini.local> Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Guilherme Vieira <46866023+GuilhermeVieiraDev@users.noreply.github.com> Co-authored-by: James <105842516+jamesx0416@users.noreply.github.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> Co-authored-by: root <root@localhost.localdomain> Co-authored-by: Andrew Forster <76947376+Andrew-Forster@users.noreply.github.com> Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Chris Michael Guzman <67719167+Chrrxs@users.noreply.github.com> Co-authored-by: Vadym Kotai <vdmkotai@gmail.com> Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> Co-authored-by: xxashxx-svg <xxanshxx9@gmail.com> Co-authored-by: Maxwell Young <maxtheyoung@gmail.com> Co-authored-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: Rhiz3K <33246262+Rhiz3K@users.noreply.github.com> Co-authored-by: Rhiz3K <rhiz3k@protonmail.com> Co-authored-by: Anirudh Coontoor <me@anirudhs.net> Co-authored-by: Rusiru Sadathana <rusirusadathana@gmail.com> Co-authored-by: ss <69873514+sandersonstabo@users.noreply.github.com> Co-authored-by: wizzoapp[bot] <254688279+wizzoapp[bot]@users.noreply.github.com>
* Use rounded depth logo for production splash screen (pingdotgg#3780) Co-authored-by: Cursor Agent <cursoragent@cursor.com> * fix(release): stage pnpm 11 allowBuilds for desktop installs (pingdotgg#3781) Co-authored-by: Cursor Agent <cursoragent@cursor.com> * Upgrade Clerk toolchain to latest versions (pingdotgg#3785) * fix(release): bump electron-builder so pnpm 11 deduped deps land in the asar (pingdotgg#3790) * Fix desktop native optional dependency packaging (pingdotgg#3816) * [codex] Upgrade Clerk stack (pingdotgg#3821) Co-authored-by: codex <codex@users.noreply.github.com> * [codex] Preserve worktree metadata during branch sync (pingdotgg#3822) Co-authored-by: codex <codex@users.noreply.github.com> * feat(client): persist offline environment data and mobile preferences (pingdotgg#3795) Co-authored-by: Julius Marminge <julius@mac.lan> Co-authored-by: codex <codex@users.noreply.github.com> * [codex] Label max and ultra reasoning (pingdotgg#3824) Co-authored-by: codex <codex@users.noreply.github.com> * fix(mobile): embed fonts and render project favicons reliably (pingdotgg#3823) Co-authored-by: codex <codex@users.noreply.github.com> * Show compact PR number badges in mobile thread rows (pingdotgg#3827) Co-authored-by: codex <codex@users.noreply.github.com> * Expose mobile PR indicator labels to accessibility (pingdotgg#3828) Co-authored-by: codex <codex@users.noreply.github.com> * Fix truncated chat error alert layout (pingdotgg#3899) * fix(marketing): show platform-appropriate commit shortcut on the website (pingdotgg#3644) * [codex] Add Android mobile support (pingdotgg#3579) Co-authored-by: Horus Lugo <horusgoul@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: maria-rcks <maria@kuuro.net> Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com> Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com> Co-authored-by: Alex <me@pixp.cc> Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Julius Marminge <julius@mac.lan> * Use client-side fallbacks for missing project favicons (pingdotgg#3959) * Skip stale working-task notifications (pingdotgg#3961) * Prepare Android beta branding and review diff UI (pingdotgg#3967) * perf(web): duty-cycle status animations and remove fixed noise overlay (pingdotgg#3978) * fix(docs): correct CI task-runner commands in ci.md (pingdotgg#3990) * fix(docs): repair broken source links in architecture overview (pingdotgg#3991) * fix(docs): replace stale codething-mvp absolute paths with repo-relative links (pingdotgg#3992) * docs: Add T3 Code Legal Docs (pingdotgg#3972) Co-authored-by: codex <codex@users.noreply.github.com> * Fix Legal modal header crash (pingdotgg#4000) Co-authored-by: codex <codex@users.noreply.github.com> * [codex] Fix onboarding connection status (pingdotgg#4001) Co-authored-by: codex <codex@users.noreply.github.com> * Isolate native diff highlight grammar state (pingdotgg#4029) * Fix macOS fullscreen titlebar spacing (pingdotgg#4019) * Prevent duplicate project workspace roots (pingdotgg#3829) Co-authored-by: codex <codex@users.noreply.github.com> * Normalize over-indented markdown list items (pingdotgg#4020) Co-authored-by: codex <codex@users.noreply.github.com> * Resolve localhost preview URLs for remote environments (pingdotgg#4011) Co-authored-by: codex <codex@users.noreply.github.com> * fix(mobile): Send composer images in upload wire format (pingdotgg#4035) * Fix iOS terminal Enter input encoding (pingdotgg#4043) * Add native mobile share target support (pingdotgg#4021) Co-authored-by: codex <codex@users.noreply.github.com> * [codex] Expand real-route app store screenshot harness (pingdotgg#4014) Co-authored-by: codex <codex@users.noreply.github.com> * fix(server): use CLAUDE_CONFIG_DIR instead of HOME for Claude instanc… (pingdotgg#4017) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * Fix dropped events during initial thread snapshot (pingdotgg#4079) * feat: show nightly update changelog tooltip (pingdotgg#3832) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(git): treat selected commit paths literally (pingdotgg#3998) * fix(server): stabilize non-repository Git diagnostics (pingdotgg#4077) * Refresh app icons across release variants (pingdotgg#4080) Co-authored-by: codex <codex@users.noreply.github.com> * Update marketing GitHub star count (pingdotgg#4088) * fix(marketing): correct Cursor icon color (pingdotgg#4090) * Normalize protocol-relative remote host input as https (pingdotgg#3971) * fix(cursor): default binary path to cursor-agent (avoid path conflict w/ grok) (pingdotgg#4094) * Fix documented task-runner commands (bun run -> vp) (pingdotgg#3965) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Allow preview panel to grow on wide displays (pingdotgg#4044) * fix: prevent initial right-click from selecting a context menu item (pingdotgg#3877) * Fix duplicate keybinding rule when replacing with an existing rule (pingdotgg#3969) Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(server): image upload crashed dispatchCommand with a stack overflow (pingdotgg#3952) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * Remove unused code parameter from describePreviewError (pingdotgg#3970) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> * [codex] prevent ACP assistant ID collisions after restarts (pingdotgg#3932) Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(web): inset Windows desktop scrollbars from resize edge (pingdotgg#4097) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> * [codex] fix mobile composer Enter behavior (pingdotgg#3930) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> * feat(server): include runtime model and effort in Codex developer instructions (pingdotgg#3948) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(ux): spamming cmd + , no longer stack opening settings (pingdotgg#2757) Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(terminal): strip AppImage runtime env from spawned terminals (pingdotgg#3108) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> * fix(server): thread cwd through Claude capability probe (pingdotgg#2048) (pingdotgg#2124) Co-authored-by: Julius Marminge <julius0216@outlook.com> * [codex] fix: guard invalid web timestamps (pingdotgg#3515) Co-authored-by: Codex <codex@openai.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * [codex] fix: tolerate invalid latest user message timestamps (pingdotgg#3521) Co-authored-by: Codex <codex@openai.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * [codex] Fix provider update checks restore defaults (pingdotgg#3531) Co-authored-by: Codex <codex@openai.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(server): skip undecodable provider runtime rows when listing sessions (pingdotgg#3951) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> Co-authored-by: codex <codex@users.noreply.github.com> * Share MCP OAuth locks across Codex shadow homes (pingdotgg#4104) * Preserve T3 Code identity in macOS development launcher (pingdotgg#4102) * fix(web): increase contrast of question option descriptions (pingdotgg#3867) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * feat: draft hero landing on the index route (pingdotgg#4055) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> * feat: file explorer mention actions and zoom-aware context menus (pingdotgg#4054) Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(web): avoid duplicate mention text on paste Co-authored-by: codex <codex@users.noreply.github.com> * fix(mobile): restore iOS home screen branding (pingdotgg#4025) Co-authored-by: Julius Marminge <julius0216@outlook.com> * perf(client): defer active thread cache writes (pingdotgg#4006) * Default diffs to working changes (pingdotgg#3974) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Add Grok to marketing site provider list (pingdotgg#3484) * Fix reopening existing Diff tab (pingdotgg#3973) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Fix sending messages during active turns (pingdotgg#3919) Co-authored-by: Julius Marminge <julius0216@outlook.com> * [codex] Route OpenCode missing-session errors through Effect (pingdotgg#3608) Co-authored-by: Codex <codex@openai.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * [fix/feat:ui] Show default option badge (pingdotgg#3232) Co-authored-by: Julius Marminge <julius0216@outlook.com> * [fix/feat:ui] Preserve open-in editor brand colors (pingdotgg#3225) Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(web): handle macOS Home and End in composer (pingdotgg#2508) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Allow failed remote environments to be removed (pingdotgg#4084) Co-authored-by: Julius Marminge <julius0216@outlook.com> * [codex] canonicalize client timestamps (pingdotgg#4112) * [fix/feat:ui] Make selected menu checks blue (pingdotgg#3234) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> * fix(desktop): Validate WSL node version against engine range after probe success (pingdotgg#3621) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Refresh splash screen and favicon branding (pingdotgg#4120) * Add terminal selection copy action (pingdotgg#2904) * Add isolated app testing workflow (pingdotgg#4121) Co-authored-by: codex <codex@users.noreply.github.com> * feat(web): themed sidebar header art for nightly and dev builds (pingdotgg#4130) Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> * feat: add headless `t3 connect` setup for SSH hosts (pingdotgg#3749) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> * Refine T3 Connect authorization surfaces (pingdotgg#4159) Co-authored-by: codex <codex@users.noreply.github.com> * fix: increase OpenCode server startup timeout from 5s to 30s (pingdotgg#4132) * fix(shared): delete unused agentAwareness phase predicates (pingdotgg#4134) * fix(mobile): Stabilize native stack option updates (pingdotgg#4037) Co-authored-by: codex <codex@users.noreply.github.com> * Make test-t3-app skill discoverable by Claude Code (pingdotgg#4162) Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> * fix(web): improve dev sidebar backdrop contrast & remove version pills (pingdotgg#4166) * Fix draft banner stack overlap (pingdotgg#4164) Co-authored-by: codex <codex@users.noreply.github.com> * Add portable mobile app testing guidance (pingdotgg#4165) Co-authored-by: codex <codex@users.noreply.github.com> * fix(client): use lightweight connection probe (pingdotgg#4137) * fix(server): resolve Claude SDK executable path on Windows npm installs (pingdotgg#3740) * Fix project action preview settings persistence (pingdotgg#3842) * fix(desktop): allow clipboard writes in the preview browser (pingdotgg#3889) * fix(web): handle sidebar shortcut before editors (pingdotgg#3921) * fix(server): recognize Bedrock-backed Claude as authenticated (pingdotgg#3931) * Fix incorrect pluralization of “entry” (pingdotgg#3933) * feat(server): title background-task work-log rows with the task name (pingdotgg#3751) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix: delegate OpenCode session titles to provider (pingdotgg#3720) * Archive selected threads from the context menu (pingdotgg#3895) * fix(cli): support force removing projects (pingdotgg#3922) * fix: allow sidebar to be shrunk when wider than viewport (pingdotgg#2456) Co-authored-by: Shoaib Ansari <shoaibansari@Shoaibs-Mac-mini.local> Co-authored-by: Julius Marminge <julius0216@outlook.com> * fix(codex): show web search query and url in tool call details (pingdotgg#2093) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Add Codex launch arguments setting (pingdotgg#2892) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> Co-authored-by: root <root@localhost.localdomain> * [orchestration] Clear stale active turn when session becomes inactive (pingdotgg#3159) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Regenerate Codex reset credit protocol bindings (pingdotgg#4173) Co-authored-by: codex <codex@users.noreply.github.com> * fix(preview): preserve direct localhost navigation (pingdotgg#3939) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> * Synchronize mobile threads with authoritative shell snapshots (pingdotgg#4163) Co-authored-by: codex <codex@users.noreply.github.com> * Gate iOS glass layout on native support (pingdotgg#4032) Co-authored-by: codex <codex@users.noreply.github.com> * fix(opencode): resume the OpenCode session on follow-ups instead of starting an empty one (pingdotgg#3617) Co-authored-by: codex <codex@users.noreply.github.com> * fix(server): use CLI for OpenCode health check instead of spawning server (pingdotgg#4153) * fix(web): scope timeline minimap hover target to the side gutter (pingdotgg#3869) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * [codex] show complete approval details (pingdotgg#4111) * fix(web): paint text selection over composer chips (pingdotgg#4139) Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> * [codex] preserve custom model slugs (pingdotgg#4168) * fix(web): preview workspace images in the file panel (pingdotgg#3996) Co-authored-by: Rhiz3K <rhiz3k@protonmail.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * feat(web): drag files from the explorer into the chat composer (pingdotgg#4140) Co-authored-by: Julius Marminge <julius0216@outlook.com> Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> * fix(desktop): preserve main window bounds (pingdotgg#3851) Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> * perf(orchestration): speed up new-chat propagation and offline catch-up (pingdotgg#4177) Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> * Finale: upgrade changed files card to fix various UI issues (pingdotgg#4113) Co-authored-by: Julius Marminge <julius0216@outlook.com> * Pass CLI OAuth config to hosted web deploy (pingdotgg#4186) Co-authored-by: codex <codex@users.noreply.github.com> * fix(web): always show environment chip for remote projects (pingdotgg#4217) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix(web): keep composer editable while disconnected (pingdotgg#4241) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix: better defaults — Claude 1M context, Codex gpt-5.6, worktrees from origin main (pingdotgg#4240) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> * fix(claude): handle all SDK stream messages; stop spurious work-log warning rows (pingdotgg#4244) Co-authored-by: Claude Fable 5 <noreply@anthropic.com> --------- Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Rowan <rowan@cardow.co> Co-authored-by: Patricio Gómez Meneses <107218376+Prgm-code@users.noreply.github.com> Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Julius Marminge <julius@mac.lan> Co-authored-by: Jake Leventhal <jakeleventhal@me.com> Co-authored-by: Vedank Purohit <VedankPurohit2@gmail.com> Co-authored-by: Horus Lugo <horusgoul@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: maria-rcks <maria@kuuro.net> Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com> Co-authored-by: Ben Davis <45952064+bmdavis419@users.noreply.github.com> Co-authored-by: Alex <me@pixp.cc> Co-authored-by: Theo Browne <me@t3.gg> Co-authored-by: Kriday Dave <technocratix902@gmail.com> Co-authored-by: Ishan <ishansachu1@gmail.com> Co-authored-by: Dimitar Stoykov <mitkostoikov1988@gmail.com> Co-authored-by: Hugo Vizcaino Santana <42343504+HugoVizcainoSantana@users.noreply.github.com> Co-authored-by: Eric Tsai <52527831+EricTsai83@users.noreply.github.com> Co-authored-by: Manuel De Ceglie <80224270+AmoonPod@users.noreply.github.com> Co-authored-by: BunnyGamezsc <146652788+BunnyGamezsc@users.noreply.github.com> Co-authored-by: Olivier Melcher <olivier.melcher@gmail.com> Co-authored-by: Fazal Kadivar <fazalkadivar7@gmail.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com> Co-authored-by: Maxwell Young <maxtheyoung@gmail.com> Co-authored-by: Yukun Shan <92423096+nateEc@users.noreply.github.com> Co-authored-by: James <105842516+jamesx0416@users.noreply.github.com> Co-authored-by: Leonel Rivas <herial_vi@icloud.com> Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com> Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Co-authored-by: Codex <codex@openai.com> Co-authored-by: xxashxx-svg <xxanshxx9@gmail.com> Co-authored-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: Chris Michael Guzman <67719167+Chrrxs@users.noreply.github.com> Co-authored-by: Aditya Mer <101453576+Aditya190803@users.noreply.github.com> Co-authored-by: ss <69873514+sandersonstabo@users.noreply.github.com> Co-authored-by: Guilherme Vieira <46866023+GuilhermeVieiraDev@users.noreply.github.com> Co-authored-by: Noah Zepner <noah@zepner.dev> Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> Co-authored-by: Taras <Taras.Fomin@gmail.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: eeinarsson <128746408+eeinarsson@users.noreply.github.com> Co-authored-by: David Whatley <nsxdavid@gmail.com> Co-authored-by: coach007 <6238600+keeperxy@users.noreply.github.com> Co-authored-by: Carlos Rico-Ospina <carlosricojr@gmail.com> Co-authored-by: Andrew Barnes <bortstheboat@gmail.com> Co-authored-by: Pieter van Zyl <20579513+PieterVanZyl-Dev@users.noreply.github.com> Co-authored-by: mel <mcmelon@nodiumhosting.com> Co-authored-by: Tristan Knight <tris203@gmail.com> Co-authored-by: Christoph Herzog <a.github@omega-id.com> Co-authored-by: Shoaib <shoaib050326@gmail.com> Co-authored-by: Shoaib Ansari <shoaibansari@Shoaibs-Mac-mini.local> Co-authored-by: root <root@localhost.localdomain> Co-authored-by: Andrew Forster <76947376+Andrew-Forster@users.noreply.github.com> Co-authored-by: Vadym Kotai <vdmkotai@gmail.com> Co-authored-by: Rhiz3K <33246262+Rhiz3K@users.noreply.github.com> Co-authored-by: Rhiz3K <rhiz3k@protonmail.com> Co-authored-by: Anirudh Coontoor <me@anirudhs.net> Co-authored-by: Rusiru Sadathana <rusirusadathana@gmail.com>

Fixes #3604.
What
The OpenCode adapter never read or emitted a resume cursor, so the upstream
ses_…id lived only in process memory. When that in-memory binding was lost —ProviderSessionReaperstopping an idle session (~30 min), or an app/server restart — the next follow-up in the same visible thread was sent to a brand-new, empty OpenCode session. t3code kept rendering its own projection DB, so the user still saw the full history while the model had no context.This makes the OpenCode adapter resumable, mirroring the existing Grok/Cursor/Codex pattern, entirely within
apps/server/src/provider/Layers/OpenCodeAdapter.ts:startSessionnow emitsresumeCursor: { schemaVersion, sessionId }on the returnedProviderSession(andsendTurnechoes it), soProviderServicepersists it intoprovider_session_runtime.resume_cursor_json.startSessionvalidates the id withsession.getand re-adopts that session instead of callingsession.create. OpenCode scopes history by session id, so prompting the same id restores the full prior conversation.session.getfailure) falls back to a fresh session, so a stale cursor can never wedge the thread.Why
This is the documented root cause in #3604 (with DB-level evidence of two OpenCode sessions per visible thread). The persistence/recovery plumbing is already provider-agnostic:
ProviderService.startSessionfalls back to the stored binding cursor when the reactor passes none, so no changes are needed outside the adapter — it just needed the adapter to start producing and consuming a cursor like every other provider already does.Scope
Intentionally small and focused — 2 files, no contract / persistence / orchestration changes:
apps/server/src/provider/Layers/OpenCodeAdapter.ts(+118/-20)apps/server/src/provider/Layers/OpenCodeAdapter.test.ts(+147) — regression tests for: fresh-session cursor emission, resume re-adopting the persisted id (nocreate), follow-up turns targeting the resumed id, stale-cursor fallback tocreate, and malformed/foreign-cursor rejection.Validation
tsgo --noEmitclean;OpenCodeAdapter.test.ts(21 tests) plus the fullsrc/provider+src/orchestrationsuites (531 tests) pass.Note
Medium Risk
Changes core session lifecycle for OpenCode threads; misclassified errors could still wedge or reset context, but behavior is guarded by structured 404 detection and extensive adapter tests.
Overview
Fixes #3604 by making the OpenCode adapter produce and consume a persisted
resumeCursor(schemaVersion+sessionId), like other providers, so follow-ups keep upstream conversation context after idle reaper or restart.startSessionnow probessession.getwhen a valid cursor is present: reuse the session when cwd matches (withsession.updatefor currentruntimeModepermissions), fork into the requested directory when cwd changed (preserving history), or create only on a confirmed 404. Transient/auth errors from the probe fail instead of silently starting fresh. Race cleanup aborts only sessions this call created, not resumed ones.sendTurnreturns the cursor so persistence stays fresh. HelpersisOpenCodeNotFoundandisSameOpenCodeDirectoryclassify SDK errors and path equivalence (symlinks, trailing slashes).Tests extend the OpenCode mock with
get/update/forkand cover resume, stale cursor, bad cursor, transient errors, cwd fork, and utility behavior.Reviewed by Cursor Bugbot for commit 8bfeff6. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Resume existing OpenCode sessions on follow-up turns instead of creating empty ones
startSessioninOpenCodeAdapter.tsnow parses a persistedresumeCursorand probessession.getto verify the session still exists before reusing it.cwd, the session is forked into the new directory; permissions are re-applied viasession.updateon resume.sendTurnresults now include the session'sresumeCursorso callers can persist it for future follow-ups.Macroscope summarized 8bfeff6.