Repository navigation
feat: Agent-backend migration and v0.0.6 features - #75
Conversation
💡 Codex ReviewOrbit/apps/agent/src/services/chat/chat-message-service.ts Lines 648 to 652 in 764621f Calling Orbit/apps/agent/src/services/chat/streaming-reveal-controller.ts Lines 151 to 153 in 764621f When ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Introduces the Agent-backend codebase (forked from opencode) as the replacement for agent-bridge, using HTTP + SSE architecture with multi-provider support.
Rewrite README to match Orbit's brand positioning: - "AI-native development environment" (not "AI-powered code editor") - Document all V1 surfaces: Agent, Editor, Browser, Terminal, Vault - Add honest "What V1 Does Not Have" section - Remove Canvas from V1 features (moved to roadmap) - Fix platform claims to macOS-only (not cross-platform) - Fix GitHub URL typo (Recusive → Recursive) - Remove "agentic" terminology (Warp's positioning)
- Add orbit-primary icon centered at top of README - Fix CI badge: Recusive/Snowflake-V0 → Recusive/Orbit (matches remote) - Center hero text and badges for better presentation
…opic> Restructured docs/plans/ from a flat directory into a categorized system: - tracked/todo/ for queued plans, tracked/done/ for shipped plans - others/ with 14 topic subfolders (browser, canvas, vault, etc.) - Added plan tracking policy to root CLAUDE.md and docs/CLAUDE.md
Introduce OpenCode as an alternative AI backend alongside the existing Claude agent-bridge. Adds OpenCode SDK package, SSE event streaming, Rust process lifecycle management, dedicated Zustand stores (session, message, permission, provider), chat UI components, conversation repository abstraction layer, and backend-switching settings UI. Refactors sidebar and chat area to support backend-agnostic conversation handling.
Add comprehensive debug/info logging to the OpenCode backend prompt loop (session routes, permission evaluation, tool resolution, LLM calls) and frontend services (SSE manager, event coordinator, session service, stores, chat hook, UI bridge) to provide full pipeline observability. Update opencode-providers cache and add two new tracked plans (structured logging, unified chat UI). Refresh learnings.md with migration findings.
Delete the separate opencode/ component folder (11 files) and migrate OpenCode chat rendering into the shared chat pipeline. Adds OcAgentSurface, OcQuestionCard, oc-control-bar, generic-tool-widget, streaming reveal hook, and chat adapter. Updates input controls, message rendering, tool widgets, permission modal, provider settings, and session service to support the unified dual-backend architecture. Includes new tests and updated plans.
…t flash Migrate OcModelSelector and OcThinkingSelector from DropdownMenu to Command/Popover with search and smooth scroll. Redesign OcProviderDialog with scroll masks and refined layout. Refactor ProvidersSettings and BackendSettings with liquid-glass styling and inline auth flows. Polish source control with pill toggle tabs, rounded action buttons, and stable scrollbar gutter. Fix TUI flash-of-invisible-text by removing reactive `last` prop from Dynamic call and patching CodeRenderable to skip ensureVisibleTextBeforeHighlight when text is already visible. Add plan docs for settings-to-page migration and full-bleed TUI layout.
…d polish Replace the modal settings dialog with an inline page rendered at the shell level (App.tsx), matching the vault pattern. Settings content is centered with the same max-width as the chat area and respects the fullWidth toggle. Key changes: - UIStore: rename settingsDialog* → settings*, add closeSecondarySurface() - SettingsPage: inline page with mx-auto width, scrollbarGutter, Suspense key - SettingsNavList: grouped sections (General, Agent, Features) with headings - PrimarySidebar: conditional settings nav, pinned Feedback button at bottom - ContentTopBar: shows "Settings | Page" breadcrumb, back arrow wires up - AccountSettings: pulsing skeleton replaces spinner flash on credential check - SubagentsStore: persistent Zustand store (mirrors commands-store pattern)
- App.tsx: use null fallback for outer Suspense (SettingsPage module is tiny, inner Suspense handles the real skeleton with proper max-width) - PrimarySidebar: hide Settings/Feedback bar on welcome page - Move SETTINGS-DIALOG-TO-PAGE plan to tracked/done
…pdate plans and changelog Rebrand internal "Backend" terminology to user-facing "Engine" (v1/v2) across settings sidebar, backend page, and health section. Move app icon picker inline as a settings row with dots inside the dock shelf. Move 4 completed plans to done/, add OpenCode hooks system plan, and expand v0.0.6 changelog.
… and add pending-send message count Predicts when the backend will generate a title (2nd real user message) and shows a skeleton loader until a non-default title arrives via SSE. Adds pendingSendSessions to bump sidebar message count immediately on send. Normalizes OpenCode's default "Session - <date>" titles to "Untitled". Adds thinking-selector icon, updates provider model cache, and moves completed plan to done/.
Cloned Ghostty and stripped upstream git history, contributions, and license files. Kept AGENTS.md, HACKING.md, and PACKAGING.md as development references.
…al, polish file explorer skeleton - Remove 4200+ unused Ghostty files (nix, flatpak, snap, fuzz corpus, examples, images, po translations, pkg, test harnesses) - Rebrand macOS Swift layer: Ghostty → Orbit Terminal across AppDelegate, features, helpers, and tests - Delete Ghostty-specific Swift modules (Ghostty.App, Ghostty.Config, Ghostty.Surface, SurfaceView, etc.) - Add file explorer skeleton with minimum display time to prevent flash - Update OpenCode provider models and chat adapter improvements
…odule to OrbitTerminalKit, optimize file explorer blur-reveal Terminal-app: The previous commit over-eagerly renamed C API constants (GHOSTTY_ACTION_*, GHOSTTY_COLOR_SCHEME_*, env vars) to ORBIT_TERMINAL_*. These symbols come from the untouched libghostty C headers and must keep their original names. Swift module renamed GhosttyKit → OrbitTerminalKit. Agent app: Moved blur-reveal animation from per-item filter:blur() (dozens of elements choking the browser) to a single container-level animate-title-in class. Added entrance animation to SettingsNavList.
Key the header wrapper on settingsOpen so animate-title-in re-triggers when toggling settings. Apply the same animation to sidebar conversation actions and bottom utilities via a composite key.
…idebar/CLI, update providers - Browser hide/show now uses NSWindow alpha transparency instead of offscreen positioning (fixes Mission Control glitches and z-order drift) - Dialog overlays coordinate with browser panel visibility via new browser-overlay-coordination module (hide browser when dialog opens) - Add decorum set_ns_window_alpha helper for NSWindow transparency control - Terminal-app: add orbitctl CLI, IPC server (Unix socket), sidebar views, and expanded config options - Update opencode-providers.json with latest model data - Move browser-overlay-dialog-fix plan to done
…minal-app window and sidebar TodoBar: add updateToolInput action to tool-store for real-time streaming, fix flicker on consecutive TodoWrite calls with payload-aware selection, update OC chat adapter to emit tool input updates. Move completed plans to done/. Terminal-app: enhance window styling, sidebar view, and controller setup.
…akeFromNib, add CLAUDE.md and browser resize plan Move fullSizeContentView and titlebar hiding from configureSidebarTitlebar() into awakeFromNib so the style is applied before AppKit computes initial layout — eliminates the brief titlebar flash on window open. Block all titlebar accessories when sidebar is active instead of hiding them after the fact. Extract hideTitlebarContainer() helper with deferred second pass for reliability.
…owser animation plans Remove unused IPC server, notification/tab metadata stores, sidebar view/manager, and orbitctl CLI binary. Streamline window and terminal controller code. Add browser atomic setframe and native NSWindow animation plan docs.
Remove OrbitLogo + separator from browser and file viewer empty states, center the contextual icon (Globe, FileCode) on its own. Remove unused Terminal-app translation files and update provider config.
…ontext limits - Add CodeSearchToolWidget for OpenCode codesearch tool visualization - Map OpenCode 'question' tool to AskUserQuestionWidget with answer extraction - Remove step-finish token count noise from chat adapter - Wire model context window limits from provider store to OcAgentSurface - Add text-md (12px) size tier for control bar pills - Unify button shapes to rounded-full, improve hover states with tinted backgrounds - Add per-agent icons (Hammer, Map, Telescope) to agent mode picker - Reorder controls: model picker before mode picker - Update opencode-providers.json with expanded model data - Fix OcThinkingSelector only showing for OpenCode backend - Update Terminal-app CLAUDE.md
Improve title generation by stripping quotes, "Title:" prefix, and trailing periods from LLM output, with smart 50-char word-boundary truncation. Add implementation plan for OpenCode session restore optimization (pre-warm sidecar, parallel data load, skeleton on mount).
… during restore - Pre-warm sidecar on welcome page (saves 800ms-2s startup) - Parallel listSessions + loadProviders, skip validateSession on happy path - Skeleton on mount during restore, hide ChatContent to prevent input flash - Error-path fallback distinguishes deleted vs transient failures - Move plan to tracked/done
…l + add provider API key flow plan Swap SlashCommandPopover from Radix Popover (portal-based, JS position recalc) to an absolutely-positioned div inside the input container. Eliminates frame lag on resize, adds integrated search bar with smooth scrolling, and refines item styling. Also adds the provider API key → model selection end-to-end flow plan.
…add upstream sync docs - Add State.reset() and Provider.reset() to invalidate cached provider state after auth mutations (API key save, OAuth, removal) - Call Provider.reset() in auth.ts, server.ts routes so frontend sees updated provider status immediately - Improve ProvidersSettings with loading spinner, inline errors, toast notifications, and proper async handling - Add upstream sync framework (CLAUDE.md, process docs, versioned diffs/plans for 1.2.26 and 1.2.27) - Add ProvidersSettings unit tests - Move completed plans to done, add rename-opencode-to-orbit plan
…o npm - Rename ~800 imports across ~230 files from @opencode-ai/* to @orbit.build/* - Rename packages/opencode-sdk → packages/orbit-sdk - Update tsconfig, vite, vitest path aliases - Fix config.ts type errors (empty object literal lacks index signature) - Add legacy @opencode-ai/plugin migration in installDependencies() - Publish @orbit.build/sdk@0.0.5 and @orbit.build/plugin@0.0.5 to npm (UNLICENSED) - Set package versions to 0.0.5, license to UNLICENSED - Rename remaining .opencode/ config references - Add docs/development/NPM-PUBLISH-GUIDE.md - Add npm_packages section to root CLAUDE.md - Move rename plan to tracked/done
Incorporates audit findings across 5 review rounds: - Add pure text-edit helpers (applyTextEdit, remapCommandStartIndex) - Replace flat sibling DOM traversal with recursive findBadgeLocation - Enforce full-token leading-only invariant via isDelimitedLeadingCommand - Add collapsed-selection guard on Backspace/Delete handlers - Add badge demotion in handleInputChange for runtime invariant repair - Add comprehensive test plan (helpers, DOM, hook, component levels)
Replace broken inline badge approach (contentEditable="false" fails in WKWebView) with a text overlay system: contentEditable stays plain text, a positioned overlay renders known /commands in blue (text-git-untracked). - Multi-command support: all known commands highlighted anywhere in text - leadingCommand state set on popover selection (flicker-free) - parseCommandSegments tokenizer for overlay rendering - Scroll sync between contentEditable and overlay - Remove ~300 lines of dead badge DOM code (rebuildInputDOM, findBadgeLocation, remapCommandStartIndex, applyTextEdit, etc.) - Revert chip approach changes (context-chips.tsx, context.ts) - Move 3 slash command plans to done
Wire OpenCode /compact through CompactIndicator instead of raw markdown, settle compaction after loadMessages to prevent flash, and rewrite token calculation to use last-assistant snapshot (matches reference app).
Add "How to Execute" sections to all 13 phase plans with concrete commands for copying files from upstream, applying patches, and deleting obsolete modules.
Major upstream migration bringing Effect dependency, branded ID system, account management, schema modules, and new database migrations. Removes deprecated .opencode config directory and old control module.
Introduce Lexical editor scaffolding for chat input, refactor use-chat-input to reduce complexity, and update tests to match new structure. Adds Lexical dependencies and Vite config aliases.
RAF-batch per-character SSE deltas into single Immer transactions per animation frame, reducing Zustand set() calls from ~400/sec to ~60/sec. Time-gate streaming reveal renders to ~80ms intervals and stabilize ThinkingBlock array references to prevent unnecessary re-renders.
CSP treated localhost and 127.0.0.1 as different origins, blocking all OpenCode API calls in production builds while Rust health checks passed. Adds contract test, updates CSP docs, marks plan as done.
…nter Extract visual/interaction logic from AskUserQuestionModal into a backend-agnostic QuestionPrompt component. Both Claude and OpenCode backends now render identical paginated question overlays while preserving their native answer contracts. - Create QuestionPrompt shared presenter with multi-select and allowCustom support - Refactor AskUserQuestionModal as thin Claude wrapper - Add OcQuestionModal as thin OpenCode wrapper (positional string[][]) - Fix keyboard shortcut conflict with isQuestionOverlayActive guard - Delete OcQuestionCard (replaced by shared presenter) - Add component tests for presenter, wrappers, and keyboard behavior
Move the "Workspaces" heading and worktree/workspace rows out of the scrollable conversation list into a shrink-0 section above the scroll container. Conversations now scroll independently while the workspace chrome stays visible — matching the existing pattern used by the search bar, tab heading, and action items. - Simplify ConversationList to conversation items only (removed 7 props) - Add capped worktree list (max-h-[160px]) with auto-scroll for active row - useLayoutEffect ensures active worktree visible on tab switch/hydration
Thinking blocks and content no longer stream in parallel. A single ordered frontier in useOcStreamingReveal sequences reveal per phase: thinking₁ → content₁ → thinking₂ → content₂. Later thinking blocks stay hidden until displayedContent reaches their contentOffset boundary. Preserves multi-phase interleaving, tool visibility, and legacy fallback.
…ted models - Wire ImageAttachment → FilePartInput through the OC adapter layer so images reach the OpenCode backend (was silently dropped at the adapter boundary) - Widen SDK overlay promptAsync.parts to accept FilePartInput union - Derive supportsImageInput from modalities.input/attachment per model - Disable image button with tooltip when selected model lacks vision support - Auto-clear image chips on model switch to unsupported model - Add send-time guard in OC adapter to strip images for non-vision models - Gate all shared-component logic with activeBackend === 'opencode'
Implement image attachment display as thumbnail tiles below chat messages, with fullscreen lightbox viewer, navigation, and broken-image fallback. SafeImage component converts data: URLs to opaque blob: URLs across all four rendering surfaces (tiles, lightbox, context chips, queued bubble) to prevent base64 data from leaking into the DOM. Includes Rust image cache, OpenCode adapter image support, and image-only message send path.
Migrate from flat model fields (attachment, modalities, reasoning) to nested capabilities object (capabilities.input.image, capabilities.reasoning). Extract resolveOcModelSupportsImageInput to shared function, make supportsImageInput required on OcProviderModel, and update SDK client types to match upstream API changes.
Comprehensive 6-phase plan to remove ~185 lint suppressions and upgrade ~83 Rust #[allow] to #[expect]. Passed 3 audit rounds covering platform- conditional lints, hashbrown sensitivity, and TUI override scoping.
Phase 1 — Config-level consolidation: - Add no-unsafe-return config block for TUI .tsx files (~150 comments removed) - Consolidate stress-test console suppressions to file-level (12→2) Phase 2 — Rust #[allow] → #[expect] conversion: - Convert ~24 allows to expects across crates/ and src-tauri/ - Discovered and removed 6 dead suppressions (needless_pass_by_value, too_many_lines no longer triggered) - Add reason strings to 12 decorum platform-conditional allows - Keep hashbrown-sensitive allows (terminal, LSP iter_over_hash_type) Phase 3 — LSP crate audit: - Convert 17 of 18 module-level allows to expects (all compile clean) - Keep iter_over_hash_type as allow (hashbrown-sensitive) Phase 4 — Orbit main TS fixes: - CanvasInputArea: replace console.log with structured logger, use params in stub handlers (removes 3 eslint-disable comments) - oc-message-store: replace 8 dynamic deletes with Reflect.deleteProperty (removes file-level eslint-disable) Phase 5 — Agent-backend targeted: - Create ambient declaration for @parcel/watcher/wrapper (eliminates @ts-ignore — the only banned suppression remaining) - Remove 3 eslint-disable comments from watcher.ts Phase 6 — Rust test standardization: already done via Phase 2 conversion. All checks pass: 1454 Vitest tests, 310 Rust tests, zero clippy warnings, zero ESLint warnings.
The .gitignore entry `SDK/` (meant for the top-level SDK docs folder) was case-insensitively matching `Agent-backend/packages/sdk/` on macOS (core.ignorecase=true), silently preventing those files from being committed. In CI (Linux, case-sensitive) the files simply didn't exist, breaking all tests that transitively import from @orbit.build/sdk. - Change `SDK/` to `/SDK/` so it only matches the root docs directory - Track Agent-backend/packages/sdk/ (SDK client library, 51 files) - Track Agent-backend/packages/opencode/src/provider/sdk/ (Copilot provider, 31 files) — also hidden by the same rule - Fix sdk .gitignore glob for .tgz files (/*.tgz → *.tgz)
The re-export from Agent-backend caused Vite to walk into the SDK's tsconfig.json which extends @tsconfig/node22 — a dependency not installed in the root workspace. Replace the re-export with a bun-bundled version (13 modules flattened into one file, zero imports) matching the existing self-contained client.d.ts pattern.
Tauri's build script requires all externalBin entries to exist. The orbit-server sidecar was added to tauri.conf.json but CI placeholder binaries were not updated to include it.
On Linux CI, macOS-only functions are compiled out so clippy::needless_pass_by_value never fires — causing unfulfilled-lint-expectations to error.
Summary
docs/plans/due/OPENCODE-MIGRATION-PLAN.mddocuments the full migration strategyWhat's included
Agent-backend/— Full opencode fork with TypeScript backend (HTTP + SSE), multi-provider AI support, and Bun-based toolingTest plan
cd Agent-backend && bun install && bun run build