You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Migrated Gemini provider to Antigravity (agy). The legacy Gemini CLI stopped serving requests on 2026-06-18. The backend now targets only the agy binary (Google's official successor). CLI args use role-based --mode flags: plan for the Mentor (read-only) and accept-edits for the Executor. Provider metadata (label, login command, install URL) updated throughout.
Updated READMEs (EN / ZH / JA / KO) to reference Antigravity instead of the sunset Gemini CLI.
Fixed
pair_resume now enforces strict status check. The command returns an error if the pair is not Paused or Awaiting Human Review. Previously, pairs in Error state could also be resumed via this path (a side effect of shared validation with pair_retry_turn).
Implemented
pair_retry_turn command — retries the current turn for pairs in Error, Paused, or Awaiting Human Review state. Bumps run_generation to invalidate stale handoffs from the failed turn.
pair_get_messages command — returns the full message history for a pair directly from MessageBroker.
Restored build/entitlements.mac.plist that was accidentally deleted in the 2.3.0 commit. Without this file, codesign fails with cannot read entitlement data, blocking all macOS release builds.
Deleted unused renderer components (OnboardingWizard, SessionRecoveryModal, ActivityIndicator, DashboardEmptyState, IntentChip, Versions, GlassCard) and hooks (useMinimumVisibleText, usePrevious) that were no longer referenced anywhere in the app.
Dropped unused runtime dependencies recharts, class-variance-authority, and geist, trimming install and bundle size.
Removed dead code: the AssignTaskInput/RecoverableSessionSummary types and renderer-side DetectedProviderProfile, the unused isUnlimitedIterations helper, orphaned Framer Motion variants, and stale CSS keyframes.
Changed
Tightened module encapsulation across lib/, store/, and types.ts by converting internal-only symbols from export to module-private.
Refactored the Rust backend with no behavior change: a bundled ActivityUpdate struct in message_broker.rs, strip_prefix-based checklist parsing in context_bridge.rs, and a shared TimedCache type alias in stubs.rs.
Documented the Pair Code terminal CLI in the README with a new "Choose Your Interface" section.
now_millis() no longer panics on pre-epoch clocks. A misconfigured system clock (VM resume, NTP correction) could crash the entire backend. Now uses unwrap_or_default().
Handoff events are no longer processed on errored pairs. The handoff guard now ignores events when a pair is in Error status, preventing unwanted agent turns on already-errored pairs.
retryTurn no longer causes unhandled promise rejections. Added proper try/catch with error state, matching all other store actions.
FileMention and SkillMention no longer leak setTimeout callbacks. Timer cleanup prevents React state updates on unmounted components.
SkillPicker no longer crashes in dev (non-Tauri) mode. Switched from raw invoke() to the window.api wrapper with runtime guards.
Mock API no longer returns mutable references.checkState and listBranches now return shallow copies, preventing callers from corrupting mock data.
Versions component handles getVersion() failures gracefully instead of leaving an unhandled rejection.
handleOpenConfig in OnboardingWizard catches errors instead of propagating unhandled rejections.
Provider inference matches future OpenAI model prefixes (o4, o5, …) via regex instead of hardcoded o1/o3 strings.
Eliminated 3 duplicate timestamp code paths in process_spawner.rs that each carried an independent .unwrap() panic risk; now all use the shared now_millis() utility.
Changed
Removed dead getRoleColors() helper (leftover from earlier design iteration).
Moved isMac/cmdKey to module-level constants in App.tsx (were recomputed on every render).
Removed unused isCompactLayout prop chain and associated viewport-height resize listener from OnboardingWizard.
Renamed files now show their diff. Git reports a rename as old -> new; the file tracker stored that entire string as the path, so clicking a renamed file showed "No changes to display". It now records the destination path and the diff resolves correctly.
Exported HTML reports sanitize agent output. The session-report export rendered model/agent markdown through an unsanitized converter, so raw <script> / <img onerror=…> markup or javascript: links in agent output could execute when the saved report was opened in a browser. Raw HTML is now escaped and script-bearing URL protocols are neutralized.
Activity stall monitor survives a backward clock jump. A wall-clock step backward (NTP correction, VM resume) could underflow the stall timer — reporting a bogus multi-century "stalled" warning, or panicking in debug builds and poisoning the shared state lock. Elapsed time is now computed with saturating subtraction.
Deleting a pair always clears its session snapshot. A repeated delete could return early and leave the snapshot orphaned on disk; cleanup now always runs.
Viewing task history no longer crashes when the pair was just deleted, and model loading no longer throws if the cached-models response is empty or not an array.
Acceptance cards no longer show "NaN%." A non-numeric confidence value is now rejected by the display fallback instead of rendering as NaN.
@file mentions no longer match path prefixes. Mentioning @lib/api-v2 no longer also attaches an unrelated @lib/api file whose path is a prefix of the mention.
Fixed stray React state updates and a leaked update listener when the file-mention, skill-mention, and recent-activity panels (or the app shell) unmount while an async load is still in flight.
Changed
Internal cleanups (no user-facing behavior change): extracted a unit-tested git status --porcelain parser, de-duplicated the model-resolution helpers, removed a dead diff branch, and hoisted a render-defined component to module scope. Adds 8 regression tests.
Plan-approval gate (human-in-the-loop review). A new per-pair toggle in the Create Pair modal pauses the workflow after the mentor's plan — before the executor starts — at an "Awaiting Human Review" checkpoint. A plan-review bar lets you Approve & start (releases the plan to the executor) or Send back with optional notes (the mentor re-plans, threading your feedback into the prompt). Your decision is recorded as a visible message in the conversation, a rejected plan re-plans rather than being mistaken for a review verdict, and the setting persists across restarts via session snapshots. If you navigate to an archived run while a plan is waiting, a banner offers a one-click return. Localized for English, Chinese, Japanese, and Korean.
Keyboard shortcuts cheat-sheet. Press Shift+? (or click the keyboard icon in the title bar) to open a lightweight overlay listing every active shortcut with its platform-aware key combo. Shortcut descriptions are localized (English, Japanese, Korean, Chinese). A new formatShortcutParts helper renders each modifier and key as a separate <kbd> token, and symbol keys like ? no longer show a redundant ⇧ prefix.
Provider Sign In and Install guidance in onboarding. When a CLI tool is installed but not authenticated — or not installed at all — the first-run onboarding screen now shows a per-provider card with a one-click Sign In button (opens a terminal running the provider's login command) or an Install button (opens the download page). The Provider trait gained login_command() and install_url() methods, each implemented for Claude Code, Codex, Gemini (agy / legacy aware), and OpenCode. A new provider_launch_login Tauri command opens the system terminal cross-platform (Terminal.app on macOS, gnome-terminal/konsole/xterm on Linux, cmd on Windows).
Auth-missing hint in the model picker. When a provider has models locked behind authentication, the picker now shows a compact "N more models available after signing in" row with an inline Sign In link, so users discover hidden models without leaving the picker.
Conversation feed is now a single left-aligned column. Mentor and executor turns previously sat on opposite sides as left/right chat bubbles; they now share one left-aligned column distinguished by a role-colored left accent border (mentor / executor / human). Long, mixed transcripts read more clearly and stay legible on narrow windows.
Provider backend refactored into a Provider trait (internal). Per-provider behavior — CLI args, token extraction, detection, and model metadata — for opencode, Codex, Claude Code, and Gemini moved out of process_spawner/provider_adapter into dedicated modules under src-tauri/src/providers/, with provider_adapter kept as a thin compatibility facade. No user-facing behavior change; adding a provider is now a self-contained module.
Fixed
Updating a pair's model now sends the bare model ID the CLI expects. The picker uses qualified IDs such as claude/claude-haiku-4-5; applying a model change to an existing pair now strips the claude/codex/gemini prefix before it reaches the backend (OpenCode provider/model IDs are left intact), preventing a mismatched or unrecognized ID on model swaps.
Onboarding shows the current brand icon. The first-run onboarding header displayed the retired icon; it now uses the current robots logo, matching the app icon and README.
Removed
Orphaned old-brand icon assets (build/icon.*, resources/icon.png, resources/the-pair-icon-1.png) and the unused scripts/generate-ico.cjs helper.
Unified model picker that merges routes. The same model reachable through more than one route — a native CLI and OpenCode, or different plans/keys — now collapses into a single entry in the picker instead of appearing as near-duplicate rows. Selecting a multi-route model reveals a nested route sub-picker so you choose how to run it (e.g. "Claude Code login" vs "OpenAI API key"), and the last route you used for each role is remembered. Merging is driven by a backend canonicalKey (brand::normalized-model, with provider prefixes and trailing date stamps stripped), so claude-sonnet-4-5 and claude-sonnet-4-5-20250929 collapse onto one entry while genuinely different versions (4-5 vs 4-6) stay apart. When there's no remembered route, plan-included native routes are preferred over pay-as-you-go OpenCode so you don't accidentally spend on an API key.
Keyboard focus rings. A crisp accent ring now appears for keyboard and assistive-tech navigation (:focus-visible) on buttons, links, and list rows that previously had no focus affordance; pointer clicks stay ring-free.
Animated, accessible modals.GlassModal and ConfirmModal now animate in (honoring prefers-reduced-motion) and expose proper role="dialog", aria-modal, and aria-label.
Changed
Reasoning effort is now inline and route-aware. The effort control lives inside the model picker as a segmented selector sourced from the currently selected route, replacing the standalone picker. Antigravity bakes effort into the model name ("Gemini 3.5 Flash (Low/Medium/High)"), so those rows now collapse onto one model with the effort offered as a sub-control; Codex o-series still passes effort through as a runtime flag. Medium is the default when a route exposes the axis.
Acceptance verdict and next action are now independent axes. A mentor's verdict ("pass"/"fail") judges the executor's latest output, while nextStep.action ("continue"/"finish") tracks whether the whole task is done. Previously a "pass" was forced to pair with "finish", which derailed multi-step tasks — a correct intermediate step had to be mislabeled "fail" just to keep the loop running. A good step with work remaining is now legitimately "pass" + "continue" with the next instructions; "fail" + "finish" is still rejected (it would leave the loop with no actionable next turn). The mentor prompt explains the two axes, and the console now renders whatever structured verdict the mentor produced instead of falling back to raw JSON on a contract mismatch.
OpenCode model list is de-noised. OpenCode mirrors the entire models.dev catalog plus any provider you hold a key for; unauthenticated rows you can't actually run are now filtered out so they no longer bury the native providers. A model offered by both a native CLI and OpenCode is no longer dropped — both routes survive and merge into one picker entry (see above). Native CLIs still surface their unavailable rows so you can see why an installed CLI isn't usable yet.
Removed
Standalone ReasoningEffortPicker component. Reasoning effort is now part of the model picker itself, sourced from the selected route.