Dev env setup, opencode SDK v2 migration, model picker, and main-flow cleanups - #58
tanishqkancharla wants to merge 15 commits into
Conversation
…nstall.sh) Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
|
Claude finished @tanishqkancharla's task in 2m 4s —— View job PR Review📋 Detailed ReviewSpec AnalysisThis PR bundles five distinct improvements:
Changed FilesEnvironment Setup
Removed Config (5000+ lines)
SDK v2 Migration
Model Picker
Main-Flow Cleanups
Stuck Busy Fix
New PatchToolCall
Test/Mock Updates
Simplicity Assessment
Correctness Assessment
SummaryWell-structured PR that delivers environment setup, SDK migration, model picker, and several quality-of-life cleanups. The main-flow refactors ( Required ActionsNone. SuggestionsNone. --- | |
Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
- Bump @opencode-ai/sdk 1.2.14 -> 1.18.30 to match the opencode server/CLI
- Adapt session.messages() to the v2 { info, parts }[] response shape
- Align FileDiffSchema with the v2 snapshot diff shape (patch/status)
Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
- New ModelSwitcher dropdown lists configured providers/models via config.providers() - Selected model is sent with each prompt (session.prompt model param) - Selection persists per-session with a global default, stored via OPENCODE lastUsedModel - Falls back to the first available model when no selection is persisted Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
… is at top Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
- Message no longer stores a text field; text is derived from store.part at render time via extractTextFromParts - eventHandlers: replace 3 copies of 'ensure message + resync text' with a single ensureMessage() helper; drop resolveMessageText - MessageItem/MessageList derive text from parts; bootstrap stops precomputing - MockSyncProvider synthesizes a text part from authoring-only mock text Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
… helpers Removes 3 copies of the summary/diff aggregation and 2 copies of the token->context-usage math (plus the duplicated 200000 magic number). Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
- Add dispatchPrompt() shared by submit / queue-drain / edit (removes 3 copies of setThinking + error parsing + logging) - sendPrompt now takes an options object instead of 6 positional args - Replace inFlightMessage object + onSessionIdle callback registry with a single pendingSessionId signal that drains the queue via store.thinking reactivity - Remove sessionIdleCallbacks from the sync store and event reducer Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
…rence Both pickers now share one default + per-session-override helper instead of two mirrored signal sets and accessor pairs. Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
Full bootstrap (agents + session list + status) runs on connect/reconnect or when globals are unloaded; session switches now only refetch messages, session detail, and permissions instead of re-pulling near-static workspace data. Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
The busy/'steering' state could get stuck after a reply had already arrived if the session.idle SSE event was missed (timing/reconnects). Add a self-healing fallback that clears thinking when the session's newest message is a completed assistant message, so the input returns to idle even without idle. Guarded to the latest message so a queued/steered follow-up still shows busy. Verified by fault-injecting a missed session.idle. Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
Tiptap getText() defaults to a '\n\n' block separator, so each Enter (new paragraph) produced a doubled newline in the submitted text. Use a single '\n' block separator. Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
Edit/write and bash tool calls forced defaultOpen=true while every other tool defaulted closed, making the open/closed state look arbitrary. Drop the override so all tool results start collapsed and only open when toggled. Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
apply_patch fell through to GenericToolCall, which showed the raw tool result
('Success. Updated the following files...') in the header. Add a dedicated
PatchToolCall that reads state.metadata.files and shows 'Patched <path>' for a
single file or 'Patched N files' for multiple, with diff stats, and the diff
collapsed by default.
Co-authored-by: Tanishq Kancharla <tanishqkancharla@users.noreply.github.com>
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 69d23de. Configure here.
| if (info.role === "assistant" && info.time?.completed) { | ||
| const latest = store.message[sessionId]; | ||
| if (latest && latest.length > 0 && latest[latest.length - 1].id === info.id) { | ||
| setStore("thinking", sessionId, false); |
There was a problem hiding this comment.
Self-heal clears busy during steering
Medium Severity
The new thinking fallback treats a completed latest assistant as session-idle, but a steered follow-up is sent over HTTP before that user message exists in the store. If the prior assistant completes in that window, thinking flips false and the pendingSessionId effect can drain the queue, hiding the stop/busy state while work is still in flight.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 69d23de. Configure here.


Summary
Environment setup, an opencode SDK v2 migration, a model picker, removal of the repo-level opencode config, main-flow "knot" cleanups, and a fix for a stuck busy/"steering" state.
Environment setup
.cursor/environment.json+ idempotent.cursor/install.sh:pnpm install+ build, OpenCode CLI install andPATHwiring, best-effort VS Code install.OPENCODE_AUTH_JSONCursor secret into~/.local/share/opencode/auth.json.Remove repo-level opencode config
.opencode/andopencode.json; the extension now uses the user's global/default opencode config.Migrate to opencode SDK v2
@opencode-ai/sdk1.2.14→1.18.30; adaptedsession.messages()to the v2{ info, parts }[]shape; alignedFileDiffSchemawith the v2 snapshot-diff shape.Model picker
ModelSwitcherdropdown fromconfig.providers(), grouped by provider; selected model sent with each prompt and persisted per-session with a global default. Opens below/right-aligned when the input is at the top.Main-flow cleanups
Message.textcache + 3 hand-maintained resync blocks; addedensureMessage).deriveFileChanges*/deriveContextInfohelpers.sendPromptoptions object + shareddispatchPromptfor submit/queue/edit.inFlightMessage+onSessionIdleregistry with apendingSessionIdsignal draining offstore.thinking.createSessionPreference.Fix: stuck busy / "steering" state
session.idleSSE event was missed (timing/reconnects). Added a self-healing fallback in the event reducer that clearsthinkingwhen a session's newest message is a completed assistant message (guarded so a queued/steered follow-up still shows busy).session.idle: reproduced the stuck state, confirmed the fallback clears it, and confirmed normal two-message flows still complete and return to idle.Testing
pnpm exec vitest run→ 313 tests passing;pnpm buildclean; changed files typecheck clean.thinking-stuck-fix-happy-path.mp4
OpenCode panel: multiple replies rendered and input returned to idle
Notes
OPENCODE_AUTH_JSONsecret (contents of~/.local/share/opencode/auth.json) to persist credentials across runs.uikit.tsx, oneSelectionAttachmentnarrowing) and are unrelated to these changes.To show artifacts inline, enable in settings.