Uh oh!
There was an error while loading. Please reload this page.
feature: interactive setup wizard - #14
Conversation
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
adamdotdevin
left a comment
There was a problem hiding this comment.
this is really great, thank you so much! left some feedback/questions!
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
adamdotdevin
commented
May 15, 2025
sorry for the delay @l0gicgate, just wanted to pull this down and run through it myself before merging; should have it merged first thing tomorrow! |
l0gicgate
commented
May 15, 2025
No worries @adamdottv, happy to address any other feedback you have before we merge! |
adamdotdevin
left a comment
There was a problem hiding this comment.
pulled this down this morning and ran through it, a few changes needed:
- if you hit
ctrl+cyou're able to exit the setup dialog and get into a weird state where there's nothing to do but close the app and restart - the list of providers/models should use the new
simple-listcomponent (it has vim navigation with j/k as well) - it's not clear to me what "API key" would be for some of the providers like Bedrock and Azure where you have to have AWS/Azure credentials configured in your environment for these to be setup correctly; not sure what we should do here, but we could just display a message when you choose one of those providers (instead of the API key form) that basically tells the user they need to ensure they have AWS/Azure creds setup and then restart the app
- had an inline note about repurposing the provider friendly names
Uh oh!
There was an error while loading. Please reload this page.
l0gicgate
commented
May 16, 2025
adamdotdevin
commented
May 16, 2025
can we just remove bedrock and azure from that dialog in the interim? |
l0gicgate
commented
May 20, 2025
@adamdottv is it safe to assume that this PR will be superseded by #38? I will close if so |
thdxr
commented
May 21, 2025
@l0gicgate that PR is overhauling the core of opencode to be powered by bun. the TUI is still going to be in go - simple server client model. this PR will probably have to change but we'll keep the TUI parts |
l0gicgate
commented
May 21, 2025
Okay cool @thdxr, thanks for the update! Let me know what changes need to be done and I’ll address right away. |
thdxr
commented
Jun 14, 2025
closing as we rewrote the codebase - appreciate it though! |
- Issue anomalyco#14: SDK cache now limited to 50 entries with LRU eviction - Issue anomalyco#15: Languages cache now limited to 100 entries with LRU eviction - Issue anomalyco#16: Instance cache now limited to 20 entries with LRU eviction Creates new createLruCache utility in src/util/cache.ts with: - maxEntries limit for bounded cache size - LRU eviction policy when limit is reached - Optional onEvict callback for cleanup
add refresh gesture to chat window
The previous flow took the three ORT sessions out of self, ran the preprocess/encode/decode pipeline in a closure, and restored them back only on normal return. Any .unwrap() panic mid-pipeline left self with three None sessions, so the next transcribe() hit "Not loaded" and the user had to wait ~1 s for ONNX to reload ~700 MB from disk. Wrap the body in std::panic::catch_unwind(AssertUnwindSafe(...)) and keep the sessions in local Options that we restore unconditionally before returning — even on unwind. The panic payload is stringified so the caller gets a meaningful error instead of a hard abort. Closes#14/21.
Fixes all 17 Copilot comments: Telemetry opt-out (#1, #2, #3, #9, #16): - tracker.ts now reads FINNY_TELEMETRY=0 / OPENCODE_TELEMETRY=0 at module load, so the opt-out applies in every entrypoint (TUI worker, server, CLI), not just the bootstrap path. - Email dialog auto-prompt and /subscribe slash command also gated on Analytics.isEnabled() — email POST goes to the same Convex deployment. Tracker correctness (#5, #14, #17): - drain() now also waits for the DeviceProfile.userId() resolution promise, not just the post-send promise. - worker rpc.shutdown() and main-thread thread.ts both call Analytics.drain() before tearing down — neither beforeExit nor SIGTERM fire on worker.terminate() / process.exit(0). - beforeExit handler runs at most once per process, preventing an infinite drain loop when a hung telemetry request later resolves and re-empties the loop. Privacy (#10, #11, #12): - Drop process.argv from tui.worker.booted (could include --prompt text and project paths). - error.surfaced now sends only error.name; error messages frequently embed user prompt content and local file paths. - Don't persist the submitted email address to local KV (no reader, just unnecessary PII retention). Email dialog state machine (#4, #6, #8): - Wait for kv.ready before evaluating the prompt gate so we don't re-show the dialog to users who already submitted/skipped. - Conditional dismiss handler — only marks "skipped" when no terminal status has been set, so a successful submit isn't overwritten by the dismiss callback that fires on dialog.clear() and isn't suppressed by another dialog replacing this one. Server-side validation (#15): - subscribe mutation now rejects empty / oversized / regex-failing emails with a ConvexError, so the public Convex client can't bypass the TUI regex. Command coverage (#13): - Hook Analytics.track() in DialogCommand.trigger() instead of the bus event handler. trigger() is the central activation point for palette, slash, keybind, plugin, and bus paths — single hook, full coverage, no double-counting. Comment wording (#7): - bootstrap.ts: "opt-in by default" → "enabled by default" (correct description of opt-out semantics). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous flow took the three ORT sessions out of self, ran the preprocess/encode/decode pipeline in a closure, and restored them back only on normal return. Any .unwrap() panic mid-pipeline left self with three None sessions, so the next transcribe() hit "Not loaded" and the user had to wait ~1 s for ONNX to reload ~700 MB from disk. Wrap the body in std::panic::catch_unwind(AssertUnwindSafe(...)) and keep the sessions in local Options that we restore unconditionally before returning — even on unwind. The panic payload is stringified so the caller gets a meaningful error instead of a hard abort. Closes#14/21.
feat: add non-invasive in-app updater
…as/refiner UI fixes: - anomalyco#15 Remove the gear-icon "Tweaks" popover (theme + collapse) — user reported it as useless chrome. Theme falls back to saved pref / system, rail collapse stays on the rail's own chevron toggle. - anomalyco#7 Task names now follow each session's title (auto-generated or user- renamed). Root cause: `newWorkflowTask` was pre-setting `title: "Workflow"` on session.create, which blocked the backend's title agent from auto-generating (the agent only fires when title matches the default ISO placeholder). New sessions now leave title unset → ensureTitle fires → each task gets a distinct name. Rail and Tasks drawer show "Untitled" for sessions that still have the default placeholder; node-tab labels prefer the bound child session's title. - Rail's sub-task list capped at 8 visible rows with internal scroll (was squeezing all tasks into the visible rail height). - anomalyco#14 Per-slave model picker: clear `local.model` before opening the picker so picking the SAME model as master still routes (previously the on(key) effect required a key change to fire, so same-model picks silently no-op'd — the user's "选其他不生效" complaint). - anomalyco#10 Canvas bottom-half occluded: `.wf-canvas-host` was `position: relative` only, so its `flex: 1` child `.wf-r2-canvas` had no flex parent to grow into. Made the host a flex column so the canvas actually fills its allotted height. - anomalyco#11 React production error anomalyco#409 fixed by un-nesting the drill-in button: the outer node card was a `<button>` wrapping an inner drill-in `<button>` — invalid HTML that React surfaces as anomalyco#409. Switched the outer to `div role="button"` with Enter/Space handling. Refiner: - anomalyco#13 Refiner no longer observes user messages addressed to the orchestrator agent (workflow planning commands aren't generalisable experiences). Gate added in `extractUserMessage`. - anomalyco#5 Archived experiences are now discoverable: new "已归档 (N)" chip in the Knowledge substrip when N > 0, toggles `includeArchived`. Archived rows already had an "Unarchive" button in the card menu — this just makes finding them obvious. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous flow took the three ORT sessions out of self, ran the preprocess/encode/decode pipeline in a closure, and restored them back only on normal return. Any .unwrap() panic mid-pipeline left self with three None sessions, so the next transcribe() hit "Not loaded" and the user had to wait ~1 s for ONNX to reload ~700 MB from disk. Wrap the body in std::panic::catch_unwind(AssertUnwindSafe(...)) and keep the sessions in local Options that we restore unconditionally before returning — even on unwind. The panic payload is stringified so the caller gets a meaningful error instead of a hard abort. Closes#14/21.
Description
On first start, when

.opencode.jsondoes not exist, we prompt the user with the setup wizard:Step 1: Select Provider

Step 2: Select Model

Step 3: Enter API Key

Demo
.opencodeand.opencode.jsonfrom your home directoryCloses#7